Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(484)

Side by Side Diff: pkg/analysis_server/lib/src/services/completion/dart/completion_manager.dart

Issue 1685653002: abort completion request - fixes #24271 (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: address comment Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2015, 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.manager; 5 library services.completion.dart.manager;
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/provisional/completion/completion_core.dart' 10 import 'package:analysis_server/src/provisional/completion/completion_core.dart'
11 show CompletionContributor, CompletionRequest; 11 show CompletionContributor, CompletionRequest;
12 import 'package:analysis_server/src/provisional/completion/dart/completion_dart. dart'; 12 import 'package:analysis_server/src/provisional/completion/dart/completion_dart. dart';
13 import 'package:analysis_server/src/provisional/completion/dart/completion_plugi n.dart'; 13 import 'package:analysis_server/src/provisional/completion/dart/completion_plugi n.dart';
14 import 'package:analysis_server/src/provisional/completion/dart/completion_targe t.dart'; 14 import 'package:analysis_server/src/provisional/completion/dart/completion_targe t.dart';
15 import 'package:analysis_server/src/services/completion/completion_core.dart'; 15 import 'package:analysis_server/src/services/completion/completion_core.dart';
16 import 'package:analysis_server/src/services/completion/completion_performance.d art'; 16 import 'package:analysis_server/src/services/completion/completion_performance.d art';
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/contribution_sorter .dart'; 18 import 'package:analysis_server/src/services/completion/dart/contribution_sorter .dart';
19 import 'package:analysis_server/src/services/completion/dart/optype.dart'; 19 import 'package:analysis_server/src/services/completion/dart/optype.dart';
20 import 'package:analysis_server/src/services/search/search_engine.dart'; 20 import 'package:analysis_server/src/services/search/search_engine.dart';
21 import 'package:analyzer/dart/element/element.dart'; 21 import 'package:analyzer/dart/element/element.dart';
22 import 'package:analyzer/dart/element/type.dart'; 22 import 'package:analyzer/dart/element/type.dart';
23 import 'package:analyzer/file_system/file_system.dart'; 23 import 'package:analyzer/file_system/file_system.dart';
24 import 'package:analyzer/src/context/context.dart' 24 import 'package:analyzer/src/context/context.dart'
25 show AnalysisFutureHelper, AnalysisContextImpl; 25 show AnalysisFutureHelper, AnalysisContextImpl;
26 import 'package:analyzer/src/generated/ast.dart'; 26 import 'package:analyzer/src/generated/ast.dart';
27 import 'package:analyzer/src/generated/engine.dart' hide AnalysisContextImpl; 27 import 'package:analyzer/src/generated/engine.dart' hide AnalysisContextImpl;
28 import 'package:analyzer/src/generated/java_engine.dart';
28 import 'package:analyzer/src/generated/scanner.dart'; 29 import 'package:analyzer/src/generated/scanner.dart';
29 import 'package:analyzer/src/generated/source.dart'; 30 import 'package:analyzer/src/generated/source.dart';
30 import 'package:analyzer/src/task/dart.dart'; 31 import 'package:analyzer/src/task/dart.dart';
31 import 'package:analyzer/task/dart.dart'; 32 import 'package:analyzer/task/dart.dart';
33 import 'package:analyzer/task/model.dart';
32 34
33 /** 35 /**
34 * [DartCompletionManager] determines if a completion request is Dart specific 36 * [DartCompletionManager] determines if a completion request is Dart specific
35 * and forwards those requests to all [DartCompletionContributor]s. 37 * and forwards those requests to all [DartCompletionContributor]s.
36 */ 38 */
37 class DartCompletionManager implements CompletionContributor { 39 class DartCompletionManager implements CompletionContributor {
38 /** 40 /**
39 * The [contributionSorter] is a long-lived object that isn't allowed 41 * The [contributionSorter] is a long-lived object that isn't allowed
40 * to maintain state between calls to [DartContributionSorter#sort(...)]. 42 * to maintain state between calls to [DartContributionSorter#sort(...)].
41 */ 43 */
42 static DartContributionSorter contributionSorter = new CommonUsageSorter(); 44 static DartContributionSorter contributionSorter = new CommonUsageSorter();
43 45
44 @override 46 @override
45 Future<List<CompletionSuggestion>> computeSuggestions( 47 Future<List<CompletionSuggestion>> computeSuggestions(
46 CompletionRequest request) async { 48 CompletionRequest request) async {
49 request.checkAborted();
47 if (!AnalysisEngine.isDartFileName(request.source.shortName)) { 50 if (!AnalysisEngine.isDartFileName(request.source.shortName)) {
48 return EMPTY_LIST; 51 return EMPTY_LIST;
49 } 52 }
50 53
51 CompletionPerformance performance = 54 CompletionPerformance performance =
52 (request as CompletionRequestImpl).performance; 55 (request as CompletionRequestImpl).performance;
53 const BUILD_REQUEST_TAG = 'build DartCompletionRequestImpl';
54 performance.logStartTime(BUILD_REQUEST_TAG);
55 DartCompletionRequestImpl dartRequest = 56 DartCompletionRequestImpl dartRequest =
56 await DartCompletionRequestImpl.from(request); 57 await DartCompletionRequestImpl.from(request);
57 performance.logElapseTime(BUILD_REQUEST_TAG);
58 58
59 // Don't suggest in comments. 59 // Don't suggest in comments.
60 if (dartRequest.target.isCommentText) { 60 if (dartRequest.target.isCommentText) {
61 return EMPTY_LIST; 61 return EMPTY_LIST;
62 } 62 }
63 63
64 ReplacementRange range = 64 ReplacementRange range =
65 new ReplacementRange.compute(dartRequest.offset, dartRequest.target); 65 new ReplacementRange.compute(dartRequest.offset, dartRequest.target);
66 (request as CompletionRequestImpl) 66 (request as CompletionRequestImpl)
67 ..replacementOffset = range.offset 67 ..replacementOffset = range.offset
68 ..replacementLength = range.length; 68 ..replacementLength = range.length;
69 69
70 // Request Dart specific completions from each contributor 70 // Request Dart specific completions from each contributor
71 Map<String, CompletionSuggestion> suggestionMap = 71 Map<String, CompletionSuggestion> suggestionMap =
72 <String, CompletionSuggestion>{}; 72 <String, CompletionSuggestion>{};
73 for (DartCompletionContributor contributor 73 for (DartCompletionContributor contributor
74 in dartCompletionPlugin.contributors) { 74 in dartCompletionPlugin.contributors) {
75 String contributorTag = 75 String contributorTag =
76 'DartCompletionManager - ${contributor.runtimeType}'; 76 'DartCompletionManager - ${contributor.runtimeType}';
77 performance.logStartTime(contributorTag); 77 performance.logStartTime(contributorTag);
78 List<CompletionSuggestion> contributorSuggestions = 78 List<CompletionSuggestion> contributorSuggestions =
79 await contributor.computeSuggestions(dartRequest); 79 await contributor.computeSuggestions(dartRequest);
80 performance.logElapseTime(contributorTag); 80 performance.logElapseTime(contributorTag);
81 request.checkAborted();
81 82
82 for (CompletionSuggestion newSuggestion in contributorSuggestions) { 83 for (CompletionSuggestion newSuggestion in contributorSuggestions) {
83 var oldSuggestion = suggestionMap.putIfAbsent( 84 var oldSuggestion = suggestionMap.putIfAbsent(
84 newSuggestion.completion, () => newSuggestion); 85 newSuggestion.completion, () => newSuggestion);
85 if (newSuggestion != oldSuggestion && 86 if (newSuggestion != oldSuggestion &&
86 newSuggestion.relevance > oldSuggestion.relevance) { 87 newSuggestion.relevance > oldSuggestion.relevance) {
87 suggestionMap[newSuggestion.completion] = newSuggestion; 88 suggestionMap[newSuggestion.completion] = newSuggestion;
88 } 89 }
89 } 90 }
90 } 91 }
91 92
92 // Adjust suggestion relevance before returning 93 // Adjust suggestion relevance before returning
93 List<CompletionSuggestion> suggestions = suggestionMap.values.toList(); 94 List<CompletionSuggestion> suggestions = suggestionMap.values.toList();
94 const SORT_TAG = 'DartCompletionManager - sort'; 95 const SORT_TAG = 'DartCompletionManager - sort';
95 performance.logStartTime(SORT_TAG); 96 performance.logStartTime(SORT_TAG);
96 await contributionSorter.sort(dartRequest, suggestions); 97 await contributionSorter.sort(dartRequest, suggestions);
97 performance.logElapseTime(SORT_TAG); 98 performance.logElapseTime(SORT_TAG);
99 request.checkAborted();
98 return suggestions; 100 return suggestions;
99 } 101 }
100 } 102 }
101 103
102 /** 104 /**
103 * The information about a requested list of completions within a Dart file. 105 * The information about a requested list of completions within a Dart file.
104 */ 106 */
105 class DartCompletionRequestImpl implements DartCompletionRequest { 107 class DartCompletionRequestImpl implements DartCompletionRequest {
106 @override 108 @override
107 final AnalysisContext context; 109 final AnalysisContext context;
(...skipping 24 matching lines...) Expand all
132 */ 134 */
133 LibraryElement _coreLib; 135 LibraryElement _coreLib;
134 136
135 /** 137 /**
136 * The [DartType] for Object in dart:core 138 * The [DartType] for Object in dart:core
137 */ 139 */
138 InterfaceType _objectType; 140 InterfaceType _objectType;
139 141
140 OpType _opType; 142 OpType _opType;
141 143
144 final CompletionRequest _originalRequest;
145
142 final CompletionPerformance performance; 146 final CompletionPerformance performance;
143 147
144 DartCompletionRequestImpl._( 148 DartCompletionRequestImpl._(
145 this.context, 149 this.context,
146 this.resourceProvider, 150 this.resourceProvider,
147 this.searchEngine, 151 this.searchEngine,
148 this.librarySource, 152 this.librarySource,
149 this.source, 153 this.source,
150 this.offset, 154 this.offset,
151 CompilationUnit unit, 155 CompilationUnit unit,
156 this._originalRequest,
152 this.performance) { 157 this.performance) {
153 _updateTargets(unit); 158 _updateTargets(unit);
154 } 159 }
155 160
156 @override 161 @override
157 LibraryElement get coreLib { 162 LibraryElement get coreLib {
158 if (_coreLib == null) { 163 if (_coreLib == null) {
159 Source coreUri = context.sourceFactory.forUri('dart:core'); 164 Source coreUri = context.sourceFactory.forUri('dart:core');
160 _coreLib = context.computeLibraryElement(coreUri); 165 _coreLib = context.computeLibraryElement(coreUri);
161 } 166 }
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
193 return _objectType; 198 return _objectType;
194 } 199 }
195 200
196 OpType get opType { 201 OpType get opType {
197 if (_opType == null) { 202 if (_opType == null) {
198 _opType = new OpType.forCompletion(target, offset); 203 _opType = new OpType.forCompletion(target, offset);
199 } 204 }
200 return _opType; 205 return _opType;
201 } 206 }
202 207
208 /**
209 * Throw [AbortCompletion] if the completion request has been aborted.
210 */
211 void checkAborted() {
212 _originalRequest.checkAborted();
213 }
214
203 // For internal use only 215 // For internal use only
204 @override 216 @override
205 Future<List<Directive>> resolveDirectives() async { 217 Future<List<Directive>> resolveDirectives() async {
218 checkAborted();
219
206 CompilationUnit libUnit; 220 CompilationUnit libUnit;
207 if (librarySource != null) { 221 if (librarySource != null) {
208 // TODO(danrubel) only resolve the directives 222 // TODO(danrubel) only resolve the directives
209 const RESOLVE_DIRECTIVES_TAG = 'resolve directives'; 223 libUnit = await _computeAsync(
210 performance.logStartTime(RESOLVE_DIRECTIVES_TAG); 224 this,
211 libUnit = await new AnalysisFutureHelper<CompilationUnit>( 225 new LibrarySpecificUnit(librarySource, librarySource),
212 context, 226 RESOLVED_UNIT3,
213 new LibrarySpecificUnit(librarySource, librarySource), 227 performance,
214 RESOLVED_UNIT3) 228 'resolve directives');
215 .computeAsync();
216 performance.logElapseTime(RESOLVE_DIRECTIVES_TAG);
217 } 229 }
218 return libUnit?.directives; 230 return libUnit?.directives;
219 } 231 }
220 232
221 @override 233 @override
222 Future resolveExpression(Expression expression) async { 234 Future resolveExpression(Expression expression) async {
235 checkAborted();
236
223 // Return immediately if the expression has already been resolved 237 // Return immediately if the expression has already been resolved
224 if (expression.propagatedType != null) { 238 if (expression.propagatedType != null) {
225 return; 239 return;
226 } 240 }
227 241
228 // Gracefully degrade if librarySource cannot be determined 242 // Gracefully degrade if librarySource cannot be determined
229 if (librarySource == null) { 243 if (librarySource == null) {
230 return; 244 return;
231 } 245 }
232 246
233 // Resolve declarations in the target unit 247 // Resolve declarations in the target unit
234 // TODO(danrubel) resolve the expression or containing method 248 // TODO(danrubel) resolve the expression or containing method
235 // rather than the entire complilation unit 249 // rather than the entire complilation unit
236 const RESOLVE_EXPRESSION_TAG = 'resolve expression'; 250 CompilationUnit resolvedUnit = await _computeAsync(
237 performance.logStartTime(RESOLVE_EXPRESSION_TAG); 251 this,
238 CompilationUnit resolvedUnit = 252 new LibrarySpecificUnit(librarySource, source),
239 await new AnalysisFutureHelper<CompilationUnit>(context, 253 RESOLVED_UNIT,
240 new LibrarySpecificUnit(librarySource, source), RESOLVED_UNIT) 254 performance,
241 .computeAsync(); 255 'resolve expression');
242 performance.logElapseTime(RESOLVE_EXPRESSION_TAG);
243 256
244 // TODO(danrubel) determine if the underlying source has been modified 257 // TODO(danrubel) determine if the underlying source has been modified
245 // in a way that invalidates the completion request 258 // in a way that invalidates the completion request
246 // and return null 259 // and return null
247 260
248 // Gracefully degrade if unit cannot be resolved 261 // Gracefully degrade if unit cannot be resolved
249 if (resolvedUnit == null) { 262 if (resolvedUnit == null) {
250 return; 263 return;
251 } 264 }
252 265
(...skipping 25 matching lines...) Expand all
278 } 291 }
279 if (node is PrefixedIdentifier) { 292 if (node is PrefixedIdentifier) {
280 if (identical(node.identifier, target.entity)) { 293 if (identical(node.identifier, target.entity)) {
281 dotTarget = node.prefix; 294 dotTarget = node.prefix;
282 } 295 }
283 } 296 }
284 } 297 }
285 298
286 /** 299 /**
287 * Return a [Future] that completes with a newly created completion request 300 * Return a [Future] that completes with a newly created completion request
288 * based on the given [request]. 301 * based on the given [request]. This method will throw [AbortCompletion]
302 * if the completion request has been aborted.
289 */ 303 */
290 static Future<DartCompletionRequest> from(CompletionRequest request) async { 304 static Future<DartCompletionRequest> from(CompletionRequest request) async {
305 request.checkAborted();
291 CompletionPerformance performance = 306 CompletionPerformance performance =
292 (request as CompletionRequestImpl).performance; 307 (request as CompletionRequestImpl).performance;
293 const BUILD_REQUEST_TAG = 'build DartCompletionRequest'; 308 const BUILD_REQUEST_TAG = 'build DartCompletionRequest';
294 performance.logStartTime(BUILD_REQUEST_TAG); 309 performance.logStartTime(BUILD_REQUEST_TAG);
295 310
296 Source source = request.source; 311 Source source = request.source;
297 AnalysisContext context = request.context; 312 AnalysisContext context = request.context;
298 313
299 const PARSE_TAG = 'parse unit'; 314 const PARSE_TAG = 'parse unit';
300 performance.logStartTime(PARSE_TAG); 315 performance.logStartTime(PARSE_TAG);
301 CompilationUnit unit = request.context.computeResult(source, PARSED_UNIT); 316 CompilationUnit unit = request.context.computeResult(source, PARSED_UNIT);
302 performance.logElapseTime(PARSE_TAG); 317 performance.logElapseTime(PARSE_TAG);
303 318
304 Source libSource; 319 Source libSource;
305 if (unit.directives.any((d) => d is PartOfDirective)) { 320 if (unit.directives.any((d) => d is PartOfDirective)) {
306 List<Source> libraries = context.getLibrariesContaining(source); 321 List<Source> libraries = context.getLibrariesContaining(source);
307 if (libraries.isNotEmpty) { 322 if (libraries.isNotEmpty) {
308 libSource = libraries[0]; 323 libSource = libraries[0];
309 } 324 }
310 } else { 325 } else {
311 libSource = source; 326 libSource = source;
312 } 327 }
313 328
314 // Most (all?) contributors need declarations in scope to be resolved 329 // Most (all?) contributors need declarations in scope to be resolved
315 if (libSource != null) { 330 if (libSource != null) {
316 const RESOLVE_DECLARATIONS_TAG = 'resolve declarations'; 331 unit = await _computeAsync(
317 performance.logStartTime(RESOLVE_DECLARATIONS_TAG); 332 request,
318 unit = await new AnalysisFutureHelper<CompilationUnit>(context, 333 new LibrarySpecificUnit(libSource, source),
319 new LibrarySpecificUnit(libSource, source), RESOLVED_UNIT3) 334 RESOLVED_UNIT3,
320 .computeAsync(); 335 performance,
321 performance.logElapseTime(RESOLVE_DECLARATIONS_TAG); 336 'resolve declarations');
322 } 337 }
323 338
324 DartCompletionRequestImpl dartRequest = new DartCompletionRequestImpl._( 339 DartCompletionRequestImpl dartRequest = new DartCompletionRequestImpl._(
325 request.context, 340 request.context,
326 request.resourceProvider, 341 request.resourceProvider,
327 request.searchEngine, 342 request.searchEngine,
328 libSource, 343 libSource,
329 request.source, 344 request.source,
330 request.offset, 345 request.offset,
331 unit, 346 unit,
347 request,
332 performance); 348 performance);
333 349
334 // Resolve the expression in which the completion occurs 350 // Resolve the expression in which the completion occurs
335 // to properly determine if identifiers should be suggested 351 // to properly determine if identifiers should be suggested
336 // rather than invocations. 352 // rather than invocations.
337 if (dartRequest.target.maybeFunctionalArgument()) { 353 if (dartRequest.target.maybeFunctionalArgument()) {
338 AstNode node = dartRequest.target.containingNode.parent; 354 AstNode node = dartRequest.target.containingNode.parent;
339 if (node is Expression) { 355 if (node is Expression) {
340 const FUNCTIONAL_ARG_TAG = 'resolve expression for isFunctionalArg'; 356 const FUNCTIONAL_ARG_TAG = 'resolve expression for isFunctionalArg';
341 performance.logStartTime(FUNCTIONAL_ARG_TAG); 357 performance.logStartTime(FUNCTIONAL_ARG_TAG);
342 await dartRequest.resolveExpression(node); 358 await dartRequest.resolveExpression(node);
343 performance.logElapseTime(FUNCTIONAL_ARG_TAG); 359 performance.logElapseTime(FUNCTIONAL_ARG_TAG);
360 dartRequest.checkAborted();
344 } 361 }
345 } 362 }
346 363
347 performance.logElapseTime(BUILD_REQUEST_TAG); 364 performance.logElapseTime(BUILD_REQUEST_TAG);
348 return dartRequest; 365 return dartRequest;
349 } 366 }
367
368 static Future _computeAsync(CompletionRequest request, AnalysisTarget target,
369 ResultDescriptor descriptor, CompletionPerformance performance, String per fTag) async {
370 request.checkAborted();
371 performance.logStartTime(perfTag);
372 var result;
373 try {
374 result =
375 await new AnalysisFutureHelper(request.context, target, descriptor)
376 .computeAsync();
377 } catch (e, s) {
378 if (e is AnalysisNotScheduledError) {
379 request.checkAborted();
380 }
381 throw new AnalysisException(
382 'failed to $perfTag', new CaughtException(e, s));
383 }
384 request.checkAborted();
385 return result;
386 }
350 } 387 }
351 388
352 /** 389 /**
353 * Utility class for computing the code completion replacement range 390 * Utility class for computing the code completion replacement range
354 */ 391 */
355 class ReplacementRange { 392 class ReplacementRange {
356 int offset; 393 int offset;
357 int length; 394 int length;
358 395
359 ReplacementRange(this.offset, this.length); 396 ReplacementRange(this.offset, this.length);
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
398 // Replacement range for import URI 435 // Replacement range for import URI
399 return new ReplacementRange(start, end - start); 436 return new ReplacementRange(start, end - start);
400 } 437 }
401 } 438 }
402 } 439 }
403 } 440 }
404 } 441 }
405 return new ReplacementRange(requestOffset, 0); 442 return new ReplacementRange(requestOffset, 0);
406 } 443 }
407 } 444 }
OLDNEW
« no previous file with comments | « pkg/analysis_server/lib/src/services/completion/completion_core.dart ('k') | pkg/analysis_server/test/analysis_abstract.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698