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

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

Issue 752833002: refactor import caching to exclude suggestions for inherited members (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: cleanup unused imports 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 import 'dart:collection';
9 9
10 import 'package:analysis_server/src/protocol_server.dart' hide Element, 10 import 'package:analysis_server/src/protocol_server.dart' hide Element,
11 ElementKind; 11 ElementKind;
12 import 'package:analysis_server/src/services/completion/dart_completion_cache.da rt';
12 import 'package:analysis_server/src/services/completion/dart_completion_manager. dart'; 13 import 'package:analysis_server/src/services/completion/dart_completion_manager. dart';
13 import 'package:analysis_server/src/services/completion/suggestion_builder.dart' ; 14 import 'package:analysis_server/src/services/completion/suggestion_builder.dart' ;
14 import 'package:analysis_server/src/services/search/search_engine.dart';
15 import 'package:analyzer/src/generated/ast.dart'; 15 import 'package:analyzer/src/generated/ast.dart';
16 import 'package:analyzer/src/generated/element.dart'; 16 import 'package:analyzer/src/generated/element.dart';
17 import 'package:analyzer/src/generated/resolver.dart';
18 import 'package:analyzer/src/generated/scanner.dart'; 17 import 'package:analyzer/src/generated/scanner.dart';
19 import 'package:analyzer/src/generated/source.dart';
20 18
21 /** 19 /**
22 * A computer for calculating imported class and top level variable 20 * A computer for calculating imported class and top level variable
23 * `completion.getSuggestions` request results. 21 * `completion.getSuggestions` request results.
24 */ 22 */
25 class ImportedComputer extends DartCompletionComputer { 23 class ImportedComputer extends DartCompletionComputer {
26 _ImportedSuggestionBuilder builder; 24 _ImportedSuggestionBuilder builder;
27 25
28 @override 26 @override
29 bool computeFast(DartCompletionRequest request) { 27 bool computeFast(DartCompletionRequest request) {
30 builder = request.node.accept(new _ImportedAstVisitor(request)); 28 builder = request.node.accept(new _ImportedAstVisitor(request));
31 if (builder != null) { 29 if (builder != null) {
32 return builder.computeFast(); 30 return builder.computeFast(request.node);
33 } 31 }
34 return true; 32 return true;
35 } 33 }
36 34
37 @override 35 @override
38 Future<bool> computeFull(DartCompletionRequest request) { 36 Future<bool> computeFull(DartCompletionRequest request) {
39 if (builder != null) { 37 if (builder != null) {
40 return builder.computeFull(request.node); 38 return builder.computeFull(request.node);
41 } 39 }
42 return new Future.value(false); 40 return new Future.value(false);
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after
205 return new _ImportedSuggestionBuilder(request, excludeVoidReturn: true); 203 return new _ImportedSuggestionBuilder(request, excludeVoidReturn: true);
206 } 204 }
207 return null; 205 return null;
208 } 206 }
209 } 207 }
210 208
211 /** 209 /**
212 * [_ImportedSuggestionBuilder] traverses the imports and builds suggestions 210 * [_ImportedSuggestionBuilder] traverses the imports and builds suggestions
213 * based upon imported elements. 211 * based upon imported elements.
214 */ 212 */
215 class _ImportedSuggestionBuilder { 213 class _ImportedSuggestionBuilder implements SuggestionBuilder {
216 final DartCompletionRequest request; 214 final DartCompletionRequest request;
217 final bool typesOnly; 215 final bool typesOnly;
218 final bool excludeVoidReturn; 216 final bool excludeVoidReturn;
219 final HashSet<String> completions = new HashSet();
220 DartCompletionCache cache; 217 DartCompletionCache cache;
221 String importKey;
222 218
223 _ImportedSuggestionBuilder(this.request, {this.typesOnly: false, 219 _ImportedSuggestionBuilder(this.request, {this.typesOnly: false,
224 this.excludeVoidReturn: false}) { 220 this.excludeVoidReturn: false}) {
225 cache = request.cache; 221 cache = request.cache;
226 } 222 }
227 223
228 /** 224 /**
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) {
279
280 if (element is ExecutableElement) {
281 if (element.isOperator) {
282 return;
283 }
284 }
285
286 String completion = element.displayName;
287 CompletionSuggestion suggestion = new CompletionSuggestion(
288 CompletionSuggestionKind.INVOCATION,
289 element.isDeprecated ? CompletionRelevance.LOW : relevance,
290 completion,
291 completion.length,
292 0,
293 element.isDeprecated,
294 false);
295
296 suggestion.element = newElement_fromEngine(element);
297
298 DartType type;
299 if (element is FunctionElement) {
300 type = element.returnType;
301 } else if (element is PropertyAccessorElement && element.isGetter) {
302 type = element.returnType;
303 } else if (element is TopLevelVariableElement) {
304 type = element.type;
305 }
306 if (type != null) {
307 String name = type.displayName;
308 if (name != null && name.length > 0 && name != 'dynamic') {
309 suggestion.returnType = name;
310 }
311 }
312
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);
326 }
327
328 void addSuggestions(List<Element> elements) {
329 elements.forEach((Element elem) {
330 addSuggestion(elem, CompletionRelevance.DEFAULT);
331 });
332 }
333
334 /**
335 * If the needed information is cached, then add suggestions and return `true` 225 * If the needed information is cached, then add suggestions and return `true`
336 * else return `false` indicating that additional work is necessary. 226 * else return `false` indicating that additional work is necessary.
337 */ 227 */
338 bool computeFast() { 228 bool computeFast(AstNode node) {
339 if (cache.importKey == computeImportKey) { 229 CompilationUnit unit = request.unit;
340 addCachedSuggestions(); 230 if (cache.isImportInfoCached(unit)) {
231 _addInheritedSuggestions(node);
232 _addTopLevelSuggestions();
341 return true; 233 return true;
342 } 234 }
343 return false; 235 return false;
344 } 236 }
345 237
346 /** 238 /**
347 * Compute suggested based upon imported elements. 239 * Compute suggested based upon imported elements.
348 */ 240 */
349 computeFull(AstNode node) { 241 Future<bool> computeFull(AstNode node) {
350 CompilationUnit unit = node.getAncestor((p) => p is CompilationUnit); 242 return cache.computeImportInfo(
351 cache.importedTypeSuggestions = <CompletionSuggestion>[]; 243 request.unit,
352 cache.libraryPrefixSuggestions = <CompletionSuggestion>[]; 244 request.searchEngine).then((_) {
353 cache.otherImportedSuggestions = <CompletionSuggestion>[]; 245 _addInheritedSuggestions(node);
354 cache.importedVoidReturnSuggestions = <CompletionSuggestion>[]; 246 _addTopLevelSuggestions();
247 return true;
248 });
249 }
355 250
356 // Exclude elements from local library 251 /**
357 // because they are provided by LocalComputer 252 * Add imported element suggestions.
358 Set<LibraryElement> excludedLibs = new Set<LibraryElement>(); 253 */
359 excludedLibs.add(unit.element.enclosingElement); 254 void _addElementSuggestions(List<Element> elements) {
360 255 elements.forEach((Element elem) {
361 // Include explicitly imported elements 256 if (elem is! ClassElement) {
362 Map<String, ClassElement> classMap = new Map<String, ClassElement>(); 257 if (typesOnly) {
363 unit.directives.forEach((Directive directive) { 258 return;
364 if (directive is ImportDirective) { 259 }
365 ImportElement importElem = directive.element; 260 if (elem is ExecutableElement) {
366 if (importElem != null && importElem.importedLibrary != null) { 261 if (elem.isOperator) {
367 if (directive.prefix == null) { 262 return;
368 Namespace importNamespace = 263 }
369 new NamespaceBuilder().createImportNamespaceForDirective(importE lem); 264 DartType returnType = elem.returnType;
370 // Include top level elements 265 if (returnType != null && returnType.isVoid) {
371 importNamespace.definedNames.forEach((String name, Element elem) { 266 if (excludeVoidReturn) {
372 if (elem is ClassElement) { 267 return;
373 classMap[name] = elem; 268 }
374 }
375 addSuggestion(elem, CompletionRelevance.DEFAULT);
376 });
377 } else {
378 // Exclude elements from prefixed imports
379 // because they are provided by InvocationComputer
380 excludedLibs.add(importElem.importedLibrary);
381 addLibraryPrefixSuggestion(importElem);
382 } 269 }
383 } 270 }
384 } 271 }
272 request.suggestions.add(
273 createElementSuggestion(elem, relevance: CompletionRelevance.DEFAULT)) ;
385 }); 274 });
275 }
386 276
387 // Include implicitly imported dart:core elements 277 /**
388 Source coreUri = request.context.sourceFactory.forUri('dart:core'); 278 * Add suggestions for any inherited imported members.
389 LibraryElement coreLib = request.context.getLibraryElement(coreUri); 279 */
390 Namespace coreNamespace = 280 void _addInheritedSuggestions(AstNode node) {
391 new NamespaceBuilder().createPublicNamespaceForLibrary(coreLib);
392 coreNamespace.definedNames.forEach((String name, Element elem) {
393 if (elem is ClassElement) {
394 classMap[name] = elem;
395 }
396 addSuggestion(elem, CompletionRelevance.DEFAULT);
397 });
398
399 // Build a list of inherited types that are imported
400 // and include any inherited imported members
401 var classDecl = node.getAncestor((p) => p is ClassDeclaration); 281 var classDecl = node.getAncestor((p) => p is ClassDeclaration);
402 if (classDecl is ClassDeclaration) { 282 if (classDecl is ClassDeclaration) {
283 // Build a list of inherited types that are imported
284 // and include any inherited imported members
403 List<String> inheritedTypes = new List<String>(); 285 List<String> inheritedTypes = new List<String>();
404 visitInheritedTypes(classDecl, (ClassDeclaration classDecl) { 286 visitInheritedTypes(classDecl, (_) {
405 // ignored 287 // local declarations are handled by the local computer
406 }, (String typeName) { 288 }, (String typeName) {
407 inheritedTypes.add(typeName); 289 inheritedTypes.add(typeName);
408 }); 290 });
409 Set<String> visited = new Set<String>(); 291 HashSet<String> visited = new HashSet<String>();
410 while (inheritedTypes.length > 0) { 292 while (inheritedTypes.length > 0) {
411 String name = inheritedTypes.removeLast(); 293 String name = inheritedTypes.removeLast();
412 ClassElement elem = classMap[name]; 294 ClassElement elem = cache.importedClassMap[name];
413 if (visited.add(name) && elem != null) { 295 if (visited.add(name) && elem != null) {
414 addSuggestions(elem.accessors); 296 _addElementSuggestions(elem.accessors);
415 addSuggestions(elem.methods); 297 _addElementSuggestions(elem.methods);
416 elem.allSupertypes.forEach((InterfaceType type) { 298 elem.allSupertypes.forEach((InterfaceType type) {
417 if (visited.add(type.name)) { 299 if (visited.add(type.name)) {
418 addSuggestions(type.accessors); 300 _addElementSuggestions(type.accessors);
419 addSuggestions(type.methods); 301 _addElementSuggestions(type.methods);
420 } 302 }
421 }); 303 });
422 } 304 }
423 } 305 }
424 } 306 }
307 }
425 308
426 // Add non-imported elements as low relevance 309 void _addTopLevelSuggestions() {
427 var future = request.searchEngine.searchTopLevelDeclarations(''); 310 DartCompletionCache cache = request.cache;
428 return future.then((List<SearchMatch> matches) { 311 request.suggestions
429 matches.forEach((SearchMatch match) { 312 ..addAll(cache.importedTypeSuggestions)
430 if (match.kind == MatchKind.DECLARATION) { 313 ..addAll(cache.libraryPrefixSuggestions);
431 Element element = match.element; 314 if (!typesOnly) {
432 if (element.isPublic && 315 request.suggestions.addAll(cache.otherImportedSuggestions);
433 !excludedLibs.contains(element.library) && 316 if (!excludeVoidReturn) {
434 !completions.contains(element.displayName)) { 317 request.suggestions.addAll(cache.importedVoidReturnSuggestions);
435 addSuggestion(element, CompletionRelevance.LOW); 318 }
436 } 319 }
437 }
438 });
439 cache.importKey = computeImportKey;
440 addCachedSuggestions();
441 return true;
442 });
443 } 320 }
444 } 321 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698