Add handling for error cases in class_test regarding too few or too many TypeParameters in augments.

Also added handling for cases involving TypeParameter bounds, and fixed
several errors leading their incorrect display.

Change-Id: Ice908849daae2e115b34f50e55be1f2fca82cc96
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/448443
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Paul Berry <paulberry@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
Reviewed-by: Johnni Winther <johnniwinther@google.com>
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart
index c8917e3..2283d02 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -4609,6 +4609,11 @@
     _setters.add(fragment);
     fragment.enclosingFragment = this;
   }
+
+  void addTypeParameter(TypeParameterFragmentImpl typeParameter) {
+    _typeParameters.add(typeParameter);
+    typeParameter.enclosingFragment = this;
+  }
 }
 
 abstract class InterfaceElementImpl extends InstanceElementImpl
@@ -10127,7 +10132,8 @@
   MetadataImpl get metadata2 => metadata;
 
   @override
-  int get offset => nameOffset ?? firstTokenOffset!;
+  int get offset =>
+      nameOffset ?? firstTokenOffset ?? enclosingFragment?.offset ?? -1;
 
   void addFragment(TypeParameterFragmentImpl fragment) {
     fragment.element = element;
diff --git a/pkg/analyzer/lib/src/summary2/element_builder.dart b/pkg/analyzer/lib/src/summary2/element_builder.dart
index ab5e759..e743c2a 100644
--- a/pkg/analyzer/lib/src/summary2/element_builder.dart
+++ b/pkg/analyzer/lib/src/summary2/element_builder.dart
@@ -195,6 +195,26 @@
       lastFragment.addFragment(fragment);
 
       var lastTypeParameterFragments = lastFragment.typeParameters;
+
+      // Trim extra type parameters.
+      if (lastTypeParameterFragments.length < fragment.typeParameters.length) {
+        fragment.typeParameters.length = lastTypeParameterFragments.length;
+      }
+
+      // Synthesize missing type parameters.
+      if (lastTypeParameterFragments.length > fragment.typeParameters.length) {
+        for (
+          var i = fragment.typeParameters.length;
+          i < lastTypeParameterFragments.length;
+          i++
+        ) {
+          fragment.addTypeParameter(
+            TypeParameterFragmentImpl(name: lastTypeParameterFragments[i].name)
+              ..isSynthetic = true,
+          );
+        }
+      }
+
       for (var i = 0; i < lastTypeParameterFragments.length; i++) {
         lastTypeParameterFragments[i].addFragment(fragment.typeParameters[i]);
       }
diff --git a/pkg/analyzer/lib/src/summary2/reference_resolver.dart b/pkg/analyzer/lib/src/summary2/reference_resolver.dart
index ec14073..5e80530 100644
--- a/pkg/analyzer/lib/src/summary2/reference_resolver.dart
+++ b/pkg/analyzer/lib/src/summary2/reference_resolver.dart
@@ -569,7 +569,9 @@
     if (bound != null) {
       bound.accept(this);
       var fragment = node.declaredFragment!;
-      fragment.element.bound = bound.type;
+      if (fragment.previousFragment == null) {
+        fragment.element.bound = bound.type;
+      }
       nodesToBuildType.addDeclaration(node);
     }
   }
diff --git a/pkg/analyzer/lib/src/summary2/types_builder.dart b/pkg/analyzer/lib/src/summary2/types_builder.dart
index 5149ee9..d3cd9c7 100644
--- a/pkg/analyzer/lib/src/summary2/types_builder.dart
+++ b/pkg/analyzer/lib/src/summary2/types_builder.dart
@@ -396,7 +396,9 @@
 
   void _typeParameter(TypeParameterImpl node) {
     var fragment = node.declaredFragment!;
-    fragment.element.bound = node.bound?.type;
+    if (fragment.previousFragment == null) {
+      fragment.element.bound = node.bound?.type;
+    }
   }
 
   List<TypeParameterFragmentImpl> _typeParameters(TypeParameterListImpl? node) {
diff --git a/pkg/analyzer/test/src/summary/elements/class_test.dart b/pkg/analyzer/test/src/summary/elements/class_test.dart
index a3b9f1e..2fc6bba 100644
--- a/pkg/analyzer/test/src/summary/elements/class_test.dart
+++ b/pkg/analyzer/test/src/summary/elements/class_test.dart
@@ -27892,7 +27892,7 @@
 ''');
   }
 
-  test_typeParameters() async {
+  test_typeParameters_111() async {
     var library = await buildLibrary(r'''
 class A<T> {}
 augment class A<T> {}
@@ -27940,6 +27940,269 @@
 ''');
   }
 
+  test_typeParameters_121() async {
+    var library = await buildLibrary(r'''
+class A<T> {}
+augment class A<T, U> {}
+augment class A<T> {}
+''');
+
+    configuration.withConstructors = false;
+    checkElementText(library, r'''
+library
+  reference: <testLibrary>
+  fragments
+    #F0 <testLibraryFragment>
+      element: <testLibrary>
+      classes
+        #F1 class A (nameOffset:6) (firstTokenOffset:0) (offset:6)
+          element: <testLibrary>::@class::A
+          nextFragment: #F2
+          typeParameters
+            #F3 T (nameOffset:8) (firstTokenOffset:8) (offset:8)
+              element: #E0 T
+              nextFragment: #F4
+        #F2 class A (nameOffset:28) (firstTokenOffset:14) (offset:28)
+          element: <testLibrary>::@class::A
+          previousFragment: #F1
+          nextFragment: #F5
+          typeParameters
+            #F4 T (nameOffset:30) (firstTokenOffset:30) (offset:30)
+              element: #E0 T
+              previousFragment: #F3
+              nextFragment: #F6
+        #F5 class A (nameOffset:53) (firstTokenOffset:39) (offset:53)
+          element: <testLibrary>::@class::A
+          previousFragment: #F2
+          typeParameters
+            #F6 T (nameOffset:55) (firstTokenOffset:55) (offset:55)
+              element: #E0 T
+              previousFragment: #F4
+  classes
+    class A
+      reference: <testLibrary>::@class::A
+      firstFragment: #F1
+      typeParameters
+        #E0 T
+          firstFragment: #F3
+''');
+  }
+
+  test_typeParameters_212() async {
+    var library = await buildLibrary(r'''
+class A<T, U> {}
+augment class A<T> {}
+augment class A<T, U> {}
+''');
+
+    configuration.withConstructors = false;
+    checkElementText(library, r'''
+library
+  reference: <testLibrary>
+  fragments
+    #F0 <testLibraryFragment>
+      element: <testLibrary>
+      classes
+        #F1 class A (nameOffset:6) (firstTokenOffset:0) (offset:6)
+          element: <testLibrary>::@class::A
+          nextFragment: #F2
+          typeParameters
+            #F3 T (nameOffset:8) (firstTokenOffset:8) (offset:8)
+              element: #E0 T
+              nextFragment: #F4
+            #F5 U (nameOffset:11) (firstTokenOffset:11) (offset:11)
+              element: #E1 U
+              nextFragment: #F6
+        #F2 class A (nameOffset:31) (firstTokenOffset:17) (offset:31)
+          element: <testLibrary>::@class::A
+          previousFragment: #F1
+          nextFragment: #F7
+          typeParameters
+            #F4 T (nameOffset:33) (firstTokenOffset:33) (offset:33)
+              element: #E0 T
+              previousFragment: #F3
+              nextFragment: #F8
+            #F6 U (nameOffset:<null>) (firstTokenOffset:<null>) (offset:31)
+              element: #E1 U
+              previousFragment: #F5
+              nextFragment: #F9
+        #F7 class A (nameOffset:53) (firstTokenOffset:39) (offset:53)
+          element: <testLibrary>::@class::A
+          previousFragment: #F2
+          typeParameters
+            #F8 T (nameOffset:55) (firstTokenOffset:55) (offset:55)
+              element: #E0 T
+              previousFragment: #F4
+            #F9 U (nameOffset:58) (firstTokenOffset:58) (offset:58)
+              element: #E1 U
+              previousFragment: #F6
+  classes
+    class A
+      reference: <testLibrary>::@class::A
+      firstFragment: #F1
+      typeParameters
+        #E0 T
+          firstFragment: #F3
+        #E1 U
+          firstFragment: #F5
+''');
+  }
+
+  test_typeParameters_bounds_01() async {
+    var library = await buildLibrary(r'''
+class A<T2> {}
+augment class A<T2 extends int> {}
+''');
+
+    configuration.withConstructors = false;
+    checkElementText(library, r'''
+library
+  reference: <testLibrary>
+  fragments
+    #F0 <testLibraryFragment>
+      element: <testLibrary>
+      classes
+        #F1 class A (nameOffset:6) (firstTokenOffset:0) (offset:6)
+          element: <testLibrary>::@class::A
+          nextFragment: #F2
+          typeParameters
+            #F3 T2 (nameOffset:8) (firstTokenOffset:8) (offset:8)
+              element: #E0 T2
+              nextFragment: #F4
+        #F2 class A (nameOffset:29) (firstTokenOffset:15) (offset:29)
+          element: <testLibrary>::@class::A
+          previousFragment: #F1
+          typeParameters
+            #F4 T2 (nameOffset:31) (firstTokenOffset:31) (offset:31)
+              element: #E0 T2
+              previousFragment: #F3
+  classes
+    class A
+      reference: <testLibrary>::@class::A
+      firstFragment: #F1
+      typeParameters
+        #E0 T2
+          firstFragment: #F3
+''');
+  }
+
+  test_typeParameters_bounds_10() async {
+    var library = await buildLibrary(r'''
+class A<T extends int> {}
+augment class A<T> {}
+''');
+
+    configuration.withConstructors = false;
+    checkElementText(library, r'''
+library
+  reference: <testLibrary>
+  fragments
+    #F0 <testLibraryFragment>
+      element: <testLibrary>
+      classes
+        #F1 class A (nameOffset:6) (firstTokenOffset:0) (offset:6)
+          element: <testLibrary>::@class::A
+          nextFragment: #F2
+          typeParameters
+            #F3 T (nameOffset:8) (firstTokenOffset:8) (offset:8)
+              element: #E0 T
+              nextFragment: #F4
+        #F2 class A (nameOffset:40) (firstTokenOffset:26) (offset:40)
+          element: <testLibrary>::@class::A
+          previousFragment: #F1
+          typeParameters
+            #F4 T (nameOffset:42) (firstTokenOffset:42) (offset:42)
+              element: #E0 T
+              previousFragment: #F3
+  classes
+    class A
+      reference: <testLibrary>::@class::A
+      firstFragment: #F1
+      typeParameters
+        #E0 T
+          firstFragment: #F3
+          bound: int
+''');
+  }
+
+  test_typeParameters_bounds_11() async {
+    var library = await buildLibrary(r'''
+class A<T extends int> {}
+augment class A<T extends int> {}
+''');
+
+    configuration.withConstructors = false;
+    checkElementText(library, r'''
+library
+  reference: <testLibrary>
+  fragments
+    #F0 <testLibraryFragment>
+      element: <testLibrary>
+      classes
+        #F1 class A (nameOffset:6) (firstTokenOffset:0) (offset:6)
+          element: <testLibrary>::@class::A
+          nextFragment: #F2
+          typeParameters
+            #F3 T (nameOffset:8) (firstTokenOffset:8) (offset:8)
+              element: #E0 T
+              nextFragment: #F4
+        #F2 class A (nameOffset:40) (firstTokenOffset:26) (offset:40)
+          element: <testLibrary>::@class::A
+          previousFragment: #F1
+          typeParameters
+            #F4 T (nameOffset:42) (firstTokenOffset:42) (offset:42)
+              element: #E0 T
+              previousFragment: #F3
+  classes
+    class A
+      reference: <testLibrary>::@class::A
+      firstFragment: #F1
+      typeParameters
+        #E0 T
+          firstFragment: #F3
+          bound: int
+''');
+  }
+
+  test_typeParameters_bounds_12() async {
+    var library = await buildLibrary(r'''
+class A<T extends int> {}
+augment class A<T extends String> {}
+''');
+
+    configuration.withConstructors = false;
+    checkElementText(library, r'''
+library
+  reference: <testLibrary>
+  fragments
+    #F0 <testLibraryFragment>
+      element: <testLibrary>
+      classes
+        #F1 class A (nameOffset:6) (firstTokenOffset:0) (offset:6)
+          element: <testLibrary>::@class::A
+          nextFragment: #F2
+          typeParameters
+            #F3 T (nameOffset:8) (firstTokenOffset:8) (offset:8)
+              element: #E0 T
+              nextFragment: #F4
+        #F2 class A (nameOffset:40) (firstTokenOffset:26) (offset:40)
+          element: <testLibrary>::@class::A
+          previousFragment: #F1
+          typeParameters
+            #F4 T (nameOffset:42) (firstTokenOffset:42) (offset:42)
+              element: #E0 T
+              previousFragment: #F3
+  classes
+    class A
+      reference: <testLibrary>::@class::A
+      firstFragment: #F1
+      typeParameters
+        #E0 T
+          firstFragment: #F3
+          bound: int
+''');
+  }
+
   test_typeParameters_defaultType() async {
     var library = await buildLibrary(r'''
 class A<T extends B> {}
@@ -28000,6 +28263,52 @@
           firstFragment: #F7
 ''');
   }
+
+  test_typeParameters_differentNames() async {
+    var library = await buildLibrary(r'''
+class A<T, U> {}
+augment class A<U, T> {}
+''');
+
+    configuration.withConstructors = false;
+    checkElementText(library, r'''
+library
+  reference: <testLibrary>
+  fragments
+    #F0 <testLibraryFragment>
+      element: <testLibrary>
+      classes
+        #F1 class A (nameOffset:6) (firstTokenOffset:0) (offset:6)
+          element: <testLibrary>::@class::A
+          nextFragment: #F2
+          typeParameters
+            #F3 T (nameOffset:8) (firstTokenOffset:8) (offset:8)
+              element: #E0 T
+              nextFragment: #F4
+            #F5 U (nameOffset:11) (firstTokenOffset:11) (offset:11)
+              element: #E1 U
+              nextFragment: #F6
+        #F2 class A (nameOffset:31) (firstTokenOffset:17) (offset:31)
+          element: <testLibrary>::@class::A
+          previousFragment: #F1
+          typeParameters
+            #F4 U (nameOffset:33) (firstTokenOffset:33) (offset:33)
+              element: #E0 T
+              previousFragment: #F3
+            #F6 T (nameOffset:36) (firstTokenOffset:36) (offset:36)
+              element: #E1 U
+              previousFragment: #F5
+  classes
+    class A
+      reference: <testLibrary>::@class::A
+      firstFragment: #F1
+      typeParameters
+        #E0 T
+          firstFragment: #F3
+        #E1 U
+          firstFragment: #F5
+''');
+  }
 }
 
 @reflectiveTest