diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart index ca48bce9d03..cc47becf9d6 100644 --- a/pkg/analyzer/lib/src/generated/error_verifier.dart +++ b/pkg/analyzer/lib/src/generated/error_verifier.dart @@ -6141,63 +6141,51 @@ class ErrorVerifier extends RecursiveAstVisitor } void _checkForValidField(FieldFormalParameter parameter) { - var parent2 = parameter.parent?.parent; - if (parent2 is! ConstructorDeclaration && - parent2?.parent is! ConstructorDeclaration) { + var constructor = parameter.parentFormalParameterList.parent; + if (constructor is PrimaryConstructorDeclaration && + constructor.parent is ExtensionTypeDeclaration) { return; } + if (constructor is! ConstructorDeclaration && + constructor is! PrimaryConstructorDeclaration) { + return; + } + var element = parameter.declaredFragment?.element; - if (element is FieldFormalParameterElementImpl) { - var fieldElement = element.field; - if (fieldElement == null || fieldElement.isOriginGetterSetter) { - diagnosticReporter.report( - diag.initializingFormalForNonExistentField - .withArguments(formalName: parameter.name.lexeme) - .at(parameter), - ); - } else { - var parameterElement = parameter.declaredFragment?.element; - if (parameterElement is FieldFormalParameterElementImpl) { - var declaredType = parameterElement.type; - var fieldType = fieldElement.type; - if (fieldElement.isOriginGetterSetter) { - diagnosticReporter.report( - diag.initializingFormalForNonExistentField - .withArguments(formalName: parameter.name.lexeme) - .at(parameter), - ); - } else if (fieldElement.isStatic) { - diagnosticReporter.report( - diag.initializerForStaticField - .withArguments(formalName: parameter.name.lexeme) - .at(parameter), - ); - } else if (!typeSystem.isSubtypeOf(declaredType, fieldType)) { - diagnosticReporter.report( - diag.fieldInitializingFormalNotAssignable - .withArguments( - formalParameterType: declaredType, - fieldType: fieldType, - ) - .at(parameter), - ); - } - } else { - if (fieldElement.isOriginGetterSetter) { - diagnosticReporter.report( - diag.initializingFormalForNonExistentField - .withArguments(formalName: parameter.name.lexeme) - .at(parameter), - ); - } else if (fieldElement.isStatic) { - diagnosticReporter.report( - diag.initializerForStaticField - .withArguments(formalName: parameter.name.lexeme) - .at(parameter), - ); - } - } - } + if (element is! FieldFormalParameterElementImpl) { + return; + } + + var fieldElement = element.field; + if (fieldElement == null || fieldElement.isOriginGetterSetter) { + diagnosticReporter.report( + diag.initializingFormalForNonExistentField + .withArguments(formalName: parameter.name.lexeme) + .at(parameter), + ); + return; + } + + if (fieldElement.isStatic) { + diagnosticReporter.report( + diag.initializerForStaticField + .withArguments(formalName: parameter.name.lexeme) + .at(parameter), + ); + return; + } + + var elementType = element.type; + var fieldType = fieldElement.type; + if (!typeSystem.isSubtypeOf(elementType, fieldType)) { + diagnosticReporter.report( + diag.fieldInitializingFormalNotAssignable + .withArguments( + formalParameterType: elementType, + fieldType: fieldType, + ) + .at(parameter), + ); } // else { // TODO(jwren): Report error, constructor initializer variable is a top level element diff --git a/pkg/analyzer/test/src/dart/constant/evaluation_test.dart b/pkg/analyzer/test/src/dart/constant/evaluation_test.dart index eb7227ed6c2..8a5a3a18c7c 100644 --- a/pkg/analyzer/test/src/dart/constant/evaluation_test.dart +++ b/pkg/analyzer/test/src/dart/constant/evaluation_test.dart @@ -6431,7 +6431,10 @@ class const A(this.x) { const a = A(1); ''', - [error(diag.initializerForNonExistentField, 33, 5)], + [ + error(diag.initializingFormalForNonExistentField, 14, 6), + error(diag.initializerForNonExistentField, 33, 5), + ], ); assertDartObjectText(_topLevelVar('a'), r''' A diff --git a/pkg/analyzer/test/src/diagnostics/initializer_for_static_field_test.dart b/pkg/analyzer/test/src/diagnostics/initializer_for_static_field_test.dart index 502fcf91ea8..f8740e3557d 100644 --- a/pkg/analyzer/test/src/diagnostics/initializer_for_static_field_test.dart +++ b/pkg/analyzer/test/src/diagnostics/initializer_for_static_field_test.dart @@ -15,7 +15,18 @@ main() { @reflectiveTest class InitializerForStaticFieldTest extends PubPackageResolutionTest { - test_fieldFormalParameter() async { + test_class_primaryConstructor_fieldFormalParameter() async { + await assertErrorsInCode( + r''' +class A(this.x) { + static int? x; +} +''', + [error(diag.initializerForStaticField, 8, 6)], + ); + } + + test_class_secondaryConstructor_fieldFormalParameter() async { await assertErrorsInCode( r''' class A { @@ -27,7 +38,7 @@ class A { ); } - test_initializer() async { + test_class_secondaryConstructor_initializerList() async { await assertErrorsInCode( r''' class A { @@ -40,4 +51,82 @@ class A { ], ); } + + test_enum_primaryConstructor_fieldFormalParameter() async { + await assertErrorsInCode( + r''' +enum E(this.x) { + v(0); + + static int? x; +} +''', + [error(diag.initializerForStaticField, 7, 6)], + ); + } + + test_enum_secondaryConstructor_fieldFormalParameter() async { + await assertErrorsInCode( + r''' +enum E { + v(0); + static int x = 0; + const E(this.x); +} +''', + [error(diag.initializerForStaticField, 47, 6)], + ); + } + + test_enum_secondaryConstructor_initializerList() async { + await assertErrorsInCode( + r''' +enum E { + v; + static int x = 1; + const E() : x = 0; +} +''', + [ + error(diag.initializerForStaticField, 48, 5, messageContains: ["'x'"]), + ], + ); + } + + test_extensionType_primaryConstructor_fieldFormalParameter_notReportedHere() async { + await assertErrorsInCode( + r''' +extension type E(this.x) { + static int? x; +} +''', + [error(diag.expectedRepresentationField, 17, 4)], + ); + } + + test_extensionType_secondaryConstructor_fieldFormalParameter() async { + await assertErrorsInCode( + r''' +extension type E(int it) { + static int x = 0; + E.named(this.x) : this.it = 0; +} +''', + [error(diag.initializerForStaticField, 57, 6)], + ); + } + + test_extensionType_secondaryConstructor_initializerList() async { + await assertErrorsInCode( + r''' +extension type E(int it) { + static int x = 1; + E.named() : x = 0, this.it = 0; +} +''', + [ + error(diag.initializerForStaticField, 61, 5, messageContains: ["'x'"]), + ], + ); + } } diff --git a/pkg/analyzer/test/src/diagnostics/initializing_formal_for_non_existent_field_test.dart b/pkg/analyzer/test/src/diagnostics/initializing_formal_for_non_existent_field_test.dart index e38f4422f33..c7d033bb232 100644 --- a/pkg/analyzer/test/src/diagnostics/initializing_formal_for_non_existent_field_test.dart +++ b/pkg/analyzer/test/src/diagnostics/initializing_formal_for_non_existent_field_test.dart @@ -16,7 +16,33 @@ main() { @reflectiveTest class InitializingFormalForNonExistentFieldTest extends PubPackageResolutionTest { - test_class_nonExistent() async { + test_class_primary_fieldExists() async { + await assertNoErrorsInCode(r''' +class C(this.x) { + final int x; +} +'''); + } + + test_class_primary_fieldMissing() async { + await assertErrorsInCode( + r''' +class C(this.x) {} +''', + [error(diag.initializingFormalForNonExistentField, 8, 6)], + ); + } + + test_class_secondary_fieldExists() async { + await assertNoErrorsInCode(r''' +class C { + final int x; + C(this.x); +} +'''); + } + + test_class_secondary_fieldMissing() async { await assertErrorsInCode( r''' class A { @@ -27,7 +53,19 @@ class A { ); } - test_class_notInEnclosingClass() async { + test_class_secondary_fieldMissing_getter() async { + await assertErrorsInCode( + r''' +class A { + int get x => 1; + A(this.x) {} +} +''', + [error(diag.initializingFormalForNonExistentField, 32, 6)], + ); + } + + test_class_secondary_notInEnclosingClass() async { await assertErrorsInCode( r''' class A { @@ -41,7 +79,7 @@ class B extends A { ); } - test_class_optional() async { + test_class_secondary_optionalPositional_fieldMissing() async { await assertErrorsInCode( r''' class A { @@ -52,19 +90,28 @@ class A { ); } - test_class_synthetic() async { + test_enum_primary_fieldExists() async { + await assertNoErrorsInCode(r''' +enum E(this.x) { + v(0); + + final int x; +} +'''); + } + + test_enum_primary_fieldMissing() async { await assertErrorsInCode( r''' -class A { - int get x => 1; - A(this.x) {} +enum E(this.x) { + v(0); } ''', - [error(diag.initializingFormalForNonExistentField, 32, 6)], + [error(diag.initializingFormalForNonExistentField, 7, 6)], ); } - test_enum_existing() async { + test_enum_secondary_fieldExists() async { await assertNoErrorsInCode(r''' enum E { v(0); @@ -74,7 +121,32 @@ enum E { '''); } - test_enum_optional() async { + test_enum_secondary_fieldMissing() async { + await assertErrorsInCode( + r''' +enum E { + v(0); + const E(this.x); +} +''', + [error(diag.initializingFormalForNonExistentField, 27, 6)], + ); + } + + test_enum_secondary_fieldMissing_getter() async { + await assertErrorsInCode( + r''' +enum E { + v(0); + const E(this.x); + int get x => 1; +} +''', + [error(diag.initializingFormalForNonExistentField, 27, 6)], + ); + } + + test_enum_secondary_optionalPositional_fieldMissing() async { await assertErrorsInCode( r''' enum E { @@ -89,28 +161,31 @@ enum E { ); } - test_enum_required() async { + test_extensionType_primary_fieldMissing_notReportedHere() async { await assertErrorsInCode( r''' -enum E { - v(0); - const E(this.x); -} +extension type E(this.x) {} ''', - [error(diag.initializingFormalForNonExistentField, 27, 6)], + [error(diag.expectedRepresentationField, 17, 4)], ); } - test_enum_synthetic() async { + test_extensionType_secondary_fieldExists() async { + await assertNoErrorsInCode(r''' +extension type E(int it) { + E.named(this.it); +} +'''); + } + + test_extensionType_secondary_fieldMissing() async { await assertErrorsInCode( r''' -enum E { - v(0); - const E(this.x); - int get x => 1; +extension type E(int it) { + E.named(this.x) : this.it = 0; } ''', - [error(diag.initializingFormalForNonExistentField, 27, 6)], + [error(diag.initializingFormalForNonExistentField, 37, 6)], ); } } diff --git a/pkg/linter/test/rules/type_init_formals_test.dart b/pkg/linter/test/rules/type_init_formals_test.dart index 6a15a955c4e..671e60aae2d 100644 --- a/pkg/linter/test/rules/type_init_formals_test.dart +++ b/pkg/linter/test/rules/type_init_formals_test.dart @@ -50,7 +50,7 @@ class Invalid { test_requiredParam_declaring() async { await assertNoDiagnostics(r''' -class A({required var String this.s}); +class A({required var String s}); '''); } diff --git a/pkg/linter/test/rules/use_late_for_private_fields_and_variables_test.dart b/pkg/linter/test/rules/use_late_for_private_fields_and_variables_test.dart index c010240c7e0..ffdc7ec2067 100644 --- a/pkg/linter/test/rules/use_late_for_private_fields_and_variables_test.dart +++ b/pkg/linter/test/rules/use_late_for_private_fields_and_variables_test.dart @@ -101,6 +101,8 @@ enum E(final String _v, [final String? v2]) { enum E(this._v, [this._v2]) { a('a'), b('b', 'c'); + final String _v; + final String? _v2; } '''); }