mirror of
https://github.com/dart-lang/sdk
synced 2024-10-06 13:57:58 +00:00
Augment. Report AUGMENTATION_EXTENDS_CLAUSE_ALREADY_PRESENT
Change-Id: I5590b68366a12129e42e19e26ac3ec4fa8330149 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/372221 Reviewed-by: Brian Wilkerson <brianwilkerson@google.com> Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
This commit is contained in:
parent
7d649303c2
commit
35cae3a8b8
|
@ -203,6 +203,8 @@ CompileTimeErrorCode.ASSIGNMENT_TO_TYPE:
|
|||
status: noFix
|
||||
CompileTimeErrorCode.ASYNC_FOR_IN_WRONG_CONTEXT:
|
||||
status: hasFix
|
||||
CompileTimeErrorCode.AUGMENTATION_EXTENDS_CLAUSE_ALREADY_PRESENT:
|
||||
status: needsEvaluation
|
||||
CompileTimeErrorCode.AUGMENTATION_MODIFIER_EXTRA:
|
||||
status: hasFix
|
||||
CompileTimeErrorCode.AUGMENTATION_MODIFIER_MISSING:
|
||||
|
|
|
@ -95,7 +95,7 @@ import 'package:meta/meta.dart';
|
|||
// TODO(scheglov): Clean up the list of implicitly analyzed files.
|
||||
class AnalysisDriver {
|
||||
/// The version of data format, should be incremented on every format change.
|
||||
static const int DATA_VERSION = 367;
|
||||
static const int DATA_VERSION = 368;
|
||||
|
||||
/// The number of exception contexts allowed to write. Once this field is
|
||||
/// zero, we stop writing any new exception contexts in this process.
|
||||
|
|
|
@ -317,6 +317,14 @@ class ClassElementImpl extends ClassOrMixinElementImpl
|
|||
super.fields = fields;
|
||||
}
|
||||
|
||||
bool get hasExtendsClause {
|
||||
return hasModifier(Modifier.HAS_EXTENDS_CLAUSE);
|
||||
}
|
||||
|
||||
set hasExtendsClause(bool value) {
|
||||
setModifier(Modifier.HAS_EXTENDS_CLAUSE, value);
|
||||
}
|
||||
|
||||
bool get hasGenerativeConstConstructor {
|
||||
return constructors.any((c) => !c.isFactory && c.isConst);
|
||||
}
|
||||
|
@ -5463,6 +5471,9 @@ enum Modifier {
|
|||
/// Indicates that the pseudo-modifier 'get' was applied to the element.
|
||||
GETTER,
|
||||
|
||||
/// Indicates that this class has an explicit `extends` clause.
|
||||
HAS_EXTENDS_CLAUSE,
|
||||
|
||||
/// A flag used for libraries indicating that the variable has an explicit
|
||||
/// initializer.
|
||||
HAS_INITIALIZER,
|
||||
|
|
|
@ -214,6 +214,17 @@ class CompileTimeErrorCode extends AnalyzerErrorCode {
|
|||
hasPublishedDocs: true,
|
||||
);
|
||||
|
||||
static const CompileTimeErrorCode
|
||||
AUGMENTATION_EXTENDS_CLAUSE_ALREADY_PRESENT = CompileTimeErrorCode(
|
||||
'AUGMENTATION_EXTENDS_CLAUSE_ALREADY_PRESENT',
|
||||
"The augmentation has an 'extends' clause, but an augmentation target "
|
||||
"already includes an 'extends' clause and it isn't allowed to be "
|
||||
"repeated or changed.",
|
||||
correctionMessage:
|
||||
"Try removing the 'extends' clause, either here or in the augmentation "
|
||||
"target.",
|
||||
);
|
||||
|
||||
/// Parameters:
|
||||
/// 0: the lexeme of the modifier.
|
||||
static const CompileTimeErrorCode AUGMENTATION_MODIFIER_EXTRA =
|
||||
|
|
|
@ -63,6 +63,7 @@ const List<ErrorCode> errorCodeValues = [
|
|||
CompileTimeErrorCode.ASSIGNMENT_TO_METHOD,
|
||||
CompileTimeErrorCode.ASSIGNMENT_TO_TYPE,
|
||||
CompileTimeErrorCode.ASYNC_FOR_IN_WRONG_CONTEXT,
|
||||
CompileTimeErrorCode.AUGMENTATION_EXTENDS_CLAUSE_ALREADY_PRESENT,
|
||||
CompileTimeErrorCode.AUGMENTATION_MODIFIER_EXTRA,
|
||||
CompileTimeErrorCode.AUGMENTATION_MODIFIER_MISSING,
|
||||
CompileTimeErrorCode.AUGMENTATION_OF_DIFFERENT_DECLARATION_KIND,
|
||||
|
|
|
@ -459,6 +459,11 @@ class ErrorVerifier extends RecursiveAstVisitor<void>
|
|||
augmentationElement: element,
|
||||
);
|
||||
|
||||
_checkClassAugmentationTargetAlreadyHasExtendsClause(
|
||||
node: node,
|
||||
augmentationTarget: element.augmentationTarget,
|
||||
);
|
||||
|
||||
_isInNativeClass = node.nativeClause != null;
|
||||
|
||||
var augmented = element.augmented;
|
||||
|
@ -1704,6 +1709,36 @@ class ErrorVerifier extends RecursiveAstVisitor<void>
|
|||
);
|
||||
}
|
||||
|
||||
void _checkClassAugmentationTargetAlreadyHasExtendsClause({
|
||||
required ClassDeclarationImpl node,
|
||||
required ClassElementImpl? augmentationTarget,
|
||||
}) {
|
||||
var extendsClause = node.extendsClause;
|
||||
if (extendsClause == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
while (augmentationTarget != null) {
|
||||
if (augmentationTarget.hasExtendsClause) {
|
||||
errorReporter.atToken(
|
||||
extendsClause.extendsKeyword,
|
||||
CompileTimeErrorCode.AUGMENTATION_EXTENDS_CLAUSE_ALREADY_PRESENT,
|
||||
contextMessages: [
|
||||
DiagnosticMessageImpl(
|
||||
filePath: augmentationTarget.source.fullName,
|
||||
offset: augmentationTarget.nameOffset,
|
||||
length: augmentationTarget.nameLength,
|
||||
message: 'The extends clause is included here.',
|
||||
url: null,
|
||||
),
|
||||
],
|
||||
);
|
||||
return;
|
||||
}
|
||||
augmentationTarget = augmentationTarget.augmentationTarget;
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks the class for problems with the superclass, mixins, or implemented
|
||||
/// interfaces.
|
||||
///
|
||||
|
|
|
@ -102,6 +102,7 @@ class ElementBuilder extends ThrowingAstVisitor<void> {
|
|||
element.isAbstract = true;
|
||||
element.isSealed = true;
|
||||
}
|
||||
element.hasExtendsClause = node.extendsClause != null;
|
||||
element.metadata = _buildAnnotations(node.metadata);
|
||||
_setCodeRange(element, node);
|
||||
_setDocumentation(element, node);
|
||||
|
|
|
@ -7,22 +7,24 @@ import 'package:analyzer/src/summary2/data_reader.dart';
|
|||
import 'package:analyzer/src/summary2/data_writer.dart';
|
||||
|
||||
class ClassElementFlags {
|
||||
static const int _isAbstract = 1 << 0;
|
||||
static const int _isAugmentation = 1 << 1;
|
||||
static const int _isBase = 1 << 2;
|
||||
static const int _isFinal = 1 << 3;
|
||||
static const int _isInterface = 1 << 4;
|
||||
static const int _isMacro = 1 << 5;
|
||||
static const int _isMixinApplication = 1 << 6;
|
||||
static const int _isMixinClass = 1 << 7;
|
||||
static const int _isSealed = 1 << 8;
|
||||
static const int _isSimplyBounded = 1 << 9;
|
||||
static const int _hasExtendsClause = 1 << 0;
|
||||
static const int _isAbstract = 1 << 1;
|
||||
static const int _isAugmentation = 1 << 2;
|
||||
static const int _isBase = 1 << 3;
|
||||
static const int _isFinal = 1 << 4;
|
||||
static const int _isInterface = 1 << 5;
|
||||
static const int _isMacro = 1 << 6;
|
||||
static const int _isMixinApplication = 1 << 7;
|
||||
static const int _isMixinClass = 1 << 8;
|
||||
static const int _isSealed = 1 << 9;
|
||||
static const int _isSimplyBounded = 1 << 10;
|
||||
|
||||
static void read(
|
||||
SummaryDataReader reader,
|
||||
ClassElementImpl element,
|
||||
) {
|
||||
var byte = reader.readUInt30();
|
||||
element.hasExtendsClause = (byte & _hasExtendsClause) != 0;
|
||||
element.isAbstract = (byte & _isAbstract) != 0;
|
||||
element.isAugmentation = (byte & _isAugmentation) != 0;
|
||||
element.isBase = (byte & _isBase) != 0;
|
||||
|
@ -40,6 +42,7 @@ class ClassElementFlags {
|
|||
ClassElementImpl element,
|
||||
) {
|
||||
var result = 0;
|
||||
result |= element.hasExtendsClause ? _hasExtendsClause : 0;
|
||||
result |= element.isAbstract ? _isAbstract : 0;
|
||||
result |= element.isAugmentation ? _isAugmentation : 0;
|
||||
result |= element.isBase ? _isBase : 0;
|
||||
|
|
|
@ -1131,6 +1131,9 @@ CompileTimeErrorCode:
|
|||
}
|
||||
}
|
||||
```
|
||||
AUGMENTATION_EXTENDS_CLAUSE_ALREADY_PRESENT:
|
||||
problemMessage: The augmentation has an 'extends' clause, but an augmentation target already includes an 'extends' clause and it isn't allowed to be repeated or changed.
|
||||
correctionMessage: Try removing the 'extends' clause, either here or in the augmentation target.
|
||||
AUGMENTATION_MODIFIER_EXTRA:
|
||||
problemMessage: The augmentation has the '{0}' modifier that the declaration doesn't have.
|
||||
correctionMessage: Try removing the '{0}' modifier, or adding it to the declaration.
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
// 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(AugmentationExtendsClauseAlreadyPresentTest);
|
||||
});
|
||||
}
|
||||
|
||||
@reflectiveTest
|
||||
class AugmentationExtendsClauseAlreadyPresentTest
|
||||
extends PubPackageResolutionTest {
|
||||
test_alreadyPresent() async {
|
||||
var a = newFile('$testPackageLibPath/a.dart', r'''
|
||||
import augment 'test.dart';
|
||||
|
||||
class A {}
|
||||
|
||||
class B extends A {};
|
||||
''');
|
||||
|
||||
await assertErrorsInCode(r'''
|
||||
augment library 'a.dart';
|
||||
|
||||
augment class B extends A {}
|
||||
''', [
|
||||
error(CompileTimeErrorCode.AUGMENTATION_EXTENDS_CLAUSE_ALREADY_PRESENT,
|
||||
43, 7,
|
||||
contextMessages: [message(a, 47, 1)]),
|
||||
]);
|
||||
}
|
||||
|
||||
test_alreadyPresent2() async {
|
||||
var a = newFile('$testPackageLibPath/a.dart', r'''
|
||||
import augment 'b.dart';
|
||||
import augment 'test.dart';
|
||||
|
||||
class A {}
|
||||
|
||||
class B extends A {};
|
||||
''');
|
||||
|
||||
newFile('$testPackageLibPath/b.dart', r'''
|
||||
augment library 'a.dart';
|
||||
|
||||
augment class B {}
|
||||
''');
|
||||
|
||||
await assertErrorsInCode(r'''
|
||||
augment library 'a.dart';
|
||||
|
||||
augment class B extends A {}
|
||||
''', [
|
||||
error(CompileTimeErrorCode.AUGMENTATION_EXTENDS_CLAUSE_ALREADY_PRESENT,
|
||||
43, 7,
|
||||
contextMessages: [message(a, 72, 1)]),
|
||||
]);
|
||||
}
|
||||
|
||||
test_notPresent() async {
|
||||
newFile('$testPackageLibPath/a.dart', r'''
|
||||
import augment 'test.dart';
|
||||
|
||||
class A {}
|
||||
|
||||
class B {};
|
||||
''');
|
||||
|
||||
await assertNoErrorsInCode(r'''
|
||||
augment library 'a.dart';
|
||||
|
||||
augment class B extends A {}
|
||||
''');
|
||||
}
|
||||
}
|
|
@ -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_extends_clause_already_present_test.dart'
|
||||
as augmentation_extends_clause_already_present;
|
||||
import 'augmentation_modifier_extra_test.dart' as augmentation_modifier_extra;
|
||||
import 'augmentation_modifier_missing_test.dart'
|
||||
as augmentation_modifier_missing;
|
||||
|
@ -943,6 +945,7 @@ main() {
|
|||
assignment_to_type.main();
|
||||
async_for_in_wrong_context.main();
|
||||
async_keyword_used_as_identifier.main();
|
||||
augmentation_extends_clause_already_present.main();
|
||||
augmentation_modifier_extra.main();
|
||||
augmentation_modifier_missing.main();
|
||||
augmentation_of_different_declaration_kind.main();
|
||||
|
|
Loading…
Reference in a new issue