| 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.computer.dart.toplevel; | 5 library services.completion.computer.dart.toplevel; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 | 8 |
| 9 import 'package:analysis_server/src/protocol.dart' as protocol show Element, | 9 import 'package:analysis_server/src/protocol.dart' as protocol show Element, |
| 10 ElementKind; | 10 ElementKind; |
| 11 import 'package:analysis_server/src/protocol.dart' hide Element, ElementKind; | 11 import 'package:analysis_server/src/protocol.dart' hide Element, ElementKind; |
| 12 import 'package:analysis_server/src/services/completion/dart_completion_manager.
dart'; | 12 import 'package:analysis_server/src/services/completion/dart_completion_manager.
dart'; |
| 13 import 'package:analysis_server/src/services/completion/suggestion_builder.dart'
; | 13 import 'package:analysis_server/src/services/completion/suggestion_builder.dart'
; |
| 14 import 'package:analysis_server/src/services/search/search_engine.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/source.dart'; |
| 17 | 19 |
| 18 /** | 20 /** |
| 19 * A computer for calculating imported class and top level variable | 21 * A computer for calculating imported class and top level variable |
| 20 * `completion.getSuggestions` request results. | 22 * `completion.getSuggestions` request results. |
| 21 */ | 23 */ |
| 22 class ImportedComputer extends DartCompletionComputer { | 24 class ImportedComputer extends DartCompletionComputer { |
| 23 | 25 |
| 24 @override | 26 @override |
| 25 bool computeFast(DartCompletionRequest request) { | 27 bool computeFast(DartCompletionRequest request) { |
| 26 // TODO: implement computeFast | 28 // TODO: implement computeFast |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 67 return new Future.value(false); | 69 return new Future.value(false); |
| 68 } | 70 } |
| 69 | 71 |
| 70 Future _addCombinatorSuggestions(Combinator node) { | 72 Future _addCombinatorSuggestions(Combinator node) { |
| 71 var directive = node.getAncestor((parent) => parent is NamespaceDirective); | 73 var directive = node.getAncestor((parent) => parent is NamespaceDirective); |
| 72 if (directive is NamespaceDirective) { | 74 if (directive is NamespaceDirective) { |
| 73 LibraryElement library = directive.uriElement; | 75 LibraryElement library = directive.uriElement; |
| 74 LibraryElementSuggestionBuilder.suggestionsFor(request, library); | 76 LibraryElementSuggestionBuilder.suggestionsFor(request, library); |
| 75 return new Future.value(true); | 77 return new Future.value(true); |
| 76 } | 78 } |
| 79 |
| 77 return new Future.value(false); | 80 return new Future.value(false); |
| 78 } | 81 } |
| 79 | 82 |
| 80 Future<bool> _addImportedElementSuggestions() { | 83 Future<bool> _addImportedElementSuggestions() { |
| 84 |
| 85 // Exclude elements from local library |
| 86 // because they are provided by LocalComputer |
| 87 Set<LibraryElement> excludedLibs = new Set<LibraryElement>(); |
| 88 excludedLibs.add(request.unit.element.enclosingElement); |
| 89 |
| 90 // Include explicitly imported elements |
| 91 request.unit.directives.forEach((Directive directive) { |
| 92 if (directive is ImportDirective) { |
| 93 ImportElement importElem = directive.element; |
| 94 if (importElem != null && importElem.importedLibrary != null) { |
| 95 if (directive.prefix == null) { |
| 96 Namespace importNamespace = |
| 97 new NamespaceBuilder().createImportNamespaceForDirective(importE
lem); |
| 98 importNamespace.definedNames.forEach((_, Element element) { |
| 99 _addElementSuggestion(element, CompletionRelevance.DEFAULT); |
| 100 }); |
| 101 } else { |
| 102 // Exclude elements from prefixed imports |
| 103 // because they are provided by InvocationComputer |
| 104 excludedLibs.add(importElem.importedLibrary); |
| 105 _addLibraryPrefixSuggestion(importElem); |
| 106 } |
| 107 } |
| 108 } |
| 109 }); |
| 110 |
| 111 // Include implicitly imported dart:core elements |
| 112 Source coreUri = request.context.sourceFactory.forUri('dart:core'); |
| 113 LibraryElement coreLib = request.context.getLibraryElement(coreUri); |
| 114 Namespace coreNamespace = |
| 115 new NamespaceBuilder().createPublicNamespaceForLibrary(coreLib); |
| 116 coreNamespace.definedNames.forEach((_, Element element) { |
| 117 _addElementSuggestion(element, CompletionRelevance.DEFAULT); |
| 118 }); |
| 119 |
| 120 // Add non-imported elements as low relevance |
| 81 var future = request.searchEngine.searchTopLevelDeclarations(''); | 121 var future = request.searchEngine.searchTopLevelDeclarations(''); |
| 82 return future.then((List<SearchMatch> matches) { | 122 return future.then((List<SearchMatch> matches) { |
| 83 | 123 Set<String> completionSet = new Set<String>(); |
| 84 Set<LibraryElement> visibleLibs = new Set<LibraryElement>(); | 124 request.suggestions.forEach((CompletionSuggestion suggestion) { |
| 85 Set<LibraryElement> excludedLibs = new Set<LibraryElement>(); | 125 completionSet.add(suggestion.completion); |
| 86 | |
| 87 Map<LibraryElement, Set<String>> showNames = | |
| 88 new Map<LibraryElement, Set<String>>(); | |
| 89 Map<LibraryElement, Set<String>> hideNames = | |
| 90 new Map<LibraryElement, Set<String>>(); | |
| 91 | |
| 92 // Exclude elements from the local library | |
| 93 // as they will be included by the LocalComputer | |
| 94 excludedLibs.add(request.unit.element.library); | |
| 95 | |
| 96 // Build the set of visible and excluded libraries | |
| 97 // and the list of names that should be shown or hidden | |
| 98 request.unit.directives.forEach((Directive directive) { | |
| 99 if (directive is ImportDirective) { | |
| 100 ImportElement element = directive.element; | |
| 101 if (element != null) { | |
| 102 LibraryElement lib = element.importedLibrary; | |
| 103 SimpleIdentifier prefix = directive.prefix; | |
| 104 if (prefix == null) { | |
| 105 visibleLibs.add(lib); | |
| 106 directive.combinators.forEach((Combinator combinator) { | |
| 107 if (combinator is ShowCombinator) { | |
| 108 showNames[lib] = | |
| 109 combinator.shownNames.map((SimpleIdentifier id) => id.name
).toSet(); | |
| 110 } else if (combinator is HideCombinator) { | |
| 111 hideNames[lib] = | |
| 112 combinator.hiddenNames.map((SimpleIdentifier id) => id.nam
e).toSet(); | |
| 113 } | |
| 114 }); | |
| 115 } else { | |
| 116 String completion = prefix.name; | |
| 117 if (completion != null && completion.length > 0) { | |
| 118 CompletionSuggestion suggestion = new CompletionSuggestion( | |
| 119 CompletionSuggestionKind.LIBRARY_PREFIX, | |
| 120 CompletionRelevance.DEFAULT, | |
| 121 completion, | |
| 122 completion.length, | |
| 123 0, | |
| 124 element.isDeprecated, | |
| 125 false); | |
| 126 suggestion.element = new protocol.Element.fromEngine(lib); | |
| 127 request.suggestions.add(suggestion); | |
| 128 } | |
| 129 excludedLibs.add(lib); | |
| 130 } | |
| 131 } | |
| 132 } | |
| 133 }); | 126 }); |
| 134 | |
| 135 // Compute the set of possible classes, functions, and top level variables | |
| 136 matches.forEach((SearchMatch match) { | 127 matches.forEach((SearchMatch match) { |
| 137 if (match.kind == MatchKind.DECLARATION) { | 128 if (match.kind == MatchKind.DECLARATION) { |
| 138 Element element = match.element; | 129 Element element = match.element; |
| 139 LibraryElement lib = element.library; | 130 if (element.isPublic && |
| 140 if (element.isPublic && !excludedLibs.contains(lib)) { | 131 !excludedLibs.contains(element.library) && |
| 141 String completion = element.displayName; | 132 !completionSet.contains(element.displayName)) { |
| 142 Set<String> show = showNames[lib]; | 133 _addElementSuggestion(element, CompletionRelevance.LOW); |
| 143 Set<String> hide = hideNames[lib]; | |
| 144 if ((show == null || show.contains(completion)) && | |
| 145 (hide == null || !hide.contains(completion))) { | |
| 146 | |
| 147 CompletionSuggestionKind kind = | |
| 148 new CompletionSuggestionKind.fromElementKind(element.kind); | |
| 149 | |
| 150 CompletionRelevance relevance; | |
| 151 if (visibleLibs.contains(lib) || lib.isDartCore) { | |
| 152 relevance = CompletionRelevance.DEFAULT; | |
| 153 } else { | |
| 154 relevance = CompletionRelevance.LOW; | |
| 155 } | |
| 156 | |
| 157 CompletionSuggestion suggestion = new CompletionSuggestion( | |
| 158 kind, | |
| 159 relevance, | |
| 160 completion, | |
| 161 completion.length, | |
| 162 0, | |
| 163 element.isDeprecated, | |
| 164 false); | |
| 165 | |
| 166 suggestion.element = new protocol.Element.fromEngine(element); | |
| 167 | |
| 168 DartType type; | |
| 169 if (element is TopLevelVariableElement) { | |
| 170 type = element.type; | |
| 171 } else if (element is FunctionElement) { | |
| 172 type = element.returnType; | |
| 173 } | |
| 174 if (type != null) { | |
| 175 String name = type.displayName; | |
| 176 if (name != null && name.length > 0 && name != 'dynamic') { | |
| 177 suggestion.returnType = name; | |
| 178 } | |
| 179 } | |
| 180 | |
| 181 request.suggestions.add(suggestion); | |
| 182 } | |
| 183 } | 134 } |
| 184 } | 135 } |
| 185 }); | 136 }); |
| 186 return true; | 137 return true; |
| 187 }); | 138 }); |
| 188 } | 139 } |
| 140 |
| 141 void _addElementSuggestion(Element element, CompletionRelevance relevance) { |
| 142 CompletionSuggestionKind kind = |
| 143 new CompletionSuggestionKind.fromElementKind(element.kind); |
| 144 |
| 145 String completion = element.displayName; |
| 146 CompletionSuggestion suggestion = new CompletionSuggestion( |
| 147 kind, |
| 148 relevance, |
| 149 completion, |
| 150 completion.length, |
| 151 0, |
| 152 element.isDeprecated, |
| 153 false); |
| 154 |
| 155 suggestion.element = new protocol.Element.fromEngine(element); |
| 156 |
| 157 DartType type; |
| 158 if (element is FunctionElement) { |
| 159 type = element.returnType; |
| 160 } else if (element is PropertyAccessorElement && element.isGetter) { |
| 161 type = element.returnType; |
| 162 } else if (element is TopLevelVariableElement) { |
| 163 type = element.type; |
| 164 } |
| 165 if (type != null) { |
| 166 String name = type.displayName; |
| 167 if (name != null && name.length > 0 && name != 'dynamic') { |
| 168 suggestion.returnType = name; |
| 169 } |
| 170 } |
| 171 |
| 172 request.suggestions.add(suggestion); |
| 173 } |
| 174 |
| 175 void _addLibraryPrefixSuggestion(ImportElement importElem) { |
| 176 String completion = importElem.prefix.displayName; |
| 177 if (completion != null && completion.length > 0) { |
| 178 CompletionSuggestion suggestion = new CompletionSuggestion( |
| 179 CompletionSuggestionKind.LIBRARY_PREFIX, |
| 180 CompletionRelevance.DEFAULT, |
| 181 completion, |
| 182 completion.length, |
| 183 0, |
| 184 importElem.isDeprecated, |
| 185 false); |
| 186 LibraryElement lib = importElem.importedLibrary; |
| 187 if (lib != null) { |
| 188 suggestion.element = new protocol.Element.fromEngine(lib); |
| 189 } |
| 190 request.suggestions.add(suggestion); |
| 191 } |
| 192 } |
| 189 } | 193 } |
| OLD | NEW |