Augment. Report augmentationInducedGetterAlreadyComplete and augmentationInducedSetterAlreadyComplete.

Change-Id: I87ba9c5b6c489417173a387bded700f52b52e7ef
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/506501
Reviewed-by: Johnni Winther <johnniwinther@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
This commit is contained in:
Konstantin Shcheglov
2026-05-27 11:17:44 -07:00
committed by dart-scoped@luci-project-accounts.iam.gserviceaccount.com
parent 19ca914f74
commit ba760c36a4
12 changed files with 504 additions and 108 deletions
@@ -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:
@@ -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<
@@ -70,7 +70,9 @@ const List<DiagnosticCode> diagnosticCodeValues = [
diag.asyncForInWrongContext,
diag.asyncKeywordUsedAsIdentifier,
diag.augmentationExtendsClauseAlreadyPresent,
diag.augmentationInducedGetterAlreadyComplete,
diag.augmentationInducedGetterReturnTypeMismatch,
diag.augmentationInducedSetterAlreadyComplete,
diag.augmentationModifierExtra,
diag.augmentationModifierMissing,
diag.augmentationOfDifferentDeclarationKind,
@@ -1042,6 +1042,10 @@ class ErrorVerifier extends RecursiveAstVisitor<void>
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<void>
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>
}
}
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,
+16
View File
@@ -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:
@@ -144,7 +144,7 @@ class A {
int foo = 0;
}
augment class A {
augment int foo = 1;
augment abstract int foo;
}
''');
}
@@ -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?'.
''');
}
@@ -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.
''');
}
@@ -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.
''');
}
@@ -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
@@ -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')
@@ -31,7 +31,7 @@ class A {
part of 'a.dart';
augment class A {
augment Future<Null>? f;
augment abstract Future<Null>? f;
}
''');
}
@@ -110,7 +110,7 @@ Future<Null>? v;
await assertNoDiagnostics(r'''
part of 'a.dart';
augment Future<Null>? v;
augment abstract Future<Null>? v;
''');
}