diff --git a/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml b/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml index 557238e08ca..4edd1371cce 100644 --- a/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml +++ b/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml @@ -235,8 +235,12 @@ async_for_in_wrong_context: status: hasFix augmentation_extends_clause_already_present: status: needsEvaluation +augmentation_induced_getter_already_complete: + status: needsEvaluation augmentation_induced_getter_return_type_mismatch: status: needsEvaluation +augmentation_induced_setter_already_complete: + status: needsEvaluation augmentation_modifier_extra: status: hasFix augmentation_modifier_missing: diff --git a/pkg/analyzer/lib/src/diagnostic/diagnostic.g.dart b/pkg/analyzer/lib/src/diagnostic/diagnostic.g.dart index 91cb3833ea7..c0caac55b17 100644 --- a/pkg/analyzer/lib/src/diagnostic/diagnostic.g.dart +++ b/pkg/analyzer/lib/src/diagnostic/diagnostic.g.dart @@ -888,6 +888,21 @@ augmentationExtendsClauseAlreadyPresent = DiagnosticWithoutArgumentsImpl( expectedTypes: [], ); +/// No parameters. +const DiagnosticWithoutArguments +augmentationInducedGetterAlreadyComplete = DiagnosticWithoutArgumentsImpl( + name: 'declaration_already_complete', + problemMessage: + "The getter induced by this augmentation is complete, but the getter being " + "augmented is already complete.", + correctionMessage: + "Try removing the augmentation, or making one of the declarations " + "'abstract'.", + type: DiagnosticType.COMPILE_TIME_ERROR, + uniqueName: 'augmentation_induced_getter_already_complete', + expectedTypes: [], +); + /// Parameters: /// Type expectedType: the return type of the getter being augmented /// Type actualType: the return type of the induced getter @@ -911,6 +926,21 @@ augmentationInducedGetterReturnTypeMismatch = DiagnosticWithArguments( expectedTypes: [ExpectedType.type, ExpectedType.type], ); +/// No parameters. +const DiagnosticWithoutArguments +augmentationInducedSetterAlreadyComplete = DiagnosticWithoutArgumentsImpl( + name: 'declaration_already_complete', + problemMessage: + "The setter induced by this augmentation is complete, but the setter being " + "augmented is already complete.", + correctionMessage: + "Try removing the augmentation, or making one of the declarations " + "'abstract'.", + type: DiagnosticType.COMPILE_TIME_ERROR, + uniqueName: 'augmentation_induced_setter_already_complete', + expectedTypes: [], +); + /// Parameters: /// String modifier: the lexeme of the modifier. const DiagnosticWithArguments< diff --git a/pkg/analyzer/lib/src/diagnostic/diagnostic_code_values.g.dart b/pkg/analyzer/lib/src/diagnostic/diagnostic_code_values.g.dart index 38ab95d7fb5..8db128b21ba 100644 --- a/pkg/analyzer/lib/src/diagnostic/diagnostic_code_values.g.dart +++ b/pkg/analyzer/lib/src/diagnostic/diagnostic_code_values.g.dart @@ -70,7 +70,9 @@ const List diagnosticCodeValues = [ diag.asyncForInWrongContext, diag.asyncKeywordUsedAsIdentifier, diag.augmentationExtendsClauseAlreadyPresent, + diag.augmentationInducedGetterAlreadyComplete, diag.augmentationInducedGetterReturnTypeMismatch, + diag.augmentationInducedSetterAlreadyComplete, diag.augmentationModifierExtra, diag.augmentationModifierMissing, diag.augmentationOfDifferentDeclarationKind, diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart index 7904d0bc247..1b74fd7ae08 100644 --- a/pkg/analyzer/lib/src/generated/error_verifier.dart +++ b/pkg/analyzer/lib/src/generated/error_verifier.dart @@ -1042,6 +1042,10 @@ class ErrorVerifier extends RecursiveAstVisitor variable.name, declaredFragment, ); + _checkForAugmentationInducedAccessorsAlreadyComplete( + errorToken: variable.name, + fragment: declaredFragment, + ); if (declaredFragment.inducedGetter case var inducedGetter?) { _checkForAugmentationReturnTypeMismatch( fragment: inducedGetter, @@ -2015,6 +2019,10 @@ class ErrorVerifier extends RecursiveAstVisitor variable.name, declaredFragment, ); + _checkForAugmentationInducedAccessorsAlreadyComplete( + errorToken: variable.name, + fragment: declaredFragment, + ); if (declaredFragment.inducedGetter case var inducedGetter?) { _checkForAugmentationReturnTypeMismatch( fragment: inducedGetter, @@ -2691,6 +2699,45 @@ class ErrorVerifier extends RecursiveAstVisitor } } + void _checkForAugmentationInducedAccessorsAlreadyComplete({ + required Token errorToken, + required PropertyInducingFragmentImpl fragment, + }) { + if (fragment.inducedGetter case var inducedGetter?) { + if (inducedGetter.isCompleteDeclaration) { + var precedingComplete = inducedGetter.nearestPrecedingCompleteFragment; + if (precedingComplete != null) { + diagnosticReporter.report( + diag.augmentationInducedGetterAlreadyComplete + .withContextMessages([ + ?precedingComplete.contextMessageAt( + "The complete declaration is here.", + ), + ]) + .at(errorToken), + ); + } + } + } + + if (fragment.inducedSetter case var inducedSetter?) { + if (inducedSetter.isCompleteDeclaration) { + var precedingComplete = inducedSetter.nearestPrecedingCompleteFragment; + if (precedingComplete != null) { + diagnosticReporter.report( + diag.augmentationInducedSetterAlreadyComplete + .withContextMessages([ + ?precedingComplete.contextMessageAt( + "The complete declaration is here.", + ), + ]) + .at(errorToken), + ); + } + } + } + } + void _checkForAugmentationReturnTypeMismatch({ required ExecutableFragmentImpl fragment, required TypeAnnotation? returnTypeNode, diff --git a/pkg/analyzer/messages.yaml b/pkg/analyzer/messages.yaml index 8220be4a0e8..bd0b1ca8734 100644 --- a/pkg/analyzer/messages.yaml +++ b/pkg/analyzer/messages.yaml @@ -1904,6 +1904,22 @@ CompileTimeErrorCode: problemMessage: "The getter induced by this augmentation has return type '#actualType', but the getter being augmented has return type '#expectedType'." correctionMessage: Try changing the augmentation's type to match the getter being augmented. hasPublishedDocs: false + augmentationInducedGetterAlreadyComplete: + type: compileTimeError + parameters: none + sharedName: declarationAlreadyComplete + experiment: augmentations + problemMessage: "The getter induced by this augmentation is complete, but the getter being augmented is already complete." + correctionMessage: Try removing the augmentation, or making one of the declarations 'abstract'. + hasPublishedDocs: false + augmentationInducedSetterAlreadyComplete: + type: compileTimeError + parameters: none + sharedName: declarationAlreadyComplete + experiment: augmentations + problemMessage: "The setter induced by this augmentation is complete, but the setter being augmented is already complete." + correctionMessage: Try removing the augmentation, or making one of the declarations 'abstract'. + hasPublishedDocs: false augmentationReturnTypeMismatch: type: compileTimeError parameters: diff --git a/pkg/analyzer/test/src/diagnostics/augmentation_of_different_declaration_kind_test.dart b/pkg/analyzer/test/src/diagnostics/augmentation_of_different_declaration_kind_test.dart index b719d6911c4..a4f01566ef2 100644 --- a/pkg/analyzer/test/src/diagnostics/augmentation_of_different_declaration_kind_test.dart +++ b/pkg/analyzer/test/src/diagnostics/augmentation_of_different_declaration_kind_test.dart @@ -144,7 +144,7 @@ class A { int foo = 0; } augment class A { - augment int foo = 1; + augment abstract int foo; } '''); } diff --git a/pkg/analyzer/test/src/diagnostics/augmentation_return_type_mismatch_test.dart b/pkg/analyzer/test/src/diagnostics/augmentation_return_type_mismatch_test.dart index 0ee3f508d14..5fca2efe079 100644 --- a/pkg/analyzer/test/src/diagnostics/augmentation_return_type_mismatch_test.dart +++ b/pkg/analyzer/test/src/diagnostics/augmentation_return_type_mismatch_test.dart @@ -23,8 +23,8 @@ class A { } augment class A { - augment final String? foo = null; -// ^^^ + augment abstract final String? foo; +// ^^^ // [diag.augmentationInducedGetterReturnTypeMismatch] The getter induced by this augmentation has return type 'String?', but the getter being augmented has return type 'int?'. } '''); @@ -37,7 +37,7 @@ class A { } augment class A { - augment int? foo; + augment abstract int? foo; } '''); } @@ -49,8 +49,8 @@ class A { } augment class A { - augment String? foo; -// ^^^ + augment abstract String? foo; +// ^^^ // [diag.augmentationInducedGetterReturnTypeMismatch] The getter induced by this augmentation has return type 'String?', but the getter being augmented has return type 'int?'. } '''); @@ -64,8 +64,8 @@ class A { } augment class A { - augment String? foo, bar; -// ^^^ + augment abstract String? foo, bar; +// ^^^ // [diag.augmentationInducedGetterReturnTypeMismatch] The getter induced by this augmentation has return type 'String?', but the getter being augmented has return type 'int?'. } '''); @@ -118,7 +118,7 @@ class A { } augment class A { - augment static int? foo; + augment static abstract int? foo; } '''); } @@ -130,8 +130,8 @@ class A { } augment class A { - augment static String? foo; -// ^^^ + augment static abstract String? foo; +// ^^^ // [diag.augmentationInducedGetterReturnTypeMismatch] The getter induced by this augmentation has return type 'String?', but the getter being augmented has return type 'int?'. } '''); @@ -305,9 +305,10 @@ augment String get foo; await resolveTestCodeWithDiagnostics(r''' int? get foo => 0; -augment final String? foo = null; -// ^^^ +augment abstract final String? foo; +// ^^^ // [diag.augmentationInducedGetterReturnTypeMismatch] The getter induced by this augmentation has return type 'String?', but the getter being augmented has return type 'int?'. +// [diag.finalNotInitialized] The final variable 'foo' must be initialized. '''); } @@ -315,7 +316,7 @@ augment final String? foo = null; await resolveTestCodeWithDiagnostics(r''' int? foo; -augment int? foo; +augment abstract int? foo; '''); } @@ -323,8 +324,8 @@ augment int? foo; await resolveTestCodeWithDiagnostics(r''' int? foo; -augment String? foo; -// ^^^ +augment abstract String? foo; +// ^^^ // [diag.augmentationInducedGetterReturnTypeMismatch] The getter induced by this augmentation has return type 'String?', but the getter being augmented has return type 'int?'. '''); } @@ -334,8 +335,8 @@ augment String? foo; String? foo; int? bar; -augment String? foo, bar; -// ^^^ +augment abstract String? foo, bar; +// ^^^ // [diag.augmentationInducedGetterReturnTypeMismatch] The getter induced by this augmentation has return type 'String?', but the getter being augmented has return type 'int?'. '''); } diff --git a/pkg/analyzer/test/src/diagnostics/augmentation_without_declaration_test.dart b/pkg/analyzer/test/src/diagnostics/augmentation_without_declaration_test.dart index 35310474dfe..07156639e0b 100644 --- a/pkg/analyzer/test/src/diagnostics/augmentation_without_declaration_test.dart +++ b/pkg/analyzer/test/src/diagnostics/augmentation_without_declaration_test.dart @@ -104,22 +104,22 @@ class A { } augment class A { - augment int foo = 1; + augment abstract int foo; } '''); } test_class_instanceField_augments_instanceField_final() async { await resolveTestCodeWithDiagnostics(r''' -class A { +abstract class A { final int foo = 0; // ^^^ // [context 1] The corresponding getter is induced by this declaration. } -augment class A { - augment int foo = 1; -// ^^^ +augment abstract class A { + augment abstract int foo; +// ^^^ // [diag.augmentationWithoutSetterDeclaration][context 1] This augmentation induces a setter, but no setter declaration named 'foo' exists to augment. } '''); @@ -127,15 +127,15 @@ augment class A { test_class_instanceField_augments_instanceGetter() async { await resolveTestCodeWithDiagnostics(r''' -class A { +abstract class A { int get foo => 0; // ^^^ // [context 1] The corresponding getter is declared here. } -augment class A { - augment int foo = 0; -// ^^^ +augment abstract class A { + augment abstract int foo; +// ^^^ // [diag.augmentationWithoutSetterDeclaration][context 1] This augmentation induces a setter, but no setter declaration named 'foo' exists to augment. } '''); @@ -147,12 +147,14 @@ class A { set foo(int _) {} // ^^^ // [context 1] The corresponding setter is declared here. +// [context 2] The complete declaration is here. } augment class A { augment int foo = 0; // ^^^ // [diag.augmentationWithoutGetterDeclaration][context 1] This augmentation induces a getter, but no getter declaration named 'foo' exists to augment. +// [diag.augmentationInducedSetterAlreadyComplete][context 2] The setter induced by this augmentation is complete, but the setter being augmented is already complete. } '''); } @@ -216,7 +218,7 @@ class A { } augment class A { - augment final int foo = 1; + augment abstract final int foo; } '''); } @@ -228,22 +230,22 @@ class A { } augment class A { - augment final int foo = 1; + augment abstract final int foo; } '''); } test_class_instanceField_final_augments_instanceSetter() async { await resolveTestCodeWithDiagnostics(r''' -class A { +abstract class A { set foo(int _) {} // ^^^ // [context 1] The corresponding setter is declared here. } -augment class A { - augment final int foo = 1; -// ^^^ +augment abstract class A { + augment abstract final int foo; +// ^^^ // [diag.augmentationWithoutGetterDeclaration][context 1] This augmentation induces a getter, but no getter declaration named 'foo' exists to augment. } '''); @@ -570,7 +572,7 @@ class A { } augment class A { - augment static int foo = 1; + augment static abstract int foo; } '''); } @@ -584,8 +586,8 @@ class A { } augment class A { - augment static int foo = 1; -// ^^^ + augment static abstract int foo; +// ^^^ // [diag.augmentationWithoutSetterDeclaration][context 1] This augmentation induces a setter, but no setter declaration named 'foo' exists to augment. } '''); @@ -600,8 +602,8 @@ class A { } augment class A { - augment static int foo = 1; -// ^^^ + augment static abstract int foo; +// ^^^ // [diag.augmentationWithoutSetterDeclaration][context 1] This augmentation induces a setter, but no setter declaration named 'foo' exists to augment. } '''); @@ -616,8 +618,8 @@ class A { } augment class A { - augment static int foo = 1; -// ^^^ + augment static abstract int foo; +// ^^^ // [diag.augmentationWithoutGetterDeclaration][context 1] This augmentation induces a getter, but no getter declaration named 'foo' exists to augment. } '''); @@ -630,7 +632,7 @@ class A { } augment class A { - augment static final int foo = 1; + augment static abstract final int foo; } '''); } @@ -642,7 +644,7 @@ class A { } augment class A { - augment static final int foo = 1; + augment static abstract final int foo; } '''); } @@ -656,8 +658,8 @@ class A { } augment class A { - augment static final int foo = 1; -// ^^^ + augment static abstract final int foo; +// ^^^ // [diag.augmentationWithoutGetterDeclaration][context 1] This augmentation induces a getter, but no getter declaration named 'foo' exists to augment. } '''); @@ -1176,73 +1178,78 @@ augment int foo = 0; test_topLevel_variable_augments_getter() async { await resolveTestCodeWithDiagnostics(r''' -int get foo => 0; -// ^^^ +int? get foo => 0; +// ^^^ // [context 1] The corresponding getter is declared here. -augment int foo = 1; -// ^^^ +augment abstract int? foo; +// ^^^ // [diag.augmentationWithoutSetterDeclaration][context 1] This augmentation induces a setter, but no setter declaration named 'foo' exists to augment. '''); } test_topLevel_variable_augments_setter() async { await resolveTestCodeWithDiagnostics(r''' -set foo(int _) {} +set foo(int? _) {} // ^^^ // [context 1] The corresponding setter is declared here. -augment int foo = 1; -// ^^^ +augment abstract int? foo; +// ^^^ // [diag.augmentationWithoutGetterDeclaration][context 1] This augmentation induces a getter, but no getter declaration named 'foo' exists to augment. '''); } test_topLevel_variable_augments_variable() async { await resolveTestCodeWithDiagnostics(r''' -int foo = 0; +int? foo = 0; -augment int foo = 1; +augment abstract int? foo; '''); } test_topLevel_variable_augments_variable_final() async { await resolveTestCodeWithDiagnostics(r''' -final int foo = 0; -// ^^^ +final int? foo = 0; +// ^^^ // [context 1] The corresponding getter is induced by this declaration. -augment int foo = 1; -// ^^^ +augment abstract int? foo; +// ^^^ // [diag.augmentationWithoutSetterDeclaration][context 1] This augmentation induces a setter, but no setter declaration named 'foo' exists to augment. '''); } test_topLevel_variable_final_augments_getter() async { await resolveTestCodeWithDiagnostics(r''' -int get foo => 0; +int? get foo => 0; -augment final int foo = 1; +augment abstract final int? foo; +// ^^^ +// [diag.finalNotInitialized] The final variable 'foo' must be initialized. '''); } test_topLevel_variable_final_augments_setter() async { await resolveTestCodeWithDiagnostics(r''' -set foo(int _) {} +set foo(int? _) {} // ^^^ // [context 1] The corresponding setter is declared here. -augment final int foo = 1; -// ^^^ +augment abstract final int? foo; +// ^^^ // [diag.augmentationWithoutGetterDeclaration][context 1] This augmentation induces a getter, but no getter declaration named 'foo' exists to augment. +// [diag.finalNotInitialized] The final variable 'foo' must be initialized. '''); } test_topLevel_variable_final_augments_variable_final() async { await resolveTestCodeWithDiagnostics(r''' -final int foo = 0; +final int? foo = 0; -augment final int foo = 1; +augment abstract final int? foo; +// ^^^ +// [diag.finalNotInitialized] The final variable 'foo' must be initialized. '''); } @@ -1258,10 +1265,10 @@ augment int foo = 0, bar = 0; test_topLevel_variable_multiple_oneMissing() async { await resolveTestCodeWithDiagnostics(r''' -int bar = 0; +int? bar = 0; -augment int foo = 1, bar = 2; -// ^^^ +augment abstract int? foo, bar; +// ^^^ // [diag.augmentationWithoutDeclaration] The declaration being augmented doesn't exist. '''); } diff --git a/pkg/analyzer/test/src/diagnostics/duplicate_definition_test.dart b/pkg/analyzer/test/src/diagnostics/duplicate_definition_test.dart index de5b4ece640..59a428ea050 100644 --- a/pkg/analyzer/test/src/diagnostics/duplicate_definition_test.dart +++ b/pkg/analyzer/test/src/diagnostics/duplicate_definition_test.dart @@ -44,7 +44,7 @@ class A { } augment class A { - augment int foo = 42; + augment abstract int foo; } '''); } @@ -686,8 +686,8 @@ class A { } augment class A { - augment static int foo = 0; -// ^^^ + augment static abstract int foo; +// ^^^ // [diag.augmentationWithoutSetterDeclaration][context 1] This augmentation induces a setter, but no setter declaration named 'foo' exists to augment. } '''); @@ -832,8 +832,8 @@ class A { } augment class A { - augment static int foo = 0; -// ^^^ + augment static abstract int foo; +// ^^^ // [diag.augmentationWithoutGetterDeclaration][context 1] This augmentation induces a getter, but no getter declaration named 'foo' exists to augment. } '''); @@ -991,7 +991,7 @@ enum E { } augment enum E {; - augment final int foo = 0; + augment abstract final int foo; } '''); } @@ -1428,8 +1428,8 @@ enum E { } augment enum E {; - augment static int foo = 0; -// ^^^ + augment static abstract int foo; +// ^^^ // [diag.augmentationWithoutSetterDeclaration][context 1] This augmentation induces a setter, but no setter declaration named 'foo' exists to augment. } '''); @@ -1585,8 +1585,8 @@ enum E { } augment enum E {; - augment static int foo = 0; -// ^^^ + augment static abstract int foo; +// ^^^ // [diag.augmentationWithoutGetterDeclaration][context 1] This augmentation induces a getter, but no getter declaration named 'foo' exists to augment. } '''); @@ -1704,8 +1704,8 @@ extension E on int { } augment extension E { - augment int foo = 0; -// ^^^ + augment abstract int foo; +// ^^^ // [diag.augmentationWithoutSetterDeclaration][context 1] This augmentation induces a setter, but no setter declaration named 'foo' exists to augment. // [diag.extensionDeclaresInstanceField] Extensions can't declare instance fields. } @@ -1857,8 +1857,8 @@ extension E on int { } augment extension E { - augment int foo = 0; -// ^^^ + augment abstract int foo; +// ^^^ // [diag.augmentationWithoutGetterDeclaration][context 1] This augmentation induces a getter, but no getter declaration named 'foo' exists to augment. // [diag.extensionDeclaresInstanceField] Extensions can't declare instance fields. } @@ -2006,8 +2006,8 @@ extension E on int { } augment extension E { - augment static int foo = 0; -// ^^^ + augment static abstract int foo; +// ^^^ // [diag.augmentationWithoutSetterDeclaration][context 1] This augmentation induces a setter, but no setter declaration named 'foo' exists to augment. } '''); @@ -2158,8 +2158,8 @@ extension E on int { } augment extension E { - augment static int foo = 0; -// ^^^ + augment static abstract int foo; +// ^^^ // [diag.augmentationWithoutGetterDeclaration][context 1] This augmentation induces a getter, but no getter declaration named 'foo' exists to augment. } '''); @@ -2254,8 +2254,8 @@ extension type E(int it) { } augment extension type E { - augment int foo = 0; -// ^^^ + augment abstract int foo; +// ^^^ // [diag.augmentationWithoutSetterDeclaration][context 1] This augmentation induces a setter, but no setter declaration named 'foo' exists to augment. // [diag.extensionTypeDeclaresInstanceField] Extension types can't declare instance fields. } @@ -2377,8 +2377,8 @@ extension type E(int it) { } augment extension type E { - augment int foo = 0; -// ^^^ + augment abstract int foo; +// ^^^ // [diag.augmentationWithoutGetterDeclaration][context 1] This augmentation induces a getter, but no getter declaration named 'foo' exists to augment. // [diag.extensionTypeDeclaresInstanceField] Extension types can't declare instance fields. } @@ -2490,8 +2490,8 @@ extension type E(int it) { } augment extension type E { - augment static int foo = 0; -// ^^^ + augment static abstract int foo; +// ^^^ // [diag.augmentationWithoutSetterDeclaration][context 1] This augmentation induces a setter, but no setter declaration named 'foo' exists to augment. } '''); @@ -2580,8 +2580,8 @@ extension type E(int it) { } augment extension type E { - augment static int foo = 0; -// ^^^ + augment static abstract int foo; +// ^^^ // [diag.augmentationWithoutGetterDeclaration][context 1] This augmentation induces a getter, but no getter declaration named 'foo' exists to augment. } '''); @@ -2706,8 +2706,8 @@ mixin M { } augment mixin M { - augment int foo = 0; -// ^^^ + augment abstract int foo; +// ^^^ // [diag.augmentationWithoutSetterDeclaration][context 1] This augmentation induces a setter, but no setter declaration named 'foo' exists to augment. } '''); @@ -2824,8 +2824,8 @@ mixin M { } augment mixin M { - augment int foo = 0; -// ^^^ + augment abstract int foo; +// ^^^ // [diag.augmentationWithoutGetterDeclaration][context 1] This augmentation induces a getter, but no getter declaration named 'foo' exists to augment. } '''); @@ -2936,8 +2936,8 @@ mixin M { } augment mixin M { - augment static int foo = 0; -// ^^^ + augment static abstract int foo; +// ^^^ // [diag.augmentationWithoutSetterDeclaration][context 1] This augmentation induces a setter, but no setter declaration named 'foo' exists to augment. } '''); @@ -3026,8 +3026,8 @@ mixin M { } augment mixin M { - augment static int foo = 0; -// ^^^ + augment static abstract int foo; +// ^^^ // [diag.augmentationWithoutGetterDeclaration][context 1] This augmentation induces a getter, but no getter declaration named 'foo' exists to augment. } '''); @@ -4356,9 +4356,12 @@ int foo = 42; } test_topLevelVariable_topLevelVariable_augment() async { + // TODO(augmentations): Should not have notInitializedNonNullableVariable await resolveTestCodeWithDiagnostics(r''' int foo = 0; -augment int foo = 42; +augment abstract int foo; +// ^^^ +// [diag.notInitializedNonNullableVariable] The non-nullable variable 'foo' must be initialized. '''); } diff --git a/pkg/analyzer/test/src/diagnostics/executable_body_test.dart b/pkg/analyzer/test/src/diagnostics/executable_body_test.dart index 8fa32cac76b..3ea86f7860d 100644 --- a/pkg/analyzer/test/src/diagnostics/executable_body_test.dart +++ b/pkg/analyzer/test/src/diagnostics/executable_body_test.dart @@ -180,6 +180,104 @@ class A { '''); } + test_class_instanceGetter_hasBody_augmentation_instanceField() async { + await resolveTestCodeWithDiagnostics(r''' +class A { + int get foo => 0; +// ^^^ +// [context 1] The corresponding getter is declared here. +// [context 2] The complete declaration is here. + augment int foo = 1; +// ^^^ +// [diag.augmentationWithoutSetterDeclaration][context 1] This augmentation induces a setter, but no setter declaration named 'foo' exists to augment. +// [diag.augmentationInducedGetterAlreadyComplete][context 2] The getter induced by this augmentation is complete, but the getter being augmented is already complete. +} +'''); + } + + test_class_instanceGetter_hasBody_augmentation_instanceField_abstractFinal() async { + await resolveTestCodeWithDiagnostics(r''' +class A { + int get foo => 0; + augment abstract final int foo; +} +'''); + } + + test_class_instanceGetter_hasBody_augmentation_instanceField_final() async { + await resolveTestCodeWithDiagnostics(r''' +class A { + int get foo => 0; +// ^^^ +// [context 1] The complete declaration is here. + augment final int foo = 1; +// ^^^ +// [diag.augmentationInducedGetterAlreadyComplete][context 1] The getter induced by this augmentation is complete, but the getter being augmented is already complete. +} +'''); + } + + test_class_instanceGetter_hasBody_instanceSetter_hasBody_augmentation_instanceField() async { + await resolveTestCodeWithDiagnostics(r''' +class A { + int get foo => 0; +// ^^^ +// [context 1] The complete declaration is here. + set foo(int _) {} +// ^^^ +// [context 2] The complete declaration is here. + augment int foo = 1; +// ^^^ +// [diag.augmentationInducedGetterAlreadyComplete][context 1] The getter induced by this augmentation is complete, but the getter being augmented is already complete. +// [diag.augmentationInducedSetterAlreadyComplete][context 2] The setter induced by this augmentation is complete, but the setter being augmented is already complete. +} +'''); + } + + test_class_instanceGetter_hasBody_instanceSetter_hasBody_augmentation_instanceField_abstract() async { + await resolveTestCodeWithDiagnostics(r''' +class A { + int get foo => 0; + set foo(int _) {} + augment abstract int foo; +} +'''); + } + + test_class_instanceGetter_noBody_augmentation_instanceField_final() async { + await resolveTestCodeWithDiagnostics(r''' +class A { + int get foo; + augment final int foo = 1; +} +'''); + } + + test_class_instanceGetter_noBody_instanceSetter_noBody_augmentation_instanceField() async { + await resolveTestCodeWithDiagnostics(r''' +class A { + int get foo; + set foo(int _); + augment int foo = 1; +} +'''); + } + + test_class_instanceSetter_hasBody_augmentation_instanceField() async { + await resolveTestCodeWithDiagnostics(r''' +class A { + set foo(int _) {} +// ^^^ +// [context 1] The corresponding setter is declared here. +// [context 2] The complete declaration is here. + augment int foo = 1; +// ^^^ +// [diag.augmentationWithoutGetterDeclaration][context 1] This augmentation induces a getter, but no getter declaration named 'foo' exists to augment. +// [diag.augmentationInducedSetterAlreadyComplete][context 2] The setter induced by this augmentation is complete, but the setter being augmented is already complete. +} +'''); + } + test_class_method_instance_external_hasBody_blockBody() async { await resolveTestCodeWithDiagnostics(r''' class C { @@ -543,6 +641,104 @@ class A { '''); } + test_class_staticGetter_hasBody_augmentation_staticField() async { + await resolveTestCodeWithDiagnostics(r''' +class A { + static int get foo => 0; +// ^^^ +// [context 1] The corresponding getter is declared here. +// [context 2] The complete declaration is here. + augment static int foo = 1; +// ^^^ +// [diag.augmentationWithoutSetterDeclaration][context 1] This augmentation induces a setter, but no setter declaration named 'foo' exists to augment. +// [diag.augmentationInducedGetterAlreadyComplete][context 2] The getter induced by this augmentation is complete, but the getter being augmented is already complete. +} +'''); + } + + test_class_staticGetter_hasBody_augmentation_staticField_abstractFinal() async { + await resolveTestCodeWithDiagnostics(r''' +class A { + static int get foo => 0; + augment static abstract final int foo; +} +'''); + } + + test_class_staticGetter_hasBody_augmentation_staticField_final() async { + await resolveTestCodeWithDiagnostics(r''' +class A { + static int get foo => 0; +// ^^^ +// [context 1] The complete declaration is here. + augment static final int foo = 1; +// ^^^ +// [diag.augmentationInducedGetterAlreadyComplete][context 1] The getter induced by this augmentation is complete, but the getter being augmented is already complete. +} +'''); + } + + test_class_staticGetter_hasBody_staticSetter_hasBody_augmentation_staticField() async { + await resolveTestCodeWithDiagnostics(r''' +class A { + static int get foo => 0; +// ^^^ +// [context 1] The complete declaration is here. + static set foo(int _) {} +// ^^^ +// [context 2] The complete declaration is here. + augment static int foo = 1; +// ^^^ +// [diag.augmentationInducedGetterAlreadyComplete][context 1] The getter induced by this augmentation is complete, but the getter being augmented is already complete. +// [diag.augmentationInducedSetterAlreadyComplete][context 2] The setter induced by this augmentation is complete, but the setter being augmented is already complete. +} +'''); + } + + test_class_staticGetter_hasBody_staticSetter_hasBody_augmentation_staticField_abstract() async { + await resolveTestCodeWithDiagnostics(r''' +class A { + static int get foo => 0; + static set foo(int _) {} + augment static abstract int foo; +} +'''); + } + + test_class_staticGetter_noBody_augmentation_staticField_final() async { + await resolveTestCodeWithDiagnostics(r''' +class A { + static int get foo; + augment static final int foo = 1; +} +'''); + } + + test_class_staticGetter_noBody_staticSetter_noBody_augmentation_staticField() async { + await resolveTestCodeWithDiagnostics(r''' +class A { + static int get foo; + static set foo(int _); + augment static int foo = 1; +} +'''); + } + + test_class_staticSetter_hasBody_augmentation_staticField() async { + await resolveTestCodeWithDiagnostics(r''' +class A { + static set foo(int _) {} +// ^^^ +// [context 1] The corresponding setter is declared here. +// [context 2] The complete declaration is here. + augment static int foo = 1; +// ^^^ +// [diag.augmentationWithoutGetterDeclaration][context 1] This augmentation induces a getter, but no getter declaration named 'foo' exists to augment. +// [diag.augmentationInducedSetterAlreadyComplete][context 2] The setter induced by this augmentation is complete, but the setter being augmented is already complete. +} +'''); + } + test_enum_getter_static_augmentation_hasBody() async { await resolveTestCodeWithDiagnostics(r''' enum E { @@ -2106,6 +2302,39 @@ augment int get foo => 1; '''); } + test_topLevel_getter_hasBody_augmentation_variable() async { + await resolveTestCodeWithDiagnostics(r''' +int get foo => 0; +// ^^^ +// [context 1] The corresponding getter is declared here. +// [context 2] The complete declaration is here. +augment int foo = 1; +// ^^^ +// [diag.augmentationWithoutSetterDeclaration][context 1] This augmentation induces a setter, but no setter declaration named 'foo' exists to augment. +// [diag.augmentationInducedGetterAlreadyComplete][context 2] The getter induced by this augmentation is complete, but the getter being augmented is already complete. +'''); + } + + test_topLevel_getter_hasBody_augmentation_variable_abstractFinal() async { + await resolveTestCodeWithDiagnostics(r''' +int get foo => 0; +augment abstract final int foo; +// ^^^ +// [diag.finalNotInitialized] The final variable 'foo' must be initialized. +'''); + } + + test_topLevel_getter_hasBody_augmentation_variable_final() async { + await resolveTestCodeWithDiagnostics(r''' +int get foo => 0; +// ^^^ +// [context 1] The complete declaration is here. +augment final int foo = 1; +// ^^^ +// [diag.augmentationInducedGetterAlreadyComplete][context 1] The getter induced by this augmentation is complete, but the getter being augmented is already complete. +'''); + } + test_topLevel_getter_hasBody_language305() async { await resolveTestCodeWithDiagnostics(r''' // @dart = 3.5 @@ -2113,6 +2342,31 @@ int get foo => 0; '''); } + test_topLevel_getter_hasBody_setter_hasBody_augmentation_variable() async { + await resolveTestCodeWithDiagnostics(r''' +int get foo => 0; +// ^^^ +// [context 1] The complete declaration is here. +set foo(int _) {} +// ^^^ +// [context 2] The complete declaration is here. +augment int foo = 1; +// ^^^ +// [diag.augmentationInducedGetterAlreadyComplete][context 1] The getter induced by this augmentation is complete, but the getter being augmented is already complete. +// [diag.augmentationInducedSetterAlreadyComplete][context 2] The setter induced by this augmentation is complete, but the setter being augmented is already complete. +'''); + } + + test_topLevel_getter_hasBody_setter_hasBody_augmentation_variable_abstract() async { + await resolveTestCodeWithDiagnostics(r''' +int get foo => 0; +set foo(int _) {} +augment abstract int foo; +// ^^^ +// [diag.notInitializedNonNullableVariable] The non-nullable variable 'foo' must be initialized. +'''); + } + test_topLevel_getter_noBody() async { await resolveTestCodeWithDiagnostics(r''' int get foo; @@ -2121,6 +2375,13 @@ int get foo; '''); } + test_topLevel_getter_noBody_augmentation_variable_final() async { + await resolveTestCodeWithDiagnostics(r''' +int get foo; +augment final int foo = 1; +'''); + } + test_topLevel_getter_noBody_language305() async { await resolveTestCodeWithDiagnostics(r''' // @dart = 3.5 @@ -2130,6 +2391,14 @@ int get foo; '''); } + test_topLevel_getter_noBody_setter_noBody_augmentation_variable() async { + await resolveTestCodeWithDiagnostics(r''' +int get foo; +set foo(int _); +augment int foo = 1; +'''); + } + test_topLevel_setter_augmentation_hasBody() async { await resolveTestCodeWithDiagnostics(r''' set foo(int _); @@ -2175,6 +2444,19 @@ augment set foo(int _) {} '''); } + test_topLevel_setter_hasBody_augmentation_variable() async { + await resolveTestCodeWithDiagnostics(r''' +set foo(int _) {} +// ^^^ +// [context 1] The corresponding setter is declared here. +// [context 2] The complete declaration is here. +augment int foo = 1; +// ^^^ +// [diag.augmentationWithoutGetterDeclaration][context 1] This augmentation induces a getter, but no getter declaration named 'foo' exists to augment. +// [diag.augmentationInducedSetterAlreadyComplete][context 2] The setter induced by this augmentation is complete, but the setter being augmented is already complete. +'''); + } + test_topLevel_setter_hasBody_language305() async { await resolveTestCodeWithDiagnostics(r''' // @dart = 3.5 diff --git a/pkg/linter/test/rules/non_constant_identifier_names_test.dart b/pkg/linter/test/rules/non_constant_identifier_names_test.dart index d9e5dd7f943..858e0102bbb 100644 --- a/pkg/linter/test/rules/non_constant_identifier_names_test.dart +++ b/pkg/linter/test/rules/non_constant_identifier_names_test.dart @@ -252,7 +252,7 @@ class A { part of 'a.dart'; augment class A { - augment int Xx = 2; + augment abstract int Xx; } '''); } @@ -378,11 +378,15 @@ part 'test.dart'; int Xx = 1; '''); - await assertNoDiagnostics(r''' + // TODO(augmentations): Should not have notInitializedNonNullableVariable + await assertDiagnostics( + r''' part of 'a.dart'; -augment int Xx = 2; -'''); +augment abstract int Xx; +''', + [error(diag.notInitializedNonNullableVariable, 40, 2)], + ); } @FailingTest(issue: 'https://github.com/dart-lang/linter/issues/5048') diff --git a/pkg/linter/test/rules/prefer_void_to_null_test.dart b/pkg/linter/test/rules/prefer_void_to_null_test.dart index 6b39fe696af..ec0cc691cb4 100644 --- a/pkg/linter/test/rules/prefer_void_to_null_test.dart +++ b/pkg/linter/test/rules/prefer_void_to_null_test.dart @@ -31,7 +31,7 @@ class A { part of 'a.dart'; augment class A { - augment Future? f; + augment abstract Future? f; } '''); } @@ -110,7 +110,7 @@ Future? v; await assertNoDiagnostics(r''' part of 'a.dart'; -augment Future? v; +augment abstract Future? v; '''); }