mirror of
https://github.com/dart-lang/sdk
synced 2024-09-05 00:13:50 +00:00
Issue 35127. Fixes for mixin implements / overrides.
R=brianwilkerson@google.com Bug: https://github.com/dart-lang/sdk/issues/35127 Change-Id: I5869175cee13b6e22ce25c2d361b0b1aa52efe48 Reviewed-on: https://dart-review.googlesource.com/c/91690 Commit-Queue: Konstantin Shcheglov <scheglov@google.com> Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
This commit is contained in:
parent
fdd477721d
commit
e5164be27e
|
@ -32,7 +32,7 @@ class DartUnitOverridesComputer {
|
|||
*/
|
||||
List<proto.Override> compute() {
|
||||
for (CompilationUnitMember unitMember in _unit.declarations) {
|
||||
if (unitMember is ClassDeclaration) {
|
||||
if (unitMember is ClassOrMixinDeclaration) {
|
||||
for (ClassMember classMember in unitMember.members) {
|
||||
if (classMember is MethodDeclaration) {
|
||||
if (classMember.isStatic) {
|
||||
|
@ -198,6 +198,7 @@ class _OverriddenElementsFinder {
|
|||
|
||||
_addSuperOverrides(type.superclass);
|
||||
type.mixins.forEach(_addSuperOverrides);
|
||||
type.superclassConstraints.forEach(_addSuperOverrides);
|
||||
}
|
||||
|
||||
Element _lookupMember(ClassElement classElement) {
|
||||
|
|
|
@ -18,26 +18,11 @@ class ImplementedComputer {
|
|||
ImplementedComputer(this.searchEngine, this.unitElement);
|
||||
|
||||
compute() async {
|
||||
// TODO(brianwilkerson) Determine whether this await is necessary.
|
||||
await null;
|
||||
for (ClassElement type in unitElement.types) {
|
||||
// Always include Object and its members.
|
||||
if (type.supertype == null) {
|
||||
_addImplementedClass(type);
|
||||
type.accessors.forEach(_addImplementedMember);
|
||||
type.fields.forEach(_addImplementedMember);
|
||||
type.methods.forEach(_addImplementedMember);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Analyze subtypes.
|
||||
subtypeMembers = await searchEngine.membersOfSubtypes(type);
|
||||
if (subtypeMembers != null) {
|
||||
_addImplementedClass(type);
|
||||
type.accessors.forEach(_addMemberIfImplemented);
|
||||
type.fields.forEach(_addMemberIfImplemented);
|
||||
type.methods.forEach(_addMemberIfImplemented);
|
||||
}
|
||||
for (var element in unitElement.mixins) {
|
||||
await _computeForClassElement(element);
|
||||
}
|
||||
for (var element in unitElement.types) {
|
||||
await _computeForClassElement(element);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -62,6 +47,26 @@ class ImplementedComputer {
|
|||
}
|
||||
}
|
||||
|
||||
Future<void> _computeForClassElement(ClassElement element) async {
|
||||
// Always include Object and its members.
|
||||
if (element.supertype == null && !element.isMixin) {
|
||||
_addImplementedClass(element);
|
||||
element.accessors.forEach(_addImplementedMember);
|
||||
element.fields.forEach(_addImplementedMember);
|
||||
element.methods.forEach(_addImplementedMember);
|
||||
return;
|
||||
}
|
||||
|
||||
// Analyze subtypes.
|
||||
subtypeMembers = await searchEngine.membersOfSubtypes(element);
|
||||
if (subtypeMembers != null) {
|
||||
_addImplementedClass(element);
|
||||
element.accessors.forEach(_addMemberIfImplemented);
|
||||
element.fields.forEach(_addMemberIfImplemented);
|
||||
element.methods.forEach(_addMemberIfImplemented);
|
||||
}
|
||||
}
|
||||
|
||||
bool _hasOverride(Element element) {
|
||||
String name = element.displayName;
|
||||
return subtypeMembers.contains(name);
|
||||
|
|
|
@ -71,7 +71,7 @@ class AnalysisNotificationImplementedTest extends AbstractAnalysisTest {
|
|||
}
|
||||
|
||||
/**
|
||||
* Validates that there is no an [ImplementedClass] at the offset of [search].
|
||||
* Validates that there is no [ImplementedMember] at the offset of [search].
|
||||
*
|
||||
* If [length] is not specified explicitly, then length of an identifier
|
||||
* from [search] is used.
|
||||
|
@ -167,6 +167,21 @@ class B implements A {}
|
|||
assertHasImplementedClass('A {');
|
||||
}
|
||||
|
||||
test_class_inMixin() async {
|
||||
addTestFile('''
|
||||
class A {} // ref
|
||||
class B {} // ref
|
||||
class C {} // ref
|
||||
class D {} // ref
|
||||
mixin M on A, B implements C, D {}
|
||||
''');
|
||||
await prepareImplementedElements();
|
||||
assertHasImplementedClass('A {} // ref');
|
||||
assertHasImplementedClass('B {} // ref');
|
||||
assertHasImplementedClass('C {} // ref');
|
||||
assertHasImplementedClass('D {} // ref');
|
||||
}
|
||||
|
||||
test_class_mixed() async {
|
||||
addTestFile('''
|
||||
class A {}
|
||||
|
@ -313,6 +328,40 @@ class B extends A {
|
|||
assertHasImplementedMember('m(); // A');
|
||||
}
|
||||
|
||||
test_mixin_implemented() async {
|
||||
addTestFile('''
|
||||
mixin M { // ref
|
||||
void foo() {} // ref
|
||||
void bar() {} // ref
|
||||
}
|
||||
|
||||
class A implements M {
|
||||
void foo() {}
|
||||
}
|
||||
''');
|
||||
await prepareImplementedElements();
|
||||
assertHasImplementedClass('M { // ref');
|
||||
assertHasImplementedMember('foo() {} // ref');
|
||||
assertNoImplementedMember('bar() {} // ref');
|
||||
}
|
||||
|
||||
test_mixin_mixed() async {
|
||||
addTestFile('''
|
||||
mixin M { // ref
|
||||
void foo() {} // ref
|
||||
void bar() {} // ref
|
||||
}
|
||||
|
||||
class A extends Object with M {
|
||||
void foo() {}
|
||||
}
|
||||
''');
|
||||
await prepareImplementedElements();
|
||||
assertHasImplementedClass('M { // ref');
|
||||
assertHasImplementedMember('foo() {} // ref');
|
||||
assertNoImplementedMember('bar() {} // ref');
|
||||
}
|
||||
|
||||
test_setter_withField() async {
|
||||
addTestFile('''
|
||||
class A {
|
||||
|
|
|
@ -305,6 +305,38 @@ class C extends B {
|
|||
assertHasInterfaceMember('m() {} // in A');
|
||||
}
|
||||
|
||||
test_inMixin_interface_method_direct_single() async {
|
||||
addTestFile('''
|
||||
class A {
|
||||
m() {} // in A
|
||||
}
|
||||
|
||||
mixin M implements A {
|
||||
m() {} // in M
|
||||
}
|
||||
''');
|
||||
await prepareOverrides();
|
||||
assertHasOverride('m() {} // in M');
|
||||
assertNoSuperMember();
|
||||
assertHasInterfaceMember('m() {} // in A');
|
||||
}
|
||||
|
||||
test_inMixin_superclassConstraint_method_direct() async {
|
||||
addTestFile('''
|
||||
class A {
|
||||
m() {} // in A
|
||||
}
|
||||
|
||||
mixin M on A {
|
||||
m() {} // in M
|
||||
}
|
||||
''');
|
||||
await prepareOverrides();
|
||||
assertHasOverride('m() {} // in M');
|
||||
assertHasSuperElement('m() {} // in A');
|
||||
assertNoInterfaceMembers();
|
||||
}
|
||||
|
||||
test_interface_method_direct_multiple() async {
|
||||
addTestFile('''
|
||||
class IA {
|
||||
|
|
|
@ -45,6 +45,9 @@ Set<String> computeSubtypedNames(CompilationUnit unit) {
|
|||
_addSubtypedName(declaration.superclass);
|
||||
_addSubtypedNames(declaration.withClause?.mixinTypes);
|
||||
_addSubtypedNames(declaration.implementsClause?.interfaces);
|
||||
} else if (declaration is MixinDeclaration) {
|
||||
_addSubtypedNames(declaration.onClause?.superclassConstraints);
|
||||
_addSubtypedNames(declaration.implementsClause?.interfaces);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -431,6 +431,14 @@ class X = A with B implements C, D, E;
|
|||
expect(names, unorderedEquals(['A', 'B', 'C', 'D', 'E']));
|
||||
}
|
||||
|
||||
void test_mixinDeclaration() {
|
||||
Set<String> names = _computeSubtypedNames('''
|
||||
import 'lib.dart';
|
||||
mixin M on A, B implements C, D {}
|
||||
''');
|
||||
expect(names, unorderedEquals(['A', 'B', 'C', 'D']));
|
||||
}
|
||||
|
||||
void test_prefixed() {
|
||||
Set<String> names = _computeSubtypedNames('''
|
||||
import 'lib.dart' as p;
|
||||
|
|
|
@ -1767,6 +1767,45 @@ class F {}
|
|||
}
|
||||
}
|
||||
|
||||
test_subtypes_mixin_superclassConstraints() async {
|
||||
await _resolveTestUnit('''
|
||||
class A {
|
||||
void methodA() {}
|
||||
}
|
||||
|
||||
class B {
|
||||
void methodB() {}
|
||||
}
|
||||
|
||||
mixin M on A, B {
|
||||
void methodA() {}
|
||||
void methodM() {}
|
||||
}
|
||||
''');
|
||||
ClassElement a = _findElement('A');
|
||||
ClassElement b = _findElement('B');
|
||||
|
||||
{
|
||||
var subtypes = await driver.search.subtypes(type: a);
|
||||
expect(subtypes, hasLength(1));
|
||||
|
||||
var m = subtypes.singleWhere((r) => r.name == 'M');
|
||||
expect(m.libraryUri, testUri);
|
||||
expect(m.id, '$testUri;$testUri;M');
|
||||
expect(m.members, ['methodA', 'methodM']);
|
||||
}
|
||||
|
||||
{
|
||||
var subtypes = await driver.search.subtypes(type: b);
|
||||
expect(subtypes, hasLength(1));
|
||||
|
||||
var m = subtypes.singleWhere((r) => r.name == 'M');
|
||||
expect(m.libraryUri, testUri);
|
||||
expect(m.id, '$testUri;$testUri;M');
|
||||
expect(m.members, ['methodA', 'methodM']);
|
||||
}
|
||||
}
|
||||
|
||||
test_subtypes_discover() async {
|
||||
var pathT = convertPath('/test/lib/t.dart');
|
||||
var pathA = convertPath('/aaa/lib/a.dart');
|
||||
|
|
Loading…
Reference in a new issue