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