Skip to content

Commit ea9d3cc

Browse files
scheglovCommit Queue
authored andcommitted
DeCo. Report nonRedirectingGenerativeConstructorWithPrimary
Bug: #61701 Change-Id: Ie6f221be25b3029a60de4960be8307930358314c Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/464244 Reviewed-by: Brian Wilkerson <[email protected]> Commit-Queue: Konstantin Shcheglov <[email protected]> Reviewed-by: Paul Berry <[email protected]>
1 parent 7b422f4 commit ea9d3cc

File tree

7 files changed

+168
-0
lines changed

7 files changed

+168
-0
lines changed

pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1277,6 +1277,8 @@ NON_GENERATIVE_IMPLICIT_CONSTRUCTOR:
12771277
status: needsFix
12781278
notes: |-
12791279
Suggest generative constructors that could be invoked.
1280+
NON_REDIRECTING_GENERATIVE_CONSTRUCTOR_WITH_PRIMARY:
1281+
status: needsEvaluation
12801282
NON_SYNC_FACTORY:
12811283
status: needsFix
12821284
notes: |-

pkg/analyzer/lib/src/diagnostic/diagnostic.g.dart

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12280,6 +12280,22 @@ const DiagnosticWithoutArguments nonPositiveArrayDimension =
1228012280
expectedTypes: [],
1228112281
);
1228212282

12283+
/// No parameters.
12284+
const DiagnosticWithoutArguments
12285+
nonRedirectingGenerativeConstructorWithPrimary = DiagnosticWithoutArgumentsImpl(
12286+
name: 'NON_REDIRECTING_GENERATIVE_CONSTRUCTOR_WITH_PRIMARY',
12287+
problemMessage:
12288+
"Classes with primary constructors can't have non-redirecting generative "
12289+
"constructors.",
12290+
correctionMessage:
12291+
"Try making the constructor redirect to the primary constructor, or "
12292+
"remove the primary constructor.",
12293+
type: DiagnosticType.COMPILE_TIME_ERROR,
12294+
uniqueName:
12295+
'CompileTimeErrorCode.NON_REDIRECTING_GENERATIVE_CONSTRUCTOR_WITH_PRIMARY',
12296+
expectedTypes: [],
12297+
);
12298+
1228312299
/// A code indicating that the activity is set to be non resizable.
1228412300
///
1228512301
/// No parameters.

pkg/analyzer/lib/src/diagnostic/diagnostic_code_values.g.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -797,6 +797,7 @@ const List<DiagnosticCode> diagnosticCodeValues = [
797797
diag.nonNullableEqualsParameter,
798798
diag.nonPartOfDirectiveInPart,
799799
diag.nonPositiveArrayDimension,
800+
diag.nonRedirectingGenerativeConstructorWithPrimary,
800801
diag.nonResizableActivity,
801802
diag.nonSizedTypeArgument,
802803
diag.nonStringLiteralAsUri,

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

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -640,6 +640,7 @@ class ErrorVerifier extends RecursiveAstVisitor<void>
640640
}
641641
_checkForUndefinedConstructorInInitializerImplicit(node);
642642
_checkForReturnInGenerativeConstructor(node);
643+
_checkForNonRedirectingGenerativeConstructorWithPrimary(node);
643644
super.visitConstructorDeclaration(node);
644645
},
645646
isAsynchronous: fragment.isAsynchronous,
@@ -4688,6 +4689,27 @@ class ErrorVerifier extends RecursiveAstVisitor<void>
46884689
);
46894690
}
46904691

4692+
void _checkForNonRedirectingGenerativeConstructorWithPrimary(
4693+
ConstructorDeclaration node,
4694+
) {
4695+
var enclosingClass = _enclosingClass;
4696+
if (enclosingClass == null ||
4697+
enclosingClass is ExtensionTypeElement ||
4698+
enclosingClass.constructors.none((c) => c.isPrimary)) {
4699+
return;
4700+
}
4701+
4702+
if (node.factoryKeyword != null ||
4703+
node.initializers.any((i) => i is RedirectingConstructorInvocation)) {
4704+
return;
4705+
}
4706+
4707+
diagnosticReporter.atConstructorDeclaration(
4708+
node,
4709+
diag.nonRedirectingGenerativeConstructorWithPrimary,
4710+
);
4711+
}
4712+
46914713
/// Verify that the given method [declaration] of operator `[]=`, has `void`
46924714
/// return type.
46934715
///

pkg/analyzer/messages.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12134,6 +12134,11 @@ CompileTimeErrorCode:
1213412134

1213512135
class B implements A {}
1213612136
```
12137+
NON_REDIRECTING_GENERATIVE_CONSTRUCTOR_WITH_PRIMARY:
12138+
parameters: none
12139+
problemMessage: "Classes with primary constructors can't have non-redirecting generative constructors."
12140+
correctionMessage: "Try making the constructor redirect to the primary constructor, or remove the primary constructor."
12141+
hasPublishedDocs: false
1213712142
NON_SYNC_FACTORY:
1213812143
parameters: none
1213912144
problemMessage: "Factory bodies can't use 'async', 'async*', or 'sync*'."
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
// Copyright (c) 2025, 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/diagnostic/diagnostic.dart' as diag;
6+
import 'package:test_reflective_loader/test_reflective_loader.dart';
7+
8+
import '../dart/resolution/context_collection_resolution.dart';
9+
10+
main() {
11+
defineReflectiveSuite(() {
12+
defineReflectiveTests(NonRedirectingGenerativeConstructorWithPrimaryTest);
13+
});
14+
}
15+
16+
@reflectiveTest
17+
class NonRedirectingGenerativeConstructorWithPrimaryTest
18+
extends PubPackageResolutionTest {
19+
test_class_factory() async {
20+
await assertNoErrorsInCode(r'''
21+
class C(int x) {
22+
factory C.named() => C(0);
23+
}
24+
''');
25+
}
26+
27+
test_class_generative_nonRedirecting() async {
28+
await assertErrorsInCode(
29+
r'''
30+
class C(int x) {
31+
C.named();
32+
}
33+
''',
34+
[error(diag.nonRedirectingGenerativeConstructorWithPrimary, 19, 7)],
35+
);
36+
}
37+
38+
test_class_generative_redirectingToNonPrimary() async {
39+
await assertErrorsInCode(
40+
r'''
41+
class C(int x) {
42+
C.named1() : this.named2();
43+
C.named2();
44+
}
45+
''',
46+
[error(diag.nonRedirectingGenerativeConstructorWithPrimary, 49, 8)],
47+
);
48+
}
49+
50+
test_class_generative_redirectingToPrimary() async {
51+
await assertNoErrorsInCode(r'''
52+
class C(int x) {
53+
C.named() : this(0);
54+
}
55+
''');
56+
}
57+
58+
test_class_noPrimaryConstructor() async {
59+
await assertNoErrorsInCode(r'''
60+
class C {
61+
C.named();
62+
}
63+
''');
64+
}
65+
66+
test_enum_factory() async {
67+
await assertNoErrorsInCode(r'''
68+
enum E(int x) {
69+
v(0);
70+
factory E.named() => E.v;
71+
}
72+
''');
73+
}
74+
75+
test_enum_generative_nonRedirecting() async {
76+
await assertErrorsInCode(
77+
r'''
78+
enum E(int x) {
79+
v(0);
80+
const E.named();
81+
}
82+
''',
83+
[
84+
error(diag.nonRedirectingGenerativeConstructorWithPrimary, 32, 7),
85+
error(diag.unusedElement, 34, 5),
86+
],
87+
);
88+
}
89+
90+
test_enum_generative_redirectingToPrimary() async {
91+
await assertErrorsInCode(
92+
r'''
93+
enum E(int x) {
94+
v(0);
95+
const E.named(int x) : this(x);
96+
}
97+
''',
98+
[error(diag.unusedElement, 34, 5)],
99+
);
100+
}
101+
102+
test_enum_noPrimaryConstructor() async {
103+
await assertNoErrorsInCode(r'''
104+
enum E {
105+
v;
106+
const E();
107+
}
108+
''');
109+
}
110+
111+
test_extensionType_generative_nonRedirecting() async {
112+
// Extension types can have non-redirecting generative constructors.
113+
await assertNoErrorsInCode(r'''
114+
extension type E(int x) {
115+
E.named(this.x);
116+
}
117+
''');
118+
}
119+
}

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -672,6 +672,8 @@ import 'non_native_function_type_argument_to_pointer_test.dart'
672672
as non_native_function_type_argument_to_pointer;
673673
import 'non_nullable_equals_parameter_test.dart' as non_null_equals_parameters;
674674
import 'non_positive_array_dimension_test.dart' as non_positive_array_dimension;
675+
import 'non_redirecting_generative_constructor_with_primary_test.dart'
676+
as non_redirecting_generative_constructor_with_primary;
675677
import 'non_sized_type_argument_test.dart' as non_sized_type_argument;
676678
import 'non_type_as_type_argument_test.dart' as non_type_as_type_argument;
677679
import 'non_type_in_catch_clause_test.dart' as non_type_in_catch_clause;
@@ -1384,6 +1386,7 @@ main() {
13841386
non_native_function_type_argument_to_pointer.main();
13851387
non_null_equals_parameters.main();
13861388
non_positive_array_dimension.main();
1389+
non_redirecting_generative_constructor_with_primary.main();
13871390
non_sized_type_argument.main();
13881391
non_type_as_type_argument.main();
13891392
non_type_in_catch_clause.main();

0 commit comments

Comments
 (0)