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 import 'dart:async'; | 5 import 'dart:async'; |
6 | 6 |
7 import 'package:analysis_server/src/analysis_server.dart'; | 7 import 'package:analysis_server/src/analysis_server.dart'; |
8 import 'package:analysis_server/src/computer/computer_highlights.dart'; | 8 import 'package:analysis_server/src/computer/computer_highlights.dart'; |
9 import 'package:analysis_server/src/computer/computer_highlights2.dart'; | 9 import 'package:analysis_server/src/computer/computer_highlights2.dart'; |
10 import 'package:analysis_server/src/computer/computer_outline.dart'; | 10 import 'package:analysis_server/src/computer/computer_outline.dart'; |
11 import 'package:analysis_server/src/computer/computer_overrides.dart'; | 11 import 'package:analysis_server/src/computer/computer_overrides.dart'; |
12 import 'package:analysis_server/src/domains/analysis/implemented_dart.dart'; | 12 import 'package:analysis_server/src/domains/analysis/implemented_dart.dart'; |
13 import 'package:analysis_server/src/domains/analysis/navigation.dart'; | |
14 import 'package:analysis_server/src/domains/analysis/occurrences.dart'; | |
15 import 'package:analysis_server/src/operation/operation.dart'; | |
16 import 'package:analysis_server/src/protocol_server.dart' as protocol; | 13 import 'package:analysis_server/src/protocol_server.dart' as protocol; |
17 import 'package:analysis_server/src/services/search/search_engine.dart'; | 14 import 'package:analysis_server/src/services/search/search_engine.dart'; |
18 import 'package:analyzer/dart/ast/ast.dart'; | 15 import 'package:analyzer/dart/ast/ast.dart'; |
19 import 'package:analyzer/dart/ast/standard_resolution_map.dart'; | |
20 import 'package:analyzer/dart/element/element.dart'; | 16 import 'package:analyzer/dart/element/element.dart'; |
21 import 'package:analyzer/error/error.dart'; | |
22 import 'package:analyzer/src/generated/engine.dart'; | 17 import 'package:analyzer/src/generated/engine.dart'; |
23 import 'package:analyzer/src/generated/source.dart'; | 18 import 'package:analyzer/src/generated/source.dart'; |
24 | 19 |
25 /** | 20 /** |
26 * Run the given function [f] with the given [context] made active. | 21 * Run the given function [f] with the given [context] made active. |
27 * Return the result of [f] invocation. | 22 * Return the result of [f] invocation. |
28 */ | 23 */ |
29 runWithActiveContext(AnalysisContext context, f()) { | 24 runWithActiveContext(AnalysisContext context, f()) { |
30 if (context is InternalAnalysisContext && !context.isActive) { | 25 if (context is InternalAnalysisContext && !context.isActive) { |
31 context.isActive = true; | 26 context.isActive = true; |
(...skipping 27 matching lines...) Expand all Loading... |
59 } catch (exception, stackTrace) { | 54 } catch (exception, stackTrace) { |
60 server.sendServerErrorNotification( | 55 server.sendServerErrorNotification( |
61 'Failed to send analysis.implemented notification.', | 56 'Failed to send analysis.implemented notification.', |
62 exception, | 57 exception, |
63 stackTrace); | 58 stackTrace); |
64 } | 59 } |
65 } | 60 } |
66 } | 61 } |
67 } | 62 } |
68 | 63 |
69 /** | |
70 * Schedules indexing of the given [file] using the resolved [dartUnit]. | |
71 */ | |
72 void scheduleIndexOperation( | |
73 AnalysisServer server, String file, CompilationUnit dartUnit) { | |
74 if (server.index != null) { | |
75 AnalysisContext context = | |
76 resolutionMap.elementDeclaredByCompilationUnit(dartUnit).context; | |
77 server.addOperation(new _DartIndexOperation(context, file, dartUnit)); | |
78 } | |
79 } | |
80 | |
81 /** | |
82 * Schedules sending notifications for the given [file] using the resolved | |
83 * [resolvedDartUnit]. | |
84 */ | |
85 void scheduleNotificationOperations( | |
86 AnalysisServer server, | |
87 Source source, | |
88 String file, | |
89 LineInfo lineInfo, | |
90 AnalysisContext context, | |
91 CompilationUnit parsedDartUnit, | |
92 CompilationUnit resolvedDartUnit, | |
93 List<AnalysisError> errors) { | |
94 // TODO(brianwilkerson) The `containingContext` will always be `null`. If this | |
95 // check is still useful, we should re-write it to use drivers. | |
96 // | |
97 // If the file belongs to any analysis root, check whether we're in it now. | |
98 // AnalysisContext containingContext = server.getContainingContext(file); | |
99 // if (containingContext != null && context != containingContext) { | |
100 // return; | |
101 // } | |
102 // Dart | |
103 CompilationUnit dartUnit = resolvedDartUnit ?? parsedDartUnit; | |
104 if (resolvedDartUnit != null) { | |
105 if (server.hasAnalysisSubscription( | |
106 protocol.AnalysisService.HIGHLIGHTS, file)) { | |
107 server.scheduleOperation( | |
108 new _DartHighlightsOperation(context, file, resolvedDartUnit)); | |
109 } | |
110 if (server.hasAnalysisSubscription( | |
111 protocol.AnalysisService.NAVIGATION, file)) { | |
112 server.scheduleOperation(new NavigationOperation(context, source)); | |
113 } | |
114 if (server.hasAnalysisSubscription( | |
115 protocol.AnalysisService.OCCURRENCES, file)) { | |
116 server.scheduleOperation(new OccurrencesOperation(context, source)); | |
117 } | |
118 if (server.hasAnalysisSubscription( | |
119 protocol.AnalysisService.OVERRIDES, file)) { | |
120 server.scheduleOperation( | |
121 new _DartOverridesOperation(context, file, resolvedDartUnit)); | |
122 } | |
123 } | |
124 if (dartUnit != null) { | |
125 if (server.hasAnalysisSubscription( | |
126 protocol.AnalysisService.OUTLINE, file)) { | |
127 SourceKind sourceKind = context.getKindOf(source); | |
128 server.scheduleOperation(new _DartOutlineOperation( | |
129 context, file, lineInfo, sourceKind, dartUnit)); | |
130 } | |
131 } | |
132 // errors | |
133 if (server.shouldSendErrorsNotificationFor(file)) { | |
134 server.scheduleOperation( | |
135 new _NotificationErrorsOperation(context, file, lineInfo, errors)); | |
136 } | |
137 } | |
138 | |
139 void sendAnalysisNotificationAnalyzedFiles(AnalysisServer server) { | 64 void sendAnalysisNotificationAnalyzedFiles(AnalysisServer server) { |
140 _sendNotification(server, () { | 65 _sendNotification(server, () { |
141 Set<String> analyzedFiles = server.driverMap.values | 66 Set<String> analyzedFiles = server.driverMap.values |
142 .map((driver) => driver.knownFiles) | 67 .map((driver) => driver.knownFiles) |
143 .expand((files) => files) | 68 .expand((files) => files) |
144 .toSet(); | 69 .toSet(); |
145 Set<String> prevAnalyzedFiles = server.prevAnalyzedFiles; | 70 Set<String> prevAnalyzedFiles = server.prevAnalyzedFiles; |
146 if (prevAnalyzedFiles != null && | 71 if (prevAnalyzedFiles != null && |
147 prevAnalyzedFiles.length == analyzedFiles.length && | 72 prevAnalyzedFiles.length == analyzedFiles.length && |
148 prevAnalyzedFiles.difference(analyzedFiles).isEmpty) { | 73 prevAnalyzedFiles.difference(analyzedFiles).isEmpty) { |
149 // No change to the set of analyzed files. No need to send another | 74 // No change to the set of analyzed files. No need to send another |
150 // notification. | 75 // notification. |
151 return; | 76 return; |
152 } | 77 } |
153 server.prevAnalyzedFiles = analyzedFiles; | 78 server.prevAnalyzedFiles = analyzedFiles; |
154 protocol.AnalysisAnalyzedFilesParams params = | 79 protocol.AnalysisAnalyzedFilesParams params = |
155 new protocol.AnalysisAnalyzedFilesParams(analyzedFiles.toList()); | 80 new protocol.AnalysisAnalyzedFilesParams(analyzedFiles.toList()); |
156 server.sendNotification(params.toNotification()); | 81 server.sendNotification(params.toNotification()); |
157 }); | 82 }); |
158 } | 83 } |
159 | 84 |
160 void sendAnalysisNotificationErrors( | |
161 AnalysisServer server, | |
162 AnalysisContext context, | |
163 String file, | |
164 LineInfo lineInfo, | |
165 List<AnalysisError> errors) { | |
166 _sendNotification(server, () { | |
167 if (errors == null) { | |
168 errors = <AnalysisError>[]; | |
169 } | |
170 AnalysisOptions analysisOptions = context.analysisOptions; | |
171 var serverErrors = protocol.doAnalysisError_listFromEngine( | |
172 analysisOptions, lineInfo, errors); | |
173 var params = new protocol.AnalysisErrorsParams(file, serverErrors); | |
174 server.sendNotification(params.toNotification()); | |
175 }); | |
176 } | |
177 | |
178 void sendAnalysisNotificationFlushResults( | 85 void sendAnalysisNotificationFlushResults( |
179 AnalysisServer server, List<String> files) { | 86 AnalysisServer server, List<String> files) { |
180 _sendNotification(server, () { | 87 _sendNotification(server, () { |
181 if (files != null && files.isNotEmpty) { | 88 if (files != null && files.isNotEmpty) { |
182 var params = new protocol.AnalysisFlushResultsParams(files); | 89 var params = new protocol.AnalysisFlushResultsParams(files); |
183 server.sendNotification(params.toNotification()); | 90 server.sendNotification(params.toNotification()); |
184 } | 91 } |
185 }); | 92 }); |
186 } | 93 } |
187 | 94 |
188 void sendAnalysisNotificationHighlights( | 95 void sendAnalysisNotificationHighlights( |
189 AnalysisServer server, String file, CompilationUnit dartUnit) { | 96 AnalysisServer server, String file, CompilationUnit dartUnit) { |
190 _sendNotification(server, () { | 97 _sendNotification(server, () { |
191 List<protocol.HighlightRegion> regions; | 98 List<protocol.HighlightRegion> regions; |
192 if (server.options.useAnalysisHighlight2) { | 99 if (server.options.useAnalysisHighlight2) { |
193 regions = new DartUnitHighlightsComputer2(dartUnit).compute(); | 100 regions = new DartUnitHighlightsComputer2(dartUnit).compute(); |
194 } else { | 101 } else { |
195 regions = new DartUnitHighlightsComputer(dartUnit).compute(); | 102 regions = new DartUnitHighlightsComputer(dartUnit).compute(); |
196 } | 103 } |
197 var params = new protocol.AnalysisHighlightsParams(file, regions); | 104 var params = new protocol.AnalysisHighlightsParams(file, regions); |
198 server.sendNotification(params.toNotification()); | 105 server.sendNotification(params.toNotification()); |
199 }); | 106 }); |
200 } | 107 } |
201 | 108 |
202 void sendAnalysisNotificationNavigation( | |
203 AnalysisServer server, AnalysisContext context, Source source) { | |
204 _sendNotification(server, () { | |
205 NavigationCollectorImpl collector = | |
206 computeNavigation(server, context, source, null, null); | |
207 String file = source.fullName; | |
208 var params = new protocol.AnalysisNavigationParams( | |
209 file, collector.regions, collector.targets, collector.files); | |
210 server.sendNotification(params.toNotification()); | |
211 }); | |
212 } | |
213 | |
214 void sendAnalysisNotificationOccurrences( | |
215 AnalysisServer server, AnalysisContext context, Source source) { | |
216 _sendNotification(server, () { | |
217 OccurrencesCollectorImpl collector = | |
218 computeOccurrences(server, context, source); | |
219 String file = source.fullName; | |
220 var params = | |
221 new protocol.AnalysisOccurrencesParams(file, collector.allOccurrences); | |
222 server.sendNotification(params.toNotification()); | |
223 }); | |
224 } | |
225 | |
226 void sendAnalysisNotificationOutline(AnalysisServer server, String file, | 109 void sendAnalysisNotificationOutline(AnalysisServer server, String file, |
227 LineInfo lineInfo, SourceKind sourceKind, CompilationUnit dartUnit) { | 110 LineInfo lineInfo, SourceKind sourceKind, CompilationUnit dartUnit) { |
228 _sendNotification(server, () { | 111 _sendNotification(server, () { |
229 // compute FileKind | 112 // compute FileKind |
230 protocol.FileKind fileKind = protocol.FileKind.LIBRARY; | 113 protocol.FileKind fileKind = protocol.FileKind.LIBRARY; |
231 if (sourceKind == SourceKind.LIBRARY) { | 114 if (sourceKind == SourceKind.LIBRARY) { |
232 fileKind = protocol.FileKind.LIBRARY; | 115 fileKind = protocol.FileKind.LIBRARY; |
233 } else if (sourceKind == SourceKind.PART) { | 116 } else if (sourceKind == SourceKind.PART) { |
234 fileKind = protocol.FileKind.PART; | 117 fileKind = protocol.FileKind.PART; |
235 } | 118 } |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
274 void _sendNotification(AnalysisServer server, f()) { | 157 void _sendNotification(AnalysisServer server, f()) { |
275 ServerPerformanceStatistics.notices.makeCurrentWhile(() { | 158 ServerPerformanceStatistics.notices.makeCurrentWhile(() { |
276 try { | 159 try { |
277 f(); | 160 f(); |
278 } catch (exception, stackTrace) { | 161 } catch (exception, stackTrace) { |
279 server.sendServerErrorNotification( | 162 server.sendServerErrorNotification( |
280 'Failed to send notification', exception, stackTrace); | 163 'Failed to send notification', exception, stackTrace); |
281 } | 164 } |
282 }); | 165 }); |
283 } | 166 } |
284 | |
285 class NavigationOperation extends _NotificationOperation | |
286 implements MergeableOperation { | |
287 NavigationOperation(AnalysisContext context, Source source) | |
288 : super(context, source); | |
289 | |
290 @override | |
291 bool merge(ServerOperation other) { | |
292 return other is NavigationOperation && | |
293 other.context == context && | |
294 other.source == source; | |
295 } | |
296 | |
297 @override | |
298 void perform(AnalysisServer server) { | |
299 sendAnalysisNotificationNavigation(server, context, source); | |
300 } | |
301 } | |
302 | |
303 class OccurrencesOperation extends _NotificationOperation | |
304 implements MergeableOperation { | |
305 OccurrencesOperation(AnalysisContext context, Source source) | |
306 : super(context, source); | |
307 | |
308 @override | |
309 bool merge(ServerOperation other) { | |
310 return other is OccurrencesOperation && | |
311 other.context == context && | |
312 other.source == source; | |
313 } | |
314 | |
315 @override | |
316 void perform(AnalysisServer server) { | |
317 sendAnalysisNotificationOccurrences(server, context, source); | |
318 } | |
319 } | |
320 | |
321 /** | |
322 * Instances of [PerformAnalysisOperation] perform a single analysis task. | |
323 */ | |
324 class PerformAnalysisOperation extends ServerOperation { | |
325 final bool isContinue; | |
326 | |
327 PerformAnalysisOperation(AnalysisContext context, this.isContinue) | |
328 : super(context); | |
329 | |
330 @override | |
331 ServerOperationPriority get priority { | |
332 if (_isPriorityContext) { | |
333 if (isContinue) { | |
334 return ServerOperationPriority.PRIORITY_ANALYSIS_CONTINUE; | |
335 } else { | |
336 return ServerOperationPriority.PRIORITY_ANALYSIS; | |
337 } | |
338 } else { | |
339 if (isContinue) { | |
340 return ServerOperationPriority.ANALYSIS_CONTINUE; | |
341 } else { | |
342 return ServerOperationPriority.ANALYSIS; | |
343 } | |
344 } | |
345 } | |
346 | |
347 bool get _isPriorityContext => | |
348 context is InternalAnalysisContext && | |
349 (context as InternalAnalysisContext).prioritySources.isNotEmpty; | |
350 | |
351 @override | |
352 void perform(AnalysisServer server) { | |
353 // | |
354 // TODO(brianwilkerson) Add an optional function-valued parameter to | |
355 // performAnalysisTask that will be called when the task has been computed | |
356 // but before it is performed and send notification in the function: | |
357 // | |
358 // AnalysisResult result = context.performAnalysisTask((taskDescription) { | |
359 // sendStatusNotification(context.toString(), taskDescription); | |
360 // }); | |
361 if (!isContinue) { | |
362 _setContextActive(true); | |
363 } | |
364 // prepare results | |
365 AnalysisResult result = context.performAnalysisTask(); | |
366 List<ChangeNotice> notices = result.changeNotices; | |
367 // nothing to analyze | |
368 if (notices == null) { | |
369 server.scheduleCacheConsistencyValidation(context); | |
370 _setContextActive(false); | |
371 server.sendContextAnalysisDoneNotifications( | |
372 context, AnalysisDoneReason.COMPLETE); | |
373 return; | |
374 } | |
375 // process results | |
376 ServerPerformanceStatistics.notices.makeCurrentWhile(() { | |
377 _sendNotices(server, notices); | |
378 _updateIndex(server, notices); | |
379 }); | |
380 // continue analysis | |
381 server.addOperation(new PerformAnalysisOperation(context, true)); | |
382 } | |
383 | |
384 /** | |
385 * Send the information in the given list of notices back to the client. | |
386 */ | |
387 void _sendNotices(AnalysisServer server, List<ChangeNotice> notices) { | |
388 for (int i = 0; i < notices.length; i++) { | |
389 ChangeNotice notice = notices[i]; | |
390 Source source = notice.source; | |
391 String file = source.fullName; | |
392 // Dart | |
393 CompilationUnit parsedDartUnit = notice.parsedDartUnit; | |
394 CompilationUnit resolvedDartUnit = notice.resolvedDartUnit; | |
395 scheduleNotificationOperations(server, source, file, notice.lineInfo, | |
396 context, parsedDartUnit, resolvedDartUnit, notice.errors); | |
397 // done | |
398 server.fileAnalyzed(notice); | |
399 } | |
400 } | |
401 | |
402 /** | |
403 * Make the [context] active or idle. | |
404 */ | |
405 void _setContextActive(bool active) { | |
406 AnalysisContext context = this.context; | |
407 if (context is InternalAnalysisContext) { | |
408 context.isActive = active; | |
409 } | |
410 } | |
411 | |
412 void _updateIndex(AnalysisServer server, List<ChangeNotice> notices) { | |
413 if (server.index == null) { | |
414 return; | |
415 } | |
416 for (ChangeNotice notice in notices) { | |
417 String file = notice.source.fullName; | |
418 // Dart | |
419 try { | |
420 CompilationUnit dartUnit = notice.resolvedDartUnit; | |
421 if (dartUnit != null) { | |
422 scheduleIndexOperation(server, file, dartUnit); | |
423 } | |
424 } catch (exception, stackTrace) { | |
425 server.sendServerErrorNotification( | |
426 'Failed to index Dart file: $file', exception, stackTrace); | |
427 } | |
428 } | |
429 } | |
430 } | |
431 | |
432 class _DartHighlightsOperation extends _DartNotificationOperation { | |
433 _DartHighlightsOperation( | |
434 AnalysisContext context, String file, CompilationUnit unit) | |
435 : super(context, file, unit); | |
436 | |
437 @override | |
438 void perform(AnalysisServer server) { | |
439 sendAnalysisNotificationHighlights(server, file, unit); | |
440 } | |
441 } | |
442 | |
443 class _DartIndexOperation extends _SingleFileOperation { | |
444 final CompilationUnit unit; | |
445 | |
446 _DartIndexOperation(AnalysisContext context, String file, this.unit) | |
447 : super(context, file); | |
448 | |
449 @override | |
450 ServerOperationPriority get priority { | |
451 return ServerOperationPriority.ANALYSIS_INDEX; | |
452 } | |
453 | |
454 @override | |
455 void perform(AnalysisServer server) { | |
456 ServerPerformanceStatistics.indexOperation.makeCurrentWhile(() { | |
457 try { | |
458 server.index?.indexUnit(unit); | |
459 } catch (exception, stackTrace) { | |
460 server.sendServerErrorNotification( | |
461 'Failed to index: $file', exception, stackTrace); | |
462 } | |
463 }); | |
464 } | |
465 } | |
466 | |
467 abstract class _DartNotificationOperation extends _SingleFileOperation { | |
468 final CompilationUnit unit; | |
469 | |
470 _DartNotificationOperation(AnalysisContext context, String file, this.unit) | |
471 : super(context, file); | |
472 | |
473 @override | |
474 ServerOperationPriority get priority { | |
475 return ServerOperationPriority.ANALYSIS_NOTIFICATION; | |
476 } | |
477 } | |
478 | |
479 class _DartOutlineOperation extends _DartNotificationOperation { | |
480 final LineInfo lineInfo; | |
481 final SourceKind sourceKind; | |
482 | |
483 _DartOutlineOperation(AnalysisContext context, String file, this.lineInfo, | |
484 this.sourceKind, CompilationUnit unit) | |
485 : super(context, file, unit); | |
486 | |
487 @override | |
488 void perform(AnalysisServer server) { | |
489 sendAnalysisNotificationOutline(server, file, lineInfo, sourceKind, unit); | |
490 } | |
491 } | |
492 | |
493 class _DartOverridesOperation extends _DartNotificationOperation { | |
494 _DartOverridesOperation( | |
495 AnalysisContext context, String file, CompilationUnit unit) | |
496 : super(context, file, unit); | |
497 | |
498 @override | |
499 void perform(AnalysisServer server) { | |
500 sendAnalysisNotificationOverrides(server, file, unit); | |
501 } | |
502 } | |
503 | |
504 class _NotificationErrorsOperation extends _SingleFileOperation { | |
505 final LineInfo lineInfo; | |
506 final List<AnalysisError> errors; | |
507 | |
508 _NotificationErrorsOperation( | |
509 AnalysisContext context, String file, this.lineInfo, this.errors) | |
510 : super(context, file); | |
511 | |
512 @override | |
513 ServerOperationPriority get priority { | |
514 return ServerOperationPriority.ANALYSIS_NOTIFICATION; | |
515 } | |
516 | |
517 @override | |
518 void perform(AnalysisServer server) { | |
519 sendAnalysisNotificationErrors(server, context, file, lineInfo, errors); | |
520 } | |
521 } | |
522 | |
523 abstract class _NotificationOperation extends SourceSensitiveOperation { | |
524 final Source source; | |
525 | |
526 _NotificationOperation(AnalysisContext context, this.source) : super(context); | |
527 | |
528 @override | |
529 ServerOperationPriority get priority { | |
530 return ServerOperationPriority.ANALYSIS_NOTIFICATION; | |
531 } | |
532 | |
533 @override | |
534 bool shouldBeDiscardedOnSourceChange(Source source) { | |
535 return source == this.source; | |
536 } | |
537 } | |
538 | |
539 abstract class _SingleFileOperation extends SourceSensitiveOperation { | |
540 final String file; | |
541 | |
542 _SingleFileOperation(AnalysisContext context, this.file) : super(context); | |
543 | |
544 @override | |
545 bool shouldBeDiscardedOnSourceChange(Source source) { | |
546 return source.fullName == file; | |
547 } | |
548 } | |
OLD | NEW |