| // 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. |
| |
| import 'package:analysis_server/src/protocol_server.dart' |
| show SearchResult, newSearchResult_fromMatch; |
| import 'package:analysis_server/src/services/search/hierarchy.dart'; |
| import 'package:analysis_server/src/services/search/search_engine.dart'; |
| import 'package:analyzer/dart/element/element.dart'; |
| import 'package:analyzer/src/util/performance/operation_performance.dart'; |
| |
| /// A computer for `search.findElementReferences` request results. |
| class ElementReferencesComputer { |
| final SearchEngine searchEngine; |
| |
| ElementReferencesComputer(this.searchEngine); |
| |
| /// Computes [SearchMatch]es for [element] references. |
| Future<List<SearchMatch>> compute(Element element, bool withPotential, |
| {OperationPerformanceImpl? performance}) async { |
| var results = <SearchMatch>[]; |
| performance ??= OperationPerformanceImpl('<root>'); |
| |
| // Add element references. |
| results.addAll(await performance.runAsync( |
| '_findElementsReferences', |
| (childPerformance) => |
| _findElementsReferences(element, childPerformance))); |
| |
| // Add potential references. |
| if (withPotential && _isMemberElement(element)) { |
| var name = element.displayName; |
| var matches = await performance.runAsync( |
| 'searchEngine.searchMemberReferences', |
| (_) => searchEngine.searchMemberReferences(name)); |
| results.addAll(matches.where((match) => !match.isResolved)); |
| } |
| |
| return results; |
| } |
| |
| /// Returns a [Future] completing with a [List] of references to [element] or |
| /// to the corresponding hierarchy [Element]s. |
| Future<List<SearchMatch>> _findElementsReferences( |
| Element element, OperationPerformanceImpl performance) async { |
| var allResults = <SearchMatch>[]; |
| var refElements = await performance.runAsync('_getRefElements', |
| (childPerformance) => _getRefElements(element, childPerformance)); |
| for (var refElement in refElements) { |
| var elementResults = await performance.runAsync( |
| '_findSingleElementReferences', |
| (_) => _findSingleElementReferences(refElement)); |
| allResults.addAll(elementResults); |
| } |
| return allResults; |
| } |
| |
| /// Returns a [Future] completing with a [List] of references to [element]. |
| Future<List<SearchMatch>> _findSingleElementReferences( |
| Element element) async { |
| return searchEngine.searchReferences(element); |
| } |
| |
| /// Returns a [Future] completing with [Element]s to search references to. |
| /// |
| /// If a [ClassMemberElement] or a named [ParameterElement] is given, each |
| /// corresponding [Element] in the hierarchy is returned. |
| /// |
| /// Otherwise, only references to [element] should be searched. |
| Future<Iterable<Element>> _getRefElements( |
| Element element, OperationPerformanceImpl performance) async { |
| if (element is ParameterElement && element.isNamed) { |
| return await performance.runAsync('getHierarchyNamedParameters', |
| (_) => getHierarchyNamedParameters(searchEngine, element)); |
| } |
| if (element is ClassMemberElement) { |
| var (members, parameters) = await performance.runAsync( |
| 'getHierarchyMembers', |
| (performance) => getHierarchyMembersAndParameters( |
| searchEngine, |
| element, |
| performance: performance, |
| includeParametersForFields: true, |
| ), |
| ); |
| |
| return {...members, ...parameters}; |
| } |
| return [element]; |
| } |
| |
| static SearchResult toResult(SearchMatch match) { |
| return newSearchResult_fromMatch(match); |
| } |
| |
| static bool _isMemberElement(Element element) { |
| if (element is ConstructorElement) { |
| return false; |
| } |
| return element.enclosingElement3 is InterfaceElement; |
| } |
| } |