Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit e0164ec

Browse files
MichaelRFairhurstcommit-bot@chromium.org
authored andcommitted
[analyzer] Fix #25874, confusing error for extending Exception.
In the case of extending Exception, the raised error is around the configuration of the constructors. However, there is no valid configuration of constructors to be found, and therefore, the better user facing message is to say that the class cannot be extended as written. Change-Id: I5950d438877c450c44cdc914f9f20d7779a64768 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/154126 Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
1 parent 22b05db commit e0164ec

File tree

7 files changed

+164
-6
lines changed

7 files changed

+164
-6
lines changed

pkg/analyzer/lib/error/error.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,7 @@ const List<ErrorCode> errorCodeValues = [
293293
CompileTimeErrorCode.NO_COMBINED_SUPER_SIGNATURE,
294294
CompileTimeErrorCode.NO_DEFAULT_SUPER_CONSTRUCTOR_EXPLICIT,
295295
CompileTimeErrorCode.NO_DEFAULT_SUPER_CONSTRUCTOR_IMPLICIT,
296+
CompileTimeErrorCode.NO_GENERATIVE_CONSTRUCTORS_IN_SUPERCLASS,
296297
CompileTimeErrorCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_FIVE_PLUS,
297298
CompileTimeErrorCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_FOUR,
298299
CompileTimeErrorCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_ONE,

pkg/analyzer/lib/src/error/codes.dart

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5904,6 +5904,21 @@ class CompileTimeErrorCode extends AnalyzerErrorCode {
59045904
correction: "Try declaring a zero argument constructor in '{0}', or "
59055905
"explicitly invoking a different constructor in '{0}'.");
59065906

5907+
/**
5908+
* User friendly specialized error for [NON_GENERATIVE_CONSTRUCTOR]. This
5909+
* handles the case of `class E extends Exception` which will never work
5910+
* because [Exception] has no generative constructors.
5911+
*/
5912+
static const CompileTimeErrorCode NO_GENERATIVE_CONSTRUCTORS_IN_SUPERCLASS =
5913+
CompileTimeErrorCode(
5914+
'NO_GENERATIVE_CONSTRUCTOR_IN_SUPERCLASS',
5915+
"The class '{0}' cannot extend '{1}' because '{1}' only has factory"
5916+
" constructors (no generative constructors), and '{0}' has at"
5917+
' least one generative constructor.',
5918+
correction: 'Try implementing the class instead, adding a generative'
5919+
" (not factory) constructor to the superclass {0}, or a factory"
5920+
' constructor to the subclass.');
5921+
59075922
/**
59085923
* Parameters:
59095924
* 0: the name of the superclass that does not define an implicitly invoked

pkg/analyzer/lib/src/generated/element_resolver.dart

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -787,7 +787,10 @@ class ElementResolver extends SimpleAstVisitor<void> {
787787
}
788788
return;
789789
} else {
790-
if (element.isFactory) {
790+
if (element.isFactory &&
791+
// Check if we've reported [NO_GENERATIVE_CONSTRUCTORS_IN_SUPERCLASS].
792+
!element.enclosingElement.constructors
793+
.every((constructor) => constructor.isFactory)) {
791794
_errorReporter.reportErrorForNode(
792795
CompileTimeErrorCode.NON_GENERATIVE_CONSTRUCTOR, node, [element]);
793796
}

pkg/analyzer/lib/src/generated/error_verifier.dart

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -401,7 +401,6 @@ class ErrorVerifier extends RecursiveAstVisitor<void> {
401401
_duplicateDefinitionVerifier.checkClass(node);
402402
_checkForBuiltInIdentifierAsName(
403403
node.name, CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_TYPE_NAME);
404-
_checkForNoDefaultSuperConstructorImplicit(node);
405404
_checkForConflictingClassTypeVariableErrorCodes();
406405
TypeName superclass = node.extendsClause?.superclass;
407406
ImplementsClause implementsClause = node.implementsClause;
@@ -1250,7 +1249,8 @@ class ErrorVerifier extends RecursiveAstVisitor<void> {
12501249
// class.
12511250
if (!_checkForExtendsDisallowedClass(superclass) &&
12521251
!_checkForImplementsClauseErrorCodes(implementsClause) &&
1253-
!_checkForAllMixinErrorCodes(withClause)) {
1252+
!_checkForAllMixinErrorCodes(withClause) &&
1253+
!_checkForNoGenerativeConstructorsInSuperclass(superclass)) {
12541254
_checkForImplicitDynamicType(superclass);
12551255
_checkForExtendsDeferredClass(superclass);
12561256
_checkForRepeatedType(implementsClause?.interfaces,
@@ -1260,6 +1260,9 @@ class ErrorVerifier extends RecursiveAstVisitor<void> {
12601260
_checkMixinInference(node, withClause);
12611261
_checkForMixinWithConflictingPrivateMember(withClause, superclass);
12621262
_checkForConflictingGenerics(node);
1263+
if (node is ClassDeclaration) {
1264+
_checkForNoDefaultSuperConstructorImplicit(node);
1265+
}
12631266
}
12641267
}
12651268

@@ -3421,6 +3424,35 @@ class ErrorVerifier extends RecursiveAstVisitor<void> {
34213424
}
34223425
}
34233426

3427+
bool _checkForNoGenerativeConstructorsInSuperclass(TypeName superclass) {
3428+
InterfaceType superType = _enclosingClass.supertype;
3429+
if (superType == null) {
3430+
return false;
3431+
}
3432+
if (_enclosingClass.constructors
3433+
.every((constructor) => constructor.isFactory)) {
3434+
// A class with no generative constructors *can* be extended if the
3435+
// subclass has only factory constructors.
3436+
return false;
3437+
}
3438+
ClassElement superElement = superType.element;
3439+
if (superElement.constructors.isEmpty) {
3440+
// Exclude empty constructor set, which indicates other errors occurred.
3441+
return false;
3442+
}
3443+
if (superElement.constructors
3444+
.every((constructor) => constructor.isFactory)) {
3445+
// For `E extends Exception`, etc., this will never work, because it has
3446+
// no generative constructors. State this clearly to users.
3447+
_errorReporter.reportErrorForNode(
3448+
CompileTimeErrorCode.NO_GENERATIVE_CONSTRUCTORS_IN_SUPERCLASS,
3449+
superclass,
3450+
[_enclosingClass.name, superElement.name]);
3451+
return true;
3452+
}
3453+
return false;
3454+
}
3455+
34243456
/// Verify the given map [literal] either:
34253457
/// * has `const modifier`
34263458
/// * has explicit type arguments
@@ -4155,6 +4187,11 @@ class ErrorVerifier extends RecursiveAstVisitor<void> {
41554187
return;
41564188
}
41574189
ClassElement superElement = superType.element;
4190+
if (superElement.constructors
4191+
.every((constructor) => constructor.isFactory)) {
4192+
// Already reported [NO_GENERATIVE_CONSTRUCTORS_IN_SUPERCLASS].
4193+
return;
4194+
}
41584195
ConstructorElement superUnnamedConstructor =
41594196
superElement.unnamedConstructor;
41604197
if (superUnnamedConstructor != null) {
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
import 'package:analyzer/src/error/codes.dart';
6+
import 'package:test_reflective_loader/test_reflective_loader.dart';
7+
8+
import '../dart/resolution/driver_resolution.dart';
9+
10+
main() {
11+
defineReflectiveSuite(() {
12+
defineReflectiveTests(NoGenerativeConstructorsInSuperclassTest);
13+
});
14+
}
15+
16+
@reflectiveTest
17+
class NoGenerativeConstructorsInSuperclassTest extends DriverResolutionTest {
18+
test_explicit() async {
19+
await assertErrorsInCode(r'''
20+
class A {
21+
factory A() => throw '';
22+
}
23+
class B extends A {
24+
B() : super();
25+
}
26+
''', [
27+
error(
28+
CompileTimeErrorCode.NO_GENERATIVE_CONSTRUCTORS_IN_SUPERCLASS, 55, 1),
29+
]);
30+
}
31+
32+
test_explicit_oneFactory() async {
33+
await assertErrorsInCode(r'''
34+
class A {
35+
factory A() => throw '';
36+
}
37+
class B extends A {
38+
B() : super();
39+
factory B.second() => throw '';
40+
}
41+
''', [
42+
error(
43+
CompileTimeErrorCode.NO_GENERATIVE_CONSTRUCTORS_IN_SUPERCLASS, 55, 1),
44+
]);
45+
}
46+
47+
test_hasFactories() async {
48+
await assertNoErrorsInCode(r'''
49+
class A {
50+
factory A() => throw '';
51+
}
52+
class B extends A {
53+
factory B() => throw '';
54+
factory B.second() => throw '';
55+
}
56+
''');
57+
}
58+
59+
test_hasFactory() async {
60+
await assertNoErrorsInCode(r'''
61+
class A {
62+
factory A() => throw '';
63+
}
64+
class B extends A {
65+
factory B() => throw '';
66+
}
67+
''');
68+
}
69+
70+
test_implicit() async {
71+
await assertErrorsInCode(r'''
72+
class A {
73+
factory A() => throw '';
74+
}
75+
class B extends A {
76+
B();
77+
}
78+
''', [
79+
error(
80+
CompileTimeErrorCode.NO_GENERATIVE_CONSTRUCTORS_IN_SUPERCLASS, 55, 1),
81+
]);
82+
}
83+
84+
test_implicit2() async {
85+
await assertErrorsInCode(r'''
86+
class A {
87+
factory A() => throw '';
88+
}
89+
class B extends A {
90+
}
91+
''', [
92+
error(
93+
CompileTimeErrorCode.NO_GENERATIVE_CONSTRUCTORS_IN_SUPERCLASS, 55, 1),
94+
]);
95+
}
96+
}

pkg/analyzer/test/src/diagnostics/non_generative_constructor_test.dart

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,13 @@ class NonGenerativeConstructorTest extends DriverResolutionTest {
1919
await assertErrorsInCode(r'''
2020
class A {
2121
factory A.named() => throw 0;
22+
A.generative();
2223
}
2324
class B extends A {
2425
B() : super.named();
2526
}
2627
''', [
27-
error(CompileTimeErrorCode.NON_GENERATIVE_CONSTRUCTOR, 72, 13),
28+
error(CompileTimeErrorCode.NON_GENERATIVE_CONSTRUCTOR, 90, 13),
2829
]);
2930
}
3031

@@ -56,24 +57,26 @@ class B extends A {
5657
await assertErrorsInCode(r'''
5758
class A {
5859
factory A() => throw 0;
60+
A.named();
5961
}
6062
class B extends A {
6163
B();
6264
}
6365
''', [
64-
error(CompileTimeErrorCode.NON_GENERATIVE_CONSTRUCTOR, 60, 1),
66+
error(CompileTimeErrorCode.NON_GENERATIVE_CONSTRUCTOR, 73, 1),
6567
]);
6668
}
6769

6870
test_implicit2() async {
6971
await assertErrorsInCode(r'''
7072
class A {
7173
factory A() => throw 0;
74+
A.named();
7275
}
7376
class B extends A {
7477
}
7578
''', [
76-
error(CompileTimeErrorCode.NON_GENERATIVE_CONSTRUCTOR, 44, 1),
79+
error(CompileTimeErrorCode.NON_GENERATIVE_CONSTRUCTOR, 57, 1),
7780
]);
7881
}
7982
}

pkg/analyzer/test/src/diagnostics/test_all.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,8 @@ import 'no_annotation_constructor_arguments_test.dart'
380380
as no_annotation_constructor_arguments;
381381
import 'no_combined_super_signature_test.dart' as no_combined_super_signature;
382382
import 'no_default_super_constructor_test.dart' as no_default_super_constructor;
383+
import 'no_generative_constructors_in_superclass_test.dart'
384+
as no_generative_constructors_in_superclass;
383385
import 'non_abstract_class_inherits_abstract_member_test.dart'
384386
as non_abstract_class_inherits_abstract_member;
385387
import 'non_bool_condition_test.dart' as non_bool_condition;
@@ -872,6 +874,7 @@ main() {
872874
no_annotation_constructor_arguments.main();
873875
no_combined_super_signature.main();
874876
no_default_super_constructor.main();
877+
no_generative_constructors_in_superclass.main();
875878
non_abstract_class_inherits_abstract_member.main();
876879
non_bool_condition.main();
877880
non_bool_expression.main();

0 commit comments

Comments
 (0)