| 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 import 'dart:collection'; | 8 import 'dart:collection'; |
| 9 | 9 |
| 10 import 'package:analysis_server/src/protocol_server.dart' | 10 import 'package:analysis_server/src/protocol_server.dart' |
| (...skipping 11 matching lines...) Expand all Loading... |
| 22 */ | 22 */ |
| 23 class ImportedComputer extends DartCompletionComputer { | 23 class ImportedComputer extends DartCompletionComputer { |
| 24 bool shouldWaitForLowPrioritySuggestions; | 24 bool shouldWaitForLowPrioritySuggestions; |
| 25 _ImportedSuggestionBuilder builder; | 25 _ImportedSuggestionBuilder builder; |
| 26 | 26 |
| 27 ImportedComputer({this.shouldWaitForLowPrioritySuggestions: false}); | 27 ImportedComputer({this.shouldWaitForLowPrioritySuggestions: false}); |
| 28 | 28 |
| 29 @override | 29 @override |
| 30 bool computeFast(DartCompletionRequest request) { | 30 bool computeFast(DartCompletionRequest request) { |
| 31 OpType optype = request.optype; | 31 OpType optype = request.optype; |
| 32 if (optype.includeTopLevelSuggestions) { | 32 if (optype.includeTopLevelSuggestions || |
| 33 optype.includeConstructorSuggestions) { |
| 33 builder = new _ImportedSuggestionBuilder(request, | 34 builder = new _ImportedSuggestionBuilder(request, |
| 34 typesOnly: optype.includeOnlyTypeNameSuggestions, | 35 typesOnly: optype.includeOnlyTypeNameSuggestions, |
| 35 excludeVoidReturn: !optype.includeVoidReturnSuggestions); | 36 excludeVoidReturn: !optype.includeVoidReturnSuggestions, |
| 37 constructorsOnly: optype.includeConstructorSuggestions); |
| 36 builder.shouldWaitForLowPrioritySuggestions = | 38 builder.shouldWaitForLowPrioritySuggestions = |
| 37 shouldWaitForLowPrioritySuggestions; | 39 shouldWaitForLowPrioritySuggestions; |
| 38 return builder.computeFast(request.node); | 40 return builder.computeFast(request.node); |
| 39 } | 41 } |
| 40 return true; | 42 return true; |
| 41 } | 43 } |
| 42 | 44 |
| 43 @override | 45 @override |
| 44 Future<bool> computeFull(DartCompletionRequest request) { | 46 Future<bool> computeFull(DartCompletionRequest request) { |
| 45 if (builder != null) { | 47 if (builder != null) { |
| 46 return builder.computeFull(request.node); | 48 return builder.computeFull(request.node); |
| 47 } | 49 } |
| 48 return new Future.value(false); | 50 return new Future.value(false); |
| 49 } | 51 } |
| 50 } | 52 } |
| 51 | 53 |
| 52 /** | 54 /** |
| 53 * [_ImportedSuggestionBuilder] traverses the imports and builds suggestions | 55 * [_ImportedSuggestionBuilder] traverses the imports and builds suggestions |
| 54 * based upon imported elements. | 56 * based upon imported elements. |
| 55 */ | 57 */ |
| 56 class _ImportedSuggestionBuilder extends ElementSuggestionBuilder | 58 class _ImportedSuggestionBuilder extends ElementSuggestionBuilder |
| 57 implements SuggestionBuilder { | 59 implements SuggestionBuilder { |
| 58 bool shouldWaitForLowPrioritySuggestions; | 60 bool shouldWaitForLowPrioritySuggestions; |
| 59 final DartCompletionRequest request; | 61 final DartCompletionRequest request; |
| 60 final bool typesOnly; | 62 final bool typesOnly; |
| 61 final bool excludeVoidReturn; | 63 final bool excludeVoidReturn; |
| 64 final bool constructorsOnly; |
| 62 DartCompletionCache cache; | 65 DartCompletionCache cache; |
| 63 | 66 |
| 64 _ImportedSuggestionBuilder(this.request, | 67 _ImportedSuggestionBuilder(this.request, {this.typesOnly: false, |
| 65 {this.typesOnly: false, this.excludeVoidReturn: false}) { | 68 this.excludeVoidReturn: false, this.constructorsOnly: false}) { |
| 66 cache = request.cache; | 69 cache = request.cache; |
| 67 } | 70 } |
| 68 | 71 |
| 69 @override | 72 @override |
| 70 CompletionSuggestionKind get kind => CompletionSuggestionKind.INVOCATION; | 73 CompletionSuggestionKind get kind => CompletionSuggestionKind.INVOCATION; |
| 71 | 74 |
| 72 /** | 75 /** |
| 73 * If the needed information is cached, then add suggestions and return `true` | 76 * If the needed information is cached, then add suggestions and return `true` |
| 74 * else return `false` indicating that additional work is necessary. | 77 * else return `false` indicating that additional work is necessary. |
| 75 */ | 78 */ |
| 76 bool computeFast(AstNode node) { | 79 bool computeFast(AstNode node) { |
| 77 CompilationUnit unit = request.unit; | 80 CompilationUnit unit = request.unit; |
| 78 if (cache.isImportInfoCached(unit)) { | 81 if (cache.isImportInfoCached(unit)) { |
| 79 _addInheritedSuggestions(node); | 82 _addSuggestions(node); |
| 80 _addTopLevelSuggestions(); | |
| 81 return true; | 83 return true; |
| 82 } | 84 } |
| 83 return false; | 85 return false; |
| 84 } | 86 } |
| 85 | 87 |
| 86 /** | 88 /** |
| 87 * Compute suggested based upon imported elements. | 89 * Compute suggested based upon imported elements. |
| 88 */ | 90 */ |
| 89 Future<bool> computeFull(AstNode node) { | 91 Future<bool> computeFull(AstNode node) { |
| 90 Future<bool> addSuggestions(_) { | 92 Future<bool> addSuggestions(_) { |
| 91 _addInheritedSuggestions(node); | 93 _addSuggestions(node); |
| 92 _addTopLevelSuggestions(); | |
| 93 return new Future.value(true); | 94 return new Future.value(true); |
| 94 } | 95 } |
| 95 | 96 |
| 96 Future future = null; | 97 Future future = null; |
| 97 if (!cache.isImportInfoCached(request.unit)) { | 98 if (!cache.isImportInfoCached(request.unit)) { |
| 98 future = cache.computeImportInfo(request.unit, request.searchEngine, | 99 future = cache.computeImportInfo(request.unit, request.searchEngine, |
| 99 shouldWaitForLowPrioritySuggestions); | 100 shouldWaitForLowPrioritySuggestions); |
| 100 } | 101 } |
| 101 if (future != null) { | 102 if (future != null) { |
| 102 return future.then(addSuggestions); | 103 return future.then(addSuggestions); |
| 103 } | 104 } |
| 104 return addSuggestions(true); | 105 return addSuggestions(true); |
| 105 } | 106 } |
| 106 | 107 |
| 107 /** | 108 /** |
| 109 * Add constructor suggestions from the cache. |
| 110 * To reduce the number of suggestions sent to the client, |
| 111 * filter the suggestions based upon the first character typed. |
| 112 * If no characters are available to use for filtering, |
| 113 * then exclude all low priority suggestions. |
| 114 */ |
| 115 void _addConstructorSuggestions() { |
| 116 String filterText = request.filterText; |
| 117 if (filterText.length > 1) { |
| 118 filterText = filterText.substring(0, 1); |
| 119 } |
| 120 DartCompletionCache cache = request.cache; |
| 121 _addFilteredSuggestions(filterText, cache.importedConstructorSuggestions); |
| 122 } |
| 123 |
| 124 /** |
| 108 * Add imported element suggestions. | 125 * Add imported element suggestions. |
| 109 */ | 126 */ |
| 110 void _addElementSuggestions(List<Element> elements, | 127 void _addElementSuggestions(List<Element> elements, |
| 111 {int relevance: DART_RELEVANCE_DEFAULT}) { | 128 {int relevance: DART_RELEVANCE_DEFAULT}) { |
| 112 elements.forEach((Element elem) { | 129 elements.forEach((Element elem) { |
| 113 if (elem is! ClassElement) { | 130 if (elem is! ClassElement) { |
| 114 if (typesOnly) { | 131 if (typesOnly) { |
| 115 return; | 132 return; |
| 116 } | 133 } |
| 117 if (elem is ExecutableElement) { | 134 if (elem is ExecutableElement) { |
| 118 DartType returnType = elem.returnType; | 135 DartType returnType = elem.returnType; |
| 119 if (returnType != null && returnType.isVoid) { | 136 if (returnType != null && returnType.isVoid) { |
| 120 if (excludeVoidReturn) { | 137 if (excludeVoidReturn) { |
| 121 return; | 138 return; |
| 122 } | 139 } |
| 123 } | 140 } |
| 124 } | 141 } |
| 125 } | 142 } |
| 126 addSuggestion(elem, relevance: relevance); | 143 addSuggestion(elem, relevance: relevance); |
| 127 }); | 144 }); |
| 128 } | 145 } |
| 129 | 146 |
| 130 /** | 147 /** |
| 148 * Add suggestions which start with the given text. |
| 149 */ |
| 150 _addFilteredSuggestions( |
| 151 String filterText, List<CompletionSuggestion> unfiltered) { |
| 152 //TODO (danrubel) Revisit this filtering once paged API has been added |
| 153 unfiltered.forEach((CompletionSuggestion suggestion) { |
| 154 if (filterText.length > 0) { |
| 155 if (suggestion.completion.startsWith(filterText)) { |
| 156 request.suggestions.add(suggestion); |
| 157 } |
| 158 } else { |
| 159 if (suggestion.relevance != DART_RELEVANCE_LOW) { |
| 160 request.suggestions.add(suggestion); |
| 161 } |
| 162 } |
| 163 }); |
| 164 } |
| 165 |
| 166 /** |
| 131 * Add suggestions for any inherited imported members. | 167 * Add suggestions for any inherited imported members. |
| 132 */ | 168 */ |
| 133 void _addInheritedSuggestions(AstNode node) { | 169 void _addInheritedSuggestions(AstNode node) { |
| 134 var classDecl = node.getAncestor((p) => p is ClassDeclaration); | 170 var classDecl = node.getAncestor((p) => p is ClassDeclaration); |
| 135 if (classDecl is ClassDeclaration) { | 171 if (classDecl is ClassDeclaration) { |
| 136 // Build a list of inherited types that are imported | 172 // Build a list of inherited types that are imported |
| 137 // and include any inherited imported members | 173 // and include any inherited imported members |
| 138 List<String> inheritedTypes = new List<String>(); | 174 List<String> inheritedTypes = new List<String>(); |
| 139 visitInheritedTypes(classDecl, (_) { | 175 visitInheritedTypes(classDecl, (_) { |
| 140 // local declarations are handled by the local computer | 176 // local declarations are handled by the local computer |
| (...skipping 20 matching lines...) Expand all Loading... |
| 161 _addElementSuggestions(type.element.methods, | 197 _addElementSuggestions(type.element.methods, |
| 162 relevance: DART_RELEVANCE_INHERITED_METHOD); | 198 relevance: DART_RELEVANCE_INHERITED_METHOD); |
| 163 } | 199 } |
| 164 }); | 200 }); |
| 165 } | 201 } |
| 166 } | 202 } |
| 167 } | 203 } |
| 168 } | 204 } |
| 169 | 205 |
| 170 /** | 206 /** |
| 207 * Add suggested based upon imported elements. |
| 208 */ |
| 209 void _addSuggestions(AstNode node) { |
| 210 if (constructorsOnly) { |
| 211 _addConstructorSuggestions(); |
| 212 } else { |
| 213 _addInheritedSuggestions(node); |
| 214 _addTopLevelSuggestions(); |
| 215 } |
| 216 } |
| 217 |
| 218 /** |
| 171 * Add top level suggestions from the cache. | 219 * Add top level suggestions from the cache. |
| 172 * To reduce the number of suggestions sent to the client, | 220 * To reduce the number of suggestions sent to the client, |
| 173 * filter the suggestions based upon the first character typed. | 221 * filter the suggestions based upon the first character typed. |
| 174 * If no characters are available to use for filtering, | 222 * If no characters are available to use for filtering, |
| 175 * then exclude all low priority suggestions. | 223 * then exclude all low priority suggestions. |
| 176 */ | 224 */ |
| 177 void _addTopLevelSuggestions() { | 225 void _addTopLevelSuggestions() { |
| 178 String filterText = request.filterText; | 226 String filterText = request.filterText; |
| 179 if (filterText.length > 1) { | 227 if (filterText.length > 1) { |
| 180 filterText = filterText.substring(0, 1); | 228 filterText = filterText.substring(0, 1); |
| 181 } | 229 } |
| 182 | |
| 183 //TODO (danrubel) Revisit this filtering once paged API has been added | |
| 184 addFilteredSuggestions(List<CompletionSuggestion> unfiltered) { | |
| 185 unfiltered.forEach((CompletionSuggestion suggestion) { | |
| 186 if (filterText.length > 0) { | |
| 187 if (suggestion.completion.startsWith(filterText)) { | |
| 188 request.suggestions.add(suggestion); | |
| 189 } | |
| 190 } else { | |
| 191 if (suggestion.relevance != DART_RELEVANCE_LOW) { | |
| 192 request.suggestions.add(suggestion); | |
| 193 } | |
| 194 } | |
| 195 }); | |
| 196 } | |
| 197 | |
| 198 DartCompletionCache cache = request.cache; | 230 DartCompletionCache cache = request.cache; |
| 199 addFilteredSuggestions(cache.importedTypeSuggestions); | 231 _addFilteredSuggestions(filterText, cache.importedTypeSuggestions); |
| 200 addFilteredSuggestions(cache.libraryPrefixSuggestions); | 232 _addFilteredSuggestions(filterText, cache.libraryPrefixSuggestions); |
| 201 if (!typesOnly) { | 233 if (!typesOnly) { |
| 202 addFilteredSuggestions(cache.otherImportedSuggestions); | 234 _addFilteredSuggestions(filterText, cache.otherImportedSuggestions); |
| 203 if (!excludeVoidReturn) { | 235 if (!excludeVoidReturn) { |
| 204 addFilteredSuggestions(cache.importedVoidReturnSuggestions); | 236 _addFilteredSuggestions( |
| 237 filterText, cache.importedVoidReturnSuggestions); |
| 205 } | 238 } |
| 206 } | 239 } |
| 207 } | 240 } |
| 208 } | 241 } |
| OLD | NEW |