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/plugin/protocol/protocol.dart'; | 9 import 'package:analysis_server/plugin/protocol/protocol.dart'; |
10 import 'package:analysis_server/src/analysis_server.dart'; | 10 import 'package:analysis_server/src/analysis_server.dart'; |
11 import 'package:analysis_server/src/provisional/completion/completion_core.dart' | 11 import 'package:analysis_server/src/provisional/completion/completion_core.dart' |
12 show AnalysisRequest, CompletionRequest; | 12 show AnalysisRequest, CompletionContributor, CompletionRequest; |
13 import 'package:analysis_server/src/provisional/completion/dart/completion_targe
t.dart'; | 13 import 'package:analysis_server/src/provisional/completion/dart/completion_targe
t.dart'; |
14 import 'package:analysis_server/src/services/completion/arglist_contributor.dart
'; | 14 import 'package:analysis_server/src/services/completion/arglist_contributor.dart
'; |
15 import 'package:analysis_server/src/services/completion/combinator_contributor.d
art'; | 15 import 'package:analysis_server/src/services/completion/combinator_contributor.d
art'; |
16 import 'package:analysis_server/src/services/completion/completion_manager.dart'
; | 16 import 'package:analysis_server/src/services/completion/completion_manager.dart'
; |
17 import 'package:analysis_server/src/services/completion/dart/common_usage_sorter
.dart'; | 17 import 'package:analysis_server/src/services/completion/dart/common_usage_sorter
.dart'; |
| 18 import 'package:analysis_server/src/services/completion/dart/completion_manager.
dart' |
| 19 as newImpl; |
18 import 'package:analysis_server/src/services/completion/dart/contribution_sorter
.dart'; | 20 import 'package:analysis_server/src/services/completion/dart/contribution_sorter
.dart'; |
19 import 'package:analysis_server/src/services/completion/dart_completion_cache.da
rt'; | 21 import 'package:analysis_server/src/services/completion/dart_completion_cache.da
rt'; |
20 import 'package:analysis_server/src/services/completion/imported_reference_contr
ibutor.dart'; | 22 import 'package:analysis_server/src/services/completion/imported_reference_contr
ibutor.dart'; |
21 import 'package:analysis_server/src/services/completion/keyword_contributor.dart
'; | |
22 import 'package:analysis_server/src/services/completion/local_reference_contribu
tor.dart'; | 23 import 'package:analysis_server/src/services/completion/local_reference_contribu
tor.dart'; |
23 import 'package:analysis_server/src/services/completion/optype.dart'; | 24 import 'package:analysis_server/src/services/completion/optype.dart'; |
24 import 'package:analysis_server/src/services/completion/prefixed_element_contrib
utor.dart'; | 25 import 'package:analysis_server/src/services/completion/prefixed_element_contrib
utor.dart'; |
25 import 'package:analysis_server/src/services/completion/uri_contributor.dart'; | 26 import 'package:analysis_server/src/services/completion/uri_contributor.dart'; |
26 import 'package:analysis_server/src/services/search/search_engine.dart'; | 27 import 'package:analysis_server/src/services/search/search_engine.dart'; |
27 import 'package:analyzer/src/generated/ast.dart'; | 28 import 'package:analyzer/src/generated/ast.dart'; |
28 import 'package:analyzer/src/generated/engine.dart' hide AnalysisContextImpl; | 29 import 'package:analyzer/src/generated/engine.dart' hide AnalysisContextImpl; |
29 import 'package:analyzer/src/generated/scanner.dart'; | 30 import 'package:analyzer/src/generated/scanner.dart'; |
30 import 'package:analyzer/src/generated/source.dart'; | 31 import 'package:analyzer/src/generated/source.dart'; |
31 | 32 |
32 const int DART_RELEVANCE_COMMON_USAGE = 1200; | 33 export 'package:analysis_server/src/provisional/completion/completion_dart.dart' |
33 const int DART_RELEVANCE_DEFAULT = 1000; | 34 show |
34 const int DART_RELEVANCE_HIGH = 2000; | 35 DART_RELEVANCE_COMMON_USAGE, |
35 const int DART_RELEVANCE_INHERITED_ACCESSOR = 1057; | 36 DART_RELEVANCE_DEFAULT, |
36 const int DART_RELEVANCE_INHERITED_FIELD = 1058; | 37 DART_RELEVANCE_HIGH, |
37 const int DART_RELEVANCE_INHERITED_METHOD = 1057; | 38 DART_RELEVANCE_INHERITED_ACCESSOR, |
38 const int DART_RELEVANCE_KEYWORD = 1055; | 39 DART_RELEVANCE_INHERITED_FIELD, |
39 const int DART_RELEVANCE_LOCAL_ACCESSOR = 1057; | 40 DART_RELEVANCE_INHERITED_METHOD, |
40 const int DART_RELEVANCE_LOCAL_FIELD = 1058; | 41 DART_RELEVANCE_KEYWORD, |
41 const int DART_RELEVANCE_LOCAL_FUNCTION = 1056; | 42 DART_RELEVANCE_LOCAL_ACCESSOR, |
42 const int DART_RELEVANCE_LOCAL_METHOD = 1057; | 43 DART_RELEVANCE_LOCAL_FIELD, |
43 const int DART_RELEVANCE_LOCAL_TOP_LEVEL_VARIABLE = 1056; | 44 DART_RELEVANCE_LOCAL_FUNCTION, |
44 const int DART_RELEVANCE_LOCAL_VARIABLE = 1059; | 45 DART_RELEVANCE_LOCAL_METHOD, |
45 const int DART_RELEVANCE_LOW = 500; | 46 DART_RELEVANCE_LOCAL_TOP_LEVEL_VARIABLE, |
46 const int DART_RELEVANCE_NAMED_PARAMETER = 1060; | 47 DART_RELEVANCE_LOCAL_VARIABLE, |
47 const int DART_RELEVANCE_PARAMETER = 1059; | 48 DART_RELEVANCE_LOW, |
| 49 DART_RELEVANCE_NAMED_PARAMETER, |
| 50 DART_RELEVANCE_PARAMETER; |
48 | 51 |
49 /** | 52 /** |
50 * The base class for contributing code completion suggestions. | 53 * The base class for contributing code completion suggestions. |
51 */ | 54 */ |
52 abstract class DartCompletionContributor { | 55 abstract class DartCompletionContributor { |
53 /** | 56 /** |
54 * Computes the initial set of [CompletionSuggestion]s based on | 57 * Computes the initial set of [CompletionSuggestion]s based on |
55 * the given completion context. The compilation unit and completion node | 58 * the given completion context. The compilation unit and completion node |
56 * in the given completion context may not be resolved. | 59 * in the given completion context may not be resolved. |
57 * This method should execute quickly and not block waiting for any analysis. | 60 * This method should execute quickly and not block waiting for any analysis. |
(...skipping 18 matching lines...) Expand all Loading... |
76 /** | 79 /** |
77 * The [defaultContributionSorter] is a long-lived object that isn't allowed | 80 * The [defaultContributionSorter] is a long-lived object that isn't allowed |
78 * to maintain state between calls to [ContributionSorter#sort(...)]. | 81 * to maintain state between calls to [ContributionSorter#sort(...)]. |
79 */ | 82 */ |
80 static DartContributionSorter defaultContributionSorter = | 83 static DartContributionSorter defaultContributionSorter = |
81 new CommonUsageSorter(); | 84 new CommonUsageSorter(); |
82 | 85 |
83 final SearchEngine searchEngine; | 86 final SearchEngine searchEngine; |
84 final DartCompletionCache cache; | 87 final DartCompletionCache cache; |
85 List<DartCompletionContributor> contributors; | 88 List<DartCompletionContributor> contributors; |
| 89 List<CompletionContributor> newContributors; |
86 DartContributionSorter contributionSorter; | 90 DartContributionSorter contributionSorter; |
87 | 91 |
88 DartCompletionManager( | 92 DartCompletionManager( |
89 AnalysisContext context, this.searchEngine, Source source, this.cache, | 93 AnalysisContext context, this.searchEngine, Source source, this.cache, |
90 [this.contributors, this.contributionSorter]) | 94 [this.contributors, this.newContributors, this.contributionSorter]) |
91 : super(context, source) { | 95 : super(context, source) { |
92 if (contributors == null) { | 96 if (contributors == null) { |
93 contributors = [ | 97 contributors = [ |
94 // LocalReferenceContributor before ImportedReferenceContributor | 98 // LocalReferenceContributor before ImportedReferenceContributor |
95 // because local suggestions take precedence | 99 // because local suggestions take precedence |
96 // and can hide other suggestions with the same name | 100 // and can hide other suggestions with the same name |
97 new LocalReferenceContributor(), | 101 new LocalReferenceContributor(), |
98 new ImportedReferenceContributor(), | 102 new ImportedReferenceContributor(), |
99 new KeywordContributor(), | 103 //new KeywordContributor(), |
100 new ArgListContributor(), | 104 new ArgListContributor(), |
101 new CombinatorContributor(), | 105 new CombinatorContributor(), |
102 new PrefixedElementContributor(), | 106 new PrefixedElementContributor(), |
103 new UriContributor(), | 107 new UriContributor(), |
104 // TODO(brianwilkerson) Use the completion contributor extension point | 108 // TODO(brianwilkerson) Use the completion contributor extension point |
105 // to add the contributor below (and eventually, all the contributors). | 109 // to add the contributor below (and eventually, all the contributors). |
106 // new NewCompletionWrapper(new InheritedContributor()) | 110 // new NewCompletionWrapper(new InheritedContributor()) |
107 ]; | 111 ]; |
108 } | 112 } |
| 113 if (newContributors == null) { |
| 114 newContributors = <CompletionContributor>[ |
| 115 // TODO(danrubel) initialize using plugin API |
| 116 new newImpl.DartCompletionManager(), |
| 117 ]; |
| 118 } |
109 if (contributionSorter == null) { | 119 if (contributionSorter == null) { |
110 contributionSorter = defaultContributionSorter; | 120 contributionSorter = defaultContributionSorter; |
111 } | 121 } |
112 } | 122 } |
113 | 123 |
114 /** | 124 /** |
115 * Create a new initialized Dart source completion manager | 125 * Create a new initialized Dart source completion manager |
116 */ | 126 */ |
117 factory DartCompletionManager.create( | 127 factory DartCompletionManager.create( |
118 AnalysisContext context, SearchEngine searchEngine, Source source) { | 128 AnalysisContext context, SearchEngine searchEngine, Source source) { |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
171 } | 181 } |
172 } | 182 } |
173 } | 183 } |
174 | 184 |
175 List<DartCompletionContributor> todo = new List.from(contributors); | 185 List<DartCompletionContributor> todo = new List.from(contributors); |
176 todo.removeWhere((DartCompletionContributor c) { | 186 todo.removeWhere((DartCompletionContributor c) { |
177 return performance.logElapseTime('computeFast ${c.runtimeType}', () { | 187 return performance.logElapseTime('computeFast ${c.runtimeType}', () { |
178 return c.computeFast(request); | 188 return c.computeFast(request); |
179 }); | 189 }); |
180 }); | 190 }); |
181 // TODO(danrubel) current sorter requires no additional analysis, | |
182 // but need to handle the returned future the same way that futures | |
183 // returned from contributors are handled once this method is refactored | |
184 // to be async. | |
185 /* await */ contributionSorter.sort(request, request.suggestions); | |
186 // TODO (danrubel) if request is obsolete | |
187 // (processAnalysisRequest returns false) | |
188 // then send empty results | |
189 if (todo.isEmpty) { | |
190 sendResults(request, todo.isEmpty); | |
191 } | |
192 return todo; | 191 return todo; |
193 }); | 192 }); |
194 } | 193 } |
195 | 194 |
196 /** | 195 /** |
197 * If there is remaining work to be done, then wait for the unit to be | 196 * If there is remaining work to be done, then wait for the unit to be |
198 * resolved and request that each remaining contributor finish their work. | 197 * resolved and request that each remaining contributor finish their work. |
199 * Return a [Future] that completes when the last notification has been sent. | 198 * Return a [Future] that completes when the last notification has been sent. |
200 */ | 199 */ |
201 Future computeFull(DartCompletionRequest request, | 200 Future computeFull( |
202 CompletionPerformance performance, List<DartCompletionContributor> todo) { | 201 DartCompletionRequest request, |
| 202 CompletionPerformance performance, |
| 203 List<DartCompletionContributor> todo) async { |
| 204 |
| 205 // Compute suggestions using the new API |
| 206 performance.logStartTime('computeSuggestions'); |
| 207 for (CompletionContributor contributor in newContributors) { |
| 208 String contributorTag = 'computeSuggestions - ${contributor.runtimeType}'; |
| 209 performance.logStartTime(contributorTag); |
| 210 List<CompletionSuggestion> newSuggestions = |
| 211 await contributor.computeSuggestions(request); |
| 212 for (CompletionSuggestion suggestion in newSuggestions) { |
| 213 request.addSuggestion(suggestion); |
| 214 } |
| 215 performance.logElapseTime(contributorTag); |
| 216 } |
| 217 performance.logElapseTime('computeSuggestions'); |
203 performance.logStartTime('waitForAnalysis'); | 218 performance.logStartTime('waitForAnalysis'); |
| 219 |
| 220 if (todo.isEmpty) { |
| 221 // TODO(danrubel) current sorter requires no additional analysis, |
| 222 // but need to handle the returned future the same way that futures |
| 223 // returned from contributors are handled once this method is refactored |
| 224 // to be async. |
| 225 /* await */ contributionSorter.sort( |
| 226 request, request.suggestions); |
| 227 // TODO (danrubel) if request is obsolete |
| 228 // (processAnalysisRequest returns false) |
| 229 // then send empty results |
| 230 sendResults(request, true); |
| 231 } |
| 232 |
| 233 // Compute the other suggestions |
204 return waitForAnalysis().then((CompilationUnit unit) { | 234 return waitForAnalysis().then((CompilationUnit unit) { |
205 if (controller.isClosed) { | 235 if (controller.isClosed) { |
206 return; | 236 return; |
207 } | 237 } |
208 performance.logElapseTime('waitForAnalysis'); | 238 performance.logElapseTime('waitForAnalysis'); |
209 if (unit == null) { | 239 if (unit == null) { |
210 sendResults(request, true); | 240 sendResults(request, true); |
211 return; | 241 return; |
212 } | 242 } |
213 performance.logElapseTime('computeFull', () { | 243 performance.logElapseTime('computeFull', () { |
214 request.unit = unit; | 244 request.unit = unit; |
215 // TODO(paulberry): Do we need to invoke _ReplacementOffsetBuilder | 245 // TODO(paulberry): Do we need to invoke _ReplacementOffsetBuilder |
216 // again? | 246 // again? |
217 request.target = new CompletionTarget.forOffset(unit, request.offset); | 247 request.target = new CompletionTarget.forOffset(unit, request.offset); |
218 int count = todo.length; | 248 int count = todo.length; |
219 todo.forEach((DartCompletionContributor c) { | 249 todo.forEach((DartCompletionContributor c) { |
220 String name = c.runtimeType.toString(); | 250 String name = c.runtimeType.toString(); |
221 String completeTag = 'computeFull $name complete'; | 251 String completeTag = 'computeFull $name complete'; |
222 performance.logStartTime(completeTag); | 252 performance.logStartTime(completeTag); |
223 performance.logElapseTime('computeFull $name', () { | 253 performance.logElapseTime('computeFull $name', () { |
224 c.computeFull(request).then((bool changed) { | 254 c.computeFull(request).then((bool changed) { |
225 performance.logElapseTime(completeTag); | 255 performance.logElapseTime(completeTag); |
226 bool last = --count == 0; | 256 bool last = --count == 0; |
227 if (changed || last) { | 257 if (changed || last) { |
228 // TODO(danrubel) current sorter requires no additional analysis
, | 258 // TODO(danrubel) current sorter requires no additional analysis
, |
229 // but need to handle the returned future the same way that futu
res | 259 // but need to handle the returned future the same way that futu
res |
230 // returned from contributors are handled once this method is re
factored | 260 // returned from contributors are handled once this method is re
factored |
231 // to be async. | 261 // to be async. |
232 /* await */ contributionSorter.sort(request, request.suggestions
); | 262 /* await */ contributionSorter.sort( |
| 263 request, request.suggestions); |
233 // TODO (danrubel) if request is obsolete | 264 // TODO (danrubel) if request is obsolete |
234 // (processAnalysisRequest returns false) | 265 // (processAnalysisRequest returns false) |
235 // then send empty results | 266 // then send empty results |
236 sendResults(request, last); | 267 sendResults(request, last); |
237 } | 268 } |
238 }); | 269 }); |
239 }); | 270 }); |
240 }); | 271 }); |
241 }); | 272 }); |
242 }); | 273 }); |
243 } | 274 } |
244 | 275 |
245 @override | 276 @override |
246 void computeSuggestions(CompletionRequest completionRequest) { | 277 void computeSuggestions(CompletionRequest completionRequest) { |
247 DartCompletionRequest request = | 278 DartCompletionRequest request = |
248 new DartCompletionRequest.from(completionRequest, cache); | 279 new DartCompletionRequest.from(completionRequest, cache); |
249 CompletionPerformance performance = new CompletionPerformance(); | 280 CompletionPerformance performance = new CompletionPerformance(); |
250 performance.logElapseTime('compute', () { | 281 performance.logElapseTime('compute', () { |
251 List<DartCompletionContributor> todo = computeFast(request, performance); | 282 List<DartCompletionContributor> todo = computeFast(request, performance); |
252 if (!todo.isEmpty) { | 283 computeFull(request, performance, todo); |
253 computeFull(request, performance, todo); | |
254 } | |
255 }); | 284 }); |
256 } | 285 } |
257 | 286 |
258 /** | 287 /** |
259 * Send the current list of suggestions to the client. | 288 * Send the current list of suggestions to the client. |
260 */ | 289 */ |
261 void sendResults(DartCompletionRequest request, bool last) { | 290 void sendResults(DartCompletionRequest request, bool last) { |
262 if (controller == null || controller.isClosed) { | 291 if (controller == null || controller.isClosed) { |
263 return; | 292 return; |
264 } | 293 } |
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
419 parameterNames: suggestion.parameterNames, | 448 parameterNames: suggestion.parameterNames, |
420 parameterTypes: suggestion.parameterTypes, | 449 parameterTypes: suggestion.parameterTypes, |
421 requiredParameterCount: suggestion.requiredParameterCount, | 450 requiredParameterCount: suggestion.requiredParameterCount, |
422 hasNamedParameters: suggestion.hasNamedParameters, | 451 hasNamedParameters: suggestion.hasNamedParameters, |
423 returnType: suggestion.returnType, | 452 returnType: suggestion.returnType, |
424 element: suggestion.element); | 453 element: suggestion.element); |
425 } | 454 } |
426 } | 455 } |
427 } | 456 } |
428 } | 457 } |
OLD | NEW |