Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(234)

Unified Diff: pkg/analyzer/test/src/summary/index_unit_test.dart

Issue 1733843007: Add tests for indexing. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: pkg/analyzer/test/src/summary/index_unit_test.dart
diff --git a/pkg/analyzer/test/src/summary/index_unit_test.dart b/pkg/analyzer/test/src/summary/index_unit_test.dart
index f73c353d0631a4dd217c33f46ecab738f7a66d66..7cf918691851e0f164700321604a26444bc40bcb 100644
--- a/pkg/analyzer/test/src/summary/index_unit_test.dart
+++ b/pkg/analyzer/test/src/summary/index_unit_test.dart
@@ -4,6 +4,7 @@
import 'dart:convert';
+import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/src/summary/format.dart';
import 'package:analyzer/src/summary/idl.dart';
@@ -40,15 +41,192 @@ class PackageIndexAssemblerTest extends AbstractSingleUnitTest {
PackageIndex packageIndex;
UnitIndex unitIndex;
+ _ElementIndexAssert assertThat(Element element) {
+ return new _ElementIndexAssert(this, element);
+ }
+
+ CompilationUnitElement importedUnit({int index: 0}) {
+ List<ImportElement> imports = testLibraryElement.imports;
+ return imports[index].importedLibrary.definingCompilationUnit;
+ }
+
void test_isExtendedBy_ClassDeclaration() {
_indexTestUnit('''
class A {} // 1
class B extends A {} // 2
''');
- ClassElement classElementA = findElement('A');
- // verify
- _assertHasRelation(classElementA, IndexRelationKind.IS_EXTENDED_BY,
- _expectedLocation('A {} // 2'));
+ ClassElement elementA = findElement('A');
+ assertThat(elementA).isExtendedAt('A {} // 2');
+ }
+
+ void test_isExtendedBy_ClassDeclaration_Object() {
+ _indexTestUnit('''
+class A {}
+''');
+ ClassElement elementA = findElement('A');
+ ClassElement elementObject = elementA.supertype.element;
+ assertThat(elementObject).isExtendedAt('A {}', length: 0);
+ }
+
+ void test_isExtendedBy_ClassTypeAlias() {
+ _indexTestUnit('''
+class A {}
+class B {}
+class C = A with B;
+''');
+ ClassElement elementA = findElement('A');
+ assertThat(elementA).isExtendedAt('A with');
+ }
+
+ void test_isImplementedBy_ClassDeclaration() {
+ _indexTestUnit('''
+class A {} // 1
+class B implements A {} // 2
+''');
+ ClassElement elementA = findElement('A');
+ assertThat(elementA).isImplementedAt('A {} // 2');
+ }
+
+ void test_isImplementedBy_ClassTypeAlias() {
+ _indexTestUnit('''
+class A {} // 1
+class B {} // 2
+class C = Object with A implements B; // 3
+''');
+ ClassElement elementB = findElement('B');
+ assertThat(elementB).isImplementedAt('B; // 3');
+ }
+
+ void test_isInvokedBy_FieldElement() {
+ _indexTestUnit('''
+class A {
+ var field;
+ main() {
+ this.field(); // q
+ field(); // nq
+ }
+}''');
+ FieldElement field = findElement('field');
+ assertThat(field.getter)
+ ..isInvokedAt('field(); // q', qualified: true)
+ ..isInvokedAt('field(); // nq');
+ }
+
+ void test_isInvokedBy_FunctionElement() {
+ addSource(
+ '/lib.dart',
+ '''
+library lib;
+foo() {}
+''');
+ _indexTestUnit('''
+import 'lib.dart';
+import 'lib.dart' as pref;
+main() {
+ pref.foo(); // q
+ foo(); // nq
+}''');
+ FunctionElement element = importedUnit().functions[0];
+ assertThat(element)
+ ..isInvokedAt('foo(); // q', qualified: true)
+ ..isInvokedAt('foo(); // nq');
+ }
+
+ void test_isInvokedBy_MethodElement() {
+ _indexTestUnit('''
+class A {
+ foo() {}
+ main() {
+ this.foo(); // q
+ foo(); // nq
+ }
+}''');
+ Element element = findElement('foo');
+ assertThat(element)
+ ..isInvokedAt('foo(); // q', qualified: true)
+ ..isInvokedAt('foo(); // nq');
+ }
+
+ void test_isInvokedBy_MethodElement_propagatedType() {
+ _indexTestUnit('''
+class A {
+ foo() {}
+}
+main() {
+ var a = new A();
+ a.foo();
+}
+''');
+ Element element = findElement('foo');
+ assertThat(element).isInvokedAt('foo();', qualified: true);
+ }
+
+ void test_isInvokedBy_operator_binary() {
+ _indexTestUnit('''
+class A {
+ operator +(other) => this;
+}
+main(A a) {
+ print(a + 1);
+ a += 2;
+ ++a;
+ a++;
+}
+''');
+ MethodElement element = findElement('+');
+ assertThat(element)
+ ..isInvokedAt('+ 1', length: 1)
+ ..isInvokedAt('+= 2', length: 2)
+ ..isInvokedAt('++a', length: 2)
+ ..isInvokedAt('++;', length: 2);
+ }
+
+ void test_isInvokedBy_operator_index() {
+ _indexTestUnit('''
+class A {
+ operator [](i) => null;
+ operator []=(i, v) {}
+}
+main(A a) {
+ print(a[0]);
+ a[1] = 42;
+}
+''');
+ MethodElement readElement = findElement('[]');
+ MethodElement writeElement = findElement('[]=');
+ assertThat(readElement).isInvokedAt('[0]', length: 1);
+ assertThat(writeElement).isInvokedAt('[1]', length: 1);
+ }
+
+ void test_isInvokedBy_operator_prefix() {
+ _indexTestUnit('''
+class A {
+ A operator ~() => this;
+}
+main(A a) {
+ print(~a);
+}
+''');
+ MethodElement element = findElement('~');
+ assertThat(element).isInvokedAt('~a', length: 1);
+ }
+
+ void test_isMixedInBy_ClassDeclaration() {
+ _indexTestUnit('''
+class A {} // 1
+class B extends Object with A {} // 2
+''');
+ ClassElement elementA = findElement('A');
+ assertThat(elementA).isMixedInAt('A {} // 2');
+ }
+
+ void test_isMixedInBy_ClassTypeAlias() {
+ _indexTestUnit('''
+class A {} // 1
+class B = Object with A; // 2
+''');
+ ClassElement elementA = findElement('A');
+ assertThat(elementA).isMixedInAt('A; // 2');
}
void test_isReferencedBy_ClassElement() {
@@ -63,18 +241,280 @@ main(A p) {
print(A.field); // 3
}
''');
- ClassElement element = findElement("A");
- // verify
- _assertHasRelation(element, IndexRelationKind.IS_REFERENCED_BY,
- _expectedLocation('A p) {'));
- _assertHasRelation(
- element, IndexRelationKind.IS_REFERENCED_BY, _expectedLocation('A v;'));
- _assertHasRelation(element, IndexRelationKind.IS_REFERENCED_BY,
- _expectedLocation('A(); // 2'));
- _assertHasRelation(element, IndexRelationKind.IS_REFERENCED_BY,
- _expectedLocation('A.field = 1;'));
- _assertHasRelation(element, IndexRelationKind.IS_REFERENCED_BY,
- _expectedLocation('A.field); // 3'));
+ ClassElement element = findElement('A');
+ assertThat(element)
+ ..isReferencedAt('A p) {')
+ ..isReferencedAt('A v;')
+ ..isReferencedAt('A(); // 2')
+ ..isReferencedAt('A.field = 1;')
+ ..isReferencedAt('A.field); // 3');
+ }
+
+ void test_isReferencedBy_ClassElement_invocation() {
+ verifyNoTestUnitErrors = false;
+ _indexTestUnit('''
+class A {}
+main() {
+ A(); // invalid code, but still a reference
+}''');
+ Element element = findElement('A');
+ assertThat(element).isReferencedAt('A();');
+ }
+
+ void test_isReferencedBy_ClassTypeAlias() {
+ _indexTestUnit('''
+class A {}
+class B = Object with A;
+main(B p) {
+ B v;
+}
+''');
+ ClassElement element = findElement('B');
+ assertThat(element)..isReferencedAt('B p) {')..isReferencedAt('B v;');
+ }
+
+ void test_isReferencedBy_CompilationUnitElement_export() {
+ addSource(
+ '/lib.dart',
+ '''
+library lib;
+''');
+ _indexTestUnit('''
+export 'lib.dart';
+''');
+ LibraryElement element = testLibraryElement.exports[0].exportedLibrary;
+ assertThat(element)..isReferencedAt("'lib.dart'", length: 10);
+ }
+
+ void test_isReferencedBy_CompilationUnitElement_import() {
+ addSource(
+ '/lib.dart',
+ '''
+library lib;
+''');
+ _indexTestUnit('''
+import 'lib.dart';
+''');
+ LibraryElement element = testLibraryElement.imports[0].importedLibrary;
+ assertThat(element)..isReferencedAt("'lib.dart'", length: 10);
+ }
+
+ void test_isReferencedBy_CompilationUnitElement_part() {
+ addSource('/my_unit.dart', 'part of my_lib;');
+ _indexTestUnit('''
+library my_lib;
+part 'my_unit.dart';
+''');
+ CompilationUnitElement element = testLibraryElement.parts[0];
+ assertThat(element)..isReferencedAt("'my_unit.dart';", length: 14);
+ }
+
+ void test_isReferencedBy_ConstructorElement() {
+ _indexTestUnit('''
+class A implements B {
+ A() {}
+ A.foo() {}
+}
+class B extends A {
+ B() : super(); // 1
+ B.foo() : super.foo(); // 2
+ factory B.bar() = A.foo; // 3
+}
+main() {
+ new A(); // 4
+ new A.foo(); // 5
+}
+''');
+ ClassElement classA = findElement('A');
+ ConstructorElement constA = classA.constructors[0];
+ ConstructorElement constA_foo = classA.constructors[1];
+ // A()
+ assertThat(constA)
+ ..isReferencedAt('(); // 1', length: 0)
+ ..isReferencedAt('(); // 4', length: 0);
+ // A.foo()
+ assertThat(constA_foo)
+ ..isReferencedAt('.foo(); // 2', length: 4)
+ ..isReferencedAt('.foo; // 3', length: 4)
+ ..isReferencedAt('.foo(); // 5', length: 4);
+ }
+
+ void test_isReferencedBy_ConstructorElement_classTypeAlias() {
+ _indexTestUnit('''
+class M {}
+class A implements B {
+ A() {}
+ A.named() {}
+}
+class B = A with M;
+main() {
+ new B(); // 1
+ new B.named(); // 2
+}
+''');
+ ClassElement classA = findElement('A');
+ ConstructorElement constA = classA.constructors[0];
+ ConstructorElement constA_named = classA.constructors[1];
+ assertThat(constA).isReferencedAt('(); // 1', length: 0);
+ assertThat(constA_named).isReferencedAt('.named(); // 2', length: 6);
+ }
+
+ void test_isReferencedBy_ConstructorElement_redirection() {
+ _indexTestUnit('''
+class A {
+ A() : this.bar(); // 1
+ A.foo() : this(); // 2
+ A.bar();
+}
+''');
+ ClassElement classA = findElement('A');
+ ConstructorElement constA = classA.constructors[0];
+ ConstructorElement constA_bar = classA.constructors[2];
+ assertThat(constA).isReferencedAt('(); // 2', length: 0);
+ assertThat(constA_bar).isReferencedAt('.bar(); // 1', length: 4);
+ }
+
+ void test_isReferencedBy_ConstructorFieldInitializer() {
+ _indexTestUnit('''
+class A {
+ int field;
+ A() : field = 5;
+}
+''');
+ FieldElement element = findElement('field');
+ assertThat(element).isReferencedAt('field = 5');
+ }
+
+ void test_isReferencedBy_FieldElement() {
+ _indexTestUnit('''
+class A {
+ var field;
+ A({this.field});
+ m() {
+ field = 1; // nq
+ print(field); // nq
+ }
+}
+main(A a) {
+ a.field = 2; // q
+ print(a.field); // q
+ new A(field: 3);
+}
+''');
+ FieldElement field = findElement('field');
+ PropertyAccessorElement getter = field.getter;
+ PropertyAccessorElement setter = field.setter;
+ // A()
+ assertThat(field)..isReferencedAt('field});');
+ // m()
+ assertThat(setter)..isReferencedAt('field = 1; // nq');
+ assertThat(getter)..isReferencedAt('field); // nq');
+ // main()
+ assertThat(setter)..isReferencedAt('field = 2; // q', qualified: true);
+ assertThat(getter)..isReferencedAt('field); // q', qualified: true);
+ assertThat(field)..isReferencedAt('field: 3');
+ }
+
+ void test_isReferencedBy_FunctionElement() {
+ _indexTestUnit('''
+foo() {}
+main() {
+ print(foo);
+ print(foo());
+}
+''');
+ FunctionElement element = findElement('foo');
+ assertThat(element)
+ ..isReferencedAt('foo);')
+ ..isInvokedAt('foo());');
+ }
+
+ void test_isReferencedBy_FunctionTypeAliasElement() {
+ _indexTestUnit('''
+typedef A();
+main(A p) {
+}
+''');
+ Element element = findElement('A');
+ assertThat(element)..isReferencedAt('A p) {');
+ }
+
+ /**
+ * There was a bug in the AST structure, when single [Comment] was cloned and
+ * assigned to both [FieldDeclaration] and [VariableDeclaration].
+ *
+ * This caused duplicate indexing.
+ * Here we test that the problem is fixed one way or another.
+ */
+ void test_isReferencedBy_identifierInComment() {
+ _indexTestUnit('''
+class A {}
+/// [A] text
+var myVariable = null;
+''');
+ Element element = findElement('A');
+ assertThat(element)..isReferencedAt('A] text');
+ }
+
+ void test_isReferencedBy_MethodElement() {
+ _indexTestUnit('''
+class A {
+ method() {}
+ main() {
+ print(this.method); // q
+ print(method); // nq
+ }
+}''');
+ MethodElement element = findElement('method');
+ assertThat(element)
+ ..isReferencedAt('method); // q', qualified: true)
+ ..isReferencedAt('method); // nq');
+ }
+
+ void test_isReferencedBy_ParameterElement() {
+ _indexTestUnit('''
+foo({var p}) {}
+main() {
+ foo(p: 1);
+}
+''');
+ Element element = findElement('p');
+ assertThat(element)..isReferencedAt('p: 1');
+ }
+
+ void test_isReferencedBy_TopLevelVariableElement() {
+ addSource(
+ '/lib.dart',
+ '''
+library lib;
+var V;
+''');
+ _indexTestUnit('''
+import 'lib.dart' show V; // imp
+import 'lib.dart' as pref;
+main() {
+ pref.V = 5; // q
+ print(pref.V); // q
+ V = 5; // nq
+ print(V); // nq
+}''');
+ TopLevelVariableElement variable = importedUnit().topLevelVariables[0];
+ assertThat(variable)..isReferencedAt('V; // imp');
+ assertThat(variable.getter)
+ ..isReferencedAt('V); // q', qualified: true)
+ ..isReferencedAt('V); // nq');
+ assertThat(variable.setter)
+ ..isReferencedAt('V = 5; // q', qualified: true)
+ ..isReferencedAt('V = 5; // nq');
+ }
+
+ void test_isReferencedBy_typeInVariableList() {
+ _indexTestUnit('''
+class A {}
+A myVariable = null;
+''');
+ Element element = findElement('A');
+ assertThat(element).isReferencedAt('A myVariable');
}
/**
@@ -89,6 +529,8 @@ main(A p) {
if (unitIndex.elements[i] == elementId &&
unitIndex.locationOffsets[i] == expectedLocation.offset &&
unitIndex.locationLengths[i] == expectedLocation.length) {
+ // TODO(scheglov) continue looking to check that only one usage at one
+ // location, e.g. no both 'reference' and 'invocation'.
return;
}
}
@@ -97,9 +539,9 @@ main(A p) {
}
ExpectedLocation _expectedLocation(String search,
- {int length: -1, bool isQualified: false, bool isResolved: true}) {
+ {int length, bool isQualified: false, bool isResolved: true}) {
int offset = findOffset(search);
- if (length == -1) {
+ if (length == null) {
length = getLeadingIdentifierLength(search);
}
return new ExpectedLocation(
@@ -117,11 +559,17 @@ main(A p) {
*/
int _findElementId(Element element) {
int elementUnitId = _getElementUnitId(element);
+ int offset = element.nameOffset;
+ if (element is LibraryElement || element is CompilationUnitElement) {
+ offset = 0;
+ }
+ IndexElementKind kind = PackageIndexAssembler.getIndexElementKind(element);
for (int elementId = 0;
elementId < packageIndex.elementUnits.length;
elementId++) {
if (packageIndex.elementUnits[elementId] == elementUnitId &&
- packageIndex.elementOffsets[elementId] == element.nameOffset) {
+ packageIndex.elementOffsets[elementId] == offset &&
+ packageIndex.elementKinds[elementId] == kind) {
return elementId;
}
}
@@ -133,14 +581,14 @@ main(A p) {
CompilationUnitElement unitElement =
PackageIndexAssembler.getUnitElement(element);
int libraryUriId = _getUriId(unitElement.library.source.uri);
- int unitUriId = _getUriId(unitElement.library.source.uri);
+ int unitUriId = _getUriId(unitElement.source.uri);
for (int i = 0; i < packageIndex.elementLibraryUris.length; i++) {
if (packageIndex.elementLibraryUris[i] == libraryUriId &&
packageIndex.elementUnitUris[i] == unitUriId) {
return i;
}
}
- fail('Unit $unitElement of $element is not referenced in the index.');
+ _failWithIndexDump('Unit $unitElement of $element is not referenced');
return -1;
}
@@ -164,3 +612,37 @@ main(A p) {
unitIndex = packageIndex.units[0];
}
}
+
+class _ElementIndexAssert {
+ final PackageIndexAssemblerTest test;
+ final Element element;
+
+ _ElementIndexAssert(this.test, this.element);
+
+ void isExtendedAt(String search, {int length}) {
+ test._assertHasRelation(element, IndexRelationKind.IS_EXTENDED_BY,
+ test._expectedLocation(search, length: length));
+ }
+
+ void isImplementedAt(String search, {int length}) {
+ test._assertHasRelation(element, IndexRelationKind.IS_IMPLEMENTED_BY,
+ test._expectedLocation(search, length: length));
+ }
+
+ void isInvokedAt(String search, {int length, bool qualified: false}) {
+ // TODO(scheglov) use 'qualified'
+ test._assertHasRelation(element, IndexRelationKind.IS_INVOKED_BY,
+ test._expectedLocation(search, length: length));
+ }
+
+ void isMixedInAt(String search, {int length}) {
+ test._assertHasRelation(element, IndexRelationKind.IS_MIXED_IN_BY,
+ test._expectedLocation(search, length: length));
+ }
+
+ void isReferencedAt(String search, {int length, bool qualified: false}) {
+ // TODO(scheglov) use 'qualified'
+ test._assertHasRelation(element, IndexRelationKind.IS_REFERENCED_BY,
+ test._expectedLocation(search, length: length));
+ }
+}
« pkg/analyzer/lib/src/summary/index_unit.dart ('K') | « pkg/analyzer/lib/src/summary/index_unit.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698