Skip to content

Commit

Permalink
Augment. Issue 55295. Report AUGMENTATION_WITHOUT_DECLARATION.
Browse files Browse the repository at this point in the history
Bug: #55295
Change-Id: I50811e1ccd7a2be0e71b18eefa9ecb76ac1aef73
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/359961
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
  • Loading branch information
scheglov authored and Commit Queue committed Mar 27, 2024
1 parent dbcf24c commit 3bf33b6
Show file tree
Hide file tree
Showing 7 changed files with 298 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,8 @@ CompileTimeErrorCode.ASSIGNMENT_TO_TYPE:
status: noFix
CompileTimeErrorCode.ASYNC_FOR_IN_WRONG_CONTEXT:
status: hasFix
CompileTimeErrorCode.AUGMENTATION_WITHOUT_DECLARATION:
status: noFix
CompileTimeErrorCode.AUGMENTATION_WITHOUT_IMPORT:
status: needsFix
notes: |-
Expand Down
8 changes: 8 additions & 0 deletions pkg/analyzer/lib/src/error/codes.g.dart
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,14 @@ class CompileTimeErrorCode extends AnalyzerErrorCode {
hasPublishedDocs: true,
);

static const CompileTimeErrorCode AUGMENTATION_WITHOUT_DECLARATION =
CompileTimeErrorCode(
'AUGMENTATION_WITHOUT_DECLARATION',
"The declaration being augmented doesn't exist.",
correctionMessage:
"Try changing the augmentation to match an existing declaration.",
);

static const CompileTimeErrorCode AUGMENTATION_WITHOUT_IMPORT =
CompileTimeErrorCode(
'AUGMENTATION_WITHOUT_IMPORT',
Expand Down
1 change: 1 addition & 0 deletions pkg/analyzer/lib/src/error/error_code_values.g.dart
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ const List<ErrorCode> errorCodeValues = [
CompileTimeErrorCode.ASSIGNMENT_TO_METHOD,
CompileTimeErrorCode.ASSIGNMENT_TO_TYPE,
CompileTimeErrorCode.ASYNC_FOR_IN_WRONG_CONTEXT,
CompileTimeErrorCode.AUGMENTATION_WITHOUT_DECLARATION,
CompileTimeErrorCode.AUGMENTATION_WITHOUT_IMPORT,
CompileTimeErrorCode.AUGMENTATION_WITHOUT_LIBRARY,
CompileTimeErrorCode.AWAIT_IN_LATE_LOCAL_VARIABLE_INITIALIZER,
Expand Down
68 changes: 58 additions & 10 deletions pkg/analyzer/lib/src/generated/error_verifier.dart
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,12 @@ class ErrorVerifier extends RecursiveAstVisitor<void>
void visitClassDeclaration(covariant ClassDeclarationImpl node) {
try {
final element = node.declaredElement!;

_checkAugmentations(
augmentKeyword: node.augmentKeyword,
element: element,
);

final augmented = element.augmented;
if (augmented == null) {
return;
Expand Down Expand Up @@ -570,6 +576,10 @@ class ErrorVerifier extends RecursiveAstVisitor<void>
}
_checkForUndefinedConstructorInInitializerImplicit(node);
_checkForReturnInGenerativeConstructor(node);
_checkAugmentations(
augmentKeyword: node.augmentKeyword,
element: element,
);
_reportMacroDiagnostics(element);
super.visitConstructorDeclaration(node);
});
Expand Down Expand Up @@ -781,9 +791,13 @@ class ErrorVerifier extends RecursiveAstVisitor<void>
_checkForNonFinalFieldInEnum(node);

for (final field in fields.variables) {
if (field.declaredElement case final FieldElementImpl element) {
_reportMacroDiagnostics(element);
}
var element = field.declaredElement;
element as FieldElementImpl;
_checkAugmentations(
augmentKeyword: node.augmentKeyword,
element: element,
);
_reportMacroDiagnostics(element);
}

super.visitFieldDeclaration(node);
Expand Down Expand Up @@ -867,6 +881,10 @@ class ErrorVerifier extends RecursiveAstVisitor<void>
_returnTypeVerifier.verifyReturnType(returnType);
_checkForMainFunction1(node.name, node.declaredElement!);
_checkForMainFunction2(node);
_checkAugmentations(
augmentKeyword: node.augmentKeyword,
element: element,
);
_reportMacroDiagnostics(element);
super.visitFunctionDeclaration(node);
});
Expand Down Expand Up @@ -1068,6 +1086,10 @@ class ErrorVerifier extends RecursiveAstVisitor<void>
_checkForTypeAnnotationDeferredClass(returnType);
_returnTypeVerifier.verifyReturnType(returnType);
_checkForWrongTypeParameterVarianceInMethod(node);
_checkAugmentations(
augmentKeyword: node.augmentKeyword,
element: element,
);
_reportMacroDiagnostics(element);
super.visitMethodDeclaration(node);
});
Expand Down Expand Up @@ -1097,6 +1119,12 @@ class ErrorVerifier extends RecursiveAstVisitor<void>
// TODO(scheglov): Verify for all mixin errors.
try {
final element = node.declaredElement!;

_checkAugmentations(
augmentKeyword: node.augmentKeyword,
element: element,
);

final augmented = element.augmented;
if (augmented == null) {
return;
Expand Down Expand Up @@ -1425,14 +1453,14 @@ class ErrorVerifier extends RecursiveAstVisitor<void>
_checkForNotInitializedNonNullableVariable(node.variables, true);

for (var variable in node.variables.variables) {
_checkForMainFunction1(variable.name, variable.declaredElement!);
}

for (final variable in node.variables.variables) {
var element = variable.declaredElement;
if (element is TopLevelVariableElementImpl) {
_reportMacroDiagnostics(element);
}
element as TopLevelVariableElementImpl;
_checkForMainFunction1(variable.name, element);
_checkAugmentations(
augmentKeyword: node.augmentKeyword,
element: element,
);
_reportMacroDiagnostics(element);
}

super.visitTopLevelVariableDeclaration(node);
Expand Down Expand Up @@ -1507,6 +1535,26 @@ class ErrorVerifier extends RecursiveAstVisitor<void>
_isInLateLocalVariable.removeLast();
}

void _checkAugmentations<T extends ElementImpl>({
required Token? augmentKeyword,
required T element,
}) {
if (augmentKeyword == null) {
return;
}

if (element is AugmentableElement<T>) {
var augmentationTarget = element.augmentationTarget;
if (augmentationTarget == null) {
errorReporter.atToken(
augmentKeyword,
CompileTimeErrorCode.AUGMENTATION_WITHOUT_DECLARATION,
);
return;
}
}
}

/// Checks the class for problems with the superclass, mixins, or implemented
/// interfaces.
///
Expand Down
3 changes: 3 additions & 0 deletions pkg/analyzer/messages.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1109,6 +1109,9 @@ CompileTimeErrorCode:
}
}
```
AUGMENTATION_WITHOUT_DECLARATION:
problemMessage: The declaration being augmented doesn't exist.
correctionMessage: Try changing the augmentation to match an existing declaration.
AUGMENTATION_WITHOUT_IMPORT:
problemMessage: The library does not import this augmentation.
correctionMessage: Try updating the augmented library to import this augmentation.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'package:analyzer/src/error/codes.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';

import '../dart/resolution/context_collection_resolution.dart';

main() {
defineReflectiveSuite(() {
defineReflectiveTests(AugmentationWithoutDeclarationTest);
});
}

@reflectiveTest
class AugmentationWithoutDeclarationTest extends PubPackageResolutionTest {
test_class() async {
newFile('$testPackageLibPath/a.dart', r'''
import augment 'test.dart';
''');

await assertErrorsInCode(r'''
library augment 'a.dart';
augment class A {}
''', [
error(CompileTimeErrorCode.AUGMENTATION_WITHOUT_DECLARATION, 27, 7),
]);
}

test_class_constructor() async {
newFile('$testPackageLibPath/a.dart', r'''
import augment 'test.dart';
class A {}
''');

await assertErrorsInCode(r'''
library augment 'a.dart';
augment class A {
augment A.named();
}
''', [
error(CompileTimeErrorCode.AUGMENTATION_WITHOUT_DECLARATION, 47, 7),
]);
}

test_class_field() async {
newFile('$testPackageLibPath/a.dart', r'''
import augment 'test.dart';
class A {}
''');

await assertErrorsInCode(r'''
library augment 'a.dart';
augment class A {
augment int foo = 0;
}
''', [
error(CompileTimeErrorCode.AUGMENTATION_WITHOUT_DECLARATION, 47, 7),
]);
}

test_class_getter() async {
newFile('$testPackageLibPath/a.dart', r'''
import augment 'test.dart';
class A {}
''');

await assertErrorsInCode(r'''
library augment 'a.dart';
augment class A {
augment int get foo => 0;
}
''', [
error(CompileTimeErrorCode.AUGMENTATION_WITHOUT_DECLARATION, 47, 7),
]);
}

test_class_method() async {
newFile('$testPackageLibPath/a.dart', r'''
import augment 'test.dart';
class A {}
''');

await assertErrorsInCode(r'''
library augment 'a.dart';
augment class A {
augment void foo() {}
}
''', [
error(CompileTimeErrorCode.AUGMENTATION_WITHOUT_DECLARATION, 47, 7),
]);
}

test_class_method_valid() async {
newFile('$testPackageLibPath/a.dart', r'''
import augment 'test.dart';
class A {
void foo() {}
}
''');

await assertNoErrorsInCode(r'''
library augment 'a.dart';
augment class A {
augment void foo() {}
}
''');
}

test_class_setter() async {
newFile('$testPackageLibPath/a.dart', r'''
import augment 'test.dart';
class A {}
''');

await assertErrorsInCode(r'''
library augment 'a.dart';
augment class A {
augment set foo(int _) {}
}
''', [
error(CompileTimeErrorCode.AUGMENTATION_WITHOUT_DECLARATION, 47, 7),
]);
}

test_mixin() async {
newFile('$testPackageLibPath/a.dart', r'''
import augment 'test.dart';
''');

await assertErrorsInCode(r'''
library augment 'a.dart';
augment mixin A {}
''', [
error(CompileTimeErrorCode.AUGMENTATION_WITHOUT_DECLARATION, 27, 7),
]);
}

test_topLevel_function() async {
newFile('$testPackageLibPath/a.dart', r'''
import augment 'test.dart';
''');

await assertErrorsInCode(r'''
library augment 'a.dart';
augment void foo() {}
''', [
error(CompileTimeErrorCode.AUGMENTATION_WITHOUT_DECLARATION, 27, 7),
]);
}

test_topLevel_function_valid() async {
newFile('$testPackageLibPath/a.dart', r'''
import augment 'test.dart';
void foo() {}
''');

await assertNoErrorsInCode(r'''
library augment 'a.dart';
augment void foo() {}
''');
}

test_topLevel_getter() async {
newFile('$testPackageLibPath/a.dart', r'''
import augment 'test.dart';
''');

await assertErrorsInCode(r'''
library augment 'a.dart';
augment int get foo => 0;
''', [
error(CompileTimeErrorCode.AUGMENTATION_WITHOUT_DECLARATION, 27, 7),
]);
}

test_topLevel_setter() async {
newFile('$testPackageLibPath/a.dart', r'''
import augment 'test.dart';
''');

await assertErrorsInCode(r'''
library augment 'a.dart';
augment set foo(int _) {}
''', [
error(CompileTimeErrorCode.AUGMENTATION_WITHOUT_DECLARATION, 27, 7),
]);
}

test_topLevel_variable() async {
newFile('$testPackageLibPath/a.dart', r'''
import augment 'test.dart';
''');

await assertErrorsInCode(r'''
library augment 'a.dart';
augment int foo = 0;
''', [
error(CompileTimeErrorCode.AUGMENTATION_WITHOUT_DECLARATION, 27, 7),
]);
}
}
Loading

0 comments on commit 3bf33b6

Please sign in to comment.