| /* |
| * Copyright (c) 2013, the Dart project authors. |
| * |
| * Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except |
| * in compliance with the License. You may obtain a copy of the License at |
| * |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Unless required by applicable law or agreed to in writing, software distributed under the License |
| * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
| * or implied. See the License for the specific language governing permissions and limitations under |
| * the License. |
| */ |
| package com.google.dart.engine.internal.search; |
| |
| import com.google.common.base.Objects; |
| import com.google.common.collect.Lists; |
| import com.google.dart.engine.EngineTestCase; |
| import com.google.dart.engine.context.AnalysisContext; |
| import com.google.dart.engine.element.ClassElement; |
| import com.google.dart.engine.element.CompilationUnitElement; |
| import com.google.dart.engine.element.ConstructorElement; |
| import com.google.dart.engine.element.Element; |
| import com.google.dart.engine.element.ElementKind; |
| import com.google.dart.engine.element.ElementLocation; |
| import com.google.dart.engine.element.FieldElement; |
| import com.google.dart.engine.element.FunctionElement; |
| import com.google.dart.engine.element.FunctionTypeAliasElement; |
| import com.google.dart.engine.element.ImportElement; |
| import com.google.dart.engine.element.LibraryElement; |
| import com.google.dart.engine.element.LocalVariableElement; |
| import com.google.dart.engine.element.MethodElement; |
| import com.google.dart.engine.element.ParameterElement; |
| import com.google.dart.engine.element.PropertyAccessorElement; |
| import com.google.dart.engine.element.TopLevelVariableElement; |
| import com.google.dart.engine.element.TypeParameterElement; |
| import com.google.dart.engine.element.angular.AngularComponentElement; |
| import com.google.dart.engine.element.angular.AngularControllerElement; |
| import com.google.dart.engine.element.angular.AngularFormatterElement; |
| import com.google.dart.engine.element.angular.AngularPropertyElement; |
| import com.google.dart.engine.element.angular.AngularScopePropertyElement; |
| import com.google.dart.engine.element.angular.AngularSelectorElement; |
| import com.google.dart.engine.index.Index; |
| import com.google.dart.engine.index.IndexFactory; |
| import com.google.dart.engine.index.IndexStore; |
| import com.google.dart.engine.index.Location; |
| import com.google.dart.engine.index.LocationWithData; |
| import com.google.dart.engine.internal.element.ElementLocationImpl; |
| import com.google.dart.engine.internal.element.member.MethodMember; |
| import com.google.dart.engine.internal.index.IndexConstants; |
| import com.google.dart.engine.internal.index.IndexImpl; |
| import com.google.dart.engine.internal.index.NameElementImpl; |
| import com.google.dart.engine.internal.index.file.MemoryNodeManager; |
| import com.google.dart.engine.internal.index.operation.IndexOperation; |
| import com.google.dart.engine.internal.index.operation.OperationProcessor; |
| import com.google.dart.engine.internal.index.operation.OperationQueue; |
| import com.google.dart.engine.internal.search.scope.LibrarySearchScope; |
| import com.google.dart.engine.search.MatchKind; |
| import com.google.dart.engine.search.MatchQuality; |
| import com.google.dart.engine.search.SearchEngine; |
| import com.google.dart.engine.search.SearchEngineFactory; |
| import com.google.dart.engine.search.SearchFilter; |
| import com.google.dart.engine.search.SearchListener; |
| import com.google.dart.engine.search.SearchMatch; |
| import com.google.dart.engine.search.SearchPattern; |
| import com.google.dart.engine.search.SearchPatternFactory; |
| import com.google.dart.engine.search.SearchScope; |
| import com.google.dart.engine.search.SearchScopeFactory; |
| import com.google.dart.engine.source.Source; |
| import com.google.dart.engine.type.Type; |
| import com.google.dart.engine.utilities.source.SourceRange; |
| |
| import static org.fest.assertions.Assertions.assertThat; |
| import static org.mockito.Mockito.mock; |
| import static org.mockito.Mockito.when; |
| |
| import java.util.List; |
| import java.util.Set; |
| import java.util.concurrent.CountDownLatch; |
| import java.util.concurrent.TimeUnit; |
| |
| public class SearchEngineImplTest extends EngineTestCase { |
| private static class ExpectedMatch { |
| Element element; |
| MatchKind kind; |
| MatchQuality quality; |
| SourceRange range; |
| boolean qualified; |
| |
| public ExpectedMatch(Element element, MatchKind kind, int offset, int length) { |
| this(element, kind, MatchQuality.EXACT, offset, length); |
| } |
| |
| public ExpectedMatch(Element element, MatchKind kind, int offset, int length, boolean qualified) { |
| this(element, kind, MatchQuality.EXACT, offset, length, qualified); |
| } |
| |
| public ExpectedMatch(Element element, MatchKind kind, MatchQuality quality, int offset, |
| int length) { |
| this(element, kind, quality, offset, length, false); |
| } |
| |
| public ExpectedMatch(Element element, MatchKind kind, MatchQuality quality, int offset, |
| int length, boolean qualified) { |
| this.element = element; |
| this.kind = kind; |
| this.quality = quality; |
| this.range = new SourceRange(offset, length); |
| this.qualified = qualified; |
| } |
| } |
| |
| private static interface SearchRunner<T> { |
| T run(OperationQueue queue, OperationProcessor processor, Index index, SearchEngine engine) |
| throws Exception; |
| } |
| |
| private static void assertMatches(List<SearchMatch> matches, ExpectedMatch... expectedMatches) { |
| assertThat(matches).hasSize(expectedMatches.length); |
| for (SearchMatch match : matches) { |
| boolean found = false; |
| String msg = match.toString(); |
| for (ExpectedMatch expectedMatch : expectedMatches) { |
| if (Objects.equal(match.getElement(), expectedMatch.element) |
| && match.getKind() == expectedMatch.kind && match.getQuality() == expectedMatch.quality |
| && Objects.equal(match.getSourceRange(), expectedMatch.range) |
| && match.isQualified() == expectedMatch.qualified) { |
| found = true; |
| break; |
| } |
| } |
| if (!found) { |
| fail("Not found: " + msg); |
| } |
| } |
| } |
| |
| private IndexStore indexStore = IndexFactory.newSplitIndexStore(new MemoryNodeManager()); |
| |
| private static final AnalysisContext CONTEXT = mock(AnalysisContext.class); |
| private int nextLocationId = 0; |
| private SearchScope scope; |
| private SearchPattern pattern = null; |
| private SearchFilter filter = null; |
| |
| private final Source source = mock(Source.class); |
| private final CompilationUnitElement unitElement = mock(CompilationUnitElement.class); |
| private final LibraryElement libraryElement = mock(LibraryElement.class); |
| private final Element elementA = mockElement(Element.class, ElementKind.CLASS); |
| private final Element elementB = mockElement(Element.class, ElementKind.CLASS); |
| private final Element elementC = mockElement(Element.class, ElementKind.CLASS); |
| private final Element elementD = mockElement(Element.class, ElementKind.CLASS); |
| private final Element elementE = mockElement(Element.class, ElementKind.CLASS); |
| |
| public void fail_searchAssignedTypes_assignments() throws Exception { |
| // TODO(scheglov) does not work - new split index store cannot store types (yet?) |
| final PropertyAccessorElement setterElement = mockElement( |
| PropertyAccessorElement.class, |
| ElementKind.SETTER); |
| final FieldElement fieldElement = mockElement(FieldElement.class, ElementKind.FIELD); |
| when(fieldElement.getSetter()).thenReturn(setterElement); |
| final Type typeA = mock(Type.class); |
| final Type typeB = mock(Type.class); |
| final Type typeC = mock(Type.class); |
| indexStore.aboutToIndexDart(CONTEXT, unitElement); |
| { |
| Location location = new Location(elementA, 1, 10); |
| location = new LocationWithData<Type>(location, typeA); |
| indexStore.recordRelationship( |
| setterElement, |
| IndexConstants.IS_REFERENCED_BY_QUALIFIED, |
| location); |
| } |
| { |
| Location location = new Location(elementB, 2, 20); |
| location = new LocationWithData<Type>(location, typeB); |
| indexStore.recordRelationship( |
| setterElement, |
| IndexConstants.IS_REFERENCED_BY_UNQUALIFIED, |
| location); |
| } |
| // will be filtered by scope |
| { |
| Location location = new Location(elementC, 3, 30); |
| location = new LocationWithData<Type>(location, typeC); |
| indexStore.recordRelationship( |
| setterElement, |
| IndexConstants.IS_REFERENCED_BY_QUALIFIED, |
| location); |
| } |
| // not LocationWithData |
| { |
| Location location = new Location(elementD, 4, 40); |
| indexStore.recordRelationship( |
| setterElement, |
| IndexConstants.IS_REFERENCED_BY_QUALIFIED, |
| location); |
| } |
| indexStore.doneIndex(); |
| // ask types |
| Set<Type> types = runSearch(new SearchRunner<Set<Type>>() { |
| @Override |
| public Set<Type> run(OperationQueue queue, OperationProcessor processor, Index index, |
| SearchEngine engine) throws Exception { |
| return engine.searchAssignedTypes(fieldElement, new SearchScope() { |
| @Override |
| public boolean encloses(Element element) { |
| return element != elementC; |
| } |
| }); |
| } |
| }); |
| assertThat(types).containsOnly(typeA, typeB); |
| } |
| |
| public void fail_searchAssignedTypes_initializers() throws Exception { |
| // TODO(scheglov) does not work - new split index store cannot store types (yet?) |
| final FieldElement fieldElement = mockElement(FieldElement.class, ElementKind.FIELD); |
| final Type typeA = mock(Type.class); |
| final Type typeB = mock(Type.class); |
| { |
| Location location = new Location(elementA, 10, 1); |
| location = new LocationWithData<Type>(location, typeA); |
| indexStore.recordRelationship(fieldElement, IndexConstants.IS_DEFINED_BY, location); |
| } |
| { |
| Location location = new Location(elementB, 20, 1); |
| location = new LocationWithData<Type>(location, typeB); |
| indexStore.recordRelationship(fieldElement, IndexConstants.IS_REFERENCED_BY, location); |
| } |
| indexStore.doneIndex(); |
| // ask types |
| Set<Type> types = runSearch(new SearchRunner<Set<Type>>() { |
| @Override |
| public Set<Type> run(OperationQueue queue, OperationProcessor processor, Index index, |
| SearchEngine engine) throws Exception { |
| return engine.searchAssignedTypes(fieldElement, null); |
| } |
| }); |
| assertThat(types).containsOnly(typeA, typeB); |
| } |
| |
| public void test_searchDeclarations_String() throws Exception { |
| Element referencedElement = new NameElementImpl("test"); |
| { |
| Location locationA = new Location(elementA, 1, 2); |
| indexStore.recordRelationship(referencedElement, IndexConstants.IS_DEFINED_BY, locationA); |
| } |
| { |
| Location locationB = new Location(elementB, 10, 20); |
| indexStore.recordRelationship(referencedElement, IndexConstants.IS_DEFINED_BY, locationB); |
| } |
| indexStore.doneIndex(); |
| // search matches |
| List<SearchMatch> matches = runSearch(new SearchRunner<List<SearchMatch>>() { |
| @Override |
| public List<SearchMatch> run(OperationQueue queue, OperationProcessor processor, Index index, |
| SearchEngine engine) throws Exception { |
| return engine.searchDeclarations("test", scope, filter); |
| } |
| }); |
| // verify |
| assertMatches( |
| matches, |
| new ExpectedMatch(elementA, MatchKind.NAME_DECLARATION, 1, 2), |
| new ExpectedMatch(elementB, MatchKind.NAME_DECLARATION, 10, 20)); |
| } |
| |
| public void test_searchFunctionDeclarations() throws Exception { |
| LibraryElement library = mockElement(LibraryElement.class, ElementKind.LIBRARY); |
| defineFunctionsAB(library); |
| scope = new LibrarySearchScope(library); |
| // search matches |
| List<SearchMatch> matches = searchFunctionDeclarationsSync(); |
| // verify |
| assertMatches( |
| matches, |
| new ExpectedMatch(elementA, MatchKind.FUNCTION_DECLARATION, 1, 2), |
| new ExpectedMatch(elementB, MatchKind.FUNCTION_DECLARATION, 10, 20)); |
| } |
| |
| public void test_searchFunctionDeclarations_async() throws Exception { |
| LibraryElement library = mockElement(LibraryElement.class, ElementKind.LIBRARY); |
| defineFunctionsAB(library); |
| scope = new LibrarySearchScope(library); |
| // search matches |
| List<SearchMatch> matches = searchFunctionDeclarationsAsync(); |
| // verify |
| assertMatches( |
| matches, |
| new ExpectedMatch(elementA, MatchKind.FUNCTION_DECLARATION, 1, 2), |
| new ExpectedMatch(elementB, MatchKind.FUNCTION_DECLARATION, 10, 20)); |
| } |
| |
| public void test_searchFunctionDeclarations_inUniverse() throws Exception { |
| { |
| Location locationA = new Location(elementA, 1, 2); |
| indexStore.recordRelationship( |
| IndexConstants.UNIVERSE, |
| IndexConstants.DEFINES_FUNCTION, |
| locationA); |
| } |
| { |
| Location locationB = new Location(elementB, 10, 20); |
| indexStore.recordRelationship( |
| IndexConstants.UNIVERSE, |
| IndexConstants.DEFINES_FUNCTION, |
| locationB); |
| } |
| indexStore.doneIndex(); |
| scope = SearchScopeFactory.createUniverseScope(); |
| // search matches |
| List<SearchMatch> matches = searchFunctionDeclarationsSync(); |
| // verify |
| assertMatches( |
| matches, |
| new ExpectedMatch(elementA, MatchKind.FUNCTION_DECLARATION, 1, 2), |
| new ExpectedMatch(elementB, MatchKind.FUNCTION_DECLARATION, 10, 20)); |
| } |
| |
| public void test_searchFunctionDeclarations_useFilter() throws Exception { |
| LibraryElement library = mockElement(LibraryElement.class, ElementKind.LIBRARY); |
| defineFunctionsAB(library); |
| scope = new LibrarySearchScope(library); |
| // search "elementA" |
| { |
| filter = new SearchFilter() { |
| @Override |
| public boolean passes(SearchMatch match) { |
| return match.getElement() == elementA; |
| } |
| }; |
| List<SearchMatch> matches = searchFunctionDeclarationsSync(); |
| assertMatches(matches, new ExpectedMatch(elementA, MatchKind.FUNCTION_DECLARATION, 1, 2)); |
| } |
| // search "elementB" |
| { |
| filter = new SearchFilter() { |
| @Override |
| public boolean passes(SearchMatch match) { |
| return match.getElement() == elementB; |
| } |
| }; |
| List<SearchMatch> matches = searchFunctionDeclarationsSync(); |
| assertMatches(matches, new ExpectedMatch(elementB, MatchKind.FUNCTION_DECLARATION, 10, 20)); |
| } |
| } |
| |
| public void test_searchFunctionDeclarations_usePattern() throws Exception { |
| LibraryElement library = mockElement(LibraryElement.class, ElementKind.LIBRARY); |
| defineFunctionsAB(library); |
| scope = new LibrarySearchScope(library); |
| // search "A" |
| { |
| pattern = SearchPatternFactory.createExactPattern("A", true); |
| List<SearchMatch> matches = searchFunctionDeclarationsSync(); |
| assertMatches(matches, new ExpectedMatch(elementA, MatchKind.FUNCTION_DECLARATION, 1, 2)); |
| } |
| // search "B" |
| { |
| pattern = SearchPatternFactory.createExactPattern("B", true); |
| List<SearchMatch> matches = searchFunctionDeclarationsSync(); |
| assertMatches(matches, new ExpectedMatch(elementB, MatchKind.FUNCTION_DECLARATION, 10, 20)); |
| } |
| } |
| |
| public void test_searchReferences_AngularComponentElement() throws Exception { |
| AngularComponentElement referencedElement = mockElement( |
| AngularComponentElement.class, |
| ElementKind.ANGULAR_COMPONENT); |
| { |
| Location locationA = new Location(elementA, 1, 2); |
| indexStore.recordRelationship(referencedElement, IndexConstants.ANGULAR_REFERENCE, locationA); |
| } |
| { |
| Location locationB = new Location(elementB, 10, 20); |
| indexStore.recordRelationship( |
| referencedElement, |
| IndexConstants.ANGULAR_CLOSING_TAG_REFERENCE, |
| locationB); |
| } |
| indexStore.doneIndex(); |
| // search matches |
| List<SearchMatch> matches = searchReferencesSync(Element.class, referencedElement); |
| assertMatches( |
| matches, |
| new ExpectedMatch(elementA, MatchKind.ANGULAR_REFERENCE, 1, 2), |
| new ExpectedMatch(elementB, MatchKind.ANGULAR_CLOSING_TAG_REFERENCE, 10, 20)); |
| } |
| |
| public void test_searchReferences_AngularControllerElement() throws Exception { |
| AngularControllerElement referencedElement = mockElement( |
| AngularControllerElement.class, |
| ElementKind.ANGULAR_CONTROLLER); |
| { |
| Location locationA = new Location(elementA, 1, 2); |
| indexStore.recordRelationship(referencedElement, IndexConstants.ANGULAR_REFERENCE, locationA); |
| } |
| { |
| Location locationB = new Location(elementB, 10, 20); |
| indexStore.recordRelationship(referencedElement, IndexConstants.ANGULAR_REFERENCE, locationB); |
| } |
| indexStore.doneIndex(); |
| // search matches |
| List<SearchMatch> matches = searchReferencesSync(Element.class, referencedElement); |
| assertMatches( |
| matches, |
| new ExpectedMatch(elementA, MatchKind.ANGULAR_REFERENCE, 1, 2), |
| new ExpectedMatch(elementB, MatchKind.ANGULAR_REFERENCE, 10, 20)); |
| } |
| |
| public void test_searchReferences_AngularFilterElement() throws Exception { |
| AngularFormatterElement referencedElement = mockElement( |
| AngularFormatterElement.class, |
| ElementKind.ANGULAR_FORMATTER); |
| { |
| Location locationA = new Location(elementA, 1, 2); |
| indexStore.recordRelationship(referencedElement, IndexConstants.ANGULAR_REFERENCE, locationA); |
| } |
| { |
| Location locationB = new Location(elementB, 10, 20); |
| indexStore.recordRelationship(referencedElement, IndexConstants.ANGULAR_REFERENCE, locationB); |
| } |
| indexStore.doneIndex(); |
| // search matches |
| List<SearchMatch> matches = searchReferencesSync(Element.class, referencedElement); |
| assertMatches( |
| matches, |
| new ExpectedMatch(elementA, MatchKind.ANGULAR_REFERENCE, 1, 2), |
| new ExpectedMatch(elementB, MatchKind.ANGULAR_REFERENCE, 10, 20)); |
| } |
| |
| public void test_searchReferences_AngularPropertyElement() throws Exception { |
| AngularPropertyElement referencedElement = mockElement( |
| AngularPropertyElement.class, |
| ElementKind.ANGULAR_PROPERTY); |
| { |
| Location locationA = new Location(elementA, 1, 2); |
| indexStore.recordRelationship(referencedElement, IndexConstants.ANGULAR_REFERENCE, locationA); |
| } |
| { |
| Location locationB = new Location(elementB, 10, 20); |
| indexStore.recordRelationship(referencedElement, IndexConstants.ANGULAR_REFERENCE, locationB); |
| } |
| indexStore.doneIndex(); |
| // search matches |
| List<SearchMatch> matches = searchReferencesSync(Element.class, referencedElement); |
| assertMatches( |
| matches, |
| new ExpectedMatch(elementA, MatchKind.ANGULAR_REFERENCE, 1, 2), |
| new ExpectedMatch(elementB, MatchKind.ANGULAR_REFERENCE, 10, 20)); |
| } |
| |
| public void test_searchReferences_AngularScopePropertyElement() throws Exception { |
| AngularScopePropertyElement referencedElement = mockElement( |
| AngularScopePropertyElement.class, |
| ElementKind.ANGULAR_SCOPE_PROPERTY); |
| { |
| Location locationA = new Location(elementA, 1, 2); |
| indexStore.recordRelationship(referencedElement, IndexConstants.ANGULAR_REFERENCE, locationA); |
| } |
| { |
| Location locationB = new Location(elementB, 10, 20); |
| indexStore.recordRelationship(referencedElement, IndexConstants.ANGULAR_REFERENCE, locationB); |
| } |
| indexStore.doneIndex(); |
| // search matches |
| List<SearchMatch> matches = searchReferencesSync(Element.class, referencedElement); |
| assertMatches( |
| matches, |
| new ExpectedMatch(elementA, MatchKind.ANGULAR_REFERENCE, 1, 2), |
| new ExpectedMatch(elementB, MatchKind.ANGULAR_REFERENCE, 10, 20)); |
| } |
| |
| public void test_searchReferences_AngularSelectorElement() throws Exception { |
| AngularSelectorElement referencedElement = mockElement( |
| AngularSelectorElement.class, |
| ElementKind.ANGULAR_SELECTOR); |
| { |
| Location locationA = new Location(elementA, 1, 2); |
| indexStore.recordRelationship(referencedElement, IndexConstants.ANGULAR_REFERENCE, locationA); |
| } |
| { |
| Location locationB = new Location(elementB, 10, 20); |
| indexStore.recordRelationship(referencedElement, IndexConstants.ANGULAR_REFERENCE, locationB); |
| } |
| indexStore.doneIndex(); |
| // search matches |
| List<SearchMatch> matches = searchReferencesSync(Element.class, referencedElement); |
| assertMatches( |
| matches, |
| new ExpectedMatch(elementA, MatchKind.ANGULAR_REFERENCE, 1, 2), |
| new ExpectedMatch(elementB, MatchKind.ANGULAR_REFERENCE, 10, 20)); |
| } |
| |
| public void test_searchReferences_ClassElement() throws Exception { |
| ClassElement referencedElement = mockElement(ClassElement.class, ElementKind.CLASS); |
| { |
| Location locationA = new Location(elementA, 1, 2); |
| indexStore.recordRelationship(referencedElement, IndexConstants.IS_REFERENCED_BY, locationA); |
| } |
| { |
| Location locationB = new Location(elementB, 10, 20); |
| indexStore.recordRelationship(referencedElement, IndexConstants.IS_REFERENCED_BY, locationB); |
| } |
| indexStore.doneIndex(); |
| // search matches |
| List<SearchMatch> matches = searchReferencesSync(Element.class, referencedElement); |
| // verify |
| assertMatches( |
| matches, |
| new ExpectedMatch(elementA, MatchKind.TYPE_REFERENCE, 1, 2), |
| new ExpectedMatch(elementB, MatchKind.TYPE_REFERENCE, 10, 20)); |
| } |
| |
| public void test_searchReferences_ClassElement_useScope() throws Exception { |
| LibraryElement libraryA = mockElement(LibraryElement.class, ElementKind.LIBRARY); |
| LibraryElement libraryB = mockElement(LibraryElement.class, ElementKind.LIBRARY); |
| ClassElement referencedElement = mockElement(ClassElement.class, ElementKind.CLASS); |
| { |
| when(elementA.getAncestor(LibraryElement.class)).thenReturn(libraryA); |
| Location locationA = new Location(elementA, 1, 2); |
| indexStore.recordRelationship(referencedElement, IndexConstants.IS_REFERENCED_BY, locationA); |
| } |
| { |
| when(elementB.getAncestor(LibraryElement.class)).thenReturn(libraryB); |
| Location locationB = new Location(elementB, 10, 20); |
| indexStore.recordRelationship(referencedElement, IndexConstants.IS_REFERENCED_BY, locationB); |
| } |
| indexStore.doneIndex(); |
| // search matches, in "libraryA" |
| scope = SearchScopeFactory.createLibraryScope(libraryA); |
| List<SearchMatch> matches = searchReferencesSync(Element.class, referencedElement); |
| // verify |
| assertMatches(matches, new ExpectedMatch(elementA, MatchKind.TYPE_REFERENCE, 1, 2)); |
| } |
| |
| public void test_searchReferences_CompilationUnitElement() throws Exception { |
| CompilationUnitElement referencedElement = mockElement( |
| CompilationUnitElement.class, |
| ElementKind.COMPILATION_UNIT); |
| { |
| Location location = new Location(elementA, 1, 2); |
| indexStore.recordRelationship(referencedElement, IndexConstants.IS_REFERENCED_BY, location); |
| } |
| indexStore.doneIndex(); |
| // search matches |
| List<SearchMatch> matches = searchReferencesSync(Element.class, referencedElement); |
| // verify |
| assertMatches(matches, new ExpectedMatch(elementA, MatchKind.UNIT_REFERENCE, 1, 2)); |
| } |
| |
| public void test_searchReferences_ConstructorElement() throws Exception { |
| ConstructorElement referencedElement = mockElement( |
| ConstructorElement.class, |
| ElementKind.CONSTRUCTOR); |
| { |
| Location location = new Location(elementA, 10, 1); |
| indexStore.recordRelationship(referencedElement, IndexConstants.IS_DEFINED_BY, location); |
| } |
| { |
| Location location = new Location(elementB, 20, 2); |
| indexStore.recordRelationship(referencedElement, IndexConstants.IS_REFERENCED_BY, location); |
| } |
| { |
| Location location = new Location(elementC, 30, 3); |
| indexStore.recordRelationship(referencedElement, IndexConstants.IS_REFERENCED_BY, location); |
| } |
| indexStore.doneIndex(); |
| // search matches |
| List<SearchMatch> matches = searchReferencesSync(Element.class, referencedElement); |
| // verify |
| assertMatches( |
| matches, |
| new ExpectedMatch(elementA, MatchKind.CONSTRUCTOR_DECLARATION, 10, 1), |
| new ExpectedMatch(elementB, MatchKind.CONSTRUCTOR_REFERENCE, 20, 2), |
| new ExpectedMatch(elementC, MatchKind.CONSTRUCTOR_REFERENCE, 30, 3)); |
| } |
| |
| public void test_searchReferences_Element_unknown() throws Exception { |
| List<SearchMatch> matches = searchReferencesSync(Element.class, null); |
| assertThat(matches).isEmpty(); |
| } |
| |
| public void test_searchReferences_FieldElement() throws Exception { |
| PropertyAccessorElement getterElement = mockElement( |
| PropertyAccessorElement.class, |
| ElementKind.GETTER); |
| PropertyAccessorElement setterElement = mockElement( |
| PropertyAccessorElement.class, |
| ElementKind.SETTER); |
| FieldElement fieldElement = mockElement(FieldElement.class, ElementKind.FIELD); |
| when(fieldElement.getGetter()).thenReturn(getterElement); |
| when(fieldElement.getSetter()).thenReturn(setterElement); |
| { |
| Location location = new Location(elementA, 1, 10); |
| indexStore.recordRelationship( |
| getterElement, |
| IndexConstants.IS_REFERENCED_BY_UNQUALIFIED, |
| location); |
| } |
| { |
| Location location = new Location(elementB, 2, 20); |
| indexStore.recordRelationship( |
| getterElement, |
| IndexConstants.IS_REFERENCED_BY_QUALIFIED, |
| location); |
| } |
| { |
| Location location = new Location(elementC, 3, 30); |
| indexStore.recordRelationship( |
| setterElement, |
| IndexConstants.IS_REFERENCED_BY_UNQUALIFIED, |
| location); |
| } |
| { |
| Location location = new Location(elementD, 4, 40); |
| indexStore.recordRelationship( |
| setterElement, |
| IndexConstants.IS_REFERENCED_BY_QUALIFIED, |
| location); |
| } |
| indexStore.doneIndex(); |
| // search matches |
| List<SearchMatch> matches = searchReferencesSync(Element.class, fieldElement); |
| // verify |
| assertMatches( |
| matches, |
| new ExpectedMatch(elementA, MatchKind.FIELD_READ, 1, 10, false), |
| new ExpectedMatch(elementB, MatchKind.FIELD_READ, 2, 20, true), |
| new ExpectedMatch(elementC, MatchKind.FIELD_WRITE, 3, 30, false), |
| new ExpectedMatch(elementD, MatchKind.FIELD_WRITE, 4, 40, true)); |
| } |
| |
| public void test_searchReferences_FieldElement_invocation() throws Exception { |
| PropertyAccessorElement getterElement = mockElement( |
| PropertyAccessorElement.class, |
| ElementKind.GETTER); |
| FieldElement fieldElement = mockElement(FieldElement.class, ElementKind.FIELD); |
| when(fieldElement.getGetter()).thenReturn(getterElement); |
| { |
| Location location = new Location(elementA, 1, 10); |
| indexStore.recordRelationship(getterElement, IndexConstants.IS_INVOKED_BY_QUALIFIED, location); |
| } |
| { |
| Location location = new Location(elementB, 2, 20); |
| indexStore.recordRelationship( |
| getterElement, |
| IndexConstants.IS_INVOKED_BY_UNQUALIFIED, |
| location); |
| } |
| indexStore.doneIndex(); |
| // search matches |
| List<SearchMatch> matches = searchReferencesSync(Element.class, fieldElement); |
| // verify |
| assertMatches( |
| matches, |
| new ExpectedMatch(elementA, MatchKind.FIELD_INVOCATION, 1, 10, true), |
| new ExpectedMatch(elementB, MatchKind.FIELD_INVOCATION, 2, 20, false)); |
| } |
| |
| public void test_searchReferences_FieldElement2() throws Exception { |
| FieldElement fieldElement = mockElement(FieldElement.class, ElementKind.FIELD); |
| { |
| Location location = new Location(elementA, 1, 10); |
| indexStore.recordRelationship(fieldElement, IndexConstants.IS_REFERENCED_BY, location); |
| } |
| { |
| Location location = new Location(elementB, 2, 20); |
| indexStore.recordRelationship( |
| fieldElement, |
| IndexConstants.IS_REFERENCED_BY_QUALIFIED, |
| location); |
| } |
| indexStore.doneIndex(); |
| // search matches |
| List<SearchMatch> matches = searchReferencesSync(Element.class, fieldElement); |
| // verify |
| assertMatches( |
| matches, |
| new ExpectedMatch(elementA, MatchKind.FIELD_REFERENCE, 1, 10, false), |
| new ExpectedMatch(elementB, MatchKind.FIELD_REFERENCE, 2, 20, true)); |
| } |
| |
| public void test_searchReferences_FunctionElement() throws Exception { |
| FunctionElement referencedElement = mockElement(FunctionElement.class, ElementKind.FUNCTION); |
| { |
| Location location = new Location(elementA, 1, 10); |
| indexStore.recordRelationship(referencedElement, IndexConstants.IS_INVOKED_BY, location); |
| } |
| { |
| Location location = new Location(elementB, 2, 20); |
| indexStore.recordRelationship(referencedElement, IndexConstants.IS_REFERENCED_BY, location); |
| } |
| indexStore.doneIndex(); |
| // search matches |
| List<SearchMatch> matches = searchReferencesSync(Element.class, referencedElement); |
| // verify |
| assertMatches( |
| matches, |
| new ExpectedMatch(elementA, MatchKind.FUNCTION_EXECUTION, 1, 10), |
| new ExpectedMatch(elementB, MatchKind.FUNCTION_REFERENCE, 2, 20)); |
| } |
| |
| public void test_searchReferences_ImportElement() throws Exception { |
| ImportElement referencedElement = mockElement(ImportElement.class, ElementKind.IMPORT); |
| { |
| Location locationA = new Location(elementA, 1, 2); |
| indexStore.recordRelationship(referencedElement, IndexConstants.IS_REFERENCED_BY, locationA); |
| } |
| { |
| Location locationB = new Location(elementB, 10, 0); |
| indexStore.recordRelationship(referencedElement, IndexConstants.IS_REFERENCED_BY, locationB); |
| } |
| indexStore.doneIndex(); |
| // search matches |
| List<SearchMatch> matches = searchReferencesSync(Element.class, referencedElement); |
| // verify |
| assertMatches( |
| matches, |
| new ExpectedMatch(elementA, MatchKind.IMPORT_REFERENCE, 1, 2), |
| new ExpectedMatch(elementB, MatchKind.IMPORT_REFERENCE, 10, 0)); |
| } |
| |
| public void test_searchReferences_LibraryElement() throws Exception { |
| LibraryElement referencedElement = mockElement(LibraryElement.class, ElementKind.LIBRARY); |
| { |
| Location location = new Location(elementA, 1, 2); |
| indexStore.recordRelationship(referencedElement, IndexConstants.IS_REFERENCED_BY, location); |
| } |
| indexStore.doneIndex(); |
| // search matches |
| List<SearchMatch> matches = searchReferencesSync(Element.class, referencedElement); |
| // verify |
| assertMatches(matches, new ExpectedMatch(elementA, MatchKind.LIBRARY_REFERENCE, 1, 2)); |
| } |
| |
| public void test_searchReferences_MethodElement() throws Exception { |
| MethodElement referencedElement = mockElement(MethodElement.class, ElementKind.METHOD); |
| { |
| Location location = new Location(elementA, 1, 10); |
| indexStore.recordRelationship( |
| referencedElement, |
| IndexConstants.IS_INVOKED_BY_UNQUALIFIED, |
| location); |
| } |
| { |
| Location location = new Location(elementB, 2, 20); |
| indexStore.recordRelationship( |
| referencedElement, |
| IndexConstants.IS_INVOKED_BY_QUALIFIED, |
| location); |
| } |
| { |
| Location location = new Location(elementC, 3, 30); |
| indexStore.recordRelationship( |
| referencedElement, |
| IndexConstants.IS_REFERENCED_BY_UNQUALIFIED, |
| location); |
| } |
| { |
| Location location = new Location(elementD, 4, 40); |
| indexStore.recordRelationship( |
| referencedElement, |
| IndexConstants.IS_REFERENCED_BY_QUALIFIED, |
| location); |
| } |
| indexStore.doneIndex(); |
| // search matches |
| List<SearchMatch> matches = searchReferencesSync(Element.class, referencedElement); |
| // verify |
| assertMatches( |
| matches, |
| new ExpectedMatch(elementA, MatchKind.METHOD_INVOCATION, 1, 10, false), |
| new ExpectedMatch(elementB, MatchKind.METHOD_INVOCATION, 2, 20, true), |
| new ExpectedMatch(elementC, MatchKind.METHOD_REFERENCE, 3, 30, false), |
| new ExpectedMatch(elementD, MatchKind.METHOD_REFERENCE, 4, 40, true)); |
| } |
| |
| public void test_searchReferences_MethodMember() throws Exception { |
| MethodElement referencedElement = mockElement(MethodElement.class, ElementKind.METHOD); |
| { |
| Location location = new Location(elementA, 1, 10); |
| indexStore.recordRelationship( |
| referencedElement, |
| IndexConstants.IS_INVOKED_BY_UNQUALIFIED, |
| location); |
| } |
| { |
| Location location = new Location(elementB, 2, 20); |
| indexStore.recordRelationship( |
| referencedElement, |
| IndexConstants.IS_INVOKED_BY_QUALIFIED, |
| location); |
| } |
| { |
| Location location = new Location(elementC, 3, 30); |
| indexStore.recordRelationship( |
| referencedElement, |
| IndexConstants.IS_REFERENCED_BY_UNQUALIFIED, |
| location); |
| } |
| { |
| Location location = new Location(elementD, 4, 40); |
| indexStore.recordRelationship( |
| referencedElement, |
| IndexConstants.IS_REFERENCED_BY_QUALIFIED, |
| location); |
| } |
| indexStore.doneIndex(); |
| // search matches |
| MethodMember referencedMember = new MethodMember(referencedElement, null); |
| List<SearchMatch> matches = searchReferencesSync(Element.class, referencedMember); |
| // verify |
| assertMatches( |
| matches, |
| new ExpectedMatch(elementA, MatchKind.METHOD_INVOCATION, 1, 10, false), |
| new ExpectedMatch(elementB, MatchKind.METHOD_INVOCATION, 2, 20, true), |
| new ExpectedMatch(elementC, MatchKind.METHOD_REFERENCE, 3, 30, false), |
| new ExpectedMatch(elementD, MatchKind.METHOD_REFERENCE, 4, 40, true)); |
| } |
| |
| public void test_searchReferences_notSupported() throws Exception { |
| Element referencedElement = mockElement(Element.class, ElementKind.UNIVERSE); |
| List<SearchMatch> matches = searchReferencesSync(Element.class, referencedElement); |
| assertThat(matches).isEmpty(); |
| } |
| |
| public void test_searchReferences_ParameterElement() throws Exception { |
| ParameterElement referencedElement = mockElement(ParameterElement.class, ElementKind.PARAMETER); |
| { |
| Location location = new Location(elementA, 1, 10); |
| indexStore.recordRelationship(referencedElement, IndexConstants.IS_READ_BY, location); |
| } |
| { |
| Location location = new Location(elementB, 2, 20); |
| indexStore.recordRelationship(referencedElement, IndexConstants.IS_WRITTEN_BY, location); |
| } |
| { |
| Location location = new Location(elementC, 3, 30); |
| indexStore.recordRelationship(referencedElement, IndexConstants.IS_READ_WRITTEN_BY, location); |
| } |
| { |
| Location location = new Location(elementD, 4, 40); |
| indexStore.recordRelationship(referencedElement, IndexConstants.IS_REFERENCED_BY, location); |
| } |
| { |
| Location location = new Location(elementD, 5, 50); |
| indexStore.recordRelationship(referencedElement, IndexConstants.IS_INVOKED_BY, location); |
| } |
| indexStore.doneIndex(); |
| // search matches |
| List<SearchMatch> matches = searchReferencesSync(Element.class, referencedElement); |
| // verify |
| // TODO(scheglov) why no MatchKind.FIELD_READ_WRITE ? |
| assertMatches( |
| matches, |
| new ExpectedMatch(elementA, MatchKind.VARIABLE_READ, 1, 10), |
| new ExpectedMatch(elementB, MatchKind.VARIABLE_WRITE, 2, 20), |
| new ExpectedMatch(elementC, MatchKind.VARIABLE_READ_WRITE, 3, 30), |
| new ExpectedMatch(elementD, MatchKind.NAMED_PARAMETER_REFERENCE, 4, 40), |
| new ExpectedMatch(elementD, MatchKind.FUNCTION_EXECUTION, 5, 50)); |
| } |
| |
| public void test_searchReferences_PropertyAccessorElement_getter() throws Exception { |
| PropertyAccessorElement accessor = mockElement( |
| PropertyAccessorElement.class, |
| ElementKind.GETTER); |
| { |
| Location location = new Location(elementA, 1, 10); |
| indexStore.recordRelationship(accessor, IndexConstants.IS_REFERENCED_BY_UNQUALIFIED, location); |
| } |
| { |
| Location location = new Location(elementB, 2, 20); |
| indexStore.recordRelationship(accessor, IndexConstants.IS_REFERENCED_BY_QUALIFIED, location); |
| } |
| indexStore.doneIndex(); |
| // search matches |
| List<SearchMatch> matches = searchReferencesSync(Element.class, accessor); |
| // verify |
| assertMatches(matches, new ExpectedMatch( |
| elementA, |
| MatchKind.PROPERTY_ACCESSOR_REFERENCE, |
| 1, |
| 10, |
| false), new ExpectedMatch(elementB, MatchKind.PROPERTY_ACCESSOR_REFERENCE, 2, 20, true)); |
| } |
| |
| public void test_searchReferences_PropertyAccessorElement_setter() throws Exception { |
| PropertyAccessorElement accessor = mockElement( |
| PropertyAccessorElement.class, |
| ElementKind.SETTER); |
| { |
| Location location = new Location(elementA, 1, 10); |
| indexStore.recordRelationship(accessor, IndexConstants.IS_REFERENCED_BY_UNQUALIFIED, location); |
| } |
| { |
| Location location = new Location(elementB, 2, 20); |
| indexStore.recordRelationship(accessor, IndexConstants.IS_REFERENCED_BY_QUALIFIED, location); |
| } |
| indexStore.doneIndex(); |
| // search matches |
| List<SearchMatch> matches = searchReferencesSync(Element.class, accessor); |
| // verify |
| assertMatches(matches, new ExpectedMatch( |
| elementA, |
| MatchKind.PROPERTY_ACCESSOR_REFERENCE, |
| 1, |
| 10, |
| false), new ExpectedMatch(elementB, MatchKind.PROPERTY_ACCESSOR_REFERENCE, 2, 20, true)); |
| } |
| |
| public void test_searchReferences_TopLevelVariableElement() throws Exception { |
| PropertyAccessorElement getterElement = mockElement( |
| PropertyAccessorElement.class, |
| ElementKind.GETTER); |
| PropertyAccessorElement setterElement = mockElement( |
| PropertyAccessorElement.class, |
| ElementKind.SETTER); |
| TopLevelVariableElement topVariableElement = mockElement( |
| TopLevelVariableElement.class, |
| ElementKind.TOP_LEVEL_VARIABLE); |
| when(topVariableElement.getGetter()).thenReturn(getterElement); |
| when(topVariableElement.getSetter()).thenReturn(setterElement); |
| { |
| Location location = new Location(elementA, 1, 10); |
| indexStore.recordRelationship( |
| getterElement, |
| IndexConstants.IS_REFERENCED_BY_UNQUALIFIED, |
| location); |
| } |
| { |
| Location location = new Location(elementC, 2, 20); |
| indexStore.recordRelationship( |
| setterElement, |
| IndexConstants.IS_REFERENCED_BY_UNQUALIFIED, |
| location); |
| } |
| indexStore.doneIndex(); |
| // search matches |
| List<SearchMatch> matches = searchReferencesSync(Element.class, topVariableElement); |
| // verify |
| assertMatches( |
| matches, |
| new ExpectedMatch(elementA, MatchKind.FIELD_READ, 1, 10, false), |
| new ExpectedMatch(elementC, MatchKind.FIELD_WRITE, 2, 20, false)); |
| } |
| |
| public void test_searchReferences_TypeAliasElement() throws Exception { |
| FunctionTypeAliasElement referencedElement = mockElement( |
| FunctionTypeAliasElement.class, |
| ElementKind.FUNCTION_TYPE_ALIAS); |
| { |
| Location locationA = new Location(elementA, 1, 2); |
| indexStore.recordRelationship(referencedElement, IndexConstants.IS_REFERENCED_BY, locationA); |
| } |
| { |
| Location locationB = new Location(elementB, 10, 20); |
| indexStore.recordRelationship(referencedElement, IndexConstants.IS_REFERENCED_BY, locationB); |
| } |
| indexStore.doneIndex(); |
| // search matches |
| List<SearchMatch> matches = searchReferencesSync(Element.class, referencedElement); |
| // verify |
| assertMatches( |
| matches, |
| new ExpectedMatch(elementA, MatchKind.FUNCTION_TYPE_REFERENCE, 1, 2), |
| new ExpectedMatch(elementB, MatchKind.FUNCTION_TYPE_REFERENCE, 10, 20)); |
| } |
| |
| public void test_searchReferences_TypeParameterElement() throws Exception { |
| TypeParameterElement referencedElement = mockElement( |
| TypeParameterElement.class, |
| ElementKind.TYPE_PARAMETER); |
| { |
| Location locationA = new Location(elementA, 1, 2); |
| indexStore.recordRelationship(referencedElement, IndexConstants.IS_REFERENCED_BY, locationA); |
| } |
| { |
| Location locationB = new Location(elementB, 10, 20); |
| indexStore.recordRelationship(referencedElement, IndexConstants.IS_REFERENCED_BY, locationB); |
| } |
| indexStore.doneIndex(); |
| // search matches |
| List<SearchMatch> matches = searchReferencesSync(Element.class, referencedElement); |
| // verify |
| assertMatches( |
| matches, |
| new ExpectedMatch(elementA, MatchKind.TYPE_PARAMETER_REFERENCE, 1, 2), |
| new ExpectedMatch(elementB, MatchKind.TYPE_PARAMETER_REFERENCE, 10, 20)); |
| } |
| |
| public void test_searchReferences_VariableElement() throws Exception { |
| LocalVariableElement referencedElement = mockElement( |
| LocalVariableElement.class, |
| ElementKind.LOCAL_VARIABLE); |
| { |
| Location location = new Location(elementA, 1, 10); |
| indexStore.recordRelationship(referencedElement, IndexConstants.IS_READ_BY, location); |
| } |
| { |
| Location location = new Location(elementB, 2, 20); |
| indexStore.recordRelationship(referencedElement, IndexConstants.IS_WRITTEN_BY, location); |
| } |
| { |
| Location location = new Location(elementC, 3, 30); |
| indexStore.recordRelationship(referencedElement, IndexConstants.IS_READ_WRITTEN_BY, location); |
| } |
| { |
| Location location = new Location(elementD, 4, 40); |
| indexStore.recordRelationship(referencedElement, IndexConstants.IS_INVOKED_BY, location); |
| } |
| indexStore.doneIndex(); |
| // search matches |
| List<SearchMatch> matches = searchReferencesSync(Element.class, referencedElement); |
| // verify |
| assertMatches( |
| matches, |
| new ExpectedMatch(elementA, MatchKind.VARIABLE_READ, 1, 10), |
| new ExpectedMatch(elementB, MatchKind.VARIABLE_WRITE, 2, 20), |
| new ExpectedMatch(elementC, MatchKind.VARIABLE_READ_WRITE, 3, 30), |
| new ExpectedMatch(elementD, MatchKind.FUNCTION_EXECUTION, 4, 40)); |
| } |
| |
| public void test_searchSubtypes() throws Exception { |
| final ClassElement referencedElement = mockElement(ClassElement.class, ElementKind.CLASS); |
| { |
| Location locationA = new Location(elementA, 10, 1); |
| indexStore.recordRelationship(referencedElement, IndexConstants.IS_EXTENDED_BY, locationA); |
| } |
| { |
| Location locationB = new Location(elementB, 20, 2); |
| indexStore.recordRelationship(referencedElement, IndexConstants.IS_MIXED_IN_BY, locationB); |
| } |
| { |
| Location locationC = new Location(elementC, 30, 3); |
| indexStore.recordRelationship(referencedElement, IndexConstants.IS_IMPLEMENTED_BY, locationC); |
| } |
| indexStore.doneIndex(); |
| // search matches |
| List<SearchMatch> matches = runSearch(new SearchRunner<List<SearchMatch>>() { |
| @Override |
| public List<SearchMatch> run(OperationQueue queue, OperationProcessor processor, Index index, |
| SearchEngine engine) throws Exception { |
| return engine.searchSubtypes(referencedElement, scope, filter); |
| } |
| }); |
| // verify |
| assertMatches( |
| matches, |
| new ExpectedMatch(elementA, MatchKind.EXTENDS_REFERENCE, 10, 1), |
| new ExpectedMatch(elementB, MatchKind.WITH_REFERENCE, 20, 2), |
| new ExpectedMatch(elementC, MatchKind.IMPLEMENTS_REFERENCE, 30, 3)); |
| } |
| |
| public void test_searchTypeDeclarations_async() throws Exception { |
| LibraryElement library = mockElement(LibraryElement.class, ElementKind.LIBRARY); |
| { |
| when(elementA.getAncestor(LibraryElement.class)).thenReturn(library); |
| Location locationA = new Location(elementA, 1, 2); |
| indexStore.recordRelationship(library, IndexConstants.DEFINES_CLASS, locationA); |
| } |
| indexStore.doneIndex(); |
| scope = new LibrarySearchScope(library); |
| // search matches |
| List<SearchMatch> matches = searchTypeDeclarationsAsync(); |
| // verify |
| assertMatches(matches, new ExpectedMatch(elementA, MatchKind.CLASS_DECLARATION, 1, 2)); |
| } |
| |
| public void test_searchTypeDeclarations_class() throws Exception { |
| LibraryElement library = mockElement(LibraryElement.class, ElementKind.LIBRARY); |
| { |
| when(elementA.getAncestor(LibraryElement.class)).thenReturn(library); |
| Location locationA = new Location(elementA, 1, 2); |
| indexStore.recordRelationship(library, IndexConstants.DEFINES_CLASS, locationA); |
| } |
| indexStore.doneIndex(); |
| scope = new LibrarySearchScope(library); |
| // search matches |
| List<SearchMatch> matches = searchTypeDeclarationsSync(); |
| // verify |
| assertMatches(matches, new ExpectedMatch(elementA, MatchKind.CLASS_DECLARATION, 1, 2)); |
| } |
| |
| public void test_searchTypeDeclarations_classAlias() throws Exception { |
| LibraryElement library = mockElement(LibraryElement.class, ElementKind.LIBRARY); |
| { |
| when(elementA.getAncestor(LibraryElement.class)).thenReturn(library); |
| Location locationA = new Location(elementA, 1, 2); |
| indexStore.recordRelationship(library, IndexConstants.DEFINES_CLASS_ALIAS, locationA); |
| } |
| indexStore.doneIndex(); |
| scope = new LibrarySearchScope(library); |
| // search matches |
| List<SearchMatch> matches = searchTypeDeclarationsSync(); |
| // verify |
| assertMatches(matches, new ExpectedMatch(elementA, MatchKind.CLASS_ALIAS_DECLARATION, 1, 2)); |
| } |
| |
| public void test_searchTypeDeclarations_functionType() throws Exception { |
| LibraryElement library = mockElement(LibraryElement.class, ElementKind.LIBRARY); |
| { |
| when(elementA.getAncestor(LibraryElement.class)).thenReturn(library); |
| Location locationA = new Location(elementA, 1, 2); |
| indexStore.recordRelationship(library, IndexConstants.DEFINES_FUNCTION_TYPE, locationA); |
| } |
| indexStore.doneIndex(); |
| scope = new LibrarySearchScope(library); |
| // search matches |
| List<SearchMatch> matches = searchTypeDeclarationsSync(); |
| // verify |
| assertMatches(matches, new ExpectedMatch(elementA, MatchKind.FUNCTION_TYPE_DECLARATION, 1, 2)); |
| } |
| |
| public void test_searchUnresolvedQualifiedReferences() throws Exception { |
| Element referencedElement = new NameElementImpl("test"); |
| { |
| Location locationA = new Location(elementA, 1, 2); |
| indexStore.recordRelationship( |
| referencedElement, |
| IndexConstants.IS_REFERENCED_BY_QUALIFIED_RESOLVED, |
| locationA); |
| } |
| { |
| Location locationB = new Location(elementB, 10, 20); |
| indexStore.recordRelationship( |
| referencedElement, |
| IndexConstants.IS_REFERENCED_BY_QUALIFIED_UNRESOLVED, |
| locationB); |
| } |
| indexStore.doneIndex(); |
| // search matches |
| List<SearchMatch> matches = searchReferencesSync( |
| "searchQualifiedMemberReferences", |
| String.class, |
| "test"); |
| // verify |
| assertMatches( |
| matches, |
| new ExpectedMatch(elementA, MatchKind.NAME_REFERENCE_RESOLVED, 1, 2), |
| new ExpectedMatch(elementB, MatchKind.NAME_REFERENCE_UNRESOLVED, 10, 20)); |
| } |
| |
| public void test_searchVariableDeclarations() throws Exception { |
| LibraryElement library = mockElement(LibraryElement.class, ElementKind.LIBRARY); |
| defineVariablesAB(library); |
| scope = new LibrarySearchScope(library); |
| // search matches |
| List<SearchMatch> matches = searchVariableDeclarationsSync(); |
| // verify |
| assertMatches( |
| matches, |
| new ExpectedMatch(elementA, MatchKind.VARIABLE_DECLARATION, 1, 2), |
| new ExpectedMatch(elementB, MatchKind.VARIABLE_DECLARATION, 10, 20)); |
| } |
| |
| public void test_searchVariableDeclarations_async() throws Exception { |
| LibraryElement library = mockElement(LibraryElement.class, ElementKind.LIBRARY); |
| defineVariablesAB(library); |
| scope = new LibrarySearchScope(library); |
| // search matches |
| List<SearchMatch> matches = searchVariableDeclarationsAsync(); |
| // verify |
| assertMatches( |
| matches, |
| new ExpectedMatch(elementA, MatchKind.VARIABLE_DECLARATION, 1, 2), |
| new ExpectedMatch(elementB, MatchKind.VARIABLE_DECLARATION, 10, 20)); |
| } |
| |
| public void test_searchVariableDeclarations_usePattern() throws Exception { |
| LibraryElement library = mockElement(LibraryElement.class, ElementKind.LIBRARY); |
| defineVariablesAB(library); |
| scope = new LibrarySearchScope(library); |
| // search "A" |
| { |
| pattern = SearchPatternFactory.createExactPattern("A", true); |
| List<SearchMatch> matches = searchVariableDeclarationsSync(); |
| assertMatches(matches, new ExpectedMatch(elementA, MatchKind.VARIABLE_DECLARATION, 1, 2)); |
| } |
| // search "B" |
| { |
| pattern = SearchPatternFactory.createExactPattern("B", true); |
| List<SearchMatch> matches = searchVariableDeclarationsSync(); |
| assertMatches(matches, new ExpectedMatch(elementB, MatchKind.VARIABLE_DECLARATION, 10, 20)); |
| } |
| } |
| |
| @Override |
| protected void setUp() throws Exception { |
| super.setUp(); |
| // library |
| when(unitElement.getLibrary()).thenReturn(libraryElement); |
| when(libraryElement.getDefiningCompilationUnit()).thenReturn(unitElement); |
| when(unitElement.getSource()).thenReturn(source); |
| when(libraryElement.getSource()).thenReturn(source); |
| when(libraryElement.getParts()).thenReturn(new CompilationUnitElement[0]); |
| // elements |
| when(elementA.toString()).thenReturn("A"); |
| when(elementB.toString()).thenReturn("B"); |
| when(elementC.toString()).thenReturn("C"); |
| when(elementD.toString()).thenReturn("D"); |
| when(elementE.toString()).thenReturn("E"); |
| when(elementA.getDisplayName()).thenReturn("A"); |
| when(elementB.getDisplayName()).thenReturn("B"); |
| when(elementC.getDisplayName()).thenReturn("C"); |
| when(elementD.getDisplayName()).thenReturn("D"); |
| when(elementE.getDisplayName()).thenReturn("E"); |
| when(elementA.getSource()).thenReturn(source); |
| when(elementB.getSource()).thenReturn(source); |
| when(elementC.getSource()).thenReturn(source); |
| when(elementD.getSource()).thenReturn(source); |
| when(elementE.getSource()).thenReturn(source); |
| when(elementA.getContext()).thenReturn(CONTEXT); |
| when(elementB.getContext()).thenReturn(CONTEXT); |
| when(elementC.getContext()).thenReturn(CONTEXT); |
| when(elementD.getContext()).thenReturn(CONTEXT); |
| when(elementE.getContext()).thenReturn(CONTEXT); |
| when(CONTEXT.getElement(elementA.getLocation())).thenReturn(elementA); |
| when(CONTEXT.getElement(elementB.getLocation())).thenReturn(elementB); |
| when(CONTEXT.getElement(elementC.getLocation())).thenReturn(elementC); |
| when(CONTEXT.getElement(elementD.getLocation())).thenReturn(elementD); |
| when(CONTEXT.getElement(elementE.getLocation())).thenReturn(elementE); |
| // start indexing |
| assertTrue(indexStore.aboutToIndexDart(CONTEXT, unitElement)); |
| } |
| |
| @Override |
| protected void tearDown() throws Exception { |
| indexStore = null; |
| super.tearDown(); |
| } |
| |
| private void defineFunctionsAB(LibraryElement library) { |
| { |
| when(elementA.getAncestor(LibraryElement.class)).thenReturn(library); |
| Location locationA = new Location(elementA, 1, 2); |
| indexStore.recordRelationship(library, IndexConstants.DEFINES_FUNCTION, locationA); |
| } |
| { |
| when(elementB.getAncestor(LibraryElement.class)).thenReturn(library); |
| Location locationB = new Location(elementB, 10, 20); |
| indexStore.recordRelationship(library, IndexConstants.DEFINES_FUNCTION, locationB); |
| } |
| indexStore.doneIndex(); |
| } |
| |
| private void defineVariablesAB(LibraryElement library) { |
| { |
| when(elementA.getAncestor(LibraryElement.class)).thenReturn(library); |
| Location locationA = new Location(elementA, 1, 2); |
| indexStore.recordRelationship(library, IndexConstants.DEFINES_VARIABLE, locationA); |
| } |
| { |
| when(elementB.getAncestor(LibraryElement.class)).thenReturn(library); |
| Location locationB = new Location(elementB, 10, 20); |
| indexStore.recordRelationship(library, IndexConstants.DEFINES_VARIABLE, locationB); |
| } |
| indexStore.doneIndex(); |
| } |
| |
| private <T extends Element> T mockElement(Class<T> clazz, ElementKind kind) { |
| T element = mock(clazz); |
| when(element.getContext()).thenReturn(CONTEXT); |
| when(element.getSource()).thenReturn(source); |
| when(element.getKind()).thenReturn(kind); |
| ElementLocation elementLocation = new ElementLocationImpl("mockLocation" + nextLocationId++); |
| when(element.getLocation()).thenReturn(elementLocation); |
| when(CONTEXT.getElement(element.getLocation())).thenReturn(element); |
| return element; |
| } |
| |
| private <T> T runSearch(SearchRunner<T> runner) throws Exception { |
| final OperationQueue queue = new OperationQueue(); |
| final OperationProcessor processor = new OperationProcessor(queue); |
| final Index index = new IndexImpl(indexStore, queue, processor); |
| final SearchEngine engine = SearchEngineFactory.createSearchEngine(index); |
| try { |
| new Thread() { |
| @Override |
| public void run() { |
| processor.run(); |
| } |
| }.start(); |
| processor.waitForRunning(); |
| return runner.run(queue, processor, index, engine); |
| } finally { |
| processor.stop(false); |
| } |
| } |
| |
| private List<SearchMatch> searchDeclarationsAsync(final String methodName) throws Exception { |
| return runSearch(new SearchRunner<List<SearchMatch>>() { |
| @Override |
| public List<SearchMatch> run(OperationQueue queue, OperationProcessor processor, Index index, |
| SearchEngine engine) throws Exception { |
| final CountDownLatch latch = new CountDownLatch(1); |
| final List<SearchMatch> matches = Lists.newArrayList(); |
| engine.getClass().getMethod( |
| methodName, |
| SearchScope.class, |
| SearchPattern.class, |
| SearchFilter.class, |
| SearchListener.class).invoke(engine, scope, pattern, filter, new SearchListener() { |
| @Override |
| public void matchFound(SearchMatch match) { |
| matches.add(match); |
| } |
| |
| @Override |
| public void searchComplete() { |
| latch.countDown(); |
| } |
| }); |
| latch.await(30, TimeUnit.SECONDS); |
| return matches; |
| } |
| }); |
| } |
| |
| @SuppressWarnings("unchecked") |
| private List<SearchMatch> searchDeclarationsSync(final String methodName) throws Exception { |
| return runSearch(new SearchRunner<List<SearchMatch>>() { |
| @Override |
| public List<SearchMatch> run(OperationQueue queue, OperationProcessor processor, Index index, |
| SearchEngine engine) throws Exception { |
| return (List<SearchMatch>) engine.getClass().getMethod( |
| methodName, |
| SearchScope.class, |
| SearchPattern.class, |
| SearchFilter.class).invoke(engine, scope, pattern, filter); |
| } |
| }); |
| } |
| |
| private List<SearchMatch> searchFunctionDeclarationsAsync() throws Exception { |
| return searchDeclarationsAsync("searchFunctionDeclarations"); |
| } |
| |
| private List<SearchMatch> searchFunctionDeclarationsSync() throws Exception { |
| return searchDeclarationsSync("searchFunctionDeclarations"); |
| } |
| |
| private List<SearchMatch> searchReferencesSync(Class<?> clazz, Object element) throws Exception { |
| return searchReferencesSync("searchReferences", clazz, element); |
| } |
| |
| @SuppressWarnings("unchecked") |
| private List<SearchMatch> searchReferencesSync(final String methodName, final Class<?> clazz, |
| final Object element) throws Exception { |
| return runSearch(new SearchRunner<List<SearchMatch>>() { |
| @Override |
| public List<SearchMatch> run(OperationQueue queue, OperationProcessor processor, Index index, |
| SearchEngine engine) throws Exception { |
| // pass some operation to wait if search will not call processor |
| queue.enqueue(mock(IndexOperation.class)); |
| // run actual search |
| return (List<SearchMatch>) engine.getClass().getMethod( |
| methodName, |
| clazz, |
| SearchScope.class, |
| SearchFilter.class).invoke(engine, element, scope, filter); |
| } |
| }); |
| } |
| |
| private List<SearchMatch> searchTypeDeclarationsAsync() throws Exception { |
| return searchDeclarationsAsync("searchTypeDeclarations"); |
| } |
| |
| private List<SearchMatch> searchTypeDeclarationsSync() throws Exception { |
| return searchDeclarationsSync("searchTypeDeclarations"); |
| } |
| |
| private List<SearchMatch> searchVariableDeclarationsAsync() throws Exception { |
| return searchDeclarationsAsync("searchVariableDeclarations"); |
| } |
| |
| private List<SearchMatch> searchVariableDeclarationsSync() throws Exception { |
| return searchDeclarationsSync("searchVariableDeclarations"); |
| } |
| } |