From 6d5773dc5ee629f1108295eb349e5feff196ef11 Mon Sep 17 00:00:00 2001 From: "scheglov@google.com" Date: Tue, 8 Jul 2014 20:53:10 +0000 Subject: [PATCH] Tests for LocalIndex and Dart index contributor. Pub spec files will be updated before commit. R=brianwilkerson@google.com BUG= Review URL: https://codereview.chromium.org//377053002 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@38071 260f80e4-7a28-3924-810f-c04153c831b5 --- pkg/analysis_server/pubspec.yaml | 2 +- .../test/computer/element_test.dart | 5 + .../lib/src/index/index_contributor.dart | 3 +- pkg/analysis_services/pubspec.yaml | 2 +- .../index/dart_index_contributor_test.dart | 1642 +++++++++++++++++ .../test/index/local_file_index_test.dart | 26 + .../test/index/local_index_test.dart | 285 ++- .../test/index/test_all.dart | 4 + .../lib/abstract_context.dart | 13 +- pkg/analysis_testing/pubspec.yaml | 2 +- 10 files changed, 1826 insertions(+), 158 deletions(-) create mode 100644 pkg/analysis_services/test/index/dart_index_contributor_test.dart create mode 100644 pkg/analysis_services/test/index/local_file_index_test.dart diff --git a/pkg/analysis_server/pubspec.yaml b/pkg/analysis_server/pubspec.yaml index 997aeb06306..e29109a36c1 100644 --- a/pkg/analysis_server/pubspec.yaml +++ b/pkg/analysis_server/pubspec.yaml @@ -13,7 +13,7 @@ dependencies: path: any watcher: any dev_dependencies: - analysis_testing: '>=0.1.0' + analysis_testing: '>=0.2.0' mock: '>=0.10.0 <0.11.0' typed_mock: '>=0.0.4 <1.0.0' unittest: '>=0.10.0 <0.12.0' diff --git a/pkg/analysis_server/test/computer/element_test.dart b/pkg/analysis_server/test/computer/element_test.dart index ee50faf6fee..09155eb0ebb 100644 --- a/pkg/analysis_server/test/computer/element_test.dart +++ b/pkg/analysis_server/test/computer/element_test.dart @@ -97,6 +97,11 @@ class ElementKindTest { @ReflectiveTestCase() class ElementTest extends AbstractContextTest { + engine.Element findElementInUnit(CompilationUnit unit, String name, + [engine.ElementKind kind]) { + return findChildElement(unit.element, name, kind); + } + void test_fromElement_CLASS() { Source source = addSource('/test.dart', ''' @deprecated diff --git a/pkg/analysis_services/lib/src/index/index_contributor.dart b/pkg/analysis_services/lib/src/index/index_contributor.dart index a6cf5cb7f02..044418396e1 100644 --- a/pkg/analysis_services/lib/src/index/index_contributor.dart +++ b/pkg/analysis_services/lib/src/index/index_contributor.dart @@ -1075,6 +1075,7 @@ class _IndexContributor extends GeneralizingAstVisitor { static Location _getLocationWithTypeAssignedToField(SimpleIdentifier identifier, Element element, Location location) { + // TODO(scheglov) decide if we want to remember assigned types // we need accessor if (element is! PropertyAccessorElement) { return location; @@ -1181,7 +1182,7 @@ class _IndexContributor extends GeneralizingAstVisitor { } Namespace namespace = new NamespaceBuilder( ).createImportNamespaceForDirective(importElement); - Set elements = new Set(); + Set elements = new Set.from(namespace.definedNames.values); importElementsMap[importElement] = elements; } // use import namespace to choose correct one diff --git a/pkg/analysis_services/pubspec.yaml b/pkg/analysis_services/pubspec.yaml index 2ac7737ee8e..66e9ac2696f 100644 --- a/pkg/analysis_services/pubspec.yaml +++ b/pkg/analysis_services/pubspec.yaml @@ -8,5 +8,5 @@ environment: dependencies: analyzer: '>=0.21.0 <1.0.0' dev_dependencies: - analysis_testing: '>=0.1.0 <1.0.0' + analysis_testing: '>=0.2.0 <1.0.0' unittest: '>=0.10.0 <0.12.0' diff --git a/pkg/analysis_services/test/index/dart_index_contributor_test.dart b/pkg/analysis_services/test/index/dart_index_contributor_test.dart new file mode 100644 index 00000000000..3892d5d15ea --- /dev/null +++ b/pkg/analysis_services/test/index/dart_index_contributor_test.dart @@ -0,0 +1,1642 @@ +// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +library test.services.src.index.dart_index_contributor; + +import 'package:analysis_services/index/index.dart'; +import 'package:analysis_services/index/index_store.dart'; +import 'package:analysis_services/src/index/index_contributor.dart'; +import 'package:analysis_testing/abstract_context.dart'; +import 'package:analysis_testing/reflective_tests.dart'; +import 'package:analyzer/src/generated/ast.dart'; +import 'package:analyzer/src/generated/element.dart'; +import 'package:analyzer/src/generated/error.dart'; +import 'package:analyzer/src/generated/java_engine.dart'; +import 'package:analyzer/src/generated/source.dart'; +import 'package:typed_mock/typed_mock.dart'; +import 'package:unittest/unittest.dart'; + + +main() { + groupSep = ' | '; + group('DartUnitContributor', () { + runReflectiveTests(DartUnitContributorTest); + }); +} + + +/** + * Returns `true` if the [actual] location the same properties as [expected]. + */ +bool _equalsLocation(Location actual, ExpectedLocation expected) { + return _equalsLocationProperties(actual, expected.element, expected.offset, + expected.length); +} + + +/** + * Returns `true` if the [actual] location the expected properties. + */ +bool _equalsLocationProperties(Location actual, Element expectedElement, + int expectedOffset, int expectedLength) { + return expectedElement == actual.element && expectedOffset == actual.offset && + expectedLength == actual.length; +} + + +bool _equalsRecordedRelation(RecordedRelation recordedRelation, + Element expectedElement, Relationship expectedRelationship, + ExpectedLocation expectedLocation) { + return expectedElement == recordedRelation.element && expectedRelationship == + recordedRelation.relationship && (expectedLocation == null || _equalsLocation( + recordedRelation.location, expectedLocation)); +} + + +int _getLeadingIdentifierLength(String search) { + int length = 0; + while (length < search.length) { + int c = search.codeUnitAt(length); + if (c >= 'a'.codeUnitAt(0) && c <= 'z'.codeUnitAt(0)) { + length++; + continue; + } + if (c >= 'A'.codeUnitAt(0) && c <= 'Z'.codeUnitAt(0)) { + length++; + continue; + } + if (c >= '0'.codeUnitAt(0) && c <= '9'.codeUnitAt(0)) { + length++; + continue; + } + break; + } + return length; +} + +@ReflectiveTestCase() +class DartUnitContributorTest extends AbstractContextTest { + IndexStore store = new MockIndexStore(); + List recordedRelations = []; + + bool verifyNoTestUnitErrors = true; + + String testCode; + Source testSource; + CompilationUnit testUnit; + CompilationUnitElement testUnitElement; + LibraryElement testLibraryElement; + + void setUp() { + super.setUp(); + when(store.aboutToIndexDart(context, anyObject)).thenReturn(true); + when(store.recordRelationship(anyObject, anyObject, anyObject)).thenInvoke( + (Element element, Relationship relationship, Location location) { + recordedRelations.add(new RecordedRelation(element, relationship, + location)); + }); + } + + void test_FieldElement_noAssignedType_notLHS() { + _indexTestUnit(''' +class A { + var myField; + main() { + print(myField); + } +}'''); + // prepare elements + Element mainElement = _findElement("main"); + FieldElement fieldElement = _findElement("myField"); + PropertyAccessorElement getterElement = fieldElement.getter; + // verify + _assertRecordedRelation(getterElement, + IndexConstants.IS_REFERENCED_BY_UNQUALIFIED, _expectedLocation(mainElement, + 'myField);')); + } + + void test_definesClass() { + _indexTestUnit('class A {}'); + // prepare elements + ClassElement classElement = _findElement("A"); + // verify + _assertDefinesTopLevelElement(IndexConstants.DEFINES_CLASS, + _expectedLocation(classElement, 'A {}')); + } + + void test_definesClassAlias() { + _indexTestUnit(''' +class Mix {} +class MyClass = Object with Mix;'''); + // prepare elements + Element classElement = _findElement("MyClass"); + // verify + _assertDefinesTopLevelElement(IndexConstants.DEFINES_CLASS_ALIAS, + _expectedLocation(classElement, 'MyClass =')); + } + + void test_definesFunction() { + _indexTestUnit('myFunction() {}'); + // prepare elements + FunctionElement functionElement = _findElement("myFunction"); + // verify + _assertDefinesTopLevelElement(IndexConstants.DEFINES_FUNCTION, + _expectedLocation(functionElement, 'myFunction() {}')); + } + + void test_definesFunctionType() { + _indexTestUnit('typedef MyFunction(int p);'); + // prepare elements + FunctionTypeAliasElement typeAliasElement = _findElement("MyFunction"); + // verify + _assertDefinesTopLevelElement(IndexConstants.DEFINES_FUNCTION_TYPE, + _expectedLocation(typeAliasElement, 'MyFunction(int p);')); + } + + + void test_definesVariable() { + _indexTestUnit('var myVar = 42;'); + // prepare elements + VariableElement varElement = _findElement("myVar"); + // verify + _assertDefinesTopLevelElement(IndexConstants.DEFINES_VARIABLE, + _expectedLocation(varElement, 'myVar = 42;')); + } + + void test_forIn() { + _indexTestUnit(''' +main() { + for (var v in []) { + } +}'''); + // prepare elements + Element mainElement = _findElement("main"); + VariableElement variableElement = _findElement("v"); + // verify + _assertNoRecordedRelation(variableElement, IndexConstants.IS_READ_BY, + _expectedLocation(mainElement, 'v in []')); + } + + void test_isDefinedBy_ConstructorElement() { + _indexTestUnit(''' +class A { + A() {} + A.foo() {} +}'''); + // prepare elements + ClassElement classA = _findElement("A"); + ConstructorElement consA = _findNodeElementAtString("A()", (node) => node is + ConstructorDeclaration); + ConstructorElement consA_foo = _findNodeElementAtString("A.foo()", (node) => + node is ConstructorDeclaration); + // verify + _assertRecordedRelation(consA, IndexConstants.IS_DEFINED_BY, + _expectedLocation(classA, '() {}')); + _assertRecordedRelation(consA_foo, IndexConstants.IS_DEFINED_BY, + _expectedLocation(classA, '.foo() {}', '.foo'.length)); + } + + void test_isDefinedBy_NameElement_method() { + _indexTestUnit(''' +class A { + m() {} +}'''); + // prepare elements + Element methodElement = _findElement("m"); + Element nameElement = new NameElement("m"); + // verify + _assertRecordedRelation(nameElement, IndexConstants.IS_DEFINED_BY, + _expectedLocation(methodElement, 'm() {}')); + } + + + void test_isDefinedBy_NameElement_operator() { + _indexTestUnit(''' +class A { + operator +(o) {} +}'''); + // prepare elements + Element methodElement = _findElement("+"); + Element nameElement = new NameElement("+"); + // verify + _assertRecordedRelation(nameElement, IndexConstants.IS_DEFINED_BY, + _expectedLocation(methodElement, '+(o) {}', 1)); + } + + void test_isExtendedBy_ClassDeclaration() { + _indexTestUnit(''' +class A {} // 1 +class B extends A {} // 2 +'''); + // prepare elements + ClassElement classElementA = _findElement("A"); + ClassElement classElementB = _findElement("B"); + // verify + _assertRecordedRelation(classElementA, IndexConstants.IS_EXTENDED_BY, + _expectedLocation(classElementB, 'A {} // 2')); + } + + void test_isExtendedBy_ClassDeclaration_Object() { + _indexTestUnit(''' +class A {} // 1 +'''); + // prepare elements + ClassElement classElementA = _findElement("A"); + ClassElement classElementObject = classElementA.supertype.element; + // verify + _assertRecordedRelation(classElementObject, IndexConstants.IS_EXTENDED_BY, + _expectedLocation(classElementA, 'A {}', 0)); + } + + void test_isExtendedBy_ClassTypeAlias() { + _indexTestUnit(''' +class A {} // 1 +class B {} // 2 +class C = A with B; // 3 +'''); + // prepare elements + ClassElement classElementA = _findElement("A"); + ClassElement classElementC = _findElement("C"); + // verify + _assertRecordedRelation(classElementA, IndexConstants.IS_EXTENDED_BY, + _expectedLocation(classElementC, 'A with')); + } + + void test_isImplementedBy_ClassDeclaration() { + _indexTestUnit(''' +class A {} // 1 +class B implements A {} // 2 +'''); + // prepare elements + ClassElement classElementA = _findElement("A"); + ClassElement classElementB = _findElement("B"); + // verify + _assertRecordedRelation(classElementA, IndexConstants.IS_IMPLEMENTED_BY, + _expectedLocation(classElementB, 'A {} // 2')); + } + + void test_isImplementedBy_ClassTypeAlias() { + _indexTestUnit(''' +class A {} // 1 +class B {} // 2 +class C = Object with A implements B; // 3 +'''); + // prepare elements + ClassElement classElementB = _findElement("B"); + ClassElement classElementC = _findElement("C"); + // verify + _assertRecordedRelation(classElementB, IndexConstants.IS_IMPLEMENTED_BY, + _expectedLocation(classElementC, 'B; // 3')); + } + + + void test_isInvokedByQualified_FieldElement() { + _indexTestUnit(''' +class A { + var field; + main() { + this.field(); + } +}'''); + // prepare elements + Element mainElement = _findElement("main"); + FieldElement fieldElement = _findElement("field"); + PropertyAccessorElement getterElement = fieldElement.getter; + // verify + _assertRecordedRelation(getterElement, + IndexConstants.IS_INVOKED_BY_QUALIFIED, _expectedLocation(mainElement, + 'field();')); + } + + + void test_isInvokedByQualified_MethodElement() { + _indexTestUnit(''' +class A { + foo() {} + main() { + this.foo(); + } +}'''); + // prepare elements + Element mainElement = _findElement("main"); + Element methodElement = _findElement("foo"); + // verify + var location = _expectedLocation(mainElement, 'foo();'); + _assertRecordedRelation(methodElement, + IndexConstants.IS_INVOKED_BY_QUALIFIED, location); + _assertNoRecordedRelation(methodElement, + IndexConstants.IS_REFERENCED_BY_QUALIFIED, location); + } + + void test_isInvokedByQualified_MethodElement_propagatedType() { + _indexTestUnit(''' +class A { + foo() {} +} +main() { + var a = new A(); + a.foo(); +} +'''); + // prepare elements + Element mainElement = _findElement("main"); + Element methodElement = _findElement("foo"); + // verify + _assertRecordedRelation(methodElement, + IndexConstants.IS_INVOKED_BY_QUALIFIED, _expectedLocation(mainElement, + 'foo();')); + } + + void test_isInvokedByUnqualified_MethodElement() { + _indexTestUnit(''' +class A { + foo() {} + main() { + foo(); + } +}'''); + // prepare elements + Element mainElement = _findElement("main"); + Element methodElement = _findElement("foo"); + // verify + _assertRecordedRelation(methodElement, + IndexConstants.IS_INVOKED_BY_UNQUALIFIED, _expectedLocation(mainElement, + 'foo();')); + } + + void test_isInvokedBy_FunctionElement() { + _indexTestUnit(''' +foo() {} +main() { + foo(); +}'''); + // prepare elements + Element mainElement = _findElement("main"); + FunctionElement functionElement = _findElement("foo"); + // verify + _assertRecordedRelation(functionElement, IndexConstants.IS_INVOKED_BY, + _expectedLocation(mainElement, 'foo();')); + } + + void test_isInvokedBy_LocalVariableElement() { + _indexTestUnit(''' +main() { + var v; + v(); +}'''); + // prepare elements + Element mainElement = _findElement("main"); + Element element = _findElement("v"); + // verify + _assertRecordedRelation(element, IndexConstants.IS_INVOKED_BY, + _expectedLocation(mainElement, 'v();')); + } + + void test_isInvokedBy_ParameterElement() { + _indexTestUnit(''' +main(p()) { + p(); +}'''); + // prepare elements + Element mainElement = _findElement("main"); + Element element = _findElement("p"); + // verify + _assertRecordedRelation(element, IndexConstants.IS_INVOKED_BY, + _expectedLocation(mainElement, 'p();')); + } + + void test_isMixedInBy_ClassDeclaration() { + _indexTestUnit(''' +class A {} // 1 +class B extends Object with A {} // 2 +'''); + // prepare elements + ClassElement classElementA = _findElement("A"); + ClassElement classElementB = _findElement("B"); + // verify + _assertRecordedRelation(classElementA, IndexConstants.IS_MIXED_IN_BY, + _expectedLocation(classElementB, 'A {} // 2')); + } + + void test_isMixedInBy_ClassTypeAlias() { + _indexTestUnit(''' +class A {} // 1 +class B = Object with A; // 2 +'''); + // prepare elements + ClassElement classElementA = _findElement("A"); + ClassElement classElementB = _findElement("B"); + // verify + _assertRecordedRelation(classElementA, IndexConstants.IS_MIXED_IN_BY, + _expectedLocation(classElementB, 'A; // 2')); + } + + void test_isReadBy_ParameterElement() { + _indexTestUnit(''' +main(var p) { + print(p); +} +'''); + // prepare elements + Element mainElement = _findElement("main"); + Element parameterElement = _findElement("p"); + // verify + _assertRecordedRelation(parameterElement, IndexConstants.IS_READ_BY, + _expectedLocation(mainElement, 'p);')); + } + + void test_isReadBy_VariableElement() { + _indexTestUnit(''' +main() { + var v = 0; + print(v); +} +'''); + // prepare elements + Element mainElement = _findElement("main"); + Element variableElement = _findElement("v"); + // verify + _assertRecordedRelation(variableElement, IndexConstants.IS_READ_BY, + _expectedLocation(mainElement, 'v);')); + } + + void test_isReadWrittenBy_ParameterElement() { + _indexTestUnit(''' +main(int p) { + p += 1; +} +'''); + // prepare elements + Element mainElement = _findElement("main"); + Element parameterElement = _findElement("p"); + // verify + _assertRecordedRelation(parameterElement, IndexConstants.IS_READ_WRITTEN_BY, + _expectedLocation(mainElement, 'p += 1')); + } + + void test_isReadWrittenBy_VariableElement() { + _indexTestUnit(''' +main() { + var v = 0; + v += 1; +} +'''); + // prepare elements + Element mainElement = _findElement("main"); + Element variableElement = _findElement("v"); + // verify + _assertRecordedRelation(variableElement, IndexConstants.IS_READ_WRITTEN_BY, + _expectedLocation(mainElement, 'v += 1')); + } + + void test_isReferencedByQualifiedResolved_NameElement_field() { + _indexTestUnit(''' +class A { + int field; +} +main(A a) { + print(a.field); +} +'''); + // prepare elements + Element mainElement = _findElement('main'); + Element nameElement = new NameElement('field'); + // verify + _assertRecordedRelation(nameElement, + IndexConstants.IS_REFERENCED_BY_QUALIFIED_RESOLVED, _expectedLocation( + mainElement, 'field);')); + } + + void test_isReferencedByQualifiedResolved_NameElement_method() { + _indexTestUnit(''' +class A { + method() {} +} +main(A a) { + a.method(); +} +'''); + // prepare elements + Element mainElement = _findElement('main'); + Element nameElement = new NameElement('method'); + // verify + _assertRecordedRelation(nameElement, + IndexConstants.IS_REFERENCED_BY_QUALIFIED_RESOLVED, _expectedLocation( + mainElement, 'method();')); + } + + void test_isReferencedByQualifiedResolved_NameElement_operator() { + _indexTestUnit(''' +class A { + operator +(o) {} + operator -(o) {} + operator ~() {} + operator ==(o) {} +} +main(A a) { + a + 5; + a += 5; + a == 5; + ++a; + --a; + ~a; + a++; + a--; +} +'''); + // prepare elements + Element mainElement = _findElement('main'); + // binary + _assertRecordedRelation(new NameElement('+'), + IndexConstants.IS_REFERENCED_BY_QUALIFIED_RESOLVED, _expectedLocation( + mainElement, '+ 5', '+'.length)); + _assertRecordedRelation(new NameElement('+'), + IndexConstants.IS_REFERENCED_BY_QUALIFIED_RESOLVED, _expectedLocation( + mainElement, '+= 5', '+='.length)); + _assertRecordedRelation(new NameElement('=='), + IndexConstants.IS_REFERENCED_BY_QUALIFIED_RESOLVED, _expectedLocation( + mainElement, '== 5', '=='.length)); + // prefix + _assertRecordedRelation(new NameElement('+'), + IndexConstants.IS_REFERENCED_BY_QUALIFIED_RESOLVED, _expectedLocation( + mainElement, '++a', '++'.length)); + _assertRecordedRelation(new NameElement('-'), + IndexConstants.IS_REFERENCED_BY_QUALIFIED_RESOLVED, _expectedLocation( + mainElement, '--a', '--'.length)); + _assertRecordedRelation(new NameElement('~'), + IndexConstants.IS_REFERENCED_BY_QUALIFIED_RESOLVED, _expectedLocation( + mainElement, '~a', '~'.length)); + // postfix + _assertRecordedRelation(new NameElement('+'), + IndexConstants.IS_REFERENCED_BY_QUALIFIED_RESOLVED, _expectedLocation( + mainElement, '++;', '++'.length)); + _assertRecordedRelation(new NameElement('-'), + IndexConstants.IS_REFERENCED_BY_QUALIFIED_RESOLVED, _expectedLocation( + mainElement, '--;', '--'.length)); + } + + void test_isReferencedByQualifiedUnresolved_NameElement_field() { + _indexTestUnit(''' +class A { + int field; +} +main(var a) { + print(a.field); +} +'''); + // prepare elements + Element mainElement = _findElement('main'); + FieldElement fieldElement = _findElement('field'); + Element nameElement = new NameElement('field'); + // verify + _assertRecordedRelation(nameElement, IndexConstants.IS_DEFINED_BY, + _expectedLocation(fieldElement, 'field;')); + _assertRecordedRelation(nameElement, + IndexConstants.IS_REFERENCED_BY_QUALIFIED_UNRESOLVED, _expectedLocation( + mainElement, 'field);')); + } + + void test_isReferencedByQualifiedUnresolved_NameElement_method() { + _indexTestUnit(''' +class A { + method() {} +} +main(var a) { + a.method(); +} +'''); + // prepare elements + Element mainElement = _findElement('main'); + MethodElement methodElement = _findElement('method'); + Element nameElement = new NameElement('method'); + // verify + _assertRecordedRelation(nameElement, IndexConstants.IS_DEFINED_BY, + _expectedLocation(methodElement, 'method() {}')); + _assertRecordedRelation(nameElement, + IndexConstants.IS_REFERENCED_BY_QUALIFIED_UNRESOLVED, _expectedLocation( + mainElement, 'method();')); + } + + void test_isReferencedByQualifiedUnresolved_NameElement_operator() { + _indexTestUnit(''' +class A { + operator +(o) {} + operator -(o) {} + operator ~() {} + operator ==(o) {} +} +main(a) { + a + 5; + a += 5; + a == 5; + ++a; + --a; + ~a; + a++; + a--; +} +'''); + // prepare elements + Element mainElement = _findElement('main'); + // binary + _assertRecordedRelation(new NameElement('+'), + IndexConstants.IS_REFERENCED_BY_QUALIFIED_UNRESOLVED, _expectedLocation( + mainElement, '+ 5', '+'.length)); + _assertRecordedRelation(new NameElement('+'), + IndexConstants.IS_REFERENCED_BY_QUALIFIED_UNRESOLVED, _expectedLocation( + mainElement, '+= 5', '+='.length)); + _assertRecordedRelation(new NameElement('=='), + IndexConstants.IS_REFERENCED_BY_QUALIFIED_UNRESOLVED, _expectedLocation( + mainElement, '== 5', '=='.length)); + // prefix + _assertRecordedRelation(new NameElement('+'), + IndexConstants.IS_REFERENCED_BY_QUALIFIED_UNRESOLVED, _expectedLocation( + mainElement, '++a', '++'.length)); + _assertRecordedRelation(new NameElement('-'), + IndexConstants.IS_REFERENCED_BY_QUALIFIED_UNRESOLVED, _expectedLocation( + mainElement, '--a', '--'.length)); + _assertRecordedRelation(new NameElement('~'), + IndexConstants.IS_REFERENCED_BY_QUALIFIED_UNRESOLVED, _expectedLocation( + mainElement, '~a', '~'.length)); + // postfix + _assertRecordedRelation(new NameElement('+'), + IndexConstants.IS_REFERENCED_BY_QUALIFIED_UNRESOLVED, _expectedLocation( + mainElement, '++;', '++'.length)); + _assertRecordedRelation(new NameElement('-'), + IndexConstants.IS_REFERENCED_BY_QUALIFIED_UNRESOLVED, _expectedLocation( + mainElement, '--;', '--'.length)); + } + + void test_isReferencedByQualified_ConstructorElement() { + _indexTestUnit(''' +class A implements B { + A() {} + A.foo() {} +} +class B extends A { + B() : super(); // marker-1 + B.foo() : super.foo(); // marker-2 + factory B.bar() = A.foo; // marker-3 +} +main() { + new A(); // marker-main-1 + new A.foo(); // marker-main-2 +} +'''); + // prepare elements + Element mainElement = _findElement('main'); + var isConstructor = (node) => node is ConstructorDeclaration; + ConstructorElement consA = _findNodeElementAtString("A()", isConstructor); + ConstructorElement consA_foo = _findNodeElementAtString("A.foo()", + isConstructor); + ConstructorElement consB = _findNodeElementAtString("B()", isConstructor); + ConstructorElement consB_foo = _findNodeElementAtString("B.foo()", + isConstructor); + ConstructorElement consB_bar = _findNodeElementAtString("B.bar()", + isConstructor); + // A() + _assertRecordedRelation(consA, IndexConstants.IS_REFERENCED_BY, + _expectedLocation(consB, '(); // marker-1', 0)); + _assertRecordedRelation(consA, IndexConstants.IS_REFERENCED_BY, + _expectedLocation(mainElement, '(); // marker-main-1', 0)); + // A.foo() + _assertRecordedRelation(consA_foo, IndexConstants.IS_REFERENCED_BY, + _expectedLocation(consB_foo, '.foo(); // marker-2', '.foo'.length)); + _assertRecordedRelation(consA_foo, IndexConstants.IS_REFERENCED_BY, + _expectedLocation(consB_bar, '.foo; // marker-3', '.foo'.length)); + _assertRecordedRelation(consA_foo, IndexConstants.IS_REFERENCED_BY, + _expectedLocation(mainElement, '.foo(); // marker-main-2', '.foo'.length)); + } + + void test_isReferencedByQualified_ConstructorElement_classTypeAlias() { + _indexTestUnit(''' +class M {} +class A implements B { + A() {} + A.named() {} +} +class B = A with M; +main() { + new B(); // marker-main-1 + new B.named(); // marker-main-2 +} +'''); + // prepare elements + Element mainElement = _findElement('main'); + var isConstructor = (node) => node is ConstructorDeclaration; + ConstructorElement consA = _findNodeElementAtString("A()", isConstructor); + ConstructorElement consA_named = _findNodeElementAtString("A.named()", + isConstructor); + // verify + _assertRecordedRelation(consA, IndexConstants.IS_REFERENCED_BY, + _expectedLocation(mainElement, '(); // marker-main-1', 0)); + _assertRecordedRelation(consA_named, IndexConstants.IS_REFERENCED_BY, + _expectedLocation(mainElement, '.named(); // marker-main-2', '.named'.length)); + } + + void test_isReferencedByQualified_FieldElement() { + _indexTestUnit(''' +class A { + static var field; +} +main() { + A.field = 1; +} +'''); + // prepare elements + Element mainElement = _findElement('main'); + FieldElement fieldElement = _findElement('field'); + PropertyAccessorElement setterElement = fieldElement.setter; + // verify + _assertRecordedRelation(setterElement, + IndexConstants.IS_REFERENCED_BY_QUALIFIED, _expectedLocation(mainElement, + 'field = 1')); + } + + void test_isReferencedByQualified_MethodElement() { + _indexTestUnit(''' +class A { + foo() {} + main() { + print(this.foo); + } +} +'''); + // prepare elements + Element fooElement = _findElement('foo'); + Element mainElement = _findElement('main'); + // verify + _assertRecordedRelation(fooElement, + IndexConstants.IS_REFERENCED_BY_QUALIFIED, _expectedLocation(mainElement, + 'foo);')); + } + + void test_isReferencedByQualified_MethodElement_operator_binary() { + _indexTestUnit(''' +class A { + operator +(other) => this; +} +main(A a) { + print(a + 1); + a += 2; + ++a; + a++; +} +'''); + // prepare elements + Element element = _findElement('+'); + Element mainElement = _findElement('main'); + // verify + _assertRecordedRelation(element, IndexConstants.IS_INVOKED_BY_QUALIFIED, + _expectedLocation(mainElement, '+ 1', "+".length)); + _assertRecordedRelation(element, IndexConstants.IS_INVOKED_BY_QUALIFIED, + _expectedLocation(mainElement, '+= 2', "+=".length)); + _assertRecordedRelation(element, IndexConstants.IS_INVOKED_BY_QUALIFIED, + _expectedLocation(mainElement, '++a;', "++".length)); + _assertRecordedRelation(element, IndexConstants.IS_INVOKED_BY_QUALIFIED, + _expectedLocation(mainElement, '++;', "++".length)); + } + + void test_isReferencedByQualified_MethodElement_operator_index() { + _indexTestUnit(''' +class A { + operator [](i) => null; + operator []=(i, v) {} +} +main(A a) { + print(a[0]); + a[1] = 42; +} +'''); + // prepare elements + MethodElement readElement = _findElement("[]"); + MethodElement writeElement = _findElement("[]="); + Element mainElement = _findElement('main'); + // verify + _assertRecordedRelation(readElement, IndexConstants.IS_INVOKED_BY_QUALIFIED, + _expectedLocation(mainElement, '[0]', "[".length)); + _assertRecordedRelation(writeElement, + IndexConstants.IS_INVOKED_BY_QUALIFIED, _expectedLocation(mainElement, '[1] =', + "[".length)); + } + + void test_isReferencedByQualified_MethodElement_operator_prefix() { + _indexTestUnit(''' +class A { + A operator ~() => this; +} +main(A a) { + print(~a); +} +'''); + // prepare elements + MethodElement element = _findElement("~"); + Element mainElement = _findElement('main'); + // verify + _assertRecordedRelation(element, IndexConstants.IS_INVOKED_BY_QUALIFIED, + _expectedLocation(mainElement, '~a', "~".length)); + } + + void test_isReferencedByQualified_PropertyAccessorElement_method_getter() { + _indexTestUnit(''' +class A { + get foo => 42; + main() { + print(this.foo); + } +} +'''); + // prepare elements + PropertyAccessorElement element = _findNodeElementAtString('foo =>'); + Element mainElement = _findElement('main'); + // verify + _assertRecordedRelation(element, IndexConstants.IS_REFERENCED_BY_QUALIFIED, + _expectedLocation(mainElement, 'foo);')); + _assertNoRecordedRelation(element, IndexConstants.IS_REFERENCED_BY, null); + } + + void test_isReferencedByQualified_PropertyAccessorElement_method_setter() { + _indexTestUnit(''' +class A { + set foo(x) {} + main() { + this.foo = 42; + } +} +'''); + // prepare elements + PropertyAccessorElement element = _findNodeElementAtString('foo(x)'); + Element mainElement = _findElement('main'); + // verify + _assertRecordedRelation(element, IndexConstants.IS_REFERENCED_BY_QUALIFIED, + _expectedLocation(mainElement, 'foo = 42;')); + _assertNoRecordedRelation(element, IndexConstants.IS_REFERENCED_BY, null); + } + + void test_isReferencedByQualified_PropertyAccessorElement_topLevelField() { + addSource('/lib.dart', ''' +library lib; +var myVar; +'''); + _indexTestUnit(''' +import 'lib.dart' as pref; +main() { + pref.myVar = 1; + print(pref.myVar); +} +'''); + // prepare elements + Element mainElement = _findElement('main'); + ImportElement importElement = testLibraryElement.imports[0]; + CompilationUnitElement impUnit = + importElement.importedLibrary.definingCompilationUnit; + TopLevelVariableElement myVar = impUnit.topLevelVariables[0]; + PropertyAccessorElement getter = myVar.getter; + PropertyAccessorElement setter = myVar.setter; + // verify + _assertRecordedRelation(setter, IndexConstants.IS_REFERENCED_BY_QUALIFIED, + _expectedLocation(mainElement, 'myVar = 1')); + _assertRecordedRelation(getter, IndexConstants.IS_REFERENCED_BY_QUALIFIED, + _expectedLocation(mainElement, 'myVar);')); + } + + void test_isReferencedByUnqualified_FieldElement() { + _indexTestUnit(''' +class A { + var field; + main() { + field = 5; + print(field); + } +}'''); + // prepare elements + Element mainElement = _findElement("main"); + FieldElement fieldElement = _findElement("field"); + PropertyAccessorElement getter = fieldElement.getter; + PropertyAccessorElement setter = fieldElement.setter; + // verify + _assertRecordedRelation(setter, IndexConstants.IS_REFERENCED_BY_UNQUALIFIED, + _expectedLocation(mainElement, 'field = 5')); + _assertRecordedRelation(getter, IndexConstants.IS_REFERENCED_BY_UNQUALIFIED, + _expectedLocation(mainElement, 'field);')); + } + + void test_isReferencedByUnqualified_MethodElement() { + _indexTestUnit(''' +class A { + method() {} + main() { + print(method); + } +}'''); + // prepare elements + Element mainElement = _findElement("main"); + MethodElement methodElement = _findElement("method"); + // verify + _assertRecordedRelation(methodElement, + IndexConstants.IS_REFERENCED_BY_UNQUALIFIED, _expectedLocation(mainElement, + 'method);')); + _assertNoRecordedRelation(methodElement, IndexConstants.IS_REFERENCED_BY, + null); + } + + void test_isReferencedByUnqualified_TopLevelVariableElement() { + _indexTestUnit(''' +var topVariable; +main() { + topVariable = 5; + print(topVariable); +}'''); + // prepare elements + Element mainElement = _findElement("main"); + TopLevelVariableElement variableElement = _findElement("topVariable"); + // verify + _assertRecordedRelation(variableElement.setter, + IndexConstants.IS_REFERENCED_BY_UNQUALIFIED, _expectedLocation(mainElement, + 'topVariable = 5')); + _assertRecordedRelation(variableElement.getter, + IndexConstants.IS_REFERENCED_BY_UNQUALIFIED, _expectedLocation(mainElement, + 'topVariable);')); + } + + void test_isReferencedBy_ClassElement() { + _indexTestUnit(''' +class A { + static var field; +} +main(A p) { + A v; + new A(); // 2 + A.field = 1; + print(A.field); // 3 +} +'''); + // prepare elements + ClassElement aElement = _findElement("A"); + Element mainElement = _findElement("main"); + ParameterElement pElement = _findElement("p"); + VariableElement vElement = _findElement("v"); + // verify + _assertRecordedRelation(aElement, IndexConstants.IS_REFERENCED_BY, + _expectedLocation(pElement, 'A p) {')); + _assertRecordedRelation(aElement, IndexConstants.IS_REFERENCED_BY, + _expectedLocation(vElement, 'A v;')); + _assertRecordedRelation(aElement, IndexConstants.IS_REFERENCED_BY, + _expectedLocation(mainElement, 'A(); // 2')); + _assertRecordedRelation(aElement, IndexConstants.IS_REFERENCED_BY, + _expectedLocation(mainElement, 'A.field = 1;')); + _assertRecordedRelation(aElement, IndexConstants.IS_REFERENCED_BY, + _expectedLocation(mainElement, 'A.field); // 3')); + } + + void test_isReferencedBy_ClassTypeAlias() { + _indexTestUnit(''' +class A {} +class B = Object with A; +main(B p) { + B v; +} +'''); + // prepare elements + ClassElement bElement = _findElement("B"); + ParameterElement pElement = _findElement("p"); + VariableElement vElement = _findElement("v"); + // verify + _assertRecordedRelation(bElement, IndexConstants.IS_REFERENCED_BY, + _expectedLocation(pElement, 'B p) {')); + _assertRecordedRelation(bElement, IndexConstants.IS_REFERENCED_BY, + _expectedLocation(vElement, 'B v;')); + } + + void test_isReferencedBy_CompilationUnitElement() { + addSource('/my_unit.dart', 'part of my_lib;'); + _indexTestUnit(''' +library my_lib; +part 'my_unit.dart'; +'''); + // prepare elements + CompilationUnitElement myUnitElement = testLibraryElement.parts[0]; + // verify + _assertRecordedRelation(myUnitElement, IndexConstants.IS_REFERENCED_BY, + _expectedLocation(testUnitElement, "'my_unit.dart';", "'my_unit.dart'".length)); + } + + void test_isReferencedBy_ConstructorFieldInitializer() { + _indexTestUnit(''' +class A { + int field; + A() : field = 5; +} +'''); + // prepare elements + ConstructorElement constructorElement = _findNodeElementAtString("A()", + (node) => node is ConstructorDeclaration); + FieldElement fieldElement = _findElement("field"); + // verify + _assertRecordedRelation(fieldElement, IndexConstants.IS_REFERENCED_BY, + _expectedLocation(constructorElement, 'field = 5')); + } + + void test_isReferencedBy_FieldFormalParameterElement() { + _indexTestUnit(''' +class A { + int field; + A(this.field); +} +'''); + // prepare elements + FieldElement fieldElement = _findElement("field"); + Element fieldParameterElement = _findNodeElementAtString("field);"); + // verify + _assertRecordedRelation(fieldElement, + IndexConstants.IS_REFERENCED_BY_QUALIFIED, _expectedLocation( + fieldParameterElement, 'field);')); + } + + void test_isReferencedBy_FunctionElement() { + _indexTestUnit(''' +foo() {} +main() { + print(foo); + print(foo()); +} +'''); + // prepare elements + FunctionElement element = _findElement("foo"); + Element mainElement = _findElement("main"); + // "referenced" here + _assertRecordedRelation(element, IndexConstants.IS_REFERENCED_BY, + _expectedLocation(mainElement, 'foo);')); + // only "invoked", but not "referenced" + { + _assertRecordedRelation(element, IndexConstants.IS_INVOKED_BY, + _expectedLocation(mainElement, 'foo());')); + _assertNoRecordedRelation(element, IndexConstants.IS_REFERENCED_BY, + _expectedLocation(mainElement, 'foo());')); + } + } + + void test_isReferencedBy_FunctionTypeAliasElement() { + _indexTestUnit(''' +typedef A(); +main(A p) { +} +'''); + // prepare elements + Element aElement = _findElement('A'); + Element pElement = _findElement('p'); + // verify + _assertRecordedRelation(aElement, IndexConstants.IS_REFERENCED_BY, + _expectedLocation(pElement, 'A p) {')); + } + + void test_isReferencedBy_ImportElement_noPrefix() { + addSource('/lib.dart', ''' +library lib; +var myVar; +myFunction() {} +myToHide() {} +'''); + _indexTestUnit(''' +import 'lib.dart' show myVar, myFunction hide myToHide; +main() { + myVar = 1; + myFunction(); + print(0); +} +'''); + // prepare elements + ImportElement importElement = testLibraryElement.imports[0]; + Element mainElement = _findElement('main'); + // verify + _assertRecordedRelation(importElement, IndexConstants.IS_REFERENCED_BY, + _expectedLocation(mainElement, 'myVar = 1;', 0)); + _assertRecordedRelation(importElement, IndexConstants.IS_REFERENCED_BY, + _expectedLocation(mainElement, 'myFunction();', 0)); + _assertNoRecordedRelation(importElement, IndexConstants.IS_REFERENCED_BY, + _expectedLocation(mainElement, 'print(0);', 0)); + // no references from import combinators + _assertNoRecordedRelation(importElement, IndexConstants.IS_REFERENCED_BY, + _expectedLocation(testUnitElement, 'myVar, ', 0)); + _assertNoRecordedRelation(importElement, IndexConstants.IS_REFERENCED_BY, + _expectedLocation(testUnitElement, 'myFunction hide', 0)); + _assertNoRecordedRelation(importElement, IndexConstants.IS_REFERENCED_BY, + _expectedLocation(testUnitElement, 'myToHide;', 0)); + } + + void test_isReferencedBy_ImportElement_withPrefix() { + addSource('/libA.dart', ''' +library libA; +var myVar; +'''); + addSource('/libB.dart', ''' +library libB; +class MyClass {} +'''); + _indexTestUnit(''' +import 'libA.dart' as pref; +import 'libB.dart' as pref; +main() { + pref.myVar = 1; + new pref.MyClass(); +} +'''); + // prepare elements + ImportElement importElementA = testLibraryElement.imports[0]; + ImportElement importElementB = testLibraryElement.imports[1]; + Element mainElement = _findElement('main'); + // verify + _assertRecordedRelation(importElementA, IndexConstants.IS_REFERENCED_BY, + _expectedLocation(mainElement, 'pref.myVar = 1;', 'pref.'.length)); + _assertRecordedRelation(importElementB, IndexConstants.IS_REFERENCED_BY, + _expectedLocation(mainElement, 'pref.MyClass();', 'pref.'.length)); + } + + void test_isReferencedBy_ImportElement_withPrefix_combinators() { + addSource('/lib.dart', ''' +library lib; +class A {} +class B {} +'''); + _indexTestUnit(''' +import 'lib.dart' as pref show A; +import 'lib.dart' as pref show B; +import 'lib.dart'; +import 'lib.dart' as otherPrefix; +main() { + new pref.A(); + new pref.B(); +} +'''); + // prepare elements + ImportElement importElementA = testLibraryElement.imports[0]; + ImportElement importElementB = testLibraryElement.imports[1]; + Element mainElement = _findElement('main'); + // verify + _assertRecordedRelation(importElementA, IndexConstants.IS_REFERENCED_BY, + _expectedLocation(mainElement, 'pref.A();', 'pref.'.length)); + _assertRecordedRelation(importElementB, IndexConstants.IS_REFERENCED_BY, + _expectedLocation(mainElement, 'pref.B();', 'pref.'.length)); + } + + void test_isReferencedBy_ImportElement_withPrefix_invocation() { + addSource('/lib.dart', ''' +library lib; +myFunc() {} +'''); + _indexTestUnit(''' +import 'lib.dart' as pref; +main() { + pref.myFunc(); +} +'''); + // prepare elements + ImportElement importElement = testLibraryElement.imports[0]; + Element mainElement = _findElement('main'); + // verify + _assertRecordedRelation(importElement, IndexConstants.IS_REFERENCED_BY, + _expectedLocation(mainElement, 'pref.myFunc();', 'pref.'.length)); + } + + void test_isReferencedBy_ImportElement_withPrefix_oneCandidate() { + addSource('/lib.dart', ''' +library lib; +class A {} +class B {} +'''); + _indexTestUnit(''' +import 'lib.dart' as pref show A; +main() { + new pref.A(); +} +'''); + // prepare elements + ImportElement importElement = testLibraryElement.imports[0]; + Element mainElement = _findElement('main'); + // verify + _assertRecordedRelation(importElement, IndexConstants.IS_REFERENCED_BY, + _expectedLocation(mainElement, 'pref.A();', 'pref.'.length)); + } + + void test_isReferencedBy_ImportElement_withPrefix_unresolvedElement() { + verifyNoTestUnitErrors = false; + addSource('/lib.dart', ''' +library lib; +'''); + _indexTestUnit(''' +import 'lib.dart' as pref; +main() { + pref.myVar = 1; +} +'''); + } + + void test_isReferencedBy_ImportElement_withPrefix_wrongInvocation() { + verifyNoTestUnitErrors = false; + _indexTestUnit(''' +import 'dart:math' as m; +main() { + m(); +}'''); + } + + void test_isReferencedBy_ImportElement_withPrefix_wrongPrefixedIdentifier() { + verifyNoTestUnitErrors = false; + _indexTestUnit(''' +import 'dart:math' as m; +main() { + x.m; +} +'''); + } + + void test_isReferencedBy_LabelElement() { + _indexTestUnit(''' +main() { + L: while (true) { + break L; + } +} +'''); + // prepare elements + Element mainElement = _findElement('main'); + Element element = _findElement('L'); + // verify + _assertRecordedRelation(element, IndexConstants.IS_REFERENCED_BY, + _expectedLocation(mainElement, 'L;')); + } + + void test_isReferencedBy_LibraryElement_export() { + addSource('/lib.dart', ''' +library lib; +'''); + _indexTestUnit(''' +export 'lib.dart'; +'''); + // prepare elements + LibraryElement libElement = testLibraryElement.exportedLibraries[0]; + CompilationUnitElement libUnitElement = libElement.definingCompilationUnit; + // verify + _assertRecordedRelation(libUnitElement, IndexConstants.IS_REFERENCED_BY, + _expectedLocation(testUnitElement, "'lib.dart'", "'lib.dart'".length)); + } + + void test_isReferencedBy_LibraryElement_import() { + addSource('/lib.dart', ''' +library lib; +'''); + _indexTestUnit(''' +import 'lib.dart'; +'''); + // prepare elements + LibraryElement libElement = testLibraryElement.imports[0].importedLibrary; + CompilationUnitElement libUnitElement = libElement.definingCompilationUnit; + // verify + _assertRecordedRelation(libUnitElement, IndexConstants.IS_REFERENCED_BY, + _expectedLocation(testUnitElement, "'lib.dart'", "'lib.dart'".length)); + } + + void test_isReferencedBy_ParameterElement() { + _indexTestUnit(''' +foo({var p}) {} +main() { + foo(p: 1); +} +'''); + // prepare elements + Element mainElement = _findElement('main'); + Element element = _findElement('p'); + // verify + _assertRecordedRelation(element, IndexConstants.IS_REFERENCED_BY, + _expectedLocation(mainElement, 'p: 1')); + } + + void test_isReferencedBy_TypeParameterElement() { + _indexTestUnit(''' +class A { + T f; + foo(T p) { + T v; + } +} +'''); + // prepare elements + Element typeParameterElement = _findElement('T'); + Element fieldElement = _findElement('f'); + Element parameterElement = _findElement('p'); + Element variableElement = _findElement('v'); + // verify + _assertRecordedRelation(typeParameterElement, + IndexConstants.IS_REFERENCED_BY, _expectedLocation(fieldElement, 'T f')); + _assertRecordedRelation(typeParameterElement, + IndexConstants.IS_REFERENCED_BY, _expectedLocation(parameterElement, 'T p')); + _assertRecordedRelation(typeParameterElement, + IndexConstants.IS_REFERENCED_BY, _expectedLocation(variableElement, 'T v')); + } + + /** + * 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; +'''); + // prepare elements + Element aElement = _findElement('A'); + Element variableElement = _findElement('myVariable'); + // verify + _assertRecordedRelation(aElement, IndexConstants.IS_REFERENCED_BY, + _expectedLocation(testUnitElement, 'A] text')); + _assertNoRecordedRelation(aElement, IndexConstants.IS_REFERENCED_BY, + _expectedLocation(variableElement, 'A] text')); + } + + void test_isReferencedBy_libraryName() { + Source libSource = addSource('/lib.dart', ''' +library lib; +part 'test.dart'; +'''); + testCode = 'part of lib;'; + testSource = addSource('/test.dart', testCode); + testUnit = resolveDartUnit(testSource, libSource); + testUnitElement = testUnit.element; + testLibraryElement = testUnitElement.library; + indexDartUnit(store, context, testUnit); + // verify + _assertRecordedRelation(testLibraryElement, IndexConstants.IS_REFERENCED_BY, + _expectedLocation(testUnitElement, "lib;")); + } + + void test_isReferencedBy_typeInVariableList() { + _indexTestUnit(''' +class A {} +A myVariable = null; +'''); + // prepare elements + Element classElementA = _findElement('A'); + Element variableElement = _findElement('myVariable'); + // verify + _assertRecordedRelation(classElementA, IndexConstants.IS_REFERENCED_BY, + _expectedLocation(variableElement, 'A myVariable')); + } + + void test_isWrittenBy_ParameterElement() { + _indexTestUnit(''' +main(var p) { + p = 1; +}'''); + // prepare elements + Element mainElement = _findElement("main"); + ParameterElement pElement = _findElement("p"); + // verify + _assertRecordedRelation(pElement, IndexConstants.IS_WRITTEN_BY, + _expectedLocation(mainElement, 'p = 1')); + } + + void test_isWrittenBy_VariableElement() { + _indexTestUnit(''' +main() { + var v = 0; + v = 1; +}'''); + // prepare elements + Element mainElement = _findElement("main"); + LocalVariableElement vElement = _findElement("v"); + // verify + _assertRecordedRelation(vElement, IndexConstants.IS_WRITTEN_BY, + _expectedLocation(mainElement, 'v = 1')); + } + + void test_nameIsInvokedBy() { + _indexTestUnit(''' +class A { + test(x) {} +} +main(A a, p) { + a.test(1); + p.test(2); +}'''); + // prepare elements + Element mainElement = _findElement("main"); + Element nameElement = new NameElement('test'); + // verify + _assertRecordedRelation(nameElement, + IndexConstants.NAME_IS_INVOKED_BY_RESOLVED, _expectedLocation(mainElement, + 'test(1)')); + _assertRecordedRelation(nameElement, + IndexConstants.NAME_IS_INVOKED_BY_UNRESOLVED, _expectedLocation(mainElement, + 'test(2)')); + _assertNoRecordedRelation(nameElement, + IndexConstants.NAME_IS_READ_BY_UNRESOLVED, _expectedLocation(mainElement, + 'test(2)')); + } + + void test_nameIsReadBy() { + _indexTestUnit(''' +class A { + var test; +} +main(A a, p) { + print(a.test); // a + print(p.test); // p +}'''); + // prepare elements + Element mainElement = _findElement("main"); + Element nameElement = new NameElement('test'); + // verify + _assertRecordedRelation(nameElement, + IndexConstants.NAME_IS_READ_BY_RESOLVED, _expectedLocation(mainElement, + 'test); // a')); + _assertRecordedRelation(nameElement, + IndexConstants.NAME_IS_READ_BY_UNRESOLVED, _expectedLocation(mainElement, + 'test); // p')); + } + + void test_nameIsReadWrittenBy() { + _indexTestUnit(''' +class A { + var test; +} +main(A a, p) { + a.test += 1; + p.test += 2; +}'''); + // prepare elements + Element mainElement = _findElement("main"); + Element nameElement = new NameElement('test'); + // verify + _assertRecordedRelation(nameElement, + IndexConstants.NAME_IS_READ_WRITTEN_BY_RESOLVED, _expectedLocation(mainElement, + 'test += 1')); + _assertRecordedRelation(nameElement, + IndexConstants.NAME_IS_READ_WRITTEN_BY_UNRESOLVED, _expectedLocation( + mainElement, 'test += 2')); + } + + void test_nameIsWrittenBy() { + _indexTestUnit(''' +class A { + var test; +} +main(A a, p) { + a.test = 1; + p.test = 2; +}'''); + // prepare elements + Element mainElement = _findElement("main"); + Element nameElement = new NameElement('test'); + // verify + _assertRecordedRelation(nameElement, + IndexConstants.NAME_IS_WRITTEN_BY_RESOLVED, _expectedLocation(mainElement, + 'test = 1')); + _assertRecordedRelation(nameElement, + IndexConstants.NAME_IS_WRITTEN_BY_UNRESOLVED, _expectedLocation(mainElement, + 'test = 2')); + } + + void test_nullUnit() { + indexDartUnit(store, context, null); + } + + void test_nullUnitElement() { + CompilationUnit unit = new CompilationUnit(null, null, [], [], null); + indexDartUnit(store, context, unit); + } + + void _assertDefinesTopLevelElement(Relationship relationship, + ExpectedLocation expectedLocation) { + _assertRecordedRelation(testLibraryElement, relationship, expectedLocation); + _assertRecordedRelation(UniverseElement.INSTANCE, relationship, + expectedLocation); + } + + void _assertNoErrorsInSource() { + List errors = context.getErrors(testSource).errors; + expect(errors, isEmpty); + } + + /** + * Asserts that [recordedRelations] has no item with the specified properties. + */ + void _assertNoRecordedRelation(Element element, Relationship relationship, + ExpectedLocation location) { + for (RecordedRelation recordedRelation in recordedRelations) { + if (_equalsRecordedRelation(recordedRelation, element, relationship, + location)) { + fail('not expected: ${recordedRelation} in\n' + recordedRelations.join( + '\n')); + } + } + } + + /** + * Asserts that [recordedRelations] has an item with the expected properties. + */ + Location _assertRecordedRelation(Element expectedElement, + Relationship expectedRelationship, ExpectedLocation expectedLocation) { + for (RecordedRelation recordedRelation in recordedRelations) { + if (_equalsRecordedRelation(recordedRelation, expectedElement, + expectedRelationship, expectedLocation)) { + return recordedRelation.location; + } + } + fail("not found\n$expectedElement $expectedRelationship " + "in $expectedLocation in\n" + recordedRelations.join('\n')); + return null; + } + + ExpectedLocation _expectedLocation(Element element, String search, [int length + = -1]) { + int offset = _findOffset(search); + if (length == -1) { + length = _getLeadingIdentifierLength(search); + } + return new ExpectedLocation(element, offset, length); + } + + Element _findElement(String name, [ElementKind kind]) { + return findChildElement(testUnitElement, name, kind); + } + + AstNode _findNodeAtOffset(int offset, [Predicate predicate]) { + AstNode result = new NodeLocator.con1(offset).searchWithin(testUnit); + if (result != null && predicate != null) { + result = result.getAncestor(predicate); + } + return result; + } + + AstNode _findNodeAtString(String search, [Predicate predicate]) { + int offset = _findOffset(search); + return _findNodeAtOffset(offset, predicate); + } + + Element _findNodeElementAtString(String search, + [Predicate predicate]) { + AstNode node = _findNodeAtString(search, predicate); + if (node == null) { + return null; + } + return ElementLocator.locate(node); + } + + int _findOffset(String search) { + int offset = testCode.indexOf(search); + expect(offset, isNonNegative, reason: "Not found '$search' in\n$testCode"); + return offset; + } + + void _indexTestUnit(String code) { + testCode = code; + testSource = addSource('/test.dart', code); + testUnit = resolveLibraryUnit(testSource); + if (verifyNoTestUnitErrors) { + _assertNoErrorsInSource(); + } + testUnitElement = testUnit.element; + testLibraryElement = testUnitElement.library; + indexDartUnit(store, context, testUnit); + } +} + +class ExpectedLocation { + Element element; + int offset; + int length; + + ExpectedLocation(this.element, this.offset, this.length); + + @override + String toString() { + return 'ExpectedLocation(element=$element; offset=$offset; length=$length)'; + } +} + +class MockIndexStore extends TypedMock implements IndexStore { + noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation); +} + + +/** + * Information about a relation recorded into {@link IndexStore}. + */ +class RecordedRelation { + final Element element; + final Relationship relationship; + final Location location; + + RecordedRelation(this.element, this.relationship, this.location); + + @override + String toString() { + return 'RecordedRelation(element=$element; relationship=$relationship; ' + 'location=$location)'; + } +} diff --git a/pkg/analysis_services/test/index/local_file_index_test.dart b/pkg/analysis_services/test/index/local_file_index_test.dart new file mode 100644 index 00000000000..8ac5fefcfe6 --- /dev/null +++ b/pkg/analysis_services/test/index/local_file_index_test.dart @@ -0,0 +1,26 @@ +// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +library test.services.src.index.local_file_index; + +import 'dart:io'; + +import 'package:analysis_services/index/index.dart'; +import 'package:analysis_services/index/local_file_index.dart'; +import 'package:unittest/unittest.dart'; + + +main() { + groupSep = ' | '; + test('createLocalFileIndex', () { + Directory indexDirectory = Directory.systemTemp.createTempSync( + 'AnalysisServer_index'); + try { + Index index = createLocalFileIndex(indexDirectory); + expect(index, isNotNull); + } finally { + indexDirectory.delete(recursive: true); + } + }); +} diff --git a/pkg/analysis_services/test/index/local_index_test.dart b/pkg/analysis_services/test/index/local_index_test.dart index 9535f484d91..f4be0a6abe8 100644 --- a/pkg/analysis_services/test/index/local_index_test.dart +++ b/pkg/analysis_services/test/index/local_index_test.dart @@ -4,159 +4,148 @@ library test.services.src.index.local_index; -//import 'dart:async'; -//import 'dart:io' show Directory; -// -//import 'package:analyzer/src/generated/ast.dart'; -//import 'package:analyzer/src/generated/element.dart'; -//import 'package:analyzer/src/generated/html.dart'; -//import 'package:analyzer/src/generated/source_io.dart'; -//import 'package:unittest/unittest.dart'; -// -//import '../reflective_tests.dart'; -//import 'store/memory_node_manager.dart'; -//import 'store/single_source_container.dart'; -//import 'package:analyzer/src/index/local_index.dart'; -//import 'package:analyzer/index/index.dart'; +import 'dart:async'; + +import 'package:analysis_services/index/index.dart'; +import 'package:analysis_services/index/local_memory_index.dart'; +import 'package:analysis_services/src/index/local_index.dart'; +import 'package:analysis_testing/abstract_context.dart'; +import 'package:analysis_testing/reflective_tests.dart'; +import 'package:analyzer/src/generated/ast.dart'; +import 'package:analyzer/src/generated/html.dart'; +import 'package:analyzer/src/generated/source_io.dart'; +import 'package:unittest/unittest.dart'; + +import 'store/single_source_container.dart'; main() { -// groupSep = ' | '; -// group('LocalIndex', () { -//// runReflectiveTests(LocalIndexTest); -// }); + groupSep = ' | '; + group('LocalIndex', () { + runReflectiveTests(LocalIndexTest); + }); } -//void _assertElementNames(List locations, List expected) { -// expect(_toElementNames(locations), unorderedEquals(expected)); -//} -// -// -//Iterable _toElementNames(List locations) { -// return locations.map((loc) => loc.element.name); -//} +void _assertElementNames(List locations, List expected) { + expect(_toElementNames(locations), unorderedEquals(expected)); +} -/** - * TODO(scheglov) Decide what what to do with AbstractContextTest, resource and - * all other testing infrastructure existing in Server, but not in Engine. - */ -class LocalIndexTest {} -//@ReflectiveTestCase() -//class LocalIndexTest extends AbstractContextTest { -// Directory indexDirectory; -// LocalIndex index; -// -// void setUp() { -// super.setUp(); -// // prepare Index -// indexDirectory = Directory.systemTemp.createTempSync( -// 'AnalysisServer_index'); -// index = new LocalIndex(new MemoryNodeManager()); -// } -// -// void tearDown() { -// super.tearDown(); -// indexDirectory.delete(recursive: true); -// index = null; -// } -// -// Future test_clear() { -// _indexTest('main() {}'); -// return _getDefinedFunctions().then((locations) { -// _assertElementNames(locations, ['main']); -// // clear -// index.clear(); -// return _getDefinedFunctions().then((locations) { -// expect(locations, isEmpty); -// }); -// }); -// } -// -// void test_indexHtmlUnit_nullUnit() { -// index.indexHtmlUnit(context, null); -// } -// -// void test_indexHtmlUnit_nullUnitElement() { -// HtmlUnit unit = new HtmlUnit(null, [], null); -// index.indexHtmlUnit(context, unit); -// } -// -// Future test_indexUnit() { -// _indexTest('main() {}'); -// return _getDefinedFunctions().then((locations) { -// _assertElementNames(locations, ['main']); -// }); -// } -// -// void test_indexUnit_nullUnit() { -// index.indexUnit(context, null); -// } -// -// void test_indexUnit_nullUnitElement() { -// CompilationUnit unit = new CompilationUnit(null, null, [], [], null); -// index.indexUnit(context, unit); -// } -// -// Future test_removeContext() { -// _indexTest('main() {}'); -// return _getDefinedFunctions().then((locations) { -// // OK, there is a location -// _assertElementNames(locations, ['main']); -// // remove context -// index.removeContext(context); -// return _getDefinedFunctions().then((locations) { -// expect(locations, isEmpty); -// }); -// }); -// } -// -// Future test_removeSource() { -// Source sourceA = _indexLibraryUnit('/testA.dart', 'fa() {}'); -// _indexLibraryUnit('/testB.dart', 'fb() {}'); -// return _getDefinedFunctions().then((locations) { -// // OK, there are 2 functions -// _assertElementNames(locations, ['fa', 'fb']); -// // remove source -// index.removeSource(context, sourceA); -// return _getDefinedFunctions().then((locations) { -// _assertElementNames(locations, ['fb']); -// }); -// }); -// } -// -// Future test_removeSources() { -// Source sourceA = _indexLibraryUnit('/testA.dart', 'fa() {}'); -// _indexLibraryUnit('/testB.dart', 'fb() {}'); -// return _getDefinedFunctions().then((locations) { -// // OK, there are 2 functions -// _assertElementNames(locations, ['fa', 'fb']); -// // remove source(s) -// index.removeSources(context, new SingleSourceContainer(sourceA)); -// return _getDefinedFunctions().then((locations) { -// _assertElementNames(locations, ['fb']); -// }); -// }); -// } -// -// void test_statistics() { -// expect(index.statistics, '[0 locations, 0 sources, 0 names]'); -// } -// -// Future> _getDefinedFunctions() { -// return index.getRelationshipsAsync(UniverseElement.INSTANCE, -// IndexConstants.DEFINES_FUNCTION); -// } -// -// Source _indexLibraryUnit(String path, String content) { -// Source source = addSource(path, content); -// CompilationUnit dartUnit = resolveLibraryUnit(source); -// index.indexUnit(context, dartUnit); -// return source; -// } -// -// void _indexTest(String content) { -// _indexLibraryUnit('/test.dart', content); -// } -//} +Iterable _toElementNames(List locations) { + return locations.map((loc) => loc.element.name); +} + + +@ReflectiveTestCase() +class LocalIndexTest extends AbstractContextTest { + LocalIndex index; + + void setUp() { + super.setUp(); + index = createLocalMemoryIndex(); + } + + void tearDown() { + super.tearDown(); + index = null; + } + + Future test_clear() { + _indexTest('main() {}'); + return _getDefinedFunctions().then((locations) { + _assertElementNames(locations, ['main']); + // clear + index.clear(); + return _getDefinedFunctions().then((locations) { + expect(locations, isEmpty); + }); + }); + } + + void test_indexHtmlUnit_nullUnit() { + index.indexHtmlUnit(context, null); + } + + void test_indexHtmlUnit_nullUnitElement() { + HtmlUnit unit = new HtmlUnit(null, [], null); + index.indexHtmlUnit(context, unit); + } + + Future test_indexUnit() { + _indexTest('main() {}'); + return _getDefinedFunctions().then((locations) { + _assertElementNames(locations, ['main']); + }); + } + + void test_indexUnit_nullUnit() { + index.indexUnit(context, null); + } + + void test_indexUnit_nullUnitElement() { + CompilationUnit unit = new CompilationUnit(null, null, [], [], null); + index.indexUnit(context, unit); + } + + Future test_removeContext() { + _indexTest('main() {}'); + return _getDefinedFunctions().then((locations) { + // OK, there is a location + _assertElementNames(locations, ['main']); + // remove context + index.removeContext(context); + return _getDefinedFunctions().then((locations) { + expect(locations, isEmpty); + }); + }); + } + + Future test_removeSource() { + Source sourceA = _indexLibraryUnit('/testA.dart', 'fa() {}'); + _indexLibraryUnit('/testB.dart', 'fb() {}'); + return _getDefinedFunctions().then((locations) { + // OK, there are 2 functions + _assertElementNames(locations, ['fa', 'fb']); + // remove source + index.removeSource(context, sourceA); + return _getDefinedFunctions().then((locations) { + _assertElementNames(locations, ['fb']); + }); + }); + } + + Future test_removeSources() { + Source sourceA = _indexLibraryUnit('/testA.dart', 'fa() {}'); + _indexLibraryUnit('/testB.dart', 'fb() {}'); + return _getDefinedFunctions().then((locations) { + // OK, there are 2 functions + _assertElementNames(locations, ['fa', 'fb']); + // remove source(s) + index.removeSources(context, new SingleSourceContainer(sourceA)); + return _getDefinedFunctions().then((locations) { + _assertElementNames(locations, ['fb']); + }); + }); + } + + void test_statistics() { + expect(index.statistics, '[0 locations, 0 sources, 0 names]'); + } + + Future> _getDefinedFunctions() { + return index.getRelationships(UniverseElement.INSTANCE, + IndexConstants.DEFINES_FUNCTION); + } + + Source _indexLibraryUnit(String path, String content) { + Source source = addSource(path, content); + CompilationUnit dartUnit = resolveLibraryUnit(source); + index.indexUnit(context, dartUnit); + return source; + } + + void _indexTest(String content) { + _indexLibraryUnit('/test.dart', content); + } +} diff --git a/pkg/analysis_services/test/index/test_all.dart b/pkg/analysis_services/test/index/test_all.dart index f2e557894b9..47bae26a829 100644 --- a/pkg/analysis_services/test/index/test_all.dart +++ b/pkg/analysis_services/test/index/test_all.dart @@ -6,6 +6,8 @@ library test.services.src.index.all; import 'package:unittest/unittest.dart'; +import 'dart_index_contributor_test.dart' as dart_index_contributor_test; +import 'local_file_index_test.dart' as local_file_index_test; import 'local_index_test.dart' as local_index_test; import 'store/test_all.dart' as store_test_all; @@ -16,6 +18,8 @@ import 'store/test_all.dart' as store_test_all; main() { groupSep = ' | '; group('index', () { + dart_index_contributor_test.main(); + local_file_index_test.main(); local_index_test.main(); store_test_all.main(); }); diff --git a/pkg/analysis_testing/lib/abstract_context.dart b/pkg/analysis_testing/lib/abstract_context.dart index 625f816c078..fe2b7407c8a 100644 --- a/pkg/analysis_testing/lib/abstract_context.dart +++ b/pkg/analysis_testing/lib/abstract_context.dart @@ -5,7 +5,6 @@ library testing.abstract_context; import 'package:analysis_testing/mock_sdk.dart'; -import 'package:analysis_testing/reflective_tests.dart'; import 'package:analyzer/file_system/file_system.dart'; import 'package:analyzer/file_system/memory_file_system.dart'; import 'package:analyzer/src/generated/ast.dart'; @@ -16,12 +15,11 @@ import 'package:analyzer/src/generated/source_io.dart'; /** - * Finds an [engine.Element] with the given [name]. + * Finds an [Element] with the given [name]. */ -Element findElementInUnit(CompilationUnit unit, String name, [ElementKind kind]) - { +Element findChildElement(Element root, String name, [ElementKind kind]) { Element result = null; - unit.element.accept(new _ElementVisitorFunctionWrapper((Element element) { + root.accept(new _ElementVisitorFunctionWrapper((Element element) { if (element.name != name) { return; } @@ -40,7 +38,6 @@ Element findElementInUnit(CompilationUnit unit, String name, [ElementKind kind]) typedef void _ElementVisitorFunction(Element element); -@ReflectiveTestCase() class AbstractContextTest { static final DartSdk SDK = new MockSdk(); @@ -57,6 +54,10 @@ class AbstractContextTest { return source; } + CompilationUnit resolveDartUnit(Source unitSource, Source librarySource) { + return context.resolveCompilationUnit2(unitSource, librarySource); + } + CompilationUnit resolveLibraryUnit(Source source) { return context.resolveCompilationUnit2(source, source); } diff --git a/pkg/analysis_testing/pubspec.yaml b/pkg/analysis_testing/pubspec.yaml index 9ffbf9859a9..f06478889aa 100644 --- a/pkg/analysis_testing/pubspec.yaml +++ b/pkg/analysis_testing/pubspec.yaml @@ -1,5 +1,5 @@ name: analysis_testing -version: 0.1.0 +version: 0.2.0 author: Dart Team description: A set of libraries for testing Analysis services and server homepage: http://www.dartlang.org