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 {}