| 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 test.services.completion.dart; | 5 library services.completion.dart; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 | 8 |
| 9 import 'package:analysis_server/src/protocol.dart'; | 9 import 'package:analysis_server/src/protocol.dart'; |
| 10 import 'package:analysis_server/src/services/completion/arglist_computer.dart'; | 10 import 'package:analysis_server/src/services/completion/arglist_computer.dart'; |
| 11 import 'package:analysis_server/src/services/completion/combinator_computer.dart
'; | 11 import 'package:analysis_server/src/services/completion/combinator_computer.dart
'; |
| 12 import 'package:analysis_server/src/services/completion/completion_manager.dart'
; | 12 import 'package:analysis_server/src/services/completion/completion_manager.dart'
; |
| 13 import 'package:analysis_server/src/services/completion/imported_computer.dart'; | 13 import 'package:analysis_server/src/services/completion/imported_computer.dart'; |
| 14 import 'package:analysis_server/src/services/completion/invocation_computer.dart
'; | 14 import 'package:analysis_server/src/services/completion/invocation_computer.dart
'; |
| 15 import 'package:analysis_server/src/services/completion/keyword_computer.dart'; | 15 import 'package:analysis_server/src/services/completion/keyword_computer.dart'; |
| 16 import 'package:analysis_server/src/services/completion/local_computer.dart'; | 16 import 'package:analysis_server/src/services/completion/local_computer.dart'; |
| 17 import 'package:analysis_server/src/services/search/search_engine.dart'; | 17 import 'package:analysis_server/src/services/search/search_engine.dart'; |
| 18 import 'package:analyzer/src/generated/ast.dart'; | 18 import 'package:analyzer/src/generated/ast.dart'; |
| 19 import 'package:analyzer/src/generated/element.dart'; | 19 import 'package:analyzer/src/generated/element.dart'; |
| 20 import 'package:analyzer/src/generated/engine.dart'; | 20 import 'package:analyzer/src/generated/engine.dart'; |
| 21 import 'package:analyzer/src/generated/source.dart'; | 21 import 'package:analyzer/src/generated/source.dart'; |
| 22 | 22 |
| 23 /** | 23 /** |
| 24 * The `DartCompletionCache` contains cached information from a prior code |
| 25 * completion operation. |
| 26 */ |
| 27 class DartCompletionCache extends CompletionCache { |
| 28 |
| 29 /** |
| 30 * A hash of the import directives. |
| 31 */ |
| 32 String importKey; |
| 33 |
| 34 /** |
| 35 * Library prefix suggestions based upon imports, |
| 36 * or `null` if nothing has been cached. |
| 37 */ |
| 38 List<CompletionSuggestion> libraryPrefixSuggestions; |
| 39 |
| 40 /** |
| 41 * Type suggestions based upon imports, |
| 42 * or `null` if nothing has been cached. |
| 43 */ |
| 44 List<CompletionSuggestion> importedTypeSuggestions; |
| 45 |
| 46 /** |
| 47 * Suggestions for methods and functions that have void return type, |
| 48 * or `null` if nothing has been cached. |
| 49 */ |
| 50 List<CompletionSuggestion> importedVoidReturnSuggestions; |
| 51 |
| 52 /** |
| 53 * Other suggestions based upon imports, |
| 54 * or `null` if nothing has been cached. |
| 55 */ |
| 56 List<CompletionSuggestion> otherImportedSuggestions; |
| 57 |
| 58 DartCompletionCache(AnalysisContext context, Source source) |
| 59 : super(context, source); |
| 60 } |
| 61 |
| 62 /** |
| 24 * The base class for computing code completion suggestions. | 63 * The base class for computing code completion suggestions. |
| 25 */ | 64 */ |
| 26 abstract class DartCompletionComputer { | 65 abstract class DartCompletionComputer { |
| 27 /** | 66 /** |
| 28 * Computes the initial set of [CompletionSuggestion]s based on | 67 * Computes the initial set of [CompletionSuggestion]s based on |
| 29 * the given completion context. The compilation unit and completion node | 68 * the given completion context. The compilation unit and completion node |
| 30 * in the given completion context may not be resolved. | 69 * in the given completion context may not be resolved. |
| 31 * This method should execute quickly and not block waiting for any analysis. | 70 * This method should execute quickly and not block waiting for any analysis. |
| 32 * Returns `true` if the computer's work is complete | 71 * Returns `true` if the computer's work is complete |
| 33 * or `false` if [computeFull] should be called to complete the work. | 72 * or `false` if [computeFull] should be called to complete the work. |
| 34 */ | 73 */ |
| 35 bool computeFast(DartCompletionRequest request); | 74 bool computeFast(DartCompletionRequest request); |
| 36 | 75 |
| 37 /** | 76 /** |
| 38 * Computes the complete set of [CompletionSuggestion]s based on | 77 * Computes the complete set of [CompletionSuggestion]s based on |
| 39 * the given completion context. The compilation unit and completion node | 78 * the given completion context. The compilation unit and completion node |
| 40 * in the given completion context are resolved. | 79 * in the given completion context are resolved. |
| 41 * Returns `true` if the receiver modified the list of suggestions. | 80 * Returns `true` if the receiver modified the list of suggestions. |
| 42 */ | 81 */ |
| 43 Future<bool> computeFull(DartCompletionRequest request); | 82 Future<bool> computeFull(DartCompletionRequest request); |
| 44 } | 83 } |
| 45 | 84 |
| 46 /** | 85 /** |
| 47 * Manages code completion for a given Dart file completion request. | 86 * Manages code completion for a given Dart file completion request. |
| 48 */ | 87 */ |
| 49 class DartCompletionManager extends CompletionManager { | 88 class DartCompletionManager extends CompletionManager { |
| 89 final DartCompletionRequest request; |
| 50 final AnalysisContext context; | 90 final AnalysisContext context; |
| 51 final Source source; | 91 final Source source; |
| 52 final int offset; | 92 final int offset; |
| 53 final CompletionPerformance performance; | 93 final CompletionPerformance performance; |
| 54 DartCompletionRequest request; | 94 final DartCompletionCache cache; |
| 55 List<DartCompletionComputer> computers; | 95 List<DartCompletionComputer> computers; |
| 56 | 96 |
| 57 DartCompletionManager(this.context, SearchEngine searchEngine, this.source, | 97 DartCompletionManager(this.request, this.context, this.source, this.offset, |
| 58 this.offset, this.performance) { | 98 this.cache, this.performance) |
| 59 request = new DartCompletionRequest(context, searchEngine, source, offset); | 99 : computers = [ |
| 100 new KeywordComputer(), |
| 101 new LocalComputer(), |
| 102 new ArgListComputer(), |
| 103 new CombinatorComputer(), |
| 104 new ImportedComputer(), |
| 105 new InvocationComputer()]; |
| 106 |
| 107 /** |
| 108 * Create a new initialized Dart source completion manager |
| 109 */ |
| 110 factory DartCompletionManager.create(AnalysisContext context, |
| 111 SearchEngine searchEngine, Source source, int offset, CompletionCache oldC
ache, |
| 112 CompletionPerformance performance) { |
| 113 DartCompletionCache newCache; |
| 114 if (oldCache is DartCompletionCache) { |
| 115 if (oldCache.context == context && oldCache.source == source) { |
| 116 newCache = oldCache; |
| 117 } |
| 118 } |
| 119 if (newCache == null) { |
| 120 newCache = new DartCompletionCache(context, source); |
| 121 } |
| 122 return new DartCompletionManager( |
| 123 new DartCompletionRequest(context, searchEngine, source, offset, newCach
e), |
| 124 context, |
| 125 source, |
| 126 offset, |
| 127 newCache, |
| 128 performance); |
| 60 } | 129 } |
| 61 | 130 |
| 62 @override | 131 @override |
| 132 CompletionCache get completionCache => cache; |
| 133 |
| 134 @override |
| 63 void compute() { | 135 void compute() { |
| 64 performance.logElapseTime('compute', () { | 136 performance.logElapseTime('compute', () { |
| 65 initComputers(); | |
| 66 computeFast(); | 137 computeFast(); |
| 67 if (!computers.isEmpty) { | 138 if (!computers.isEmpty) { |
| 68 computeFull(); | 139 computeFull(); |
| 69 } | 140 } |
| 70 }); | 141 }); |
| 71 } | 142 } |
| 72 | 143 |
| 73 /** | 144 /** |
| 74 * Compute suggestions based upon cached information only | 145 * Compute suggestions based upon cached information only |
| 75 * then send an initial response to the client. | 146 * then send an initial response to the client. |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 117 sendResults(last); | 188 sendResults(last); |
| 118 } | 189 } |
| 119 }); | 190 }); |
| 120 }); | 191 }); |
| 121 }); | 192 }); |
| 122 }); | 193 }); |
| 123 }); | 194 }); |
| 124 } | 195 } |
| 125 | 196 |
| 126 /** | 197 /** |
| 127 * Build and initialize the list of completion computers | |
| 128 */ | |
| 129 void initComputers() { | |
| 130 if (computers == null) { | |
| 131 computers = [ | |
| 132 new KeywordComputer(), | |
| 133 new LocalComputer(), | |
| 134 new ArgListComputer(), | |
| 135 new CombinatorComputer(), | |
| 136 new ImportedComputer(), | |
| 137 new InvocationComputer()]; | |
| 138 } | |
| 139 } | |
| 140 | |
| 141 /** | |
| 142 * Send the current list of suggestions to the client. | 198 * Send the current list of suggestions to the client. |
| 143 */ | 199 */ |
| 144 void sendResults(bool last) { | 200 void sendResults(bool last) { |
| 145 controller.add( | 201 controller.add( |
| 146 new CompletionResult( | 202 new CompletionResult( |
| 147 request.replacementOffset, | 203 request.replacementOffset, |
| 148 request.replacementLength, | 204 request.replacementLength, |
| 149 request.suggestions, | 205 request.suggestions, |
| 150 last)); | 206 last)); |
| 151 if (last) { | 207 if (last) { |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 189 * The source in which the completion is requested. | 245 * The source in which the completion is requested. |
| 190 */ | 246 */ |
| 191 final Source source; | 247 final Source source; |
| 192 | 248 |
| 193 /** | 249 /** |
| 194 * The offset within the source at which the completion is requested. | 250 * The offset within the source at which the completion is requested. |
| 195 */ | 251 */ |
| 196 final int offset; | 252 final int offset; |
| 197 | 253 |
| 198 /** | 254 /** |
| 255 * Cached information from a prior code completion operation. |
| 256 */ |
| 257 final DartCompletionCache cache; |
| 258 |
| 259 /** |
| 199 * The compilation unit in which the completion was requested. This unit | 260 * The compilation unit in which the completion was requested. This unit |
| 200 * may or may not be resolved when [DartCompletionComputer.computeFast] | 261 * may or may not be resolved when [DartCompletionComputer.computeFast] |
| 201 * is called but is resolved when [DartCompletionComputer.computeFull]. | 262 * is called but is resolved when [DartCompletionComputer.computeFull]. |
| 202 */ | 263 */ |
| 203 CompilationUnit unit; | 264 CompilationUnit unit; |
| 204 | 265 |
| 205 /** | 266 /** |
| 206 * The node in which the completion occurred. This node | 267 * The node in which the completion occurred. This node |
| 207 * may or may not be resolved when [DartCompletionComputer.computeFast] | 268 * may or may not be resolved when [DartCompletionComputer.computeFast] |
| 208 * is called but is resolved when [DartCompletionComputer.computeFull]. | 269 * is called but is resolved when [DartCompletionComputer.computeFull]. |
| (...skipping 12 matching lines...) Expand all Loading... |
| 221 /** | 282 /** |
| 222 * The length of the text to be replaced if the remainder of the identifier | 283 * The length of the text to be replaced if the remainder of the identifier |
| 223 * containing the cursor is to be replaced when the suggestion is applied | 284 * containing the cursor is to be replaced when the suggestion is applied |
| 224 * (that is, the number of characters in the existing identifier). | 285 * (that is, the number of characters in the existing identifier). |
| 225 */ | 286 */ |
| 226 int replacementLength; | 287 int replacementLength; |
| 227 | 288 |
| 228 /** | 289 /** |
| 229 * The list of suggestions to be sent to the client. | 290 * The list of suggestions to be sent to the client. |
| 230 */ | 291 */ |
| 231 final List<CompletionSuggestion> suggestions = []; | 292 final List<CompletionSuggestion> suggestions = <CompletionSuggestion>[]; |
| 232 | 293 |
| 233 DartCompletionRequest(this.context, this.searchEngine, this.source, | 294 DartCompletionRequest(this.context, this.searchEngine, this.source, |
| 234 this.offset); | 295 this.offset, this.cache); |
| 235 } | 296 } |
| 236 | 297 |
| 237 /** | 298 /** |
| 238 * Visitor used to determine the replacement offset and length | 299 * Visitor used to determine the replacement offset and length |
| 239 * based upon the cursor location. | 300 * based upon the cursor location. |
| 240 */ | 301 */ |
| 241 class _ReplacementOffsetBuilder extends SimpleAstVisitor { | 302 class _ReplacementOffsetBuilder extends SimpleAstVisitor { |
| 242 final DartCompletionRequest request; | 303 final DartCompletionRequest request; |
| 243 | 304 |
| 244 _ReplacementOffsetBuilder(this.request) { | 305 _ReplacementOffsetBuilder(this.request) { |
| 245 request.replacementOffset = request.offset; | 306 request.replacementOffset = request.offset; |
| 246 request.replacementLength = 0; | 307 request.replacementLength = 0; |
| 247 } | 308 } |
| 248 | 309 |
| 249 visitSimpleIdentifier(SimpleIdentifier node) { | 310 visitSimpleIdentifier(SimpleIdentifier node) { |
| 250 request.replacementOffset = node.offset; | 311 request.replacementOffset = node.offset; |
| 251 request.replacementLength = node.length; | 312 request.replacementLength = node.length; |
| 252 } | 313 } |
| 253 } | 314 } |
| OLD | NEW |