| OLD | NEW |
| 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2016, 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 services.src.search.search_engine2; | 5 library services.src.search.search_engine2; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 | 8 |
| 9 import 'package:analysis_server/src/services/index2/index2.dart'; | 9 import 'package:analysis_server/src/services/index2/index2.dart'; |
| 10 import 'package:analysis_server/src/services/search/search_engine.dart'; | 10 import 'package:analysis_server/src/services/search/search_engine.dart'; |
| 11 import 'package:analyzer/dart/ast/ast.dart'; |
| 12 import 'package:analyzer/dart/ast/visitor.dart'; |
| 11 import 'package:analyzer/dart/element/element.dart'; | 13 import 'package:analyzer/dart/element/element.dart'; |
| 12 import 'package:analyzer/src/dart/element/member.dart'; | 14 import 'package:analyzer/src/dart/element/member.dart'; |
| 13 import 'package:analyzer/src/generated/engine.dart' show AnalysisContext; | 15 import 'package:analyzer/src/generated/engine.dart'; |
| 14 import 'package:analyzer/src/generated/source.dart' show SourceRange; | 16 import 'package:analyzer/src/generated/source.dart'; |
| 15 import 'package:analyzer/src/summary/idl.dart'; | 17 import 'package:analyzer/src/summary/idl.dart'; |
| 16 | 18 |
| 17 /** | 19 /** |
| 18 * A [SearchEngine] implementation. | 20 * A [SearchEngine] implementation. |
| 19 */ | 21 */ |
| 20 class SearchEngineImpl2 implements SearchEngine { | 22 class SearchEngineImpl2 implements SearchEngine { |
| 21 final AnalysisContext context; | 23 final AnalysisContext context; |
| 22 final Index2 _index; | 24 final Index2 _index; |
| 23 | 25 |
| 24 SearchEngineImpl2(this.context, this._index); | 26 SearchEngineImpl2(this.context, this._index); |
| (...skipping 29 matching lines...) Expand all Loading... |
| 54 kind == ElementKind.COMPILATION_UNIT || | 56 kind == ElementKind.COMPILATION_UNIT || |
| 55 kind == ElementKind.CONSTRUCTOR || | 57 kind == ElementKind.CONSTRUCTOR || |
| 56 kind == ElementKind.FUNCTION_TYPE_ALIAS || | 58 kind == ElementKind.FUNCTION_TYPE_ALIAS || |
| 57 kind == ElementKind.GETTER || | 59 kind == ElementKind.GETTER || |
| 58 kind == ElementKind.SETTER) { | 60 kind == ElementKind.SETTER) { |
| 59 return _searchReferences(element); | 61 return _searchReferences(element); |
| 60 } else if (kind == ElementKind.FIELD || | 62 } else if (kind == ElementKind.FIELD || |
| 61 kind == ElementKind.TOP_LEVEL_VARIABLE) { | 63 kind == ElementKind.TOP_LEVEL_VARIABLE) { |
| 62 return _searchReferences_Field(element as PropertyInducingElement); | 64 return _searchReferences_Field(element as PropertyInducingElement); |
| 63 } else if (kind == ElementKind.FUNCTION || kind == ElementKind.METHOD) { | 65 } else if (kind == ElementKind.FUNCTION || kind == ElementKind.METHOD) { |
| 66 if (element.enclosingElement is ExecutableElement) { |
| 67 return _searchReferences_Local(element, (n) => n is Block); |
| 68 } |
| 64 return _searchReferences_Function(element); | 69 return _searchReferences_Function(element); |
| 65 } else if (kind == ElementKind.IMPORT) { | 70 } else if (kind == ElementKind.IMPORT) { |
| 71 // TODO(scheglov) implement whole library search |
| 66 return _searchReferences(element); | 72 return _searchReferences(element); |
| 67 } else if (kind == ElementKind.LABEL) { | 73 } else if (kind == ElementKind.LABEL || |
| 74 kind == ElementKind.LOCAL_VARIABLE) { |
| 75 return _searchReferences_Local(element, (n) => n is Block); |
| 76 } else if (kind == ElementKind.LIBRARY) { |
| 77 // TODO(scheglov) implement whole library search |
| 68 return _searchReferences(element); | 78 return _searchReferences(element); |
| 69 } else if (kind == ElementKind.LIBRARY) { | |
| 70 return _searchReferences(element); | |
| 71 } else if (kind == ElementKind.LOCAL_VARIABLE) { | |
| 72 return _searchReferences_LocalVariable(element as LocalVariableElement); | |
| 73 } else if (kind == ElementKind.PARAMETER) { | 79 } else if (kind == ElementKind.PARAMETER) { |
| 74 return _searchReferences_Parameter(element as ParameterElement); | 80 return _searchReferences_Parameter(element); |
| 75 } else if (kind == ElementKind.PREFIX) { | 81 } else if (kind == ElementKind.PREFIX) { |
| 82 // TODO(scheglov) implement whole library search |
| 76 return _searchReferences(element); | 83 return _searchReferences(element); |
| 77 } else if (kind == ElementKind.TYPE_PARAMETER) { | 84 } else if (kind == ElementKind.TYPE_PARAMETER) { |
| 78 return _searchReferences_TypeParameter(element); | 85 return _searchReferences_Local(element, (n) => n is ClassDeclaration); |
| 79 } | 86 } |
| 80 return new Future.value(<SearchMatch>[]); | 87 return new Future.value(<SearchMatch>[]); |
| 81 } | 88 } |
| 82 | 89 |
| 83 @override | 90 @override |
| 84 Future<List<SearchMatch>> searchSubtypes(ClassElement type) { | 91 Future<List<SearchMatch>> searchSubtypes(ClassElement type) { |
| 85 // TODO: implement searchSubtypes | 92 // TODO: implement searchSubtypes |
| 86 throw new UnimplementedError(); | 93 throw new UnimplementedError(); |
| 87 } | 94 } |
| 88 | 95 |
| 89 @override | 96 @override |
| 90 Future<List<SearchMatch>> searchTopLevelDeclarations(String pattern) { | 97 Future<List<SearchMatch>> searchTopLevelDeclarations(String pattern) { |
| 91 // TODO: implement searchTopLevelDeclarations | 98 // TODO: implement searchTopLevelDeclarations |
| 92 throw new UnimplementedError(); | 99 throw new UnimplementedError(); |
| 93 } | 100 } |
| 94 | 101 |
| 95 Future<List<SearchMatch>> _searchReferences(Element element) { | 102 _addMatches(List<SearchMatch> matches, Element element, |
| 96 _Requestor requestor = new _Requestor(context, _index); | 103 IndexRelationKind relationKind, MatchKind kind) async { |
| 97 requestor.addElement( | 104 List<Location> locations = await _index.getRelations(element, relationKind); |
| 98 element, IndexRelationKind.IS_REFERENCED_BY, MatchKind.REFERENCE); | 105 for (Location location in locations) { |
| 99 return requestor.merge(); | 106 matches.add(new SearchMatch( |
| 107 context, |
| 108 location.libraryUri, |
| 109 location.unitUri, |
| 110 kind, |
| 111 new SourceRange(location.offset, location.length), |
| 112 true, |
| 113 location.isQualified)); |
| 114 } |
| 115 } |
| 116 |
| 117 Future<List<SearchMatch>> _searchReferences(Element element) async { |
| 118 List<SearchMatch> matches = <SearchMatch>[]; |
| 119 await _addMatches(matches, element, IndexRelationKind.IS_REFERENCED_BY, |
| 120 MatchKind.REFERENCE); |
| 121 return matches; |
| 100 } | 122 } |
| 101 | 123 |
| 102 Future<List<SearchMatch>> _searchReferences_Field( | 124 Future<List<SearchMatch>> _searchReferences_Field( |
| 103 PropertyInducingElement field) { | 125 PropertyInducingElement field) async { |
| 126 List<SearchMatch> matches = <SearchMatch>[]; |
| 104 PropertyAccessorElement getter = field.getter; | 127 PropertyAccessorElement getter = field.getter; |
| 105 PropertyAccessorElement setter = field.setter; | 128 PropertyAccessorElement setter = field.setter; |
| 106 _Requestor requestor = new _Requestor(context, _index); | |
| 107 // field itself | 129 // field itself |
| 108 requestor.addElement( | 130 await _addMatches(matches, field, IndexRelationKind.IS_REFERENCED_BY, |
| 109 field, IndexRelationKind.IS_REFERENCED_BY, MatchKind.REFERENCE); | 131 MatchKind.REFERENCE); |
| 110 // getter | 132 // getter |
| 111 if (getter != null) { | 133 if (getter != null) { |
| 112 requestor.addElement( | 134 await _addMatches( |
| 113 getter, IndexRelationKind.IS_REFERENCED_BY, MatchKind.READ); | 135 matches, getter, IndexRelationKind.IS_REFERENCED_BY, MatchKind.READ); |
| 114 requestor.addElement( | 136 await _addMatches(matches, getter, IndexRelationKind.IS_INVOKED_BY, |
| 115 getter, IndexRelationKind.IS_INVOKED_BY, MatchKind.INVOCATION); | 137 MatchKind.INVOCATION); |
| 116 } | 138 } |
| 117 // setter | 139 // setter |
| 118 if (setter != null) { | 140 if (setter != null) { |
| 119 requestor.addElement( | 141 await _addMatches( |
| 120 setter, IndexRelationKind.IS_REFERENCED_BY, MatchKind.WRITE); | 142 matches, setter, IndexRelationKind.IS_REFERENCED_BY, MatchKind.WRITE); |
| 121 } | 143 } |
| 122 // done | 144 // done |
| 123 return requestor.merge(); | 145 return matches; |
| 124 } | 146 } |
| 125 | 147 |
| 126 Future<List<SearchMatch>> _searchReferences_Function(Element element) { | 148 Future<List<SearchMatch>> _searchReferences_Function(Element element) async { |
| 127 if (element is Member) { | 149 if (element is Member) { |
| 128 element = (element as Member).baseElement; | 150 element = (element as Member).baseElement; |
| 129 } | 151 } |
| 130 _Requestor requestor = new _Requestor(context, _index); | 152 List<SearchMatch> matches = <SearchMatch>[]; |
| 131 requestor.addElement( | 153 await _addMatches(matches, element, IndexRelationKind.IS_REFERENCED_BY, |
| 132 element, IndexRelationKind.IS_REFERENCED_BY, MatchKind.REFERENCE); | 154 MatchKind.REFERENCE); |
| 133 requestor.addElement( | 155 await _addMatches(matches, element, IndexRelationKind.IS_INVOKED_BY, |
| 134 element, IndexRelationKind.IS_INVOKED_BY, MatchKind.INVOCATION); | 156 MatchKind.INVOCATION); |
| 135 return requestor.merge(); | 157 return matches; |
| 136 } | 158 } |
| 137 | 159 |
| 138 Future<List<SearchMatch>> _searchReferences_LocalVariable( | 160 Future<List<SearchMatch>> _searchReferences_Local( |
| 139 LocalVariableElement variable) { | 161 Element element, bool isRootNode(AstNode n)) async { |
| 140 // TODO(scheglov) implement using AST visitor | 162 AstNode node = element.computeNode(); |
| 141 throw new UnimplementedError(); | 163 AstNode enclosingNode = node.getAncestor(isRootNode); |
| 142 // _Requestor requestor = new _Requestor(context, _index); | 164 _LocalReferencesVisitor visitor = new _LocalReferencesVisitor(element); |
| 143 // requestor.addElement(variable, IndexRelationKind.IS_READ_BY, MatchKind.REA
D); | 165 enclosingNode.accept(visitor); |
| 144 // requestor.addElement( | 166 return visitor.matches; |
| 145 // variable, IndexRelationKind.IS_READ_WRITTEN_BY, MatchKind.READ_WRITE); | |
| 146 // requestor.addElement( | |
| 147 // variable, IndexRelationKind.IS_WRITTEN_BY, MatchKind.WRITE); | |
| 148 // requestor.addElement( | |
| 149 // variable, IndexRelationKind.IS_INVOKED_BY, MatchKind.INVOCATION); | |
| 150 // return requestor.merge(); | |
| 151 } | 167 } |
| 152 | 168 |
| 153 Future<List<SearchMatch>> _searchReferences_Parameter( | 169 Future<List<SearchMatch>> _searchReferences_Parameter( |
| 154 ParameterElement parameter) { | 170 ParameterElement parameter) async { |
| 155 // TODO(scheglov) implement using AST visitor | 171 List<SearchMatch> matches = <SearchMatch>[]; |
| 156 throw new UnimplementedError(); | 172 matches.addAll(await _searchReferences(parameter)); |
| 157 // _Requestor requestor = new _Requestor(context, _index); | 173 matches.addAll(await _searchReferences_Local( |
| 158 // requestor.addElement(parameter, IndexRelationKind.IS_READ_BY, MatchKind.RE
AD); | 174 parameter, (n) => n is MethodDeclaration || n is FunctionExpression)); |
| 159 // requestor.addElement( | 175 return matches; |
| 160 // parameter, IndexRelationKind.IS_READ_WRITTEN_BY, MatchKind.READ_WRITE)
; | |
| 161 // requestor.addElement( | |
| 162 // parameter, IndexRelationKind.IS_WRITTEN_BY, MatchKind.WRITE); | |
| 163 // requestor.addElement( | |
| 164 // parameter, IndexRelationKind.IS_REFERENCED_BY, MatchKind.REFERENCE); | |
| 165 // requestor.addElement( | |
| 166 // parameter, IndexRelationKind.IS_INVOKED_BY, MatchKind.INVOCATION); | |
| 167 // return requestor.merge(); | |
| 168 } | |
| 169 | |
| 170 Future<List<SearchMatch>> _searchReferences_TypeParameter( | |
| 171 ParameterElement parameter) { | |
| 172 // TODO(scheglov) implement using AST visitor | |
| 173 throw new UnimplementedError(); | |
| 174 } | 176 } |
| 175 } | 177 } |
| 176 | 178 |
| 177 class _Requestor { | 179 /** |
| 180 * Visitor that adds [SearchMatch]es for local elements - labels, local |
| 181 * functions, local variables and parameters. |
| 182 */ |
| 183 class _LocalReferencesVisitor extends RecursiveAstVisitor { |
| 184 final List<SearchMatch> matches = <SearchMatch>[]; |
| 185 |
| 186 final Element element; |
| 178 final AnalysisContext context; | 187 final AnalysisContext context; |
| 179 final Index2 index; | 188 final String libraryUri; |
| 180 final List<Future<List<SearchMatch>>> futures = <Future<List<SearchMatch>>>[]; | 189 final String unitUri; |
| 181 | 190 |
| 182 _Requestor(this.context, this.index); | 191 _LocalReferencesVisitor(Element element) |
| 192 : element = element, |
| 193 context = element.context, |
| 194 libraryUri = element.library.source.uri.toString(), |
| 195 unitUri = element.source.uri.toString(); |
| 183 | 196 |
| 184 void addElement( | 197 @override |
| 185 Element element, IndexRelationKind relationKind, MatchKind kind) { | 198 visitSimpleIdentifier(SimpleIdentifier node) { |
| 186 Future relationsFuture = index.getRelations(element, relationKind); | 199 if (node.inDeclarationContext()) { |
| 187 Future matchesFuture = relationsFuture.then((List<Location> locations) { | 200 return; |
| 188 List<SearchMatch> matches = <SearchMatch>[]; | 201 } |
| 189 for (Location location in locations) { | 202 if (node.bestElement == element) { |
| 190 matches.add(_convertLocation(location, kind)); | 203 AstNode parent = node.parent; |
| 204 MatchKind kind = MatchKind.REFERENCE; |
| 205 if (element is FunctionElement) { |
| 206 if (parent is MethodInvocation && parent.methodName == node) { |
| 207 kind = MatchKind.INVOCATION; |
| 208 } |
| 209 } else if (element is VariableElement) { |
| 210 bool isGet = node.inGetterContext(); |
| 211 bool isSet = node.inSetterContext(); |
| 212 if (isGet && isSet) { |
| 213 kind = MatchKind.READ_WRITE; |
| 214 } else if (isGet) { |
| 215 if (parent is MethodInvocation && parent.methodName == node) { |
| 216 kind = MatchKind.INVOCATION; |
| 217 } else { |
| 218 kind = MatchKind.READ; |
| 219 } |
| 220 } else if (isSet) { |
| 221 kind = MatchKind.WRITE; |
| 222 } |
| 191 } | 223 } |
| 192 return matches; | 224 _addMatch(node, kind); |
| 193 }); | 225 } |
| 194 futures.add(matchesFuture); | |
| 195 } | 226 } |
| 196 | 227 |
| 197 // void addElement( | 228 void _addMatch(SimpleIdentifier node, MatchKind kind) { |
| 198 // Element element, RelationshipImpl relationship, MatchKind kind) { | 229 matches.add(new SearchMatch(context, libraryUri, unitUri, kind, |
| 199 // IndexableElement indexable = new IndexableElement(element); | 230 new SourceRange(node.offset, node.length), true, node.isQualified)); |
| 200 // add(indexable, relationship, kind); | |
| 201 // } | |
| 202 | |
| 203 Future<List<SearchMatch>> merge() { | |
| 204 return Future.wait(futures).then((List<List<SearchMatch>> matchesList) { | |
| 205 return matchesList.expand((matches) => matches).toList(); | |
| 206 }); | |
| 207 } | |
| 208 | |
| 209 SearchMatch _convertLocation(Location location, MatchKind kind) { | |
| 210 return new SearchMatch( | |
| 211 context, | |
| 212 location.libraryUri, | |
| 213 location.unitUri, | |
| 214 kind, | |
| 215 new SourceRange(location.offset, location.length), | |
| 216 true, | |
| 217 location.isQualified); | |
| 218 } | 231 } |
| 219 } | 232 } |
| OLD | NEW |