Augment. Report IMPLEMENTS_REPEATED and ON_REPEATED.
Change-Id: Ib3ccad6ea7e67b7512dc2f428f39229fb1d9c971
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/373721
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart
index 0fe0d5f..dd68abf 100644
--- a/pkg/analyzer/lib/src/generated/error_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
@@ -242,7 +242,7 @@
/// The features enabled in the unit currently being checked for errors.
FeatureSet? _featureSet;
- final LibraryVerificationContext libraryVerificationContext;
+ final LibraryVerificationContext libraryContext;
final RequiredParametersVerifier _requiredParametersVerifier;
final ConstArgumentsVerifier _constArgumentsVerifier;
final DuplicateDefinitionVerifier _duplicateDefinitionVerifier;
@@ -257,7 +257,7 @@
this._currentLibrary,
this._typeProvider,
this._inheritanceManager,
- this.libraryVerificationContext,
+ this.libraryContext,
this.options, {
required this.typeSystemOperations,
}) : _uninstantiatedBoundChecker =
@@ -269,7 +269,7 @@
_inheritanceManager,
_currentLibrary,
errorReporter,
- libraryVerificationContext.duplicationDefinitionContext,
+ libraryContext.duplicationDefinitionContext,
) {
_isInSystemLibrary = _currentLibrary.source.uri.isScheme('dart');
_isInStaticVariableDeclaration = false;
@@ -494,14 +494,14 @@
superclass != null ||
withClause != null) {
var moreChecks = _checkClassInheritance(
- node, superclass, withClause, implementsClause);
+ declarationElement, node, superclass, withClause, implementsClause);
if (moreChecks) {
_checkForNoDefaultSuperConstructorImplicit(element, augmented);
}
}
if (node.nativeClause == null) {
- libraryVerificationContext.constructorFieldsVerifier
+ libraryContext.constructorFieldsVerifier
.addConstructors(errorReporter, augmented, members);
}
@@ -530,13 +530,17 @@
}
@override
- void visitClassTypeAlias(ClassTypeAlias node) {
+ void visitClassTypeAlias(covariant ClassTypeAliasImpl node) {
+ var element = node.declaredElement!;
+ var augmented = element.augmented;
+ var declarationElement = augmented.declaration;
+
_checkForBuiltInIdentifierAsName(
node.name, CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_TYPEDEF_NAME);
try {
- _enclosingClass = node.declaredElement as ClassElementImpl;
- _checkClassInheritance(
- node, node.superclass, node.withClause, node.implementsClause);
+ _enclosingClass = declarationElement;
+ _checkClassInheritance(declarationElement, node, node.superclass,
+ node.withClause, node.implementsClause);
_checkForMainFunction1(node.name, node.declaredElement!);
_checkForMixinClassErrorCodes(
node, List.empty(), node.superclass, node.withClause);
@@ -691,7 +695,8 @@
var withClause = node.withClause;
if (implementsClause != null || withClause != null) {
- _checkClassInheritance(node, null, withClause, implementsClause);
+ _checkClassInheritance(
+ declarationElement, node, null, withClause, implementsClause);
}
if (!element.isAugmentation) {
@@ -704,7 +709,7 @@
}
var members = node.members;
- libraryVerificationContext.constructorFieldsVerifier
+ libraryContext.constructorFieldsVerifier
.addConstructors(errorReporter, augmented, members);
_checkForFinalNotInitializedInClass(element, members);
_checkForWrongTypeParameterVarianceInSuperinterfaces();
@@ -813,11 +818,14 @@
var members = node.members;
_duplicateDefinitionVerifier.checkExtensionType(node, declarationElement);
- _checkForRepeatedType(node.implementsClause?.interfaces,
- CompileTimeErrorCode.IMPLEMENTS_REPEATED);
+ _checkForRepeatedType(
+ libraryContext.setOfImplements(declarationElement),
+ node.implementsClause?.interfaces,
+ CompileTimeErrorCode.IMPLEMENTS_REPEATED,
+ );
_checkForConflictingClassMembers(element);
_checkForConflictingGenerics(node);
- libraryVerificationContext.constructorFieldsVerifier
+ libraryContext.constructorFieldsVerifier
.addConstructors(errorReporter, augmented, members);
_checkForNonCovariantTypeParameterPositionInRepresentationType(
node, element);
@@ -1242,7 +1250,8 @@
// Only do error checks only if there is a non-null clause.
if (onClause != null || implementsClause != null) {
- _checkMixinInheritance(node, onClause, implementsClause);
+ _checkMixinInheritance(
+ declarationElement, node, onClause, implementsClause);
}
_checkForConflictingClassMembers(element);
@@ -1863,6 +1872,7 @@
/// Returns `false` if a severe hierarchy error was found, so that further
/// checking is not useful.
bool _checkClassInheritance(
+ InterfaceElementImpl declarationElement,
NamedCompilationUnitMember node,
NamedType? superclass,
WithClause? withClause,
@@ -1875,8 +1885,11 @@
!_checkForAllMixinErrorCodes(withClause) &&
!_checkForNoGenerativeConstructorsInSuperclass(superclass)) {
_checkForExtendsDeferredClass(superclass);
- _checkForRepeatedType(implementsClause?.interfaces,
- CompileTimeErrorCode.IMPLEMENTS_REPEATED);
+ _checkForRepeatedType(
+ libraryContext.setOfImplements(declarationElement),
+ implementsClause?.interfaces,
+ CompileTimeErrorCode.IMPLEMENTS_REPEATED,
+ );
_checkImplementsSuperClass(implementsClause);
_checkMixinsSuperClass(withClause);
_checkForMixinWithConflictingPrivateMember(withClause, superclass);
@@ -5142,30 +5155,26 @@
}
}
- void _checkForRepeatedType(List<NamedType>? namedTypes, ErrorCode errorCode) {
+ void _checkForRepeatedType(
+ Set<InstanceElement> accumulatedElements,
+ List<NamedType>? namedTypes,
+ ErrorCode errorCode,
+ ) {
if (namedTypes == null) {
return;
}
- int count = namedTypes.length;
- List<bool> detectedRepeatOnIndex = List<bool>.filled(count, false);
- for (int i = 0; i < count; i++) {
- if (!detectedRepeatOnIndex[i]) {
- var type = namedTypes[i].type;
- if (type is InterfaceType) {
- var element = type.element;
- for (int j = i + 1; j < count; j++) {
- var otherNode = namedTypes[j];
- var otherType = otherNode.type;
- if (otherType is InterfaceType && otherType.element == element) {
- detectedRepeatOnIndex[j] = true;
- errorReporter.atNode(
- otherNode,
- errorCode,
- arguments: [element.name],
- );
- }
- }
+ for (var namedType in namedTypes) {
+ var type = namedType.type;
+ if (type is InterfaceType) {
+ var element = type.element;
+ var added = accumulatedElements.add(element);
+ if (!added) {
+ errorReporter.atNode(
+ namedType,
+ errorCode,
+ arguments: [element.name],
+ );
}
}
}
@@ -6062,7 +6071,10 @@
/// Checks the class for problems with the superclass, mixins, or implemented
/// interfaces.
- void _checkMixinInheritance(MixinDeclaration node, MixinOnClause? onClause,
+ void _checkMixinInheritance(
+ MixinElementImpl declarationElement,
+ MixinDeclaration node,
+ MixinOnClause? onClause,
ImplementsClause? implementsClause) {
// Only check for all of the inheritance logic around clauses if there
// isn't an error code such as "Cannot implement double" already.
@@ -6070,10 +6082,12 @@
!_checkForImplementsClauseErrorCodes(implementsClause)) {
// _checkForImplicitDynamicType(superclass);
_checkForRepeatedType(
+ libraryContext.setOfOn(declarationElement),
onClause?.superclassConstraints,
CompileTimeErrorCode.ON_REPEATED,
);
_checkForRepeatedType(
+ libraryContext.setOfImplements(declarationElement),
implementsClause?.interfaces,
CompileTimeErrorCode.IMPLEMENTS_REPEATED,
);
@@ -6394,7 +6408,7 @@
void _reportMacroDiagnostics(MacroTargetElement element) {
_MacroDiagnosticsReporter(
- libraryContext: libraryVerificationContext,
+ libraryContext: libraryContext,
errorReporter: errorReporter,
element: element,
).report();
@@ -6528,6 +6542,15 @@
final ConstructorFieldsVerifier constructorFieldsVerifier;
final Map<FileState, UnitAnalysis> units;
+ /// Elements referenced in `implements` clauses.
+ /// Key: the declaration element.
+ final Map<InstanceElement, Set<InstanceElement>> _setOfImplementsMap =
+ Map.identity();
+
+ /// Elements referenced in `on` clauses.
+ /// Key: the declaration element.
+ final Map<MixinElement, Set<InterfaceElement>> _setOfOnMaps = Map.identity();
+
LibraryVerificationContext({
required this.libraryKind,
required this.constructorFieldsVerifier,
@@ -6565,6 +6588,14 @@
bool libraryCycleContains(Uri uri) {
return libraryKind.libraryCycle.libraryUris.contains(uri);
}
+
+ Set<InstanceElement> setOfImplements(InstanceElement declaration) {
+ return _setOfImplementsMap[declaration] ??= Set.identity();
+ }
+
+ Set<InterfaceElement> setOfOn(MixinElement declaration) {
+ return _setOfOnMaps[declaration] ??= Set.identity();
+ }
}
class _MacroDiagnosticsReporter {
diff --git a/pkg/analyzer/test/src/diagnostics/implements_repeated_test.dart b/pkg/analyzer/test/src/diagnostics/implements_repeated_test.dart
index 558f003..285fc3f 100644
--- a/pkg/analyzer/test/src/diagnostics/implements_repeated_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/implements_repeated_test.dart
@@ -39,6 +39,27 @@
''');
}
+ test_class_implements_2times_augmentation() async {
+ var a = newFile('$testPackageLibPath/a.dart', r'''
+import augment 'b.dart';
+
+class A {}
+class B implements A {}
+''');
+
+ var b = newFile('$testPackageLibPath/b.dart', r'''
+augment library 'a.dart';
+
+augment class B implements A {}
+''');
+
+ await assertErrorsInFile2(a, []);
+
+ await assertErrorsInFile2(b, [
+ error(CompileTimeErrorCode.IMPLEMENTS_REPEATED, 54, 1),
+ ]);
+ }
+
test_class_implements_2times_viaTypeAlias() async {
await assertErrorsInCode(r'''
class A {}
@@ -102,6 +123,27 @@
''');
}
+ test_enum_implements_2times_augmentation() async {
+ var a = newFile('$testPackageLibPath/a.dart', r'''
+import augment 'b.dart';
+
+class A {}
+enum E implements A {v}
+''');
+
+ var b = newFile('$testPackageLibPath/b.dart', r'''
+augment library 'a.dart';
+
+augment enum E implements A {}
+''');
+
+ await assertErrorsInFile2(a, []);
+
+ await assertErrorsInFile2(b, [
+ error(CompileTimeErrorCode.IMPLEMENTS_REPEATED, 53, 1),
+ ]);
+ }
+
test_enum_implements_2times_viaTypeAlias() async {
await assertErrorsInCode(r'''
class A {}
@@ -166,6 +208,26 @@
''');
}
+ test_extensionType_implements_2times_augmentation() async {
+ var a = newFile('$testPackageLibPath/a.dart', r'''
+import augment 'b.dart';
+
+extension type A(int it) implements int {}
+''');
+
+ var b = newFile('$testPackageLibPath/b.dart', r'''
+augment library 'a.dart';
+
+augment extension type A(int it) implements int {}
+''');
+
+ await assertErrorsInFile2(a, []);
+
+ await assertErrorsInFile2(b, [
+ error(CompileTimeErrorCode.IMPLEMENTS_REPEATED, 71, 3),
+ ]);
+ }
+
test_extensionType_implements_2times_viaTypeAlias() async {
await assertErrorsInCode(r'''
typedef A = int;
@@ -210,6 +272,27 @@
]);
}
+ test_mixin_implements_2times_augmentation() async {
+ var a = newFile('$testPackageLibPath/a.dart', r'''
+import augment 'b.dart';
+
+class A {}
+mixin M implements A {}
+''');
+
+ var b = newFile('$testPackageLibPath/b.dart', r'''
+augment library 'a.dart';
+
+augment mixin M implements A {}
+''');
+
+ await assertErrorsInFile2(a, []);
+
+ await assertErrorsInFile2(b, [
+ error(CompileTimeErrorCode.IMPLEMENTS_REPEATED, 54, 1),
+ ]);
+ }
+
test_mixin_implements_4times() async {
await assertErrorsInCode(r'''
class A {}
diff --git a/pkg/analyzer/test/src/diagnostics/on_repeated_test.dart b/pkg/analyzer/test/src/diagnostics/on_repeated_test.dart
index 41c3a90..2daf11c 100644
--- a/pkg/analyzer/test/src/diagnostics/on_repeated_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/on_repeated_test.dart
@@ -24,6 +24,27 @@
]);
}
+ test_2times_augmentation() async {
+ var a = newFile('$testPackageLibPath/a.dart', r'''
+import augment 'b.dart';
+
+class A {}
+mixin M on A {}
+''');
+
+ var b = newFile('$testPackageLibPath/b.dart', r'''
+augment library 'a.dart';
+
+augment mixin M on A {}
+''');
+
+ await assertErrorsInFile2(a, []);
+
+ await assertErrorsInFile2(b, [
+ error(CompileTimeErrorCode.ON_REPEATED, 46, 1),
+ ]);
+ }
+
test_2times_viaTypeAlias() async {
await assertErrorsInCode(r'''
class A {}