diff --git a/pkg/analysis_server/lib/src/search/element_references.dart b/pkg/analysis_server/lib/src/search/element_references.dart index 30ae4222da58..399ea8bf2756 100644 --- a/pkg/analysis_server/lib/src/search/element_references.dart +++ b/pkg/analysis_server/lib/src/search/element_references.dart @@ -6,7 +6,6 @@ library search.element_references; import 'dart:async'; -import 'package:analysis_server/src/collections.dart'; import 'package:analysis_server/src/protocol_server.dart' show SearchResult, newSearchResult_fromMatch; import 'package:analysis_server/src/services/search/hierarchy.dart'; @@ -25,21 +24,23 @@ class ElementReferencesComputer { /** * Computes [SearchResult]s for [element] references. */ - Future> compute(Element element, bool withPotential) { - var futureGroup = new _ConcatFutureGroup(); - // find element references - futureGroup.add(_findElementsReferences(element)); - // add potential references + Future> compute( + Element element, bool withPotential) async { + List results = []; + + // Add element references. + results.addAll(await _findElementsReferences(element)); + + // Add potential references. if (withPotential && _isMemberElement(element)) { String name = element.displayName; - var matchesFuture = searchEngine.searchMemberReferences(name); - var resultsFuture = matchesFuture.then((List matches) { - return matches.where((match) => !match.isResolved).map(toResult); - }); - futureGroup.add(resultsFuture); + List matches = + await searchEngine.searchMemberReferences(name); + matches = SearchMatch.withNotNullElement(matches); + results.addAll(matches.where((match) => !match.isResolved).map(toResult)); } - // merge results - return futureGroup.future; + + return results; } /** @@ -47,18 +48,20 @@ class ElementReferencesComputer { * to the corresponding hierarchy [Element]s. */ Future> _findElementsReferences(Element element) async { + List allResults = []; Iterable refElements = await _getRefElements(element); - var futureGroup = new _ConcatFutureGroup(); for (Element refElement in refElements) { // add declaration if (_isDeclarationInteresting(refElement)) { SearchResult searchResult = _newDeclarationResult(refElement); - futureGroup.add(searchResult); + allResults.add(searchResult); } // do search - futureGroup.add(_findSingleElementReferences(refElement)); + List elementResults = + await _findSingleElementReferences(refElement); + allResults.addAll(elementResults); } - return futureGroup.future; + return allResults; } /** @@ -67,6 +70,7 @@ class ElementReferencesComputer { Future> _findSingleElementReferences( Element element) async { List matches = await searchEngine.searchReferences(element); + matches = SearchMatch.withNotNullElement(matches); return matches.map(toResult).toList(); } @@ -129,26 +133,3 @@ class ElementReferencesComputer { return element.enclosingElement is ClassElement; } } - -/** - * A collection of [Future]s that concats [List] results of added [Future]s into - * a single [List]. - */ -class _ConcatFutureGroup { - final List>> _futures = >>[]; - - Future> get future { - return Future.wait(_futures).then(concatToList); - } - - /** - * Adds a [Future] or an [E] value to results. - */ - void add(value) { - if (value is Future) { - _futures.add(value as Future>); - } else { - _futures.add(new Future.value([value as E])); - } - } -} diff --git a/pkg/analysis_server/lib/src/search/search_domain.dart b/pkg/analysis_server/lib/src/search/search_domain.dart index 37c58a69e581..cdd39a3ca7ef 100644 --- a/pkg/analysis_server/lib/src/search/search_domain.dart +++ b/pkg/analysis_server/lib/src/search/search_domain.dart @@ -98,6 +98,7 @@ class SearchDomainHandler implements protocol.RequestHandler { // search List matches = await searchEngine.searchMemberDeclarations(params.name); + matches = SearchMatch.withNotNullElement(matches); _sendSearchNotification(searchId, true, matches.map(toResult)); } @@ -112,6 +113,7 @@ class SearchDomainHandler implements protocol.RequestHandler { // search List matches = await searchEngine.searchMemberReferences(params.name); + matches = SearchMatch.withNotNullElement(matches); _sendSearchNotification(searchId, true, matches.map(toResult)); } @@ -135,6 +137,7 @@ class SearchDomainHandler implements protocol.RequestHandler { // search List matches = await searchEngine.searchTopLevelDeclarations(params.pattern); + matches = SearchMatch.withNotNullElement(matches); _sendSearchNotification(searchId, true, matches.map(toResult)); } diff --git a/pkg/analysis_server/lib/src/services/search/search_engine.dart b/pkg/analysis_server/lib/src/services/search/search_engine.dart index 72ca48283123..e9c681d3c3fd 100644 --- a/pkg/analysis_server/lib/src/services/search/search_engine.dart +++ b/pkg/analysis_server/lib/src/services/search/search_engine.dart @@ -155,16 +155,20 @@ class SearchMatch { this.sourceRange, this.isResolved, this.isQualified); /** - * Return the [Element] containing the match. + * Return the [Element] containing the match. Can return `null` if the unit + * does not exist, or its element was invalidated, or the element cannot be + * found, etc. */ Element get element { if (_element == null) { CompilationUnitElement unitElement = context.getCompilationUnitElement(unitSource, librarySource); - _ContainingElementFinder finder = - new _ContainingElementFinder(sourceRange.offset); - unitElement.accept(finder); - _element = finder.containingElement; + if (unitElement != null) { + _ContainingElementFinder finder = + new _ContainingElementFinder(sourceRange.offset); + unitElement.accept(finder); + _element = finder.containingElement; + } } return _element; } @@ -237,6 +241,16 @@ class SearchMatch { buffer.write(")"); return buffer.toString(); } + + /** + * Return elements of [matches] which has not-null elements. + * + * When [SearchMatch.element] is not `null` we cache its value, so it cannot + * become `null` later. + */ + static List withNotNullElement(List matches) { + return matches.where((match) => match.element != null).toList(); + } } /** diff --git a/pkg/analysis_server/test/services/search/search_engine_test.dart b/pkg/analysis_server/test/services/search/search_engine_test.dart index 86f1d6f0241f..8072301d51af 100644 --- a/pkg/analysis_server/test/services/search/search_engine_test.dart +++ b/pkg/analysis_server/test/services/search/search_engine_test.dart @@ -617,6 +617,23 @@ main(A a) { await _verifyReferences(method, expected); } + test_searchReferences_null_noUnitElement() async { + _indexTestUnit(''' +class A { + m() {} +} +main(A a) { + a.m(); +} +'''); + MethodElement method = findElement('m'); + List matches = await searchEngine.searchReferences(method); + expect(matches, hasLength(1)); + // Set the source contents, so the element is invalidated. + context.setContents(testSource, ''); + expect(matches.single.element, isNull); + } + test_searchReferences_ParameterElement_ofConstructor() async { _indexTestUnit(''' class C {