Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(789)

Side by Side Diff: pkg/analysis_server/lib/src/services/completion/imported_computer.dart

Issue 742163002: cache import suggestions (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: merge Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 services.completion.computer.dart.toplevel; 5 library services.completion.computer.dart.toplevel;
6 6
7 import 'dart:async'; 7 import 'dart:async';
8 import 'dart:collection';
8 9
9 import 'package:analysis_server/src/protocol_server.dart' hide Element, 10 import 'package:analysis_server/src/protocol_server.dart' hide Element,
10 ElementKind; 11 ElementKind;
11 import 'package:analysis_server/src/services/completion/dart_completion_manager. dart'; 12 import 'package:analysis_server/src/services/completion/dart_completion_manager. dart';
12 import 'package:analysis_server/src/services/completion/suggestion_builder.dart' ; 13 import 'package:analysis_server/src/services/completion/suggestion_builder.dart' ;
13 import 'package:analysis_server/src/services/search/search_engine.dart'; 14 import 'package:analysis_server/src/services/search/search_engine.dart';
14 import 'package:analyzer/src/generated/ast.dart'; 15 import 'package:analyzer/src/generated/ast.dart';
15 import 'package:analyzer/src/generated/element.dart'; 16 import 'package:analyzer/src/generated/element.dart';
16 import 'package:analyzer/src/generated/resolver.dart'; 17 import 'package:analyzer/src/generated/resolver.dart';
17 import 'package:analyzer/src/generated/scanner.dart'; 18 import 'package:analyzer/src/generated/scanner.dart';
18 import 'package:analyzer/src/generated/source.dart'; 19 import 'package:analyzer/src/generated/source.dart';
19 20
20 /** 21 /**
21 * A computer for calculating imported class and top level variable 22 * A computer for calculating imported class and top level variable
22 * `completion.getSuggestions` request results. 23 * `completion.getSuggestions` request results.
23 */ 24 */
24 class ImportedComputer extends DartCompletionComputer { 25 class ImportedComputer extends DartCompletionComputer {
26 _ImportedSuggestionBuilder builder;
25 27
26 @override 28 @override
27 bool computeFast(DartCompletionRequest request) { 29 bool computeFast(DartCompletionRequest request) {
28 // TODO: implement computeFast 30 builder = request.node.accept(new _ImportedAstVisitor(request));
29 // - compute results based upon current search, then replace those results 31 if (builder != null) {
30 // during the full compute phase 32 return builder.computeFast();
31 // - filter results based upon completion offset 33 }
32 return false; 34 return true;
33 } 35 }
34 36
35 @override 37 @override
36 Future<bool> computeFull(DartCompletionRequest request) { 38 Future<bool> computeFull(DartCompletionRequest request) {
37 return request.node.accept(new _ImportedVisitor(request)); 39 if (builder != null) {
40 return builder.computeFull(request.node);
41 }
42 return new Future.value(false);
38 } 43 }
39 } 44 }
40 45
41 /** 46 /**
42 * A visitor for determining which imported classes and top level variables 47 * [_ImportedAstVisitor] determines whether an import suggestions are needed
43 * should be suggested and building those suggestions. 48 * and instantiates the builder to create those suggestions.
44 */ 49 */
45 class _ImportedVisitor extends GeneralizingAstVisitor<Future<bool>> { 50 class _ImportedAstVisitor extends
51 GeneralizingAstVisitor<_ImportedSuggestionBuilder> {
46 final DartCompletionRequest request; 52 final DartCompletionRequest request;
47 53
48 _ImportedVisitor(this.request); 54 _ImportedAstVisitor(this.request);
49 55
50 @override 56 @override
51 Future<bool> visitArgumentList(ArgumentList node) { 57 _ImportedSuggestionBuilder visitArgumentList(ArgumentList node) {
52 return _addImportedElementSuggestions(node, excludeVoidReturn: true); 58 return new _ImportedSuggestionBuilder(request, excludeVoidReturn: true);
53 } 59 }
54 60
55 @override 61 @override
56 Future<bool> visitBlock(Block node) { 62 _ImportedSuggestionBuilder visitBlock(Block node) {
57 return _addImportedElementSuggestions(node); 63 return new _ImportedSuggestionBuilder(request);
58 } 64 }
59 65
60 @override 66 @override
61 Future<bool> visitCascadeExpression(CascadeExpression node) { 67 _ImportedSuggestionBuilder visitCascadeExpression(CascadeExpression node) {
62 // Make suggestions for the target, but not for the selector 68 // Make suggestions for the target, but not for the selector
63 // InvocationComputer makes selector suggestions 69 // InvocationComputer makes selector suggestions
64 Expression target = node.target; 70 Expression target = node.target;
65 if (target != null && request.offset <= target.end) { 71 if (target != null && request.offset <= target.end) {
66 return _addImportedElementSuggestions(node, excludeVoidReturn: true); 72 return new _ImportedSuggestionBuilder(request, excludeVoidReturn: true);
67 } 73 }
68 return new Future.value(false); 74 return null;
69 } 75 }
70 76
71 @override 77 @override
72 Future<bool> visitClassDeclaration(ClassDeclaration node) { 78 _ImportedSuggestionBuilder visitClassDeclaration(ClassDeclaration node) {
73 // Make suggestions in the body of the class declaration 79 // Make suggestions in the body of the class declaration
74 Token leftBracket = node.leftBracket; 80 Token leftBracket = node.leftBracket;
75 if (leftBracket != null && request.offset >= leftBracket.end) { 81 if (leftBracket != null && request.offset >= leftBracket.end) {
76 return _addImportedElementSuggestions(node); 82 return new _ImportedSuggestionBuilder(request);
77 } 83 }
78 return new Future.value(false); 84 return null;
79 } 85 }
80 86
81 @override 87 @override
82 Future<bool> visitExpression(Expression node) { 88 _ImportedSuggestionBuilder visitExpression(Expression node) {
83 return _addImportedElementSuggestions(node, excludeVoidReturn: true); 89 return new _ImportedSuggestionBuilder(request, excludeVoidReturn: true);
84 } 90 }
85 91
86 @override 92 @override
87 Future<bool> visitExpressionStatement(ExpressionStatement node) { 93 _ImportedSuggestionBuilder
94 visitExpressionStatement(ExpressionStatement node) {
88 Expression expression = node.expression; 95 Expression expression = node.expression;
89 // A pre-variable declaration (e.g. C ^) is parsed as an expression 96 // A pre-variable declaration (e.g. C ^) is parsed as an expression
90 // statement. Do not make suggestions for the variable name. 97 // statement. Do not make suggestions for the variable name.
91 if (expression is SimpleIdentifier && request.offset <= expression.end) { 98 if (expression is SimpleIdentifier && request.offset <= expression.end) {
92 return _addImportedElementSuggestions(node); 99 return new _ImportedSuggestionBuilder(request);
93 } 100 }
94 return new Future.value(false); 101 return null;
95 } 102 }
96 103
97 @override 104 @override
98 Future<bool> visitFormalParameterList(FormalParameterList node) { 105 _ImportedSuggestionBuilder
106 visitFormalParameterList(FormalParameterList node) {
99 Token leftParen = node.leftParenthesis; 107 Token leftParen = node.leftParenthesis;
100 if (leftParen != null && request.offset > leftParen.offset) { 108 if (leftParen != null && request.offset > leftParen.offset) {
101 Token rightParen = node.rightParenthesis; 109 Token rightParen = node.rightParenthesis;
102 if (rightParen == null || request.offset <= rightParen.offset) { 110 if (rightParen == null || request.offset <= rightParen.offset) {
103 return _addImportedElementSuggestions(node); 111 return new _ImportedSuggestionBuilder(request);
104 } 112 }
105 } 113 }
106 return new Future.value(false); 114 return null;
107 } 115 }
108 116
109 @override 117 @override
110 Future<bool> visitForStatement(ForStatement node) { 118 _ImportedSuggestionBuilder visitForStatement(ForStatement node) {
111 Token leftParen = node.leftParenthesis; 119 Token leftParen = node.leftParenthesis;
112 if (leftParen != null && request.offset >= leftParen.end) { 120 if (leftParen != null && request.offset >= leftParen.end) {
113 return _addImportedElementSuggestions(node); 121 return new _ImportedSuggestionBuilder(request);
114 } 122 }
115 return new Future.value(false); 123 return null;
116 } 124 }
117 125
118 @override 126 @override
119 Future<bool> visitIfStatement(IfStatement node) { 127 _ImportedSuggestionBuilder visitIfStatement(IfStatement node) {
120 Token leftParen = node.leftParenthesis; 128 Token leftParen = node.leftParenthesis;
121 if (leftParen != null && request.offset >= leftParen.end) { 129 if (leftParen != null && request.offset >= leftParen.end) {
122 Token rightParen = node.rightParenthesis; 130 Token rightParen = node.rightParenthesis;
123 if (rightParen == null || request.offset <= rightParen.offset) { 131 if (rightParen == null || request.offset <= rightParen.offset) {
124 return _addImportedElementSuggestions(node, excludeVoidReturn: true); 132 return new _ImportedSuggestionBuilder(request, excludeVoidReturn: true);
125 } 133 }
126 } 134 }
127 return new Future.value(false); 135 return null;
128 } 136 }
129 137
130 @override 138 @override
131 Future<bool> visitInterpolationExpression(InterpolationExpression node) { 139 _ImportedSuggestionBuilder
140 visitInterpolationExpression(InterpolationExpression node) {
132 Expression expression = node.expression; 141 Expression expression = node.expression;
133 if (expression is SimpleIdentifier) { 142 if (expression is SimpleIdentifier) {
134 return _addImportedElementSuggestions(node, excludeVoidReturn: true); 143 return new _ImportedSuggestionBuilder(request, excludeVoidReturn: true);
135 } 144 }
136 return new Future.value(false); 145 return null;
137 } 146 }
138 147
139 @override 148 @override
140 Future<bool> visitMethodInvocation(MethodInvocation node) { 149 _ImportedSuggestionBuilder visitMethodInvocation(MethodInvocation node) {
141 Token period = node.period; 150 Token period = node.period;
142 if (period == null || request.offset <= period.offset) { 151 if (period == null || request.offset <= period.offset) {
143 return _addImportedElementSuggestions(node, excludeVoidReturn: true); 152 return new _ImportedSuggestionBuilder(request, excludeVoidReturn: true);
144 } 153 }
145 return new Future.value(false); 154 return null;
146 } 155 }
147 156
148 @override 157 @override
149 Future<bool> visitNode(AstNode node) { 158 _ImportedSuggestionBuilder visitNode(AstNode node) {
150 return new Future.value(false); 159 return null;
151 } 160 }
152 161
153 @override 162 @override
154 Future<bool> visitPrefixedIdentifier(PrefixedIdentifier node) { 163 _ImportedSuggestionBuilder visitPrefixedIdentifier(PrefixedIdentifier node) {
155 // Make suggestions for the prefix, but not for the selector 164 // Make suggestions for the prefix, but not for the selector
156 // InvocationComputer makes selector suggestions 165 // InvocationComputer makes selector suggestions
157 Token period = node.period; 166 Token period = node.period;
158 if (period != null && request.offset <= period.offset) { 167 if (period != null && request.offset <= period.offset) {
159 return _addImportedElementSuggestions(node, excludeVoidReturn: true); 168 return new _ImportedSuggestionBuilder(request, excludeVoidReturn: true);
160 } 169 }
161 return new Future.value(false); 170 return null;
162 } 171 }
163 172
164 @override 173 @override
165 Future<bool> visitPropertyAccess(PropertyAccess node) { 174 _ImportedSuggestionBuilder visitPropertyAccess(PropertyAccess node) {
166 // Make suggestions for the target, but not for the property name 175 // Make suggestions for the target, but not for the property name
167 // InvocationComputer makes property name suggestions 176 // InvocationComputer makes property name suggestions
168 var operator = node.operator; 177 var operator = node.operator;
169 if (operator != null && request.offset < operator.offset) { 178 if (operator != null && request.offset < operator.offset) {
170 return _addImportedElementSuggestions(node, excludeVoidReturn: true); 179 return new _ImportedSuggestionBuilder(request, excludeVoidReturn: true);
171 } 180 }
172 return new Future.value(false); 181 return null;
173 } 182 }
174 183
175 @override 184 @override
176 Future<bool> visitSimpleIdentifier(SimpleIdentifier node) { 185 _ImportedSuggestionBuilder visitSimpleIdentifier(SimpleIdentifier node) {
177 return node.parent.accept(this); 186 return node.parent.accept(this);
178 } 187 }
179 188
180 @override 189 @override
181 Future<bool> visitStringLiteral(StringLiteral node) { 190 _ImportedSuggestionBuilder visitStringLiteral(StringLiteral node) {
182 return new Future.value(false); 191 return null;
183 } 192 }
184 193
185 @override 194 @override
186 Future<bool> visitTypeName(TypeName node) { 195 _ImportedSuggestionBuilder visitTypeName(TypeName node) {
187 return _addImportedElementSuggestions(node, typesOnly: true); 196 return new _ImportedSuggestionBuilder(request, typesOnly: true);
188 } 197 }
189 198
190 @override 199 @override
191 visitVariableDeclaration(VariableDeclaration node) { 200 _ImportedSuggestionBuilder
201 visitVariableDeclaration(VariableDeclaration node) {
192 Token equals = node.equals; 202 Token equals = node.equals;
193 // Make suggestions for the RHS of a variable declaration 203 // Make suggestions for the RHS of a variable declaration
194 if (equals != null && request.offset >= equals.end) { 204 if (equals != null && request.offset >= equals.end) {
195 return _addImportedElementSuggestions(node, excludeVoidReturn: true); 205 return new _ImportedSuggestionBuilder(request, excludeVoidReturn: true);
196 } 206 }
197 return new Future.value(false); 207 return null;
198 } 208 }
199 209 }
200 void _addElementSuggestion(Element element, bool typesOnly, 210
201 bool excludeVoidReturn, CompletionRelevance relevance) { 211 /**
212 * [_ImportedSuggestionBuilder] traverses the imports and builds suggestions
213 * based upon imported elements.
214 */
215 class _ImportedSuggestionBuilder {
216 final DartCompletionRequest request;
217 final bool typesOnly;
218 final bool excludeVoidReturn;
219 final HashSet<String> completions = new HashSet();
220 DartCompletionCache cache;
221 String importKey;
222
223 _ImportedSuggestionBuilder(this.request, {this.typesOnly: false,
224 this.excludeVoidReturn: false}) {
225 cache = request.cache;
226 }
227
228 /**
229 * Compute a hash of the import directives.
230 */
231 String get computeImportKey {
232 if (importKey == null) {
233 StringBuffer sb = new StringBuffer();
234 request.unit.directives.forEach((Directive directive) {
235 if (directive is ImportDirective) {
236 sb.write(directive.toSource());
237 }
238 });
239 importKey = sb.toString();
240 }
241 return importKey;
242 }
243
244 void addCachedSuggestions() {
245 DartCompletionCache cache = request.cache;
246 request.suggestions
247 ..addAll(cache.importedTypeSuggestions)
248 ..addAll(cache.libraryPrefixSuggestions);
249 if (!typesOnly) {
250 request.suggestions.addAll(cache.otherImportedSuggestions);
251 if (!excludeVoidReturn) {
252 request.suggestions.addAll(cache.importedVoidReturnSuggestions);
253 }
254 }
255 }
256
257 void addLibraryPrefixSuggestion(ImportElement importElem) {
258 CompletionSuggestion suggestion = null;
259 String completion = importElem.prefix.displayName;
260 if (completion != null && completion.length > 0) {
261 suggestion = new CompletionSuggestion(
262 CompletionSuggestionKind.INVOCATION,
263 CompletionRelevance.DEFAULT,
264 completion,
265 completion.length,
266 0,
267 importElem.isDeprecated,
268 false);
269 LibraryElement lib = importElem.importedLibrary;
270 if (lib != null) {
271 suggestion.element = newElement_fromEngine(lib);
272 }
273 cache.libraryPrefixSuggestions.add(suggestion);
274 completions.add(suggestion.completion);
275 }
276 }
277
278 void addSuggestion(Element element, CompletionRelevance relevance) {
202 279
203 if (element is ExecutableElement) { 280 if (element is ExecutableElement) {
204 if (element.isOperator) { 281 if (element.isOperator) {
205 return; 282 return;
206 } 283 }
207 if (excludeVoidReturn) {
208 DartType returnType = element.returnType;
209 if (returnType != null && returnType.isVoid) {
210 return;
211 }
212 }
213 }
214 if (typesOnly && element is! ClassElement) {
215 return;
216 } 284 }
217 285
218 String completion = element.displayName; 286 String completion = element.displayName;
219 CompletionSuggestion suggestion = new CompletionSuggestion( 287 CompletionSuggestion suggestion = new CompletionSuggestion(
220 CompletionSuggestionKind.INVOCATION, 288 CompletionSuggestionKind.INVOCATION,
221 element.isDeprecated ? CompletionRelevance.LOW : relevance, 289 element.isDeprecated ? CompletionRelevance.LOW : relevance,
222 completion, 290 completion,
223 completion.length, 291 completion.length,
224 0, 292 0,
225 element.isDeprecated, 293 element.isDeprecated,
226 false); 294 false);
227 295
228 suggestion.element = newElement_fromEngine(element); 296 suggestion.element = newElement_fromEngine(element);
229 297
230 DartType type; 298 DartType type;
231 if (element is FunctionElement) { 299 if (element is FunctionElement) {
232 type = element.returnType; 300 type = element.returnType;
233 } else if (element is PropertyAccessorElement && element.isGetter) { 301 } else if (element is PropertyAccessorElement && element.isGetter) {
234 type = element.returnType; 302 type = element.returnType;
235 } else if (element is TopLevelVariableElement) { 303 } else if (element is TopLevelVariableElement) {
236 type = element.type; 304 type = element.type;
237 } 305 }
238 if (type != null) { 306 if (type != null) {
239 String name = type.displayName; 307 String name = type.displayName;
240 if (name != null && name.length > 0 && name != 'dynamic') { 308 if (name != null && name.length > 0 && name != 'dynamic') {
241 suggestion.returnType = name; 309 suggestion.returnType = name;
242 } 310 }
243 } 311 }
244 312
245 request.suggestions.add(suggestion); 313 if (element is ExecutableElement) {
314 DartType returnType = element.returnType;
315 if (returnType != null && returnType.isVoid) {
316 cache.importedVoidReturnSuggestions.add(suggestion);
317 } else {
318 cache.otherImportedSuggestions.add(suggestion);
319 }
320 } else if (element is ClassElement) {
321 cache.importedTypeSuggestions.add(suggestion);
322 } else {
323 cache.otherImportedSuggestions.add(suggestion);
324 }
325 completions.add(suggestion.completion);
246 } 326 }
247 327
248 void _addElementSuggestions(List<Element> elements, bool typesOnly, 328 void addSuggestions(List<Element> elements) {
249 bool excludeVoidReturn) {
250 elements.forEach((Element elem) { 329 elements.forEach((Element elem) {
251 _addElementSuggestion( 330 addSuggestion(elem, CompletionRelevance.DEFAULT);
252 elem,
253 typesOnly,
254 excludeVoidReturn,
255 CompletionRelevance.DEFAULT);
256 }); 331 });
257 } 332 }
258 333
259 Future<bool> _addImportedElementSuggestions(AstNode node, {bool typesOnly: 334 /**
260 false, bool excludeVoidReturn: false}) { 335 * If the needed information is cached, then add suggestions and return `true`
336 * else return `false` indicating that additional work is necessary.
337 */
338 bool computeFast() {
339 if (cache.importKey == computeImportKey) {
340 addCachedSuggestions();
341 return true;
342 }
343 return false;
344 }
345
346 /**
347 * Compute suggested based upon imported elements.
348 */
349 computeFull(AstNode node) {
350 CompilationUnit unit = node.getAncestor((p) => p is CompilationUnit);
351 cache.importedTypeSuggestions = <CompletionSuggestion>[];
352 cache.libraryPrefixSuggestions = <CompletionSuggestion>[];
353 cache.otherImportedSuggestions = <CompletionSuggestion>[];
354 cache.importedVoidReturnSuggestions = <CompletionSuggestion>[];
261 355
262 // Exclude elements from local library 356 // Exclude elements from local library
263 // because they are provided by LocalComputer 357 // because they are provided by LocalComputer
264 Set<LibraryElement> excludedLibs = new Set<LibraryElement>(); 358 Set<LibraryElement> excludedLibs = new Set<LibraryElement>();
265 excludedLibs.add(request.unit.element.enclosingElement); 359 excludedLibs.add(unit.element.enclosingElement);
266 360
267 // Include explicitly imported elements 361 // Include explicitly imported elements
268 Map<String, ClassElement> classMap = new Map<String, ClassElement>(); 362 Map<String, ClassElement> classMap = new Map<String, ClassElement>();
269 request.unit.directives.forEach((Directive directive) { 363 unit.directives.forEach((Directive directive) {
270 if (directive is ImportDirective) { 364 if (directive is ImportDirective) {
271 ImportElement importElem = directive.element; 365 ImportElement importElem = directive.element;
272 if (importElem != null && importElem.importedLibrary != null) { 366 if (importElem != null && importElem.importedLibrary != null) {
273 if (directive.prefix == null) { 367 if (directive.prefix == null) {
274 Namespace importNamespace = 368 Namespace importNamespace =
275 new NamespaceBuilder().createImportNamespaceForDirective(importE lem); 369 new NamespaceBuilder().createImportNamespaceForDirective(importE lem);
276 // Include top level elements 370 // Include top level elements
277 importNamespace.definedNames.forEach((String name, Element elem) { 371 importNamespace.definedNames.forEach((String name, Element elem) {
278 if (elem is ClassElement) { 372 if (elem is ClassElement) {
279 classMap[name] = elem; 373 classMap[name] = elem;
280 } 374 }
281 _addElementSuggestion( 375 addSuggestion(elem, CompletionRelevance.DEFAULT);
282 elem,
283 typesOnly,
284 excludeVoidReturn,
285 CompletionRelevance.DEFAULT);
286 }); 376 });
287 } else { 377 } else {
288 // Exclude elements from prefixed imports 378 // Exclude elements from prefixed imports
289 // because they are provided by InvocationComputer 379 // because they are provided by InvocationComputer
290 excludedLibs.add(importElem.importedLibrary); 380 excludedLibs.add(importElem.importedLibrary);
291 _addLibraryPrefixSuggestion(importElem); 381 addLibraryPrefixSuggestion(importElem);
292 } 382 }
293 } 383 }
294 } 384 }
295 }); 385 });
296 386
297 // Include implicitly imported dart:core elements 387 // Include implicitly imported dart:core elements
298 Source coreUri = request.context.sourceFactory.forUri('dart:core'); 388 Source coreUri = request.context.sourceFactory.forUri('dart:core');
299 LibraryElement coreLib = request.context.getLibraryElement(coreUri); 389 LibraryElement coreLib = request.context.getLibraryElement(coreUri);
300 Namespace coreNamespace = 390 Namespace coreNamespace =
301 new NamespaceBuilder().createPublicNamespaceForLibrary(coreLib); 391 new NamespaceBuilder().createPublicNamespaceForLibrary(coreLib);
302 coreNamespace.definedNames.forEach((String name, Element elem) { 392 coreNamespace.definedNames.forEach((String name, Element elem) {
303 if (elem is ClassElement) { 393 if (elem is ClassElement) {
304 classMap[name] = elem; 394 classMap[name] = elem;
305 } 395 }
306 _addElementSuggestion( 396 addSuggestion(elem, CompletionRelevance.DEFAULT);
307 elem,
308 typesOnly,
309 excludeVoidReturn,
310 CompletionRelevance.DEFAULT);
311 }); 397 });
312 398
313 // Build a list of inherited types that are imported 399 // Build a list of inherited types that are imported
314 // and include any inherited imported members 400 // and include any inherited imported members
315 var classDecl = node.getAncestor((p) => p is ClassDeclaration); 401 var classDecl = node.getAncestor((p) => p is ClassDeclaration);
316 if (classDecl is ClassDeclaration) { 402 if (classDecl is ClassDeclaration) {
317 List<String> inheritedTypes = new List<String>(); 403 List<String> inheritedTypes = new List<String>();
318 visitInheritedTypes(classDecl, (ClassDeclaration classDecl) { 404 visitInheritedTypes(classDecl, (ClassDeclaration classDecl) {
319 // ignored 405 // ignored
320 }, (String typeName) { 406 }, (String typeName) {
321 inheritedTypes.add(typeName); 407 inheritedTypes.add(typeName);
322 }); 408 });
323 Set<String> visited = new Set<String>(); 409 Set<String> visited = new Set<String>();
324 while (inheritedTypes.length > 0) { 410 while (inheritedTypes.length > 0) {
325 String name = inheritedTypes.removeLast(); 411 String name = inheritedTypes.removeLast();
326 ClassElement elem = classMap[name]; 412 ClassElement elem = classMap[name];
327 if (visited.add(name) && elem != null) { 413 if (visited.add(name) && elem != null) {
328 _addElementSuggestions(elem.accessors, typesOnly, excludeVoidReturn); 414 addSuggestions(elem.accessors);
329 _addElementSuggestions(elem.methods, typesOnly, excludeVoidReturn); 415 addSuggestions(elem.methods);
330 elem.allSupertypes.forEach((InterfaceType type) { 416 elem.allSupertypes.forEach((InterfaceType type) {
331 if (visited.add(type.name)) { 417 if (visited.add(type.name)) {
332 _addElementSuggestions( 418 addSuggestions(type.accessors);
333 type.accessors, 419 addSuggestions(type.methods);
334 typesOnly,
335 excludeVoidReturn);
336 _addElementSuggestions(
337 type.methods,
338 typesOnly,
339 excludeVoidReturn);
340 } 420 }
341 }); 421 });
342 } 422 }
343 } 423 }
344 } 424 }
345 425
346 // Add non-imported elements as low relevance 426 // Add non-imported elements as low relevance
347 var future = request.searchEngine.searchTopLevelDeclarations(''); 427 var future = request.searchEngine.searchTopLevelDeclarations('');
348 return future.then((List<SearchMatch> matches) { 428 return future.then((List<SearchMatch> matches) {
349 Set<String> completionSet = new Set<String>();
350 request.suggestions.forEach((CompletionSuggestion suggestion) {
351 completionSet.add(suggestion.completion);
352 });
353 matches.forEach((SearchMatch match) { 429 matches.forEach((SearchMatch match) {
354 if (match.kind == MatchKind.DECLARATION) { 430 if (match.kind == MatchKind.DECLARATION) {
355 Element element = match.element; 431 Element element = match.element;
356 if (element.isPublic && 432 if (element.isPublic &&
357 !excludedLibs.contains(element.library) && 433 !excludedLibs.contains(element.library) &&
358 !completionSet.contains(element.displayName)) { 434 !completions.contains(element.displayName)) {
359 if (!typesOnly || element is ClassElement) { 435 addSuggestion(element, CompletionRelevance.LOW);
360 _addElementSuggestion(
361 element,
362 typesOnly,
363 excludeVoidReturn,
364 CompletionRelevance.LOW);
365 }
366 } 436 }
367 } 437 }
368 }); 438 });
439 cache.importKey = computeImportKey;
440 addCachedSuggestions();
369 return true; 441 return true;
370 }); 442 });
371 } 443 }
372
373 void _addLibraryPrefixSuggestion(ImportElement importElem) {
374 String completion = importElem.prefix.displayName;
375 if (completion != null && completion.length > 0) {
376 CompletionSuggestion suggestion = new CompletionSuggestion(
377 CompletionSuggestionKind.INVOCATION,
378 CompletionRelevance.DEFAULT,
379 completion,
380 completion.length,
381 0,
382 importElem.isDeprecated,
383 false);
384 LibraryElement lib = importElem.importedLibrary;
385 if (lib != null) {
386 suggestion.element = newElement_fromEngine(lib);
387 }
388 request.suggestions.add(suggestion);
389 }
390 }
391 } 444 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698