| 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.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'; |
| (...skipping 23 matching lines...) Expand all Loading... |
| 34 const int DART_RELEVANCE_LOCAL_ACCESSOR = 1057; | 34 const int DART_RELEVANCE_LOCAL_ACCESSOR = 1057; |
| 35 const int DART_RELEVANCE_LOCAL_FIELD = 1058; | 35 const int DART_RELEVANCE_LOCAL_FIELD = 1058; |
| 36 const int DART_RELEVANCE_LOCAL_FUNCTION = 1056; | 36 const int DART_RELEVANCE_LOCAL_FUNCTION = 1056; |
| 37 const int DART_RELEVANCE_LOCAL_METHOD = 1057; | 37 const int DART_RELEVANCE_LOCAL_METHOD = 1057; |
| 38 const int DART_RELEVANCE_LOCAL_TOP_LEVEL_VARIABLE = 1056; | 38 const int DART_RELEVANCE_LOCAL_TOP_LEVEL_VARIABLE = 1056; |
| 39 const int DART_RELEVANCE_LOCAL_VARIABLE = 1059; | 39 const int DART_RELEVANCE_LOCAL_VARIABLE = 1059; |
| 40 const int DART_RELEVANCE_LOW = 500; | 40 const int DART_RELEVANCE_LOW = 500; |
| 41 const int DART_RELEVANCE_PARAMETER = 1059; | 41 const int DART_RELEVANCE_PARAMETER = 1059; |
| 42 | 42 |
| 43 /** | 43 /** |
| 44 * The base class for computing code completion suggestions. | 44 * The base class for contributing code completion suggestions. |
| 45 */ | 45 */ |
| 46 abstract class DartCompletionComputer { | 46 abstract class DartCompletionContributor { |
| 47 /** | 47 /** |
| 48 * Computes the initial set of [CompletionSuggestion]s based on | 48 * Computes the initial set of [CompletionSuggestion]s based on |
| 49 * the given completion context. The compilation unit and completion node | 49 * the given completion context. The compilation unit and completion node |
| 50 * in the given completion context may not be resolved. | 50 * in the given completion context may not be resolved. |
| 51 * This method should execute quickly and not block waiting for any analysis. | 51 * This method should execute quickly and not block waiting for any analysis. |
| 52 * Returns `true` if the computer's work is complete | 52 * Returns `true` if the contributor's work is complete |
| 53 * or `false` if [computeFull] should be called to complete the work. | 53 * or `false` if [computeFull] should be called to complete the work. |
| 54 */ | 54 */ |
| 55 bool computeFast(DartCompletionRequest request); | 55 bool computeFast(DartCompletionRequest request); |
| 56 | 56 |
| 57 /** | 57 /** |
| 58 * Computes the complete set of [CompletionSuggestion]s based on | 58 * Computes the complete set of [CompletionSuggestion]s based on |
| 59 * the given completion context. The compilation unit and completion node | 59 * the given completion context. The compilation unit and completion node |
| 60 * in the given completion context are resolved. | 60 * in the given completion context are resolved. |
| 61 * Returns `true` if the receiver modified the list of suggestions. | 61 * Returns `true` if the receiver modified the list of suggestions. |
| 62 */ | 62 */ |
| 63 Future<bool> computeFull(DartCompletionRequest request); | 63 Future<bool> computeFull(DartCompletionRequest request); |
| 64 } | 64 } |
| 65 | 65 |
| 66 /** | 66 /** |
| 67 * Manages code completion for a given Dart file completion request. | 67 * Manages code completion for a given Dart file completion request. |
| 68 */ | 68 */ |
| 69 class DartCompletionManager extends CompletionManager { | 69 class DartCompletionManager extends CompletionManager { |
| 70 final SearchEngine searchEngine; | 70 final SearchEngine searchEngine; |
| 71 final DartCompletionCache cache; | 71 final DartCompletionCache cache; |
| 72 List<DartCompletionComputer> computers; | 72 List<DartCompletionContributor> contributors; |
| 73 CommonUsageComputer commonUsageComputer; | 73 CommonUsageComputer commonUsageComputer; |
| 74 | 74 |
| 75 DartCompletionManager( | 75 DartCompletionManager( |
| 76 AnalysisContext context, this.searchEngine, Source source, this.cache, | 76 AnalysisContext context, this.searchEngine, Source source, this.cache, |
| 77 [this.computers, this.commonUsageComputer]) | 77 [this.contributors, this.commonUsageComputer]) |
| 78 : super(context, source) { | 78 : super(context, source) { |
| 79 if (computers == null) { | 79 if (contributors == null) { |
| 80 computers = [ | 80 contributors = [ |
| 81 // LocalComputer before ImportedComputer | 81 // LocalReferenceContributor before ImportedReferenceContributor |
| 82 // because local suggestions take precedence | 82 // because local suggestions take precedence |
| 83 new LocalComputer(), | 83 // and can hide other suggestions with the same name |
| 84 new ImportedComputer(), | 84 new LocalReferenceContributor(), |
| 85 new KeywordComputer(), | 85 new ImportedReferenceContributor(), |
| 86 new ArgListComputer(), | 86 new KeywordContributor(), |
| 87 new CombinatorComputer(), | 87 new ArgListContributor(), |
| 88 new InvocationComputer() | 88 new CombinatorContributor(), |
| 89 new PrefixedElementContributor() |
| 89 ]; | 90 ]; |
| 90 } | 91 } |
| 91 if (commonUsageComputer == null) { | 92 if (commonUsageComputer == null) { |
| 92 commonUsageComputer = new CommonUsageComputer(); | 93 commonUsageComputer = new CommonUsageComputer(); |
| 93 } | 94 } |
| 94 } | 95 } |
| 95 | 96 |
| 96 /** | 97 /** |
| 97 * Create a new initialized Dart source completion manager | 98 * Create a new initialized Dart source completion manager |
| 98 */ | 99 */ |
| (...skipping 10 matching lines...) Expand all Loading... |
| 109 return cache.computeImportInfo(unit, searchEngine, true); | 110 return cache.computeImportInfo(unit, searchEngine, true); |
| 110 } else { | 111 } else { |
| 111 return new Future.value(false); | 112 return new Future.value(false); |
| 112 } | 113 } |
| 113 }); | 114 }); |
| 114 } | 115 } |
| 115 | 116 |
| 116 /** | 117 /** |
| 117 * Compute suggestions based upon cached information only | 118 * Compute suggestions based upon cached information only |
| 118 * then send an initial response to the client. | 119 * then send an initial response to the client. |
| 119 * Return a list of computers for which [computeFull] should be called | 120 * Return a list of contributors for which [computeFull] should be called |
| 120 */ | 121 */ |
| 121 List<DartCompletionComputer> computeFast(DartCompletionRequest request) { | 122 List<DartCompletionContributor> computeFast(DartCompletionRequest request) { |
| 122 return request.performance.logElapseTime('computeFast', () { | 123 return request.performance.logElapseTime('computeFast', () { |
| 123 CompilationUnit unit = context.parseCompilationUnit(source); | 124 CompilationUnit unit = context.parseCompilationUnit(source); |
| 124 request.unit = unit; | 125 request.unit = unit; |
| 125 request.target = new CompletionTarget.forOffset(unit, request.offset); | 126 request.target = new CompletionTarget.forOffset(unit, request.offset); |
| 126 request.replacementOffset = request.offset; | 127 request.replacementOffset = request.offset; |
| 127 request.replacementLength = 0; | 128 request.replacementLength = 0; |
| 128 if (request.offset < 0 || request.offset > unit.end) { | 129 if (request.offset < 0 || request.offset > unit.end) { |
| 129 sendResults(request, true); | 130 sendResults(request, true); |
| 130 return []; | 131 return []; |
| 131 } | 132 } |
| 132 | 133 |
| 133 var entity = request.target.entity; | 134 var entity = request.target.entity; |
| 134 Token token = entity is AstNode ? entity.beginToken : entity; | 135 Token token = entity is AstNode ? entity.beginToken : entity; |
| 135 if (token != null && | 136 if (token != null && |
| 136 token.offset <= request.offset && | 137 token.offset <= request.offset && |
| 137 (token.type == TokenType.KEYWORD || | 138 (token.type == TokenType.KEYWORD || |
| 138 token.type == TokenType.IDENTIFIER)) { | 139 token.type == TokenType.IDENTIFIER)) { |
| 139 request.replacementOffset = token.offset; | 140 request.replacementOffset = token.offset; |
| 140 request.replacementLength = token.length; | 141 request.replacementLength = token.length; |
| 141 } | 142 } |
| 142 | 143 |
| 143 List<DartCompletionComputer> todo = new List.from(computers); | 144 List<DartCompletionContributor> todo = new List.from(contributors); |
| 144 todo.removeWhere((DartCompletionComputer c) { | 145 todo.removeWhere((DartCompletionContributor c) { |
| 145 return request.performance.logElapseTime('computeFast ${c.runtimeType}', | 146 return request.performance.logElapseTime('computeFast ${c.runtimeType}', |
| 146 () { | 147 () { |
| 147 return c.computeFast(request); | 148 return c.computeFast(request); |
| 148 }); | 149 }); |
| 149 }); | 150 }); |
| 150 commonUsageComputer.computeFast(request); | 151 commonUsageComputer.computeFast(request); |
| 151 sendResults(request, todo.isEmpty); | 152 sendResults(request, todo.isEmpty); |
| 152 return todo; | 153 return todo; |
| 153 }); | 154 }); |
| 154 } | 155 } |
| 155 | 156 |
| 156 /** | 157 /** |
| 157 * If there is remaining work to be done, then wait for the unit to be | 158 * If there is remaining work to be done, then wait for the unit to be |
| 158 * resolved and request that each remaining computer finish their work. | 159 * resolved and request that each remaining contributor finish their work. |
| 159 * Return a [Future] that completes when the last notification has been sent. | 160 * Return a [Future] that completes when the last notification has been sent. |
| 160 */ | 161 */ |
| 161 Future computeFull( | 162 Future computeFull( |
| 162 DartCompletionRequest request, List<DartCompletionComputer> todo) { | 163 DartCompletionRequest request, List<DartCompletionContributor> todo) { |
| 163 request.performance.logStartTime('waitForAnalysis'); | 164 request.performance.logStartTime('waitForAnalysis'); |
| 164 return waitForAnalysis().then((CompilationUnit unit) { | 165 return waitForAnalysis().then((CompilationUnit unit) { |
| 165 if (controller.isClosed) { | 166 if (controller.isClosed) { |
| 166 return; | 167 return; |
| 167 } | 168 } |
| 168 request.performance.logElapseTime('waitForAnalysis'); | 169 request.performance.logElapseTime('waitForAnalysis'); |
| 169 if (unit == null) { | 170 if (unit == null) { |
| 170 sendResults(request, true); | 171 sendResults(request, true); |
| 171 return; | 172 return; |
| 172 } | 173 } |
| 173 request.performance.logElapseTime('computeFull', () { | 174 request.performance.logElapseTime('computeFull', () { |
| 174 request.unit = unit; | 175 request.unit = unit; |
| 175 // TODO(paulberry): Do we need to invoke _ReplacementOffsetBuilder | 176 // TODO(paulberry): Do we need to invoke _ReplacementOffsetBuilder |
| 176 // again? | 177 // again? |
| 177 request.target = new CompletionTarget.forOffset(unit, request.offset); | 178 request.target = new CompletionTarget.forOffset(unit, request.offset); |
| 178 int count = todo.length; | 179 int count = todo.length; |
| 179 todo.forEach((DartCompletionComputer c) { | 180 todo.forEach((DartCompletionContributor c) { |
| 180 String name = c.runtimeType.toString(); | 181 String name = c.runtimeType.toString(); |
| 181 String completeTag = 'computeFull $name complete'; | 182 String completeTag = 'computeFull $name complete'; |
| 182 request.performance.logStartTime(completeTag); | 183 request.performance.logStartTime(completeTag); |
| 183 request.performance.logElapseTime('computeFull $name', () { | 184 request.performance.logElapseTime('computeFull $name', () { |
| 184 c.computeFull(request).then((bool changed) { | 185 c.computeFull(request).then((bool changed) { |
| 185 request.performance.logElapseTime(completeTag); | 186 request.performance.logElapseTime(completeTag); |
| 186 bool last = --count == 0; | 187 bool last = --count == 0; |
| 187 if (changed || last) { | 188 if (changed || last) { |
| 188 commonUsageComputer.computeFull(request); | 189 commonUsageComputer.computeFull(request); |
| 189 sendResults(request, last); | 190 sendResults(request, last); |
| 190 } | 191 } |
| 191 }); | 192 }); |
| 192 }); | 193 }); |
| 193 }); | 194 }); |
| 194 }); | 195 }); |
| 195 }); | 196 }); |
| 196 } | 197 } |
| 197 | 198 |
| 198 @override | 199 @override |
| 199 void computeSuggestions(CompletionRequest completionRequest) { | 200 void computeSuggestions(CompletionRequest completionRequest) { |
| 200 DartCompletionRequest request = new DartCompletionRequest(context, | 201 DartCompletionRequest request = new DartCompletionRequest(context, |
| 201 searchEngine, source, completionRequest.offset, cache, | 202 searchEngine, source, completionRequest.offset, cache, |
| 202 completionRequest.performance); | 203 completionRequest.performance); |
| 203 request.performance.logElapseTime('compute', () { | 204 request.performance.logElapseTime('compute', () { |
| 204 List<DartCompletionComputer> todo = computeFast(request); | 205 List<DartCompletionContributor> todo = computeFast(request); |
| 205 if (!todo.isEmpty) { | 206 if (!todo.isEmpty) { |
| 206 computeFull(request, todo); | 207 computeFull(request, todo); |
| 207 } | 208 } |
| 208 }); | 209 }); |
| 209 } | 210 } |
| 210 | 211 |
| 211 /** | 212 /** |
| 212 * Send the current list of suggestions to the client. | 213 * Send the current list of suggestions to the client. |
| 213 */ | 214 */ |
| 214 void sendResults(DartCompletionRequest request, bool last) { | 215 void sendResults(DartCompletionRequest request, bool last) { |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 264 */ | 265 */ |
| 265 final Source source; | 266 final Source source; |
| 266 | 267 |
| 267 /** | 268 /** |
| 268 * Cached information from a prior code completion operation. | 269 * Cached information from a prior code completion operation. |
| 269 */ | 270 */ |
| 270 final DartCompletionCache cache; | 271 final DartCompletionCache cache; |
| 271 | 272 |
| 272 /** | 273 /** |
| 273 * The compilation unit in which the completion was requested. This unit | 274 * The compilation unit in which the completion was requested. This unit |
| 274 * may or may not be resolved when [DartCompletionComputer.computeFast] | 275 * may or may not be resolved when [DartCompletionContributor.computeFast] |
| 275 * is called but is resolved when [DartCompletionComputer.computeFull]. | 276 * is called but is resolved when [DartCompletionContributor.computeFull]. |
| 276 */ | 277 */ |
| 277 CompilationUnit unit; | 278 CompilationUnit unit; |
| 278 | 279 |
| 279 /** | 280 /** |
| 280 * The completion target. This determines what part of the parse tree | 281 * The completion target. This determines what part of the parse tree |
| 281 * will receive the newly inserted text. | 282 * will receive the newly inserted text. |
| 282 */ | 283 */ |
| 283 CompletionTarget target; | 284 CompletionTarget target; |
| 284 | 285 |
| 285 /** | 286 /** |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 372 parameterNames: suggestion.parameterNames, | 373 parameterNames: suggestion.parameterNames, |
| 373 parameterTypes: suggestion.parameterTypes, | 374 parameterTypes: suggestion.parameterTypes, |
| 374 requiredParameterCount: suggestion.requiredParameterCount, | 375 requiredParameterCount: suggestion.requiredParameterCount, |
| 375 hasNamedParameters: suggestion.hasNamedParameters, | 376 hasNamedParameters: suggestion.hasNamedParameters, |
| 376 returnType: suggestion.returnType, | 377 returnType: suggestion.returnType, |
| 377 element: suggestion.element); | 378 element: suggestion.element); |
| 378 } | 379 } |
| 379 } | 380 } |
| 380 } | 381 } |
| 381 } | 382 } |
| OLD | NEW |