Resolve using mixin(s) in 'with' clauses.
This also allows searching for mixin(s), which we test now.
R=brianwilkerson@google.com
Change-Id: I6c1944db0e6ecbc0f7352188968e53ef38603426
Reviewed-on: https://dart-review.googlesource.com/72554
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
diff --git a/pkg/analysis_server/test/search/element_references_test.dart b/pkg/analysis_server/test/search/element_references_test.dart
index 2db2647..fb3aa88 100644
--- a/pkg/analysis_server/test/search/element_references_test.dart
+++ b/pkg/analysis_server/test/search/element_references_test.dart
@@ -408,6 +408,17 @@
assertHasResult(SearchResultKind.REFERENCE, 'mmm);');
}
+ Future<void> test_mixin() async {
+ addTestFile('''
+mixin A {}
+class B extends Object with A {} // B
+''');
+ await findElementReferences('A {}', false);
+ expect(searchElement.kind, ElementKind.MIXIN);
+ expect(results, hasLength(1));
+ assertHasResult(SearchResultKind.REFERENCE, 'A {} // B');
+ }
+
Future<void> test_noElement() async {
addTestFile('''
main() {
diff --git a/pkg/analyzer/lib/src/dart/element/builder.dart b/pkg/analyzer/lib/src/dart/element/builder.dart
index 998a242..fa3788d 100644
--- a/pkg/analyzer/lib/src/dart/element/builder.dart
+++ b/pkg/analyzer/lib/src/dart/element/builder.dart
@@ -620,6 +620,7 @@
element.typeParameters = holder.typeParameters;
setElementDocumentationComment(element, node);
element.accessors = holder.accessors;
+ element.constructors = holder.constructors;
element.fields = holder.fields;
element.methods = holder.methods;
_currentHolder.addMixin(element);
diff --git a/pkg/analyzer/lib/src/dart/resolver/scope.dart b/pkg/analyzer/lib/src/dart/resolver/scope.dart
index f78400a..2e688d6 100644
--- a/pkg/analyzer/lib/src/dart/resolver/scope.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/scope.dart
@@ -638,6 +638,9 @@
in compilationUnit.functionTypeAliases) {
define(element);
}
+ for (ClassElement element in compilationUnit.mixins) {
+ define(element);
+ }
for (ClassElement element in compilationUnit.types) {
define(element);
}
diff --git a/pkg/analyzer/lib/src/summary/link.dart b/pkg/analyzer/lib/src/summary/link.dart
index f802e71..8bce0e0 100644
--- a/pkg/analyzer/lib/src/summary/link.dart
+++ b/pkg/analyzer/lib/src/summary/link.dart
@@ -552,6 +552,9 @@
*/
final UnlinkedClass _unlinkedClass;
+ @override
+ final bool isMixin;
+
List<ConstructorElementForLink> _constructors;
ConstructorElementForLink _unnamedConstructor;
bool _unnamedConstructorComputed = false;
@@ -563,8 +566,8 @@
List<InterfaceType> _interfaces;
List<PropertyAccessorElementForLink> _accessors;
- ClassElementForLink_Class(
- CompilationUnitElementForLink enclosingElement, this._unlinkedClass)
+ ClassElementForLink_Class(CompilationUnitElementForLink enclosingElement,
+ this._unlinkedClass, this.isMixin)
: super(enclosingElement);
@override
@@ -1001,6 +1004,7 @@
*/
final String _absoluteUri;
+ List<ClassElementForLink_Class> _mixins;
List<ClassElementForLink_Class> _types;
Map<String, ReferenceableElementForLink> _containedNames;
List<TopLevelVariableElementForLink> _topLevelVariables;
@@ -1130,6 +1134,17 @@
LibraryElementForLink get library => enclosingElement;
@override
+ List<ClassElementForLink_Class> get mixins {
+ if (_mixins == null) {
+ _mixins = <ClassElementForLink_Class>[];
+ for (UnlinkedClass unlinkedClass in _unlinkedUnit.mixins) {
+ _mixins.add(new ClassElementForLink_Class(this, unlinkedClass, true));
+ }
+ }
+ return _mixins;
+ }
+
+ @override
ResynthesizerContext get resynthesizerContext => this;
@override
@@ -1149,7 +1164,7 @@
if (_types == null) {
_types = <ClassElementForLink_Class>[];
for (UnlinkedClass unlinkedClass in _unlinkedUnit.classes) {
- _types.add(new ClassElementForLink_Class(this, unlinkedClass));
+ _types.add(new ClassElementForLink_Class(this, unlinkedClass, false));
}
}
return _types;
diff --git a/pkg/analyzer/test/src/dart/analysis/index_test.dart b/pkg/analyzer/test/src/dart/analysis/index_test.dart
index d961a28..9a28fc6 100644
--- a/pkg/analyzer/test/src/dart/analysis/index_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/index_test.dart
@@ -360,7 +360,7 @@
..isInvokedAt('ggg(); // nq', false);
}
- test_isMixedInBy_ClassDeclaration() async {
+ test_isMixedInBy_ClassDeclaration_class() async {
await _indexTestUnit('''
class A {} // 1
class B extends Object with A {} // 2
@@ -383,7 +383,18 @@
assertThat(elementA).isMixedInAt('A {} // 2', true);
}
- test_isMixedInBy_ClassTypeAlias() async {
+ test_isMixedInBy_ClassDeclaration_mixin() async {
+ await _indexTestUnit('''
+mixin A {} // 1
+class B extends Object with A {} // 2
+''');
+ ClassElement elementA = findElement('A');
+ assertThat(elementA)
+ ..isMixedInAt('A {} // 2', false)
+ ..isReferencedAt('A {} // 2', false);
+ }
+
+ test_isMixedInBy_ClassTypeAlias_class() async {
await _indexTestUnit('''
class A {} // 1
class B = Object with A; // 2
@@ -392,6 +403,15 @@
assertThat(elementA).isMixedInAt('A; // 2', false);
}
+ test_isMixedInBy_ClassTypeAlias_mixin() async {
+ await _indexTestUnit('''
+mixin A {} // 1
+class B = Object with A; // 2
+''');
+ ClassElement elementA = findElement('A');
+ assertThat(elementA).isMixedInAt('A; // 2', false);
+ }
+
test_isReferencedBy_ClassElement() async {
await _indexTestUnit('''
class A {
diff --git a/pkg/analyzer/test/src/dart/analysis/search_test.dart b/pkg/analyzer/test/src/dart/analysis/search_test.dart
index 2508050..cbadbb3 100644
--- a/pkg/analyzer/test/src/dart/analysis/search_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/search_test.dart
@@ -699,6 +699,19 @@
await _verifyReferences(element, expected);
}
+ test_searchReferences_ClassElement_mixin() async {
+ await _resolveTestUnit('''
+mixin A {}
+class B extends Object with A {} // with
+''');
+ ClassElement element = _findElementAtString('A {}');
+ Element b = _findElement('B');
+ var expected = [
+ _expectId(b, SearchResultKind.REFERENCE, 'A {} // with'),
+ ];
+ await _verifyReferences(element, expected);
+ }
+
test_searchReferences_CompilationUnitElement() async {
provider.newFile(_p('$testProject/foo.dart'), '');
await _resolveTestUnit('''
diff --git a/pkg/analyzer/test/src/dart/resolution/mixin_test.dart b/pkg/analyzer/test/src/dart/resolution/mixin_test.dart
index 047499e..a39a2c3 100644
--- a/pkg/analyzer/test/src/dart/resolution/mixin_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/mixin_test.dart
@@ -89,6 +89,40 @@
assertElementName(fields[0], 's', isSynthetic: true);
}
+ test_classDeclaration_with() async {
+ addTestFile(r'''
+mixin M {}
+class A extends Object with M {} // A
+''');
+ await resolveTestFile();
+ assertNoTestErrors();
+
+ var mElement = findElement.mixin('M');
+
+ var aElement = findElement.class_('A');
+ assertElementTypes(aElement.mixins, [mElement.type]);
+
+ var mRef = findNode.typeName('M {} // A');
+ assertTypeName(mRef, mElement, 'M');
+ }
+
+ test_classTypeAlias_with() async {
+ addTestFile(r'''
+mixin M {}
+class A = Object with M;
+''');
+ await resolveTestFile();
+ assertNoTestErrors();
+
+ var mElement = findElement.mixin('M');
+
+ var aElement = findElement.class_('A');
+ assertElementTypes(aElement.mixins, [mElement.type]);
+
+ var mRef = findNode.typeName('M;');
+ assertTypeName(mRef, mElement, 'M');
+ }
+
test_commentReference() async {
addTestFile(r'''
const a = 0;