| 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 services.completion.suggestion.builder; | 5 library services.completion.suggestion.builder; |
| 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' as protocol; | 10 import 'package:analysis_server/src/protocol_server.dart' as protocol; |
| 11 import 'package:analysis_server/src/protocol_server.dart' | 11 import 'package:analysis_server/src/protocol_server.dart' |
| 12 hide Element, ElementKind; | 12 hide Element, ElementKind; |
| 13 import 'package:analysis_server/src/services/completion/dart_completion_manager.
dart'; | 13 import 'package:analysis_server/src/services/completion/dart_completion_manager.
dart'; |
| 14 import 'package:analyzer/src/generated/ast.dart'; | 14 import 'package:analyzer/src/generated/ast.dart'; |
| 15 import 'package:analyzer/src/generated/element.dart'; | 15 import 'package:analyzer/src/generated/element.dart'; |
| 16 import 'package:analyzer/src/generated/utilities_dart.dart'; | 16 import 'package:analyzer/src/generated/utilities_dart.dart'; |
| 17 import 'package:analyzer/src/generated/source.dart'; | 17 import 'package:analyzer/src/generated/source.dart'; |
| 18 import 'package:path/path.dart' as path; | 18 import 'package:path/path.dart' as path; |
| 19 | 19 |
| 20 const String DYNAMIC = 'dynamic'; | 20 const String DYNAMIC = 'dynamic'; |
| 21 | 21 |
| 22 /** | 22 /** |
| 23 * Return a suggestion based upon the given element | 23 * Return a suggestion based upon the given element |
| 24 * or `null` if a suggestion is not appropriate for the given element. | 24 * or `null` if a suggestion is not appropriate for the given element. |
| 25 * If the suggestion is not currently in scope, then specify | 25 * If the suggestion is not currently in scope, then specify |
| 26 * importForSource as the source to which an import should be added. | 26 * importForSource as the source to which an import should be added. |
| 27 */ | 27 */ |
| 28 CompletionSuggestion createSuggestion(Element element, | 28 CompletionSuggestion createSuggestion(Element element, {String completion, |
| 29 {CompletionSuggestionKind kind: CompletionSuggestionKind.INVOCATION, | 29 CompletionSuggestionKind kind: CompletionSuggestionKind.INVOCATION, |
| 30 int relevance: DART_RELEVANCE_DEFAULT, Source importForSource}) { | 30 int relevance: DART_RELEVANCE_DEFAULT, Source importForSource}) { |
| 31 if (element is ExecutableElement && element.isOperator) { | 31 if (element is ExecutableElement && element.isOperator) { |
| 32 // Do not include operators in suggestions | 32 // Do not include operators in suggestions |
| 33 return null; | 33 return null; |
| 34 } | 34 } |
| 35 String completion = element.displayName; | 35 if (completion == null) { |
| 36 completion = element.displayName; |
| 37 } |
| 36 bool isDeprecated = element.isDeprecated; | 38 bool isDeprecated = element.isDeprecated; |
| 37 CompletionSuggestion suggestion = new CompletionSuggestion(kind, | 39 CompletionSuggestion suggestion = new CompletionSuggestion(kind, |
| 38 isDeprecated ? DART_RELEVANCE_LOW : relevance, completion, | 40 isDeprecated ? DART_RELEVANCE_LOW : relevance, completion, |
| 39 completion.length, 0, isDeprecated, false); | 41 completion.length, 0, isDeprecated, false); |
| 40 suggestion.element = protocol.newElement_fromEngine(element); | 42 suggestion.element = protocol.newElement_fromEngine(element); |
| 41 Element enclosingElement = element.enclosingElement; | 43 Element enclosingElement = element.enclosingElement; |
| 42 if (enclosingElement is ClassElement) { | 44 if (enclosingElement is ClassElement) { |
| 43 suggestion.declaringType = enclosingElement.displayName; | 45 suggestion.declaringType = enclosingElement.displayName; |
| 44 } | 46 } |
| 45 suggestion.returnType = getReturnTypeString(element); | 47 suggestion.returnType = getReturnTypeString(element); |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 182 CompletionSuggestionKind get kind; | 184 CompletionSuggestionKind get kind; |
| 183 | 185 |
| 184 /** | 186 /** |
| 185 * Return the request on which the builder is operating. | 187 * Return the request on which the builder is operating. |
| 186 */ | 188 */ |
| 187 DartCompletionRequest get request; | 189 DartCompletionRequest get request; |
| 188 | 190 |
| 189 /** | 191 /** |
| 190 * Add a suggestion based upon the given element. | 192 * Add a suggestion based upon the given element. |
| 191 */ | 193 */ |
| 192 void addSuggestion(Element element, {int relevance: DART_RELEVANCE_DEFAULT}) { | 194 void addSuggestion(Element element, |
| 195 {String prefix, int relevance: DART_RELEVANCE_DEFAULT}) { |
| 193 if (element.isPrivate) { | 196 if (element.isPrivate) { |
| 194 LibraryElement elementLibrary = element.library; | 197 LibraryElement elementLibrary = element.library; |
| 195 CompilationUnitElement unitElem = request.unit.element; | 198 CompilationUnitElement unitElem = request.unit.element; |
| 196 if (unitElem == null) { | 199 if (unitElem == null) { |
| 197 return; | 200 return; |
| 198 } | 201 } |
| 199 LibraryElement unitLibrary = unitElem.library; | 202 LibraryElement unitLibrary = unitElem.library; |
| 200 if (elementLibrary != unitLibrary) { | 203 if (elementLibrary != unitLibrary) { |
| 201 return; | 204 return; |
| 202 } | 205 } |
| 203 } | 206 } |
| 204 if (element.isSynthetic) { | 207 if (prefix == null && element.isSynthetic) { |
| 205 if ((element is PropertyAccessorElement) || | 208 if ((element is PropertyAccessorElement) || |
| 206 element is FieldElement && !_isSpecialEnumField(element)) { | 209 element is FieldElement && !_isSpecialEnumField(element)) { |
| 207 return; | 210 return; |
| 208 } | 211 } |
| 209 } | 212 } |
| 210 String completion = element.displayName; | 213 String completion = element.displayName; |
| 214 if (prefix != null && prefix.length > 0) { |
| 215 if (completion == null || completion.length <= 0) { |
| 216 completion = prefix; |
| 217 } else { |
| 218 completion = '$prefix.$completion'; |
| 219 } |
| 220 } |
| 211 if (completion == null || completion.length <= 0) { | 221 if (completion == null || completion.length <= 0) { |
| 212 return; | 222 return; |
| 213 } | 223 } |
| 214 CompletionSuggestion suggestion = | 224 CompletionSuggestion suggestion = createSuggestion(element, |
| 215 createSuggestion(element, kind: kind, relevance: relevance); | 225 completion: completion, kind: kind, relevance: relevance); |
| 216 if (suggestion != null) { | 226 if (suggestion != null) { |
| 217 request.addSuggestion(suggestion); | 227 request.addSuggestion(suggestion); |
| 218 } | 228 } |
| 219 } | 229 } |
| 220 | 230 |
| 221 /** | 231 /** |
| 222 * Determine if the given element is one of the synthetic enum accessors | 232 * Determine if the given element is one of the synthetic enum accessors |
| 223 * for which we should generate a suggestion. | 233 * for which we should generate a suggestion. |
| 224 */ | 234 */ |
| 225 bool _isSpecialEnumField(FieldElement element) { | 235 bool _isSpecialEnumField(FieldElement element) { |
| (...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 433 /** | 443 /** |
| 434 * This class visits elements in a library and provides suggestions based upon | 444 * This class visits elements in a library and provides suggestions based upon |
| 435 * the visible members in that library. Clients should call | 445 * the visible members in that library. Clients should call |
| 436 * [LibraryElementSuggestionBuilder.suggestionsFor]. | 446 * [LibraryElementSuggestionBuilder.suggestionsFor]. |
| 437 */ | 447 */ |
| 438 class LibraryElementSuggestionBuilder extends GeneralizingElementVisitor | 448 class LibraryElementSuggestionBuilder extends GeneralizingElementVisitor |
| 439 with ElementSuggestionBuilder { | 449 with ElementSuggestionBuilder { |
| 440 final DartCompletionRequest request; | 450 final DartCompletionRequest request; |
| 441 final CompletionSuggestionKind kind; | 451 final CompletionSuggestionKind kind; |
| 442 final bool typesOnly; | 452 final bool typesOnly; |
| 453 final bool instCreation; |
| 443 | 454 |
| 444 LibraryElementSuggestionBuilder(this.request, this.kind, this.typesOnly); | 455 LibraryElementSuggestionBuilder( |
| 456 this.request, this.kind, this.typesOnly, this.instCreation); |
| 445 | 457 |
| 446 @override | 458 @override |
| 447 visitClassElement(ClassElement element) { | 459 visitClassElement(ClassElement element) { |
| 448 addSuggestion(element); | 460 if (instCreation) { |
| 461 element.visitChildren(this); |
| 462 } else { |
| 463 addSuggestion(element); |
| 464 } |
| 449 } | 465 } |
| 450 | 466 |
| 451 @override | 467 @override |
| 452 visitCompilationUnitElement(CompilationUnitElement element) { | 468 visitCompilationUnitElement(CompilationUnitElement element) { |
| 453 element.visitChildren(this); | 469 element.visitChildren(this); |
| 454 LibraryElement containingLibrary = element.library; | 470 LibraryElement containingLibrary = element.library; |
| 455 if (containingLibrary != null) { | 471 if (containingLibrary != null) { |
| 456 for (var lib in containingLibrary.exportedLibraries) { | 472 for (var lib in containingLibrary.exportedLibraries) { |
| 457 lib.visitChildren(this); | 473 lib.visitChildren(this); |
| 458 } | 474 } |
| 459 } | 475 } |
| 460 } | 476 } |
| 461 | 477 |
| 462 @override | 478 @override |
| 479 visitConstructorElement(ConstructorElement element) { |
| 480 if (instCreation) { |
| 481 ClassElement classElem = element.enclosingElement; |
| 482 if (classElem != null) { |
| 483 String prefix = classElem.name; |
| 484 if (prefix != null && prefix.length > 0) { |
| 485 addSuggestion(element, prefix: prefix); |
| 486 } |
| 487 } |
| 488 } |
| 489 } |
| 490 |
| 491 @override |
| 463 visitElement(Element element) { | 492 visitElement(Element element) { |
| 464 // ignored | 493 // ignored |
| 465 } | 494 } |
| 466 | 495 |
| 467 @override | 496 @override |
| 468 visitFunctionElement(FunctionElement element) { | 497 visitFunctionElement(FunctionElement element) { |
| 469 if (!typesOnly) { | 498 if (!typesOnly) { |
| 470 addSuggestion(element); | 499 addSuggestion(element); |
| 471 } | 500 } |
| 472 } | 501 } |
| 473 | 502 |
| 474 @override | 503 @override |
| 475 visitFunctionTypeAliasElement(FunctionTypeAliasElement element) { | 504 visitFunctionTypeAliasElement(FunctionTypeAliasElement element) { |
| 476 addSuggestion(element); | 505 if (!instCreation) { |
| 506 addSuggestion(element); |
| 507 } |
| 477 } | 508 } |
| 478 | 509 |
| 479 @override | 510 @override |
| 480 visitTopLevelVariableElement(TopLevelVariableElement element) { | 511 visitTopLevelVariableElement(TopLevelVariableElement element) { |
| 481 if (!typesOnly) { | 512 if (!typesOnly) { |
| 482 addSuggestion(element); | 513 addSuggestion(element); |
| 483 } | 514 } |
| 484 } | 515 } |
| 485 | 516 |
| 486 /** | 517 /** |
| 487 * Add suggestions for the visible members in the given library | 518 * Add suggestions for the visible members in the given library |
| 488 */ | 519 */ |
| 489 static void suggestionsFor(DartCompletionRequest request, | 520 static void suggestionsFor(DartCompletionRequest request, |
| 490 CompletionSuggestionKind kind, LibraryElement library, bool typesOnly) { | 521 CompletionSuggestionKind kind, LibraryElement library, bool typesOnly, |
| 522 bool instCreation) { |
| 491 if (library != null) { | 523 if (library != null) { |
| 492 library.visitChildren( | 524 library.visitChildren(new LibraryElementSuggestionBuilder( |
| 493 new LibraryElementSuggestionBuilder(request, kind, typesOnly)); | 525 request, kind, typesOnly, instCreation)); |
| 494 } | 526 } |
| 495 } | 527 } |
| 496 } | 528 } |
| 497 | 529 |
| 498 /** | 530 /** |
| 499 * This class visits elements in a class and provides suggestions based upon | 531 * This class visits elements in a class and provides suggestions based upon |
| 500 * the visible named constructors in that class. | 532 * the visible named constructors in that class. |
| 501 */ | 533 */ |
| 502 class NamedConstructorSuggestionBuilder extends GeneralizingElementVisitor | 534 class NamedConstructorSuggestionBuilder extends GeneralizingElementVisitor |
| 503 with ElementSuggestionBuilder implements SuggestionBuilder { | 535 with ElementSuggestionBuilder implements SuggestionBuilder { |
| (...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 625 * or `false` if [computeFull] should be called. | 657 * or `false` if [computeFull] should be called. |
| 626 */ | 658 */ |
| 627 bool computeFast(AstNode node); | 659 bool computeFast(AstNode node); |
| 628 | 660 |
| 629 /** | 661 /** |
| 630 * Return a future that computes the suggestions given a fully resolved AST. | 662 * Return a future that computes the suggestions given a fully resolved AST. |
| 631 * The future returns `true` if suggestions were added, else `false`. | 663 * The future returns `true` if suggestions were added, else `false`. |
| 632 */ | 664 */ |
| 633 Future<bool> computeFull(AstNode node); | 665 Future<bool> computeFull(AstNode node); |
| 634 } | 666 } |
| OLD | NEW |