OLD | NEW |
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2016, 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 import 'dart:collection'; | 6 import 'dart:collection'; |
7 import 'dart:convert'; | 7 import 'dart:convert'; |
8 | 8 |
9 import 'package:analyzer/dart/ast/ast.dart'; | 9 import 'package:analyzer/dart/ast/ast.dart'; |
10 import 'package:analyzer/dart/ast/token.dart'; | 10 import 'package:analyzer/dart/ast/token.dart'; |
(...skipping 213 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
224 * More than one result might be produced for the same file, even if the | 224 * More than one result might be produced for the same file, even if the |
225 * client does not change the state of the files. | 225 * client does not change the state of the files. |
226 * | 226 * |
227 * Results might be produced even for files that have never been added | 227 * Results might be produced even for files that have never been added |
228 * using [addFile], for example when [getResult] was called for a file. | 228 * using [addFile], for example when [getResult] was called for a file. |
229 */ | 229 */ |
230 Stream<AnalysisResult> get results async* { | 230 Stream<AnalysisResult> get results async* { |
231 try { | 231 try { |
232 PerformanceLogSection analysisSection = null; | 232 PerformanceLogSection analysisSection = null; |
233 while (true) { | 233 while (true) { |
234 await pumpEventQueue(100); | 234 // Pump the event queue to allow IO and other asynchronous data |
| 235 // processing while analysis is active. For example Analysis Server |
| 236 // needs to be able to process `updateContent` or `setPriorityFiles` |
| 237 // requests while background analysis is in progress. |
| 238 // |
| 239 // The number of pumpings is arbitrary, might be changed if we see that |
| 240 // analysis or other data processing tasks are starving. Ideally we |
| 241 // would need to be able to set priority of (continuous) asynchronous |
| 242 // tasks. |
| 243 await _pumpEventQueue(128); |
| 244 |
235 await _hasWork.signal; | 245 await _hasWork.signal; |
236 | 246 |
237 if (analysisSection == null) { | 247 if (analysisSection == null) { |
238 analysisSection = _logger.enter('Analyzing'); | 248 analysisSection = _logger.enter('Analyzing'); |
239 } | 249 } |
240 | 250 |
241 // Verify all changed files one at a time. | 251 // Verify all changed files one at a time. |
242 if (_changedFiles.isNotEmpty) { | 252 if (_changedFiles.isNotEmpty) { |
243 String path = _removeFirst(_changedFiles); | 253 String path = _removeFirst(_changedFiles); |
244 _verifyApiSignatureOfChangedFile(path); | 254 _verifyApiSignatureOfChangedFile(path); |
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
378 | 388 |
379 /** | 389 /** |
380 * Return `true` if the file with the given [path] was explicitly added | 390 * Return `true` if the file with the given [path] was explicitly added |
381 * to analysis using [addFile]. | 391 * to analysis using [addFile]. |
382 */ | 392 */ |
383 bool isAddedFile(String path) { | 393 bool isAddedFile(String path) { |
384 return _explicitFiles.contains(path); | 394 return _explicitFiles.contains(path); |
385 } | 395 } |
386 | 396 |
387 /** | 397 /** |
388 * Returns a [Future] that completes after pumping the event queue [times] | |
389 * times. By default, this should pump the event queue enough times to allow | |
390 * any code to run, as long as it's not waiting on some external event. | |
391 */ | |
392 Future pumpEventQueue([int times = 5000]) { | |
393 if (times == 0) return new Future.value(); | |
394 // We use a delayed future to allow microtask events to finish. The | |
395 // Future.value or Future() constructors use scheduleMicrotask themselves an
d | |
396 // would therefore not wait for microtask callbacks that are scheduled after | |
397 // invoking this method. | |
398 return new Future.delayed(Duration.ZERO, () => pumpEventQueue(times - 1)); | |
399 } | |
400 | |
401 /** | |
402 * Remove the file with the given [path] from the list of files to analyze. | 398 * Remove the file with the given [path] from the list of files to analyze. |
403 * | 399 * |
404 * The [path] must be absolute and normalized. | 400 * The [path] must be absolute and normalized. |
405 * | 401 * |
406 * The results of analysis of the file might still be produced by the | 402 * The results of analysis of the file might still be produced by the |
407 * [results] stream. The driver will try to stop producing these results, | 403 * [results] stream. The driver will try to stop producing these results, |
408 * but does not guarantee this. | 404 * but does not guarantee this. |
409 */ | 405 */ |
410 void removeFile(String path) { | 406 void removeFile(String path) { |
411 _explicitFiles.remove(path); | 407 _explicitFiles.remove(path); |
(...skipping 314 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
726 // resolution results are invalid. | 722 // resolution results are invalid. |
727 if (oldSignature != null && oldSignature != newSignature) { | 723 if (oldSignature != null && oldSignature != newSignature) { |
728 _logger.writeln('API signatures mismatch found for $newFile'); | 724 _logger.writeln('API signatures mismatch found for $newFile'); |
729 _dependencySignatureMap.clear(); | 725 _dependencySignatureMap.clear(); |
730 _filesToAnalyze.addAll(_explicitFiles); | 726 _filesToAnalyze.addAll(_explicitFiles); |
731 } | 727 } |
732 }); | 728 }); |
733 } | 729 } |
734 | 730 |
735 /** | 731 /** |
| 732 * Returns a [Future] that completes after performing [times] pumpings of |
| 733 * the event queue. |
| 734 */ |
| 735 static Future _pumpEventQueue(int times) { |
| 736 if (times == 0) { |
| 737 return new Future.value(); |
| 738 } |
| 739 return new Future.delayed(Duration.ZERO, () => _pumpEventQueue(times - 1)); |
| 740 } |
| 741 |
| 742 /** |
736 * Remove and return the first item in the given [set]. | 743 * Remove and return the first item in the given [set]. |
737 */ | 744 */ |
738 static Object/*=T*/ _removeFirst/*<T>*/(LinkedHashSet<Object/*=T*/ > set) { | 745 static Object/*=T*/ _removeFirst/*<T>*/(LinkedHashSet<Object/*=T*/ > set) { |
739 Object/*=T*/ element = set.first; | 746 Object/*=T*/ element = set.first; |
740 set.remove(element); | 747 set.remove(element); |
741 return element; | 748 return element; |
742 } | 749 } |
743 } | 750 } |
744 | 751 |
745 /** | 752 /** |
(...skipping 484 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1230 } | 1237 } |
1231 } | 1238 } |
1232 for (UnlinkedExportPublic export in unit.publicNamespace.exports) { | 1239 for (UnlinkedExportPublic export in unit.publicNamespace.exports) { |
1233 referenced.exported.add(export.uri); | 1240 referenced.exported.add(export.uri); |
1234 } | 1241 } |
1235 return referenced; | 1242 return referenced; |
1236 } | 1243 } |
1237 | 1244 |
1238 _ReferencedUris._(); | 1245 _ReferencedUris._(); |
1239 } | 1246 } |
OLD | NEW |