| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library search.element_references; | 5 library search.element_references; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 | 8 |
| 9 import 'package:analysis_server/src/collections.dart'; |
| 9 import 'package:analysis_server/src/search/search_result.dart'; | 10 import 'package:analysis_server/src/search/search_result.dart'; |
| 11 import 'package:analysis_services/search/hierarchy.dart'; |
| 10 import 'package:analysis_services/search/search_engine.dart'; | 12 import 'package:analysis_services/search/search_engine.dart'; |
| 11 import 'package:analyzer/src/generated/element.dart'; | 13 import 'package:analyzer/src/generated/element.dart'; |
| 12 import 'package:analyzer/src/generated/source.dart'; | 14 import 'package:analyzer/src/generated/source.dart'; |
| 13 | 15 |
| 14 | 16 |
| 15 /** | 17 /** |
| 16 * A computer for `search.findElementReferences` request results. | 18 * A computer for `search.findElementReferences` request results. |
| 17 */ | 19 */ |
| 18 class ElementReferencesComputer { | 20 class ElementReferencesComputer { |
| 19 final SearchEngine searchEngine; | 21 final SearchEngine searchEngine; |
| 20 | 22 |
| 21 ElementReferencesComputer(this.searchEngine); | 23 ElementReferencesComputer(this.searchEngine); |
| 22 | 24 |
| 23 /** | 25 /** |
| 24 * Computes [SearchResult]s for [element] references. | 26 * Computes [SearchResult]s for [element] references. |
| 25 */ | 27 */ |
| 26 Future<List<SearchResult>> compute(Element element, bool withPotential) { | 28 Future<List<SearchResult>> compute(Element element, bool withPotential) { |
| 27 var futures = <Future<List<SearchResult>>>[]; | 29 var futureGroup = new _ConcatFutureGroup<SearchResult>(); |
| 28 // tweak element | 30 // tweak element |
| 29 if (element is FieldFormalParameterElement) { | 31 if (element is FieldFormalParameterElement) { |
| 30 element = (element as FieldFormalParameterElement).field; | 32 element = (element as FieldFormalParameterElement).field; |
| 31 } | 33 } |
| 32 if (element is PropertyAccessorElement) { | 34 if (element is PropertyAccessorElement) { |
| 33 element = (element as PropertyAccessorElement).variable; | 35 element = (element as PropertyAccessorElement).variable; |
| 34 } | 36 } |
| 35 // prepare Element(s) to find references to | 37 // find element references |
| 36 List<Element> refElements = <Element>[]; | 38 futureGroup.add(_findElementsReferences(element)); |
| 37 if (element != null) { | 39 // add potential references |
| 38 // TODO(scheglov) find all hierarchy members | 40 if (withPotential) { |
| 39 // if (element is ClassMemberElement) { | 41 String name = element.displayName; |
| 40 // refElements = HierarchyUtils.getHierarchyMembers(searchEngine, element
); | 42 var matchesFuture = searchEngine.searchMemberReferences(name); |
| 41 // } else { | 43 var resultsFuture = matchesFuture.then((List<SearchMatch> matches) { |
| 42 // refElements = <Element>[element]; | 44 return matches.where((match) => !match.isResolved).map(toResult); |
| 43 // } | |
| 44 refElements = <Element>[element]; | |
| 45 } | |
| 46 // process each 'refElement' | |
| 47 for (Element refElement in refElements) { | |
| 48 // add variable declaration | |
| 49 if (_isVariableLikeElement(refElement)) { | |
| 50 int nameOffset = refElement.nameOffset; | |
| 51 int nameLength = refElement.name.length; | |
| 52 SearchMatch searchMatch = | |
| 53 new SearchMatch( | |
| 54 MatchKind.DECLARATION, | |
| 55 refElement, | |
| 56 new SourceRange(nameOffset, nameLength), | |
| 57 true, | |
| 58 false); | |
| 59 SearchResult searchResult = new SearchResult.fromMatch(searchMatch); | |
| 60 futures.add(new Future.value(<SearchResult>[searchResult])); | |
| 61 } | |
| 62 // do search | |
| 63 Future<List<SearchMatch>> matchesFuture = | |
| 64 searchEngine.searchReferences(refElement); | |
| 65 Future<List<SearchResult>> resultsFuture = | |
| 66 matchesFuture.then((List<SearchMatch> matches) { | |
| 67 return matches.map(toResult).toList(); | |
| 68 }); | 45 }); |
| 69 futures.add(resultsFuture); | 46 futureGroup.add(resultsFuture); |
| 70 } | |
| 71 // report potential references | |
| 72 if (withPotential) { | |
| 73 var matchesFuture = searchEngine.searchMemberReferences(element.name); | |
| 74 var resultsFuture = matchesFuture.then((List<SearchMatch> matches) { | |
| 75 return matches.where( | |
| 76 (match) => !match.isResolved).map(toResult).toList(); | |
| 77 }); | |
| 78 futures.add(resultsFuture); | |
| 79 } | 47 } |
| 80 // merge results | 48 // merge results |
| 81 var futuresFuture = Future.wait(futures); | 49 return futureGroup.future; |
| 82 return futuresFuture.then((List<List<SearchResult>> lists) { | 50 } |
| 83 // TODO(scheglov) extract? | 51 |
| 84 return lists.expand((List<SearchResult> matches) => matches).toList(); | 52 /** |
| 53 * Returns a [Future] completing with a [List] of references to [element] or |
| 54 * to the corresponding hierarchy [Element]s. |
| 55 */ |
| 56 Future<List<SearchResult>> _findElementsReferences(Element element) { |
| 57 return _getRefElements(element).then((Iterable<Element> refElements) { |
| 58 var futureGroup = new _ConcatFutureGroup<SearchResult>(); |
| 59 for (Element refElement in refElements) { |
| 60 // add variable declaration |
| 61 if (_isVariableLikeElement(refElement)) { |
| 62 SearchResult searchResult = _newDeclarationResult(refElement); |
| 63 futureGroup.add(searchResult); |
| 64 } |
| 65 // do search |
| 66 futureGroup.add(_findSingleElementReferences(refElement)); |
| 67 } |
| 68 return futureGroup.future; |
| 85 }); | 69 }); |
| 86 } | 70 } |
| 87 | 71 |
| 72 /** |
| 73 * Returns a [Future] completing with a [List] of references to [element]. |
| 74 */ |
| 75 Future<List<SearchResult>> _findSingleElementReferences(Element element) { |
| 76 Future<List<SearchMatch>> matchesFuture = |
| 77 searchEngine.searchReferences(element); |
| 78 return matchesFuture.then((List<SearchMatch> matches) { |
| 79 return matches.map(toResult).toList(); |
| 80 }); |
| 81 } |
| 82 |
| 83 /** |
| 84 * Returns a [Future] completing with [Element]s to search references to. |
| 85 * |
| 86 * If a [ClassMemberElement] is given, each corresponding [Element] in the |
| 87 * hierarchy is returned. |
| 88 * |
| 89 * Otherwise, only references to [element] should be searched. |
| 90 */ |
| 91 Future<Iterable<Element>> _getRefElements(Element element) { |
| 92 if (element is ClassMemberElement) { |
| 93 return getHierarchyMembers(searchEngine, element); |
| 94 } |
| 95 return new Future.value([element]); |
| 96 } |
| 97 |
| 98 SearchResult _newDeclarationResult(Element refElement) { |
| 99 int nameOffset = refElement.nameOffset; |
| 100 int nameLength = refElement.name.length; |
| 101 SearchMatch searchMatch = |
| 102 new SearchMatch( |
| 103 MatchKind.DECLARATION, |
| 104 refElement, |
| 105 new SourceRange(nameOffset, nameLength), |
| 106 true, |
| 107 false); |
| 108 return new SearchResult.fromMatch(searchMatch); |
| 109 } |
| 110 |
| 88 static SearchResult toResult(SearchMatch match) { | 111 static SearchResult toResult(SearchMatch match) { |
| 89 return new SearchResult.fromMatch(match); | 112 return new SearchResult.fromMatch(match); |
| 90 } | 113 } |
| 91 | 114 |
| 92 static bool _isVariableLikeElement(Element element) { | 115 static bool _isVariableLikeElement(Element element) { |
| 93 if (element is LocalVariableElement) { | 116 if (element is LocalVariableElement) { |
| 94 return true; | 117 return true; |
| 95 } | 118 } |
| 96 if (element is ParameterElement) { | 119 if (element is ParameterElement) { |
| 97 return true; | 120 return true; |
| 98 } | 121 } |
| 99 if (element is PropertyInducingElement) { | 122 if (element is PropertyInducingElement) { |
| 100 return !element.isSynthetic; | 123 return !element.isSynthetic; |
| 101 } | 124 } |
| 102 return false; | 125 return false; |
| 103 } | 126 } |
| 104 } | 127 } |
| 128 |
| 129 |
| 130 /** |
| 131 * A collection of [Future]s that concats [List] results of added [Future]s into |
| 132 * a single [List]. |
| 133 */ |
| 134 class _ConcatFutureGroup<E> { |
| 135 final List<Future<List<E>>> _futures = <Future<List<E>>>[]; |
| 136 |
| 137 Future<List<E>> get future { |
| 138 return Future.wait(_futures).then(concatToList); |
| 139 } |
| 140 |
| 141 /** |
| 142 * Adds a [Future] or an [E] value to results. |
| 143 */ |
| 144 void add(value) { |
| 145 if (value is Future) { |
| 146 _futures.add(value); |
| 147 } else { |
| 148 _futures.add(new Future.value(<E>[value])); |
| 149 } |
| 150 } |
| 151 } |
| OLD | NEW |