Augment. Issue 55295. Report AUGMENTATION_WITHOUT_DECLARATION.

Bug: https://github.com/dart-lang/sdk/issues/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>
This commit is contained in:
Konstantin Shcheglov
2024-03-27 00:22:59 +00:00
committed by Commit Queue
parent dbcf24cedb
commit 3bf33b667c
7 changed files with 298 additions and 10 deletions
@@ -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: |-
+8
View File
@@ -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',
@@ -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,
@@ -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;
@@ -570,6 +576,10 @@ class ErrorVerifier extends RecursiveAstVisitor<void>
}
_checkForUndefinedConstructorInInitializerImplicit(node);
_checkForReturnInGenerativeConstructor(node);
_checkAugmentations(
augmentKeyword: node.augmentKeyword,
element: element,
);
_reportMacroDiagnostics(element);
super.visitConstructorDeclaration(node);
});
@@ -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);
@@ -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);
});
@@ -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);
});
@@ -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;
@@ -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);
@@ -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.
///
+3
View File
@@ -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.
@@ -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),
]);
}
}
@@ -38,6 +38,8 @@ import 'assignment_to_type_test.dart' as assignment_to_type;
import 'async_for_in_wrong_context_test.dart' as async_for_in_wrong_context;
import 'async_keyword_used_as_identifier_test.dart'
as async_keyword_used_as_identifier;
import 'augmentation_without_declaration_test.dart'
as augmentation_without_declaration;
import 'await_in_late_local_variable_initializer_test.dart'
as await_in_late_local_variable_initializer;
import 'await_in_wrong_context_test.dart' as await_in_wrong_context;
@@ -929,6 +931,7 @@ main() {
assignment_to_type.main();
async_for_in_wrong_context.main();
async_keyword_used_as_identifier.main();
augmentation_without_declaration.main();
await_in_late_local_variable_initializer.main();
await_in_wrong_context.main();
await_of_incompatible_type.main();