Copy lookup methods from InterfaceElement to Augmented classes
Change-Id: Ie93e6aee9dc0f7a918d694303b0f640296e2df42 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/352971 Reviewed-by: Konstantin Shcheglov <scheglov@google.com> Commit-Queue: Brian Wilkerson <brianwilkerson@google.com>
This commit is contained in:
committed by
Commit Queue
parent
8fe47542f5
commit
1af1f2ea8d
@@ -143,6 +143,39 @@ abstract class AugmentedInstanceElement {
|
||||
|
||||
/// Returns the setter from [accessors] that has the given [name].
|
||||
PropertyAccessorElement? getSetter(String name);
|
||||
|
||||
/// Returns the element representing the getter that results from looking up
|
||||
/// the given [name] in this class with respect to the given [library],
|
||||
/// or `null` if the look up fails.
|
||||
///
|
||||
/// The behavior of this method is defined by the Dart Language Specification
|
||||
/// in section 17.18 Lookup.
|
||||
PropertyAccessorElement? lookUpGetter({
|
||||
required String name,
|
||||
required LibraryElement library,
|
||||
});
|
||||
|
||||
/// Returns the element representing the method that results from looking up
|
||||
/// the given [name] in this class with respect to the given [library],
|
||||
/// or `null` if the look up fails.
|
||||
///
|
||||
/// The behavior of this method is defined by the Dart Language Specification
|
||||
/// in section 17.18 Lookup.
|
||||
MethodElement? lookUpMethod({
|
||||
required String name,
|
||||
required LibraryElement library,
|
||||
});
|
||||
|
||||
/// Returns the element representing the setter that results from looking up
|
||||
/// the given [name] in this class with respect to the given [library],
|
||||
/// or `null` if the look up fails.
|
||||
///
|
||||
/// The behavior of this method is defined by the Dart Language Specification
|
||||
/// in section 17.18 Lookup.
|
||||
PropertyAccessorElement? lookUpSetter({
|
||||
required String name,
|
||||
required LibraryElement library,
|
||||
});
|
||||
}
|
||||
|
||||
/// The result of applying augmentations to a [InterfaceElement].
|
||||
|
||||
@@ -941,6 +941,18 @@ class CompilationUnitElementImpl extends UriReferencedElementImpl
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Returns the mixin defined in this compilation unit that has the given
|
||||
/// [name], or `null` if this compilation unit does not define a mixin with
|
||||
/// the given name.
|
||||
MixinElement? getMixin(String name) {
|
||||
for (final mixin in mixins) {
|
||||
if (mixin.name == name) {
|
||||
return mixin;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
void setLinkedData(Reference reference, ElementLinkedData linkedData) {
|
||||
this.reference = reference;
|
||||
reference.element = this;
|
||||
@@ -4420,6 +4432,16 @@ class LibraryElementImpl extends LibraryOrAugmentationElementImpl
|
||||
return null;
|
||||
}
|
||||
|
||||
MixinElement? getMixin(String name) {
|
||||
for (final unitElement in units) {
|
||||
final element = unitElement.getMixin(name);
|
||||
if (element != null) {
|
||||
return element;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Return `true` if [reference] comes only from deprecated exports.
|
||||
bool isFromDeprecatedExport(ExportedReference reference) {
|
||||
if (reference is ExportedReferenceExported) {
|
||||
@@ -4981,6 +5003,131 @@ mixin MaybeAugmentedInstanceElementMixin implements AugmentedInstanceElement {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
PropertyAccessorElement? lookUpGetter({
|
||||
required String name,
|
||||
required LibraryElement library,
|
||||
}) {
|
||||
return _implementationsOfGetter(name)
|
||||
.firstWhereOrNull((getter) => getter.isAccessibleIn(library));
|
||||
}
|
||||
|
||||
@override
|
||||
MethodElement? lookUpMethod({
|
||||
required String name,
|
||||
required LibraryElement library,
|
||||
}) {
|
||||
return _implementationsOfMethod(name).firstWhereOrNull(
|
||||
(MethodElement method) => method.isAccessibleIn(library));
|
||||
}
|
||||
|
||||
@override
|
||||
PropertyAccessorElement? lookUpSetter({
|
||||
required String name,
|
||||
required LibraryElement library,
|
||||
}) {
|
||||
return _implementationsOfSetter(name).firstWhereOrNull(
|
||||
(PropertyAccessorElement setter) => setter.isAccessibleIn(library));
|
||||
}
|
||||
|
||||
/// Return an iterable containing all of the implementations of a getter with
|
||||
/// the given [name] that are defined in this class and any superclass of this
|
||||
/// class (but not in interfaces).
|
||||
///
|
||||
/// The getters that are returned are not filtered in any way. In particular,
|
||||
/// they can include getters that are not visible in some context. Clients
|
||||
/// must perform any necessary filtering.
|
||||
///
|
||||
/// The getters are returned based on the depth of their defining class; if
|
||||
/// this class contains a definition of the getter it will occur first, if
|
||||
/// Object contains a definition of the getter it will occur last.
|
||||
Iterable<PropertyAccessorElement> _implementationsOfGetter(
|
||||
String name) sync* {
|
||||
final visitedClasses = <AugmentedInstanceElement>{};
|
||||
AugmentedInstanceElement? augmented = this;
|
||||
while (augmented != null && visitedClasses.add(augmented)) {
|
||||
var getter = augmented.getGetter(name);
|
||||
if (getter != null) {
|
||||
yield getter;
|
||||
}
|
||||
if (augmented is! AugmentedInterfaceElement) {
|
||||
return;
|
||||
}
|
||||
for (InterfaceType mixin in augmented.mixins.reversed) {
|
||||
getter = mixin.element.augmented?.getGetter(name);
|
||||
if (getter != null) {
|
||||
yield getter;
|
||||
}
|
||||
}
|
||||
augmented = augmented.declaration.supertype?.element.augmented;
|
||||
}
|
||||
}
|
||||
|
||||
/// Return an iterable containing all of the implementations of a method with
|
||||
/// the given [name] that are defined in this class and any superclass of this
|
||||
/// class (but not in interfaces).
|
||||
///
|
||||
/// The methods that are returned are not filtered in any way. In particular,
|
||||
/// they can include methods that are not visible in some context. Clients
|
||||
/// must perform any necessary filtering.
|
||||
///
|
||||
/// The methods are returned based on the depth of their defining class; if
|
||||
/// this class contains a definition of the method it will occur first, if
|
||||
/// Object contains a definition of the method it will occur last.
|
||||
Iterable<MethodElement> _implementationsOfMethod(String name) sync* {
|
||||
final visitedClasses = <AugmentedInstanceElement>{};
|
||||
AugmentedInstanceElement? augmented = this;
|
||||
while (augmented != null && visitedClasses.add(augmented)) {
|
||||
var method = augmented.getMethod(name);
|
||||
if (method != null) {
|
||||
yield method;
|
||||
}
|
||||
if (augmented is! AugmentedInterfaceElement) {
|
||||
return;
|
||||
}
|
||||
for (InterfaceType mixin in augmented.mixins.reversed) {
|
||||
method = mixin.element.augmented?.getMethod(name);
|
||||
if (method != null) {
|
||||
yield method;
|
||||
}
|
||||
}
|
||||
augmented = augmented.declaration.supertype?.element.augmented;
|
||||
}
|
||||
}
|
||||
|
||||
/// Return an iterable containing all of the implementations of a setter with
|
||||
/// the given [name] that are defined in this class and any superclass of this
|
||||
/// class (but not in interfaces).
|
||||
///
|
||||
/// The setters that are returned are not filtered in any way. In particular,
|
||||
/// they can include setters that are not visible in some context. Clients
|
||||
/// must perform any necessary filtering.
|
||||
///
|
||||
/// The setters are returned based on the depth of their defining class; if
|
||||
/// this class contains a definition of the setter it will occur first, if
|
||||
/// Object contains a definition of the setter it will occur last.
|
||||
Iterable<PropertyAccessorElement> _implementationsOfSetter(
|
||||
String name) sync* {
|
||||
final visitedClasses = <AugmentedInstanceElement>{};
|
||||
AugmentedInstanceElement? augmented = this;
|
||||
while (augmented != null && visitedClasses.add(augmented)) {
|
||||
var setter = augmented.getSetter(name);
|
||||
if (setter != null) {
|
||||
yield setter;
|
||||
}
|
||||
if (augmented is! AugmentedInterfaceElement) {
|
||||
return;
|
||||
}
|
||||
for (InterfaceType mixin in augmented.mixins.reversed) {
|
||||
setter = mixin.element.augmented?.getSetter(name);
|
||||
if (setter != null) {
|
||||
yield setter;
|
||||
}
|
||||
}
|
||||
augmented = augmented.declaration.supertype?.element.augmented;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mixin MaybeAugmentedInterfaceElementMixin on MaybeAugmentedInstanceElementMixin
|
||||
|
||||
@@ -15,6 +15,7 @@ import 'package:test_reflective_loader/test_reflective_loader.dart';
|
||||
|
||||
import '../../../generated/type_system_base.dart';
|
||||
import '../../../util/feature_sets.dart';
|
||||
import '../../summary/elements_base.dart';
|
||||
import '../resolution/context_collection_resolution.dart';
|
||||
import 'string_types.dart';
|
||||
|
||||
@@ -24,6 +25,7 @@ main() {
|
||||
defineReflectiveTests(FieldElementImplTest);
|
||||
defineReflectiveTests(FunctionTypeImplTest);
|
||||
defineReflectiveTests(InterfaceTypeImplTest);
|
||||
defineReflectiveTests(MaybeAugmentedInstanceElementMixinTest);
|
||||
defineReflectiveTests(MethodElementImplTest);
|
||||
defineReflectiveTests(TypeParameterTypeImplTest);
|
||||
defineReflectiveTests(VoidTypeImplTest);
|
||||
@@ -1622,6 +1624,303 @@ A<int>?
|
||||
}
|
||||
}
|
||||
|
||||
@reflectiveTest
|
||||
class MaybeAugmentedInstanceElementMixinTest extends ElementsBaseTest {
|
||||
@override
|
||||
bool get keepLinkingLibraries => true;
|
||||
|
||||
test_lookUpGetter_declared() async {
|
||||
var library = await buildLibrary('''
|
||||
class A {
|
||||
int get g {}
|
||||
}
|
||||
''');
|
||||
var classA = library.getClass('A')!;
|
||||
var getter = classA.accessors[0];
|
||||
expect(classA.augmented?.lookUpGetter(name: 'g', library: library),
|
||||
same(getter));
|
||||
}
|
||||
|
||||
test_lookUpGetter_fromAugmentation() async {
|
||||
newFile('$testPackageLibPath/a.dart', '''
|
||||
library augment 'test.dart';
|
||||
|
||||
augment class A {
|
||||
int get g {}
|
||||
}
|
||||
''');
|
||||
var library = await buildLibrary('''
|
||||
import augment 'a.dart';
|
||||
|
||||
class A {}
|
||||
''');
|
||||
var classA = library.getClass('A')!;
|
||||
var getter = classA.augmented!.accessors[0];
|
||||
expect(classA.augmented?.lookUpGetter(name: 'g', library: library),
|
||||
same(getter));
|
||||
}
|
||||
|
||||
test_lookUpGetter_inherited() async {
|
||||
var library = await buildLibrary('''
|
||||
class A {
|
||||
int get g {}
|
||||
}
|
||||
class B extends A {}
|
||||
''');
|
||||
var classA = library.getClass('A')!;
|
||||
var getter = classA.accessors[0];
|
||||
var classB = library.getClass('B')!;
|
||||
expect(classB.augmented?.lookUpGetter(name: 'g', library: library),
|
||||
same(getter));
|
||||
}
|
||||
|
||||
test_lookUpGetter_inherited_fromAugmentation() async {
|
||||
newFile('$testPackageLibPath/a.dart', '''
|
||||
library augment 'test.dart';
|
||||
|
||||
augment class A {
|
||||
int get g {}
|
||||
}
|
||||
''');
|
||||
var library = await buildLibrary('''
|
||||
import augment 'a.dart';
|
||||
|
||||
class A {}
|
||||
class B extends A {}
|
||||
''');
|
||||
var classA = library.getClass('A')!;
|
||||
var getter = classA.augmented!.accessors[0];
|
||||
var classB = library.getClass('B')!;
|
||||
expect(classB.augmented?.lookUpGetter(name: 'g', library: library),
|
||||
same(getter));
|
||||
}
|
||||
|
||||
test_lookUpGetter_inherited_fromMixin() async {
|
||||
var library = await buildLibrary('''
|
||||
mixin A {
|
||||
int get g {}
|
||||
}
|
||||
class B with A {}
|
||||
''');
|
||||
var mixinA = library.getMixin('A')!;
|
||||
var getter = mixinA.accessors[0];
|
||||
var classB = library.getClass('B')!;
|
||||
expect(classB.augmented?.lookUpGetter(name: 'g', library: library),
|
||||
same(getter));
|
||||
}
|
||||
|
||||
test_lookUpGetter_undeclared() async {
|
||||
var library = await buildLibrary('''
|
||||
class A {}
|
||||
''');
|
||||
var classA = library.getClass('A')!;
|
||||
expect(classA.augmented?.lookUpGetter(name: 'g', library: library), isNull);
|
||||
}
|
||||
|
||||
test_lookUpGetter_undeclared_recursive() async {
|
||||
var library = await buildLibrary('''
|
||||
class A extends B {}
|
||||
class B extends A {}
|
||||
''');
|
||||
var classA = library.getClass('A')!;
|
||||
expect(classA.augmented?.lookUpGetter(name: 'g', library: library), isNull);
|
||||
}
|
||||
|
||||
test_lookUpMethod_declared() async {
|
||||
var library = await buildLibrary('''
|
||||
class A {
|
||||
int m() {}
|
||||
}
|
||||
''');
|
||||
var classA = library.getClass('A')!;
|
||||
var method = classA.methods[0];
|
||||
expect(classA.augmented?.lookUpMethod(name: 'm', library: library),
|
||||
same(method));
|
||||
}
|
||||
|
||||
test_lookUpMethod_fromAugmentation() async {
|
||||
newFile('$testPackageLibPath/a.dart', '''
|
||||
library augment 'test.dart';
|
||||
|
||||
augment class A {
|
||||
int m() {}
|
||||
}
|
||||
''');
|
||||
var library = await buildLibrary('''
|
||||
import augment 'a.dart';
|
||||
|
||||
class A {}
|
||||
''');
|
||||
var classA = library.getClass('A')!;
|
||||
var method = classA.augmented!.methods[0];
|
||||
expect(classA.augmented?.lookUpMethod(name: 'm', library: library),
|
||||
same(method));
|
||||
}
|
||||
|
||||
test_lookUpMethod_inherited() async {
|
||||
var library = await buildLibrary('''
|
||||
class A {
|
||||
int m() {}
|
||||
}
|
||||
class B extends A {}
|
||||
''');
|
||||
var classA = library.getClass('A')!;
|
||||
var method = classA.methods[0];
|
||||
var classB = library.getClass('B')!;
|
||||
expect(classB.augmented?.lookUpMethod(name: 'm', library: library),
|
||||
same(method));
|
||||
}
|
||||
|
||||
test_lookUpMethod_inherited_fromAugmentation() async {
|
||||
newFile('$testPackageLibPath/a.dart', '''
|
||||
library augment 'test.dart';
|
||||
|
||||
augment class A {
|
||||
int m() {}
|
||||
}
|
||||
''');
|
||||
var library = await buildLibrary('''
|
||||
import augment 'a.dart';
|
||||
|
||||
class A {}
|
||||
class B extends A {}
|
||||
''');
|
||||
var classA = library.getClass('A')!;
|
||||
var method = classA.augmented!.methods[0];
|
||||
var classB = library.getClass('B')!;
|
||||
expect(classB.augmented?.lookUpMethod(name: 'm', library: library),
|
||||
same(method));
|
||||
}
|
||||
|
||||
test_lookUpMethod_inherited_fromMixin() async {
|
||||
var library = await buildLibrary('''
|
||||
mixin A {
|
||||
int m() {}
|
||||
}
|
||||
class B with A {}
|
||||
''');
|
||||
var mixinA = library.getMixin('A')!;
|
||||
var method = mixinA.methods[0];
|
||||
var classB = library.getClass('B')!;
|
||||
expect(classB.augmented?.lookUpMethod(name: 'm', library: library),
|
||||
same(method));
|
||||
}
|
||||
|
||||
test_lookUpMethod_undeclared() async {
|
||||
var library = await buildLibrary('''
|
||||
class A {}
|
||||
''');
|
||||
var classA = library.getClass('A')!;
|
||||
expect(classA.augmented?.lookUpMethod(name: 'm', library: library), isNull);
|
||||
}
|
||||
|
||||
test_lookUpMethod_undeclared_recursive() async {
|
||||
var library = await buildLibrary('''
|
||||
class A extends B {}
|
||||
class B extends A {}
|
||||
''');
|
||||
var classA = library.getClass('A')!;
|
||||
expect(classA.augmented?.lookUpMethod(name: 'm', library: library), isNull);
|
||||
}
|
||||
|
||||
test_lookUpSetter_declared() async {
|
||||
var library = await buildLibrary('''
|
||||
class A {
|
||||
set s(x) {}
|
||||
}
|
||||
''');
|
||||
var classA = library.getClass('A')!;
|
||||
var setter = classA.accessors[0];
|
||||
expect(classA.augmented?.lookUpSetter(name: 's', library: library),
|
||||
same(setter));
|
||||
}
|
||||
|
||||
test_lookUpSetter_fromAugmentation() async {
|
||||
newFile('$testPackageLibPath/a.dart', '''
|
||||
library augment 'test.dart';
|
||||
|
||||
augment class A {
|
||||
set s(x) {}
|
||||
}
|
||||
''');
|
||||
var library = await buildLibrary('''
|
||||
import augment 'a.dart';
|
||||
|
||||
class A {}
|
||||
''');
|
||||
var classA = library.getClass('A')!;
|
||||
var setter = classA.augmented!.accessors[0];
|
||||
expect(classA.augmented?.lookUpSetter(name: 's', library: library),
|
||||
same(setter));
|
||||
}
|
||||
|
||||
test_lookUpSetter_inherited() async {
|
||||
var library = await buildLibrary('''
|
||||
class A {
|
||||
set s(x) {}
|
||||
}
|
||||
class B extends A {}
|
||||
''');
|
||||
var classA = library.getClass('A')!;
|
||||
var setter = classA.accessors[0];
|
||||
var classB = library.getClass('B')!;
|
||||
expect(classB.augmented?.lookUpSetter(name: 's', library: library),
|
||||
same(setter));
|
||||
}
|
||||
|
||||
test_lookUpSetter_inherited_fromAugmentation() async {
|
||||
newFile('$testPackageLibPath/a.dart', '''
|
||||
library augment 'test.dart';
|
||||
|
||||
augment class A {
|
||||
set s(x) {}
|
||||
}
|
||||
''');
|
||||
var library = await buildLibrary('''
|
||||
import augment 'a.dart';
|
||||
|
||||
class A {}
|
||||
class B extends A {}
|
||||
''');
|
||||
var classA = library.getClass('A')!;
|
||||
var setter = classA.augmented!.accessors[0];
|
||||
var classB = library.getClass('B')!;
|
||||
expect(classB.augmented?.lookUpSetter(name: 's', library: library),
|
||||
same(setter));
|
||||
}
|
||||
|
||||
test_lookUpSetter_inherited_fromMixin() async {
|
||||
var library = await buildLibrary('''
|
||||
mixin A {
|
||||
set s(x) {}
|
||||
}
|
||||
class B with A {}
|
||||
''');
|
||||
var mixinA = library.getMixin('A')!;
|
||||
var setter = mixinA.accessors[0];
|
||||
var classB = library.getClass('B')!;
|
||||
expect(classB.augmented?.lookUpSetter(name: 's', library: library),
|
||||
same(setter));
|
||||
}
|
||||
|
||||
test_lookUpSetter_undeclared() async {
|
||||
var library = await buildLibrary('''
|
||||
class A {}
|
||||
''');
|
||||
var classA = library.getClass('A')!;
|
||||
expect(classA.augmented?.lookUpSetter(name: 's', library: library), isNull);
|
||||
}
|
||||
|
||||
test_lookUpSetter_undeclared_recursive() async {
|
||||
var library = await buildLibrary('''
|
||||
class A extends B {}
|
||||
class B extends A {}
|
||||
''');
|
||||
var classA = library.getClass('A')!;
|
||||
expect(classA.augmented?.lookUpSetter(name: 's', library: library), isNull);
|
||||
}
|
||||
}
|
||||
|
||||
@reflectiveTest
|
||||
class MethodElementImplTest extends AbstractTypeSystemTest {
|
||||
void test_equal() {
|
||||
|
||||
Reference in New Issue
Block a user