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:typed_data'; | 7 import 'dart:typed_data'; |
8 | 8 |
9 import 'package:analyzer/context/declared_variables.dart'; | 9 import 'package:analyzer/context/declared_variables.dart'; |
10 import 'package:analyzer/dart/ast/ast.dart'; | 10 import 'package:analyzer/dart/ast/ast.dart'; |
11 import 'package:analyzer/dart/element/element.dart' show CompilationUnitElement; | 11 import 'package:analyzer/dart/element/element.dart' |
| 12 show CompilationUnitElement, LibraryElement; |
12 import 'package:analyzer/error/error.dart'; | 13 import 'package:analyzer/error/error.dart'; |
13 import 'package:analyzer/error/listener.dart'; | 14 import 'package:analyzer/error/listener.dart'; |
14 import 'package:analyzer/exception/exception.dart'; | 15 import 'package:analyzer/exception/exception.dart'; |
15 import 'package:analyzer/file_system/file_system.dart'; | 16 import 'package:analyzer/file_system/file_system.dart'; |
16 import 'package:analyzer/src/dart/analysis/byte_store.dart'; | 17 import 'package:analyzer/src/dart/analysis/byte_store.dart'; |
17 import 'package:analyzer/src/dart/analysis/file_state.dart'; | 18 import 'package:analyzer/src/dart/analysis/file_state.dart'; |
18 import 'package:analyzer/src/dart/analysis/file_tracker.dart'; | 19 import 'package:analyzer/src/dart/analysis/file_tracker.dart'; |
19 import 'package:analyzer/src/dart/analysis/index.dart'; | 20 import 'package:analyzer/src/dart/analysis/index.dart'; |
20 import 'package:analyzer/src/dart/analysis/library_analyzer.dart'; | 21 import 'package:analyzer/src/dart/analysis/library_analyzer.dart'; |
21 import 'package:analyzer/src/dart/analysis/library_context.dart'; | 22 import 'package:analyzer/src/dart/analysis/library_context.dart'; |
22 import 'package:analyzer/src/dart/analysis/search.dart'; | 23 import 'package:analyzer/src/dart/analysis/search.dart'; |
23 import 'package:analyzer/src/dart/analysis/status.dart'; | 24 import 'package:analyzer/src/dart/analysis/status.dart'; |
24 import 'package:analyzer/src/dart/analysis/top_level_declaration.dart'; | 25 import 'package:analyzer/src/dart/analysis/top_level_declaration.dart'; |
25 import 'package:analyzer/src/generated/engine.dart' | 26 import 'package:analyzer/src/generated/engine.dart' |
26 show AnalysisContext, AnalysisEngine, AnalysisOptions; | 27 show AnalysisContext, AnalysisEngine, AnalysisOptions; |
27 import 'package:analyzer/src/generated/source.dart'; | 28 import 'package:analyzer/src/generated/source.dart'; |
28 import 'package:analyzer/src/services/lint.dart'; | 29 import 'package:analyzer/src/services/lint.dart'; |
29 import 'package:analyzer/src/summary/api_signature.dart'; | 30 import 'package:analyzer/src/summary/api_signature.dart'; |
30 import 'package:analyzer/src/summary/format.dart'; | 31 import 'package:analyzer/src/summary/format.dart'; |
31 import 'package:analyzer/src/summary/idl.dart'; | 32 import 'package:analyzer/src/summary/idl.dart'; |
| 33 import 'package:analyzer/src/summary/package_bundle_reader.dart'; |
32 import 'package:meta/meta.dart'; | 34 import 'package:meta/meta.dart'; |
33 | 35 |
34 /** | 36 /** |
35 * This class computes [AnalysisResult]s for Dart files. | 37 * This class computes [AnalysisResult]s for Dart files. |
36 * | 38 * |
37 * Let the set of "explicitly analyzed files" denote the set of paths that have | 39 * Let the set of "explicitly analyzed files" denote the set of paths that have |
38 * been passed to [addFile] but not subsequently passed to [removeFile]. Let | 40 * been passed to [addFile] but not subsequently passed to [removeFile]. Let |
39 * the "current analysis results" denote the map from the set of explicitly | 41 * the "current analysis results" denote the map from the set of explicitly |
40 * analyzed files to the most recent [AnalysisResult] delivered to [results] | 42 * analyzed files to the most recent [AnalysisResult] delivered to [results] |
41 * for each file. Let the "current file state" represent a map from file path | 43 * for each file. Let the "current file state" represent a map from file path |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
102 final ResourceProvider _resourceProvider; | 104 final ResourceProvider _resourceProvider; |
103 | 105 |
104 /** | 106 /** |
105 * The byte storage to get and put serialized data. | 107 * The byte storage to get and put serialized data. |
106 * | 108 * |
107 * It can be shared with other [AnalysisDriver]s. | 109 * It can be shared with other [AnalysisDriver]s. |
108 */ | 110 */ |
109 final ByteStore _byteStore; | 111 final ByteStore _byteStore; |
110 | 112 |
111 /** | 113 /** |
| 114 * TODO(scheglov) document |
| 115 */ |
| 116 final SummaryDataStore externalSummaries; |
| 117 |
| 118 /** |
112 * This [ContentCache] is consulted for a file content before reading | 119 * This [ContentCache] is consulted for a file content before reading |
113 * the content from the file. | 120 * the content from the file. |
114 */ | 121 */ |
115 final FileContentOverlay _contentOverlay; | 122 final FileContentOverlay _contentOverlay; |
116 | 123 |
117 /** | 124 /** |
118 * The analysis options to analyze with. | 125 * The analysis options to analyze with. |
119 */ | 126 */ |
120 AnalysisOptions _analysisOptions; | 127 AnalysisOptions _analysisOptions; |
121 | 128 |
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
229 */ | 236 */ |
230 Search _search; | 237 Search _search; |
231 | 238 |
232 AnalysisDriverTestView _testView; | 239 AnalysisDriverTestView _testView; |
233 | 240 |
234 /** | 241 /** |
235 * The [FileTracker] used by this driver. | 242 * The [FileTracker] used by this driver. |
236 */ | 243 */ |
237 FileTracker _fileTracker; | 244 FileTracker _fileTracker; |
238 | 245 |
| 246 final _cachedResults = {}; |
| 247 |
239 /** | 248 /** |
240 * Create a new instance of [AnalysisDriver]. | 249 * Create a new instance of [AnalysisDriver]. |
241 * | 250 * |
242 * The given [SourceFactory] is cloned to ensure that it does not contain a | 251 * The given [SourceFactory] is cloned to ensure that it does not contain a |
243 * reference to a [AnalysisContext] in which it could have been used. | 252 * reference to a [AnalysisContext] in which it could have been used. |
244 */ | 253 */ |
245 AnalysisDriver( | 254 AnalysisDriver( |
246 this._scheduler, | 255 this._scheduler, |
247 PerformanceLog logger, | 256 PerformanceLog logger, |
248 this._resourceProvider, | 257 this._resourceProvider, |
249 this._byteStore, | 258 this._byteStore, |
250 this._contentOverlay, | 259 this._contentOverlay, |
251 this.name, | 260 this.name, |
252 SourceFactory sourceFactory, | 261 SourceFactory sourceFactory, |
253 this._analysisOptions, | 262 this._analysisOptions, |
254 {PackageBundle sdkBundle, | 263 {PackageBundle sdkBundle, |
255 this.analyzeWithoutTasks: true}) | 264 this.analyzeWithoutTasks: true, |
| 265 SummaryDataStore externalSummaries}) |
256 : _logger = logger, | 266 : _logger = logger, |
257 _sourceFactory = sourceFactory.clone(), | 267 _sourceFactory = sourceFactory.clone(), |
258 _sdkBundle = sdkBundle { | 268 _sdkBundle = sdkBundle, |
| 269 externalSummaries = externalSummaries { |
259 _testView = new AnalysisDriverTestView(this); | 270 _testView = new AnalysisDriverTestView(this); |
260 _createFileTracker(logger); | 271 _createFileTracker(logger); |
261 _scheduler.add(this); | 272 _scheduler.add(this); |
262 _search = new Search(this); | 273 _search = new Search(this); |
263 } | 274 } |
264 | 275 |
265 /** | 276 /** |
266 * Return the set of files explicitly added to analysis using [addFile]. | 277 * Return the set of files explicitly added to analysis using [addFile]. |
267 */ | 278 */ |
268 Set<String> get addedFiles => _fileTracker.addedFiles; | 279 Set<String> get addedFiles => _fileTracker.addedFiles; |
(...skipping 268 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
537 return new Future.value(); | 548 return new Future.value(); |
538 } | 549 } |
539 var completer = new Completer<AnalysisDriverUnitIndex>(); | 550 var completer = new Completer<AnalysisDriverUnitIndex>(); |
540 _indexRequestedFiles | 551 _indexRequestedFiles |
541 .putIfAbsent(path, () => <Completer<AnalysisDriverUnitIndex>>[]) | 552 .putIfAbsent(path, () => <Completer<AnalysisDriverUnitIndex>>[]) |
542 .add(completer); | 553 .add(completer); |
543 _scheduler.notify(this); | 554 _scheduler.notify(this); |
544 return completer.future; | 555 return completer.future; |
545 } | 556 } |
546 | 557 |
| 558 ApiSignature getResolvedUnitKeyByPath(String path) { |
| 559 ApiSignature signature = getUnitKeyByPath(path); |
| 560 var file = fsState.getFileForPath(path); |
| 561 signature.addString(file.contentHash); |
| 562 return signature; |
| 563 } |
| 564 |
547 /** | 565 /** |
548 * Return a [Future] that completes with a [AnalysisResult] for the Dart | 566 * Return a [Future] that completes with a [AnalysisResult] for the Dart |
549 * file with the given [path]. If the file is not a Dart file or cannot | 567 * file with the given [path]. If the file is not a Dart file or cannot |
550 * be analyzed, the [Future] completes with `null`. | 568 * be analyzed, the [Future] completes with `null`. |
551 * | 569 * |
552 * The [path] must be absolute and normalized. | 570 * The [path] must be absolute and normalized. |
553 * | 571 * |
554 * The [path] can be any file - explicitly or implicitly analyzed, or neither. | 572 * The [path] can be any file - explicitly or implicitly analyzed, or neither. |
555 * | 573 * |
556 * If the driver has the cached analysis result for the file, it is returned. | 574 * If the driver has the cached analysis result for the file, it is returned. |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
640 return new Future.value(); | 658 return new Future.value(); |
641 } | 659 } |
642 var completer = new Completer<String>(); | 660 var completer = new Completer<String>(); |
643 _unitElementSignatureRequests | 661 _unitElementSignatureRequests |
644 .putIfAbsent(path, () => <Completer<String>>[]) | 662 .putIfAbsent(path, () => <Completer<String>>[]) |
645 .add(completer); | 663 .add(completer); |
646 _scheduler.notify(this); | 664 _scheduler.notify(this); |
647 return completer.future; | 665 return completer.future; |
648 } | 666 } |
649 | 667 |
| 668 ApiSignature getUnitKeyByPath(String path) { |
| 669 var file = fsState.getFileForPath(path); |
| 670 ApiSignature signature = new ApiSignature(); |
| 671 signature.addUint32List(_salt); |
| 672 signature.addString(file.transitiveSignature); |
| 673 return signature; |
| 674 } |
| 675 |
650 /** | 676 /** |
651 * Return a [Future] that completes with a [ParseResult] for the file | 677 * Return a [Future] that completes with a [ParseResult] for the file |
652 * with the given [path]. | 678 * with the given [path]. |
653 * | 679 * |
654 * The [path] must be absolute and normalized. | 680 * The [path] must be absolute and normalized. |
655 * | 681 * |
656 * The [path] can be any file - explicitly or implicitly analyzed, or neither. | 682 * The [path] can be any file - explicitly or implicitly analyzed, or neither. |
657 * | 683 * |
658 * The parsing is performed in the method itself, and the result is not | 684 * The parsing is performed in the method itself, and the result is not |
659 * produced through the [results] stream (just because it is not a fully | 685 * produced through the [results] stream (just because it is not a fully |
660 * resolved unit). | 686 * resolved unit). |
661 */ | 687 */ |
662 Future<ParseResult> parseFile(String path) async { | 688 Future<ParseResult> parseFile(String path) async { |
663 FileState file = _fileTracker.verifyApiSignature(path); | 689 FileState file = _fileTracker.verifyApiSignature(path); |
664 RecordingErrorListener listener = new RecordingErrorListener(); | 690 RecordingErrorListener listener = new RecordingErrorListener(); |
665 CompilationUnit unit = file.parse(listener); | 691 CompilationUnit unit = file.parse(listener); |
666 return new ParseResult(file.path, file.uri, file.content, file.contentHash, | 692 return new ParseResult(file.path, file.uri, file.content, file.contentHash, |
667 unit.lineInfo, unit, listener.errors); | 693 unit.lineInfo, unit, listener.errors); |
668 } | 694 } |
669 | 695 |
670 /** | 696 /** |
| 697 * Perform a single chunk of work and produce [results]. |
| 698 */ |
| 699 Future<Null> performWork() async { |
| 700 if (_fileTracker.verifyChangedFilesIfNeeded()) { |
| 701 return; |
| 702 } |
| 703 |
| 704 // Analyze a requested file. |
| 705 if (_requestedFiles.isNotEmpty) { |
| 706 String path = _requestedFiles.keys.first; |
| 707 try { |
| 708 AnalysisResult result = _computeAnalysisResult(path, withUnit: true); |
| 709 // If a part without a library, delay its analysis. |
| 710 if (result == null) { |
| 711 _requestedParts |
| 712 .putIfAbsent(path, () => []) |
| 713 .addAll(_requestedFiles.remove(path)); |
| 714 return; |
| 715 } |
| 716 // Notify the completers. |
| 717 _requestedFiles.remove(path).forEach((completer) { |
| 718 completer.complete(result); |
| 719 }); |
| 720 // Remove from to be analyzed and produce it now. |
| 721 _fileTracker.fileWasAnalyzed(path); |
| 722 _resultController.add(result); |
| 723 } catch (exception, stackTrace) { |
| 724 _fileTracker.fileWasAnalyzed(path); |
| 725 _requestedFiles.remove(path).forEach((completer) { |
| 726 completer.completeError(exception, stackTrace); |
| 727 }); |
| 728 } |
| 729 return; |
| 730 } |
| 731 |
| 732 // Process an index request. |
| 733 if (_indexRequestedFiles.isNotEmpty) { |
| 734 String path = _indexRequestedFiles.keys.first; |
| 735 AnalysisDriverUnitIndex index = _computeIndex(path); |
| 736 _indexRequestedFiles.remove(path).forEach((completer) { |
| 737 completer.complete(index); |
| 738 }); |
| 739 return; |
| 740 } |
| 741 |
| 742 // Process a unit element key request. |
| 743 if (_unitElementSignatureRequests.isNotEmpty) { |
| 744 String path = _unitElementSignatureRequests.keys.first; |
| 745 String signature = _computeUnitElementSignature(path); |
| 746 _unitElementSignatureRequests.remove(path).forEach((completer) { |
| 747 completer.complete(signature); |
| 748 }); |
| 749 return; |
| 750 } |
| 751 |
| 752 // Process a unit element request. |
| 753 if (_unitElementRequestedFiles.isNotEmpty) { |
| 754 String path = _unitElementRequestedFiles.keys.first; |
| 755 UnitElementResult result = _computeUnitElement(path); |
| 756 _unitElementRequestedFiles.remove(path).forEach((completer) { |
| 757 completer.complete(result); |
| 758 }); |
| 759 return; |
| 760 } |
| 761 |
| 762 // Compute files defining a name. |
| 763 if (_definingClassMemberNameTasks.isNotEmpty) { |
| 764 _FilesDefiningClassMemberNameTask task = |
| 765 _definingClassMemberNameTasks.first; |
| 766 bool isDone = await task.perform(); |
| 767 if (isDone) { |
| 768 _definingClassMemberNameTasks.remove(task); |
| 769 } |
| 770 return; |
| 771 } |
| 772 |
| 773 // Compute files referencing a name. |
| 774 if (_referencingNameTasks.isNotEmpty) { |
| 775 _FilesReferencingNameTask task = _referencingNameTasks.first; |
| 776 bool isDone = await task.perform(); |
| 777 if (isDone) { |
| 778 _referencingNameTasks.remove(task); |
| 779 } |
| 780 return; |
| 781 } |
| 782 |
| 783 // Compute top-level declarations. |
| 784 if (_topLevelNameDeclarationsTasks.isNotEmpty) { |
| 785 _TopLevelNameDeclarationsTask task = _topLevelNameDeclarationsTasks.first; |
| 786 bool isDone = await task.perform(); |
| 787 if (isDone) { |
| 788 _topLevelNameDeclarationsTasks.remove(task); |
| 789 } |
| 790 return; |
| 791 } |
| 792 |
| 793 // Analyze a priority file. |
| 794 if (_priorityFiles.isNotEmpty) { |
| 795 for (String path in _priorityFiles) { |
| 796 if (_fileTracker.isFilePending(path)) { |
| 797 try { |
| 798 AnalysisResult result = |
| 799 _computeAnalysisResult(path, withUnit: true); |
| 800 if (result == null) { |
| 801 _partsToAnalyze.add(path); |
| 802 } else { |
| 803 _resultController.add(result); |
| 804 } |
| 805 } catch (exception, stackTrace) { |
| 806 _reportException(path, exception, stackTrace); |
| 807 } finally { |
| 808 _fileTracker.fileWasAnalyzed(path); |
| 809 } |
| 810 return; |
| 811 } |
| 812 } |
| 813 } |
| 814 |
| 815 // Analyze a general file. |
| 816 if (_fileTracker.hasPendingFiles) { |
| 817 String path = _fileTracker.anyPendingFile; |
| 818 try { |
| 819 AnalysisResult result = _computeAnalysisResult(path, |
| 820 withUnit: false, skipIfSameSignature: true); |
| 821 if (result == null) { |
| 822 _partsToAnalyze.add(path); |
| 823 } else if (result == AnalysisResult._UNCHANGED) { |
| 824 // We found that the set of errors is the same as we produced the |
| 825 // last time, so we don't need to produce it again now. |
| 826 } else { |
| 827 _resultController.add(result); |
| 828 _lastProducedSignatures[result.path] = result._signature; |
| 829 } |
| 830 } catch (exception, stackTrace) { |
| 831 _reportException(path, exception, stackTrace); |
| 832 } finally { |
| 833 _fileTracker.fileWasAnalyzed(path); |
| 834 } |
| 835 return; |
| 836 } |
| 837 |
| 838 // Analyze a requested part file. |
| 839 if (_requestedParts.isNotEmpty) { |
| 840 String path = _requestedParts.keys.first; |
| 841 try { |
| 842 AnalysisResult result = _computeAnalysisResult(path, |
| 843 withUnit: true, asIsIfPartWithoutLibrary: true); |
| 844 // Notify the completers. |
| 845 _requestedParts.remove(path).forEach((completer) { |
| 846 completer.complete(result); |
| 847 }); |
| 848 // Remove from to be analyzed and produce it now. |
| 849 _partsToAnalyze.remove(path); |
| 850 _resultController.add(result); |
| 851 } catch (exception, stackTrace) { |
| 852 _partsToAnalyze.remove(path); |
| 853 _requestedParts.remove(path).forEach((completer) { |
| 854 completer.completeError(exception, stackTrace); |
| 855 }); |
| 856 } |
| 857 return; |
| 858 } |
| 859 |
| 860 // Analyze a general part. |
| 861 if (_partsToAnalyze.isNotEmpty) { |
| 862 String path = _partsToAnalyze.first; |
| 863 _partsToAnalyze.remove(path); |
| 864 try { |
| 865 AnalysisResult result = _computeAnalysisResult(path, |
| 866 withUnit: _priorityFiles.contains(path), |
| 867 asIsIfPartWithoutLibrary: true); |
| 868 _resultController.add(result); |
| 869 } catch (exception, stackTrace) { |
| 870 _reportException(path, exception, stackTrace); |
| 871 } |
| 872 return; |
| 873 } |
| 874 } |
| 875 |
| 876 /** |
671 * Remove the file with the given [path] from the list of files to analyze. | 877 * Remove the file with the given [path] from the list of files to analyze. |
672 * | 878 * |
673 * The [path] must be absolute and normalized. | 879 * The [path] must be absolute and normalized. |
674 * | 880 * |
675 * The results of analysis of the file might still be produced by the | 881 * The results of analysis of the file might still be produced by the |
676 * [results] stream. The driver will try to stop producing these results, | 882 * [results] stream. The driver will try to stop producing these results, |
677 * but does not guarantee this. | 883 * but does not guarantee this. |
678 */ | 884 */ |
679 void removeFile(String path) { | 885 void removeFile(String path) { |
680 _fileTracker.removeFile(path); | 886 _fileTracker.removeFile(path); |
681 _priorityResults.clear(); | 887 _priorityResults.clear(); |
682 } | 888 } |
683 | 889 |
684 /** | 890 /** |
| 891 * TODO(scheglov) document |
| 892 */ |
| 893 Future<LibraryElement> resynthesizeLibrary(String uri) async { |
| 894 if (externalSummaries.hasUnlinkedUnit(uri)) { |
| 895 return LibraryContext.resynthesizeLibrary(analysisOptions, |
| 896 declaredVariables, sourceFactory, externalSummaries, uri); |
| 897 } |
| 898 Source source = sourceFactory.resolveUri(null, uri); |
| 899 var unitResult = await getUnitElement(source.fullName); |
| 900 return unitResult.element.library; |
| 901 } |
| 902 |
| 903 /** |
685 * Handles a notification from the [FileTracker] that there has been a change | 904 * Handles a notification from the [FileTracker] that there has been a change |
686 * of state. | 905 * of state. |
687 */ | 906 */ |
688 void _changeHook() { | 907 void _changeHook() { |
689 _priorityResults.clear(); | 908 _priorityResults.clear(); |
690 _scheduler.notify(this); | 909 _scheduler.notify(this); |
691 } | 910 } |
692 | 911 |
693 /** | 912 /** |
694 * Return the cached or newly computed analysis result of the file with the | 913 * Return the cached or newly computed analysis result of the file with the |
695 * given [path]. | 914 * given [path]. |
696 * | 915 * |
697 * The result will have the fully resolved unit and will always be newly | 916 * The result will have the fully resolved unit and will always be newly |
698 * compute only if [withUnit] is `true`. | 917 * compute only if [withUnit] is `true`. |
699 * | 918 * |
700 * Return `null` if the file is a part of an unknown library, so cannot be | 919 * Return `null` if the file is a part of an unknown library, so cannot be |
701 * analyzed yet. But [asIsIfPartWithoutLibrary] is `true`, then the file is | 920 * analyzed yet. But [asIsIfPartWithoutLibrary] is `true`, then the file is |
702 * analyzed anyway, even without a library. | 921 * analyzed anyway, even without a library. |
703 * | 922 * |
704 * Return [AnalysisResult._UNCHANGED] if [skipIfSameSignature] is `true` and | 923 * Return [AnalysisResult._UNCHANGED] if [skipIfSameSignature] is `true` and |
705 * the resolved signature of the file in its library is the same as the one | 924 * the resolved signature of the file in its library is the same as the one |
706 * that was the most recently produced to the client. | 925 * that was the most recently produced to the client. |
707 */ | 926 */ |
708 AnalysisResult _computeAnalysisResult(String path, | 927 AnalysisResult _computeAnalysisResult(String path, |
709 {bool withUnit: false, | 928 {bool withUnit: false, |
710 bool asIsIfPartWithoutLibrary: false, | 929 bool asIsIfPartWithoutLibrary: false, |
711 bool skipIfSameSignature: false}) { | 930 bool skipIfSameSignature: false}) { |
712 FileState file = _fileTracker.fsState.getFileForPath(path); | 931 FileState file = _fileTracker.fsState.getFileForPath(path); |
713 | 932 |
| 933 { |
| 934 UnitAnalysisResult unitResult = _cachedResults[file]; |
| 935 if (unitResult != null) { |
| 936 return new AnalysisResult( |
| 937 this, |
| 938 sourceFactory, |
| 939 path, |
| 940 file.uri, |
| 941 file.exists, |
| 942 file.content, |
| 943 file.contentHash, |
| 944 file.lineInfo, |
| 945 null, |
| 946 unitResult.unit, |
| 947 unitResult.errors, |
| 948 null); |
| 949 } |
| 950 } |
| 951 |
714 // Prepare the library - the file itself, or the known library. | 952 // Prepare the library - the file itself, or the known library. |
715 FileState library = file.isPart ? file.library : file; | 953 FileState library = file.isPart ? file.library : file; |
716 if (library == null) { | 954 if (library == null) { |
717 if (asIsIfPartWithoutLibrary) { | 955 if (asIsIfPartWithoutLibrary) { |
718 library = file; | 956 library = file; |
719 } else { | 957 } else { |
720 return null; | 958 return null; |
721 } | 959 } |
722 } | 960 } |
723 | 961 |
(...skipping 26 matching lines...) Expand all Loading... |
750 List<int> bytes; | 988 List<int> bytes; |
751 if (analyzeWithoutTasks) { | 989 if (analyzeWithoutTasks) { |
752 LibraryAnalyzer analyzer = new LibraryAnalyzer( | 990 LibraryAnalyzer analyzer = new LibraryAnalyzer( |
753 analysisOptions, | 991 analysisOptions, |
754 declaredVariables, | 992 declaredVariables, |
755 sourceFactory, | 993 sourceFactory, |
756 _fileTracker.fsState, | 994 _fileTracker.fsState, |
757 libraryContext.store, | 995 libraryContext.store, |
758 library); | 996 library); |
759 Map<FileState, UnitAnalysisResult> results = analyzer.analyze(); | 997 Map<FileState, UnitAnalysisResult> results = analyzer.analyze(); |
| 998 _cachedResults.addAll(results); |
760 for (FileState unitFile in results.keys) { | 999 for (FileState unitFile in results.keys) { |
761 UnitAnalysisResult unitResult = results[unitFile]; | 1000 UnitAnalysisResult unitResult = results[unitFile]; |
762 List<int> unitBytes = | 1001 List<int> unitBytes = |
763 _serializeResolvedUnit(unitResult.unit, unitResult.errors); | 1002 _serializeResolvedUnit(unitResult.unit, unitResult.errors); |
764 String unitSignature = | 1003 String unitSignature = |
765 _getResolvedUnitSignature(library, unitFile); | 1004 _getResolvedUnitSignature(library, unitFile); |
766 String unitKey = _getResolvedUnitKey(unitSignature); | 1005 String unitKey = _getResolvedUnitKey(unitSignature); |
767 _byteStore.put(unitKey, unitBytes); | 1006 _byteStore.put(unitKey, unitBytes); |
768 if (unitFile == file) { | 1007 if (unitFile == file) { |
769 bytes = unitBytes; | 1008 bytes = unitBytes; |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
803 } | 1042 } |
804 | 1043 |
805 AnalysisDriverUnitIndex _computeIndex(String path) { | 1044 AnalysisDriverUnitIndex _computeIndex(String path) { |
806 AnalysisResult analysisResult = _computeAnalysisResult(path, | 1045 AnalysisResult analysisResult = _computeAnalysisResult(path, |
807 withUnit: false, asIsIfPartWithoutLibrary: true); | 1046 withUnit: false, asIsIfPartWithoutLibrary: true); |
808 return analysisResult._index; | 1047 return analysisResult._index; |
809 } | 1048 } |
810 | 1049 |
811 UnitElementResult _computeUnitElement(String path) { | 1050 UnitElementResult _computeUnitElement(String path) { |
812 FileState file = _fileTracker.fsState.getFileForPath(path); | 1051 FileState file = _fileTracker.fsState.getFileForPath(path); |
| 1052 if (path.startsWith('dart:')) { |
| 1053 file = _fileTracker.fsState.getFileForUri(Uri.parse(path)); |
| 1054 } |
813 FileState library = file.library ?? file; | 1055 FileState library = file.library ?? file; |
814 | 1056 |
815 // Create the AnalysisContext to resynthesize elements in. | 1057 // Create the AnalysisContext to resynthesize elements in. |
816 LibraryContext libraryContext = _createLibraryContext(library); | 1058 LibraryContext libraryContext = _createLibraryContext(library); |
817 | 1059 |
818 // Resynthesize the CompilationUnitElement in the context. | 1060 // Resynthesize the CompilationUnitElement in the context. |
819 try { | 1061 try { |
820 CompilationUnitElement element = | 1062 CompilationUnitElement element = |
821 libraryContext.computeUnitElement(library.source, file.source); | 1063 libraryContext.computeUnitElement(library.source, file.source); |
822 String signature = library.transitiveSignature; | 1064 String signature = library.transitiveSignature; |
(...skipping 10 matching lines...) Expand all Loading... |
833 } | 1075 } |
834 | 1076 |
835 /** | 1077 /** |
836 * Creates a new [FileTracker] object and stores it in [_fileTracker]. | 1078 * Creates a new [FileTracker] object and stores it in [_fileTracker]. |
837 * | 1079 * |
838 * This is used both on initial construction and whenever the configuration | 1080 * This is used both on initial construction and whenever the configuration |
839 * changes. | 1081 * changes. |
840 */ | 1082 */ |
841 void _createFileTracker(PerformanceLog logger) { | 1083 void _createFileTracker(PerformanceLog logger) { |
842 _fillSalt(); | 1084 _fillSalt(); |
843 _fileTracker = new FileTracker(logger, _byteStore, _contentOverlay, | 1085 _fileTracker = new FileTracker( |
844 _resourceProvider, sourceFactory, _analysisOptions, _salt, _changeHook); | 1086 logger, |
| 1087 _byteStore, |
| 1088 _contentOverlay, |
| 1089 _resourceProvider, |
| 1090 sourceFactory, |
| 1091 _analysisOptions, |
| 1092 _salt, |
| 1093 externalSummaries, |
| 1094 _changeHook); |
845 } | 1095 } |
846 | 1096 |
847 /** | 1097 /** |
848 * Return the context in which the [library] should be analyzed. | 1098 * Return the context in which the [library] should be analyzed. |
849 */ | 1099 */ |
850 LibraryContext _createLibraryContext(FileState library) => | 1100 LibraryContext _createLibraryContext(FileState library) => |
851 new LibraryContext.forSingleLibrary( | 1101 new LibraryContext.forSingleLibrary( |
852 library, | 1102 library, |
853 _logger, | 1103 _logger, |
854 _sdkBundle, | 1104 _sdkBundle, |
855 _byteStore, | 1105 _byteStore, |
856 _analysisOptions, | 1106 _analysisOptions, |
857 declaredVariables, | 1107 declaredVariables, |
858 _sourceFactory, | 1108 _sourceFactory, |
| 1109 externalSummaries, |
859 _fileTracker); | 1110 _fileTracker); |
860 | 1111 |
861 /** | 1112 /** |
862 * Fill [_salt] with data. | 1113 * Fill [_salt] with data. |
863 */ | 1114 */ |
864 void _fillSalt() { | 1115 void _fillSalt() { |
865 _salt[0] = DATA_VERSION; | 1116 _salt[0] = DATA_VERSION; |
866 List<int> crossContextOptions = _analysisOptions.signature; | 1117 List<int> crossContextOptions = _analysisOptions.signature; |
867 assert(crossContextOptions.length == AnalysisOptions.signatureLength); | 1118 assert(crossContextOptions.length == AnalysisOptions.signatureLength); |
868 for (int i = 0; i < crossContextOptions.length; i++) { | 1119 for (int i = 0; i < crossContextOptions.length; i++) { |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
926 * in the [library], e.g. element model, errors, index, etc. | 1177 * in the [library], e.g. element model, errors, index, etc. |
927 */ | 1178 */ |
928 String _getResolvedUnitSignature(FileState library, FileState file) { | 1179 String _getResolvedUnitSignature(FileState library, FileState file) { |
929 ApiSignature signature = new ApiSignature(); | 1180 ApiSignature signature = new ApiSignature(); |
930 signature.addUint32List(_salt); | 1181 signature.addUint32List(_salt); |
931 signature.addString(library.transitiveSignature); | 1182 signature.addString(library.transitiveSignature); |
932 signature.addString(file.contentHash); | 1183 signature.addString(file.contentHash); |
933 return signature.toHex(); | 1184 return signature.toHex(); |
934 } | 1185 } |
935 | 1186 |
936 ApiSignature getUnitKeyByPath(String path) { | |
937 var file = fsState.getFileForPath(path); | |
938 ApiSignature signature = new ApiSignature(); | |
939 signature.addUint32List(_salt); | |
940 signature.addString(file.transitiveSignature); | |
941 return signature; | |
942 } | |
943 | |
944 ApiSignature getResolvedUnitKeyByPath(String path) { | |
945 ApiSignature signature = getUnitKeyByPath(path); | |
946 var file = fsState.getFileForPath(path); | |
947 signature.addString(file.contentHash); | |
948 return signature; | |
949 } | |
950 | |
951 /** | 1187 /** |
952 * Return the lint code with the given [errorName], or `null` if there is no | 1188 * Return the lint code with the given [errorName], or `null` if there is no |
953 * lint registered with that name or the lint is not enabled in the analysis | 1189 * lint registered with that name or the lint is not enabled in the analysis |
954 * options. | 1190 * options. |
955 */ | 1191 */ |
956 ErrorCode _lintCodeByUniqueName(String errorName) { | 1192 ErrorCode _lintCodeByUniqueName(String errorName) { |
957 if (errorName.startsWith('_LintCode.')) { | 1193 if (errorName.startsWith('_LintCode.')) { |
958 String lintName = errorName.substring(10); | 1194 String lintName = errorName.substring(10); |
959 List<Linter> lintRules = _analysisOptions.lintRules; | 1195 List<Linter> lintRules = _analysisOptions.lintRules; |
960 for (Linter linter in lintRules) { | 1196 for (Linter linter in lintRules) { |
961 if (linter.name == lintName) { | 1197 if (linter.name == lintName) { |
962 return linter.lintCode; | 1198 return linter.lintCode; |
963 } | 1199 } |
964 } | 1200 } |
965 } | 1201 } |
966 return null; | 1202 return null; |
967 } | 1203 } |
968 | 1204 |
969 /** | |
970 * Perform a single chunk of work and produce [results]. | |
971 */ | |
972 Future<Null> performWork() async { | |
973 if (_fileTracker.verifyChangedFilesIfNeeded()) { | |
974 return; | |
975 } | |
976 | |
977 // Analyze a requested file. | |
978 if (_requestedFiles.isNotEmpty) { | |
979 String path = _requestedFiles.keys.first; | |
980 try { | |
981 AnalysisResult result = _computeAnalysisResult(path, withUnit: true); | |
982 // If a part without a library, delay its analysis. | |
983 if (result == null) { | |
984 _requestedParts | |
985 .putIfAbsent(path, () => []) | |
986 .addAll(_requestedFiles.remove(path)); | |
987 return; | |
988 } | |
989 // Notify the completers. | |
990 _requestedFiles.remove(path).forEach((completer) { | |
991 completer.complete(result); | |
992 }); | |
993 // Remove from to be analyzed and produce it now. | |
994 _fileTracker.fileWasAnalyzed(path); | |
995 _resultController.add(result); | |
996 } catch (exception, stackTrace) { | |
997 _fileTracker.fileWasAnalyzed(path); | |
998 _requestedFiles.remove(path).forEach((completer) { | |
999 completer.completeError(exception, stackTrace); | |
1000 }); | |
1001 } | |
1002 return; | |
1003 } | |
1004 | |
1005 // Process an index request. | |
1006 if (_indexRequestedFiles.isNotEmpty) { | |
1007 String path = _indexRequestedFiles.keys.first; | |
1008 AnalysisDriverUnitIndex index = _computeIndex(path); | |
1009 _indexRequestedFiles.remove(path).forEach((completer) { | |
1010 completer.complete(index); | |
1011 }); | |
1012 return; | |
1013 } | |
1014 | |
1015 // Process a unit element key request. | |
1016 if (_unitElementSignatureRequests.isNotEmpty) { | |
1017 String path = _unitElementSignatureRequests.keys.first; | |
1018 String signature = _computeUnitElementSignature(path); | |
1019 _unitElementSignatureRequests.remove(path).forEach((completer) { | |
1020 completer.complete(signature); | |
1021 }); | |
1022 return; | |
1023 } | |
1024 | |
1025 // Process a unit element request. | |
1026 if (_unitElementRequestedFiles.isNotEmpty) { | |
1027 String path = _unitElementRequestedFiles.keys.first; | |
1028 UnitElementResult result = _computeUnitElement(path); | |
1029 _unitElementRequestedFiles.remove(path).forEach((completer) { | |
1030 completer.complete(result); | |
1031 }); | |
1032 return; | |
1033 } | |
1034 | |
1035 // Compute files defining a name. | |
1036 if (_definingClassMemberNameTasks.isNotEmpty) { | |
1037 _FilesDefiningClassMemberNameTask task = | |
1038 _definingClassMemberNameTasks.first; | |
1039 bool isDone = await task.perform(); | |
1040 if (isDone) { | |
1041 _definingClassMemberNameTasks.remove(task); | |
1042 } | |
1043 return; | |
1044 } | |
1045 | |
1046 // Compute files referencing a name. | |
1047 if (_referencingNameTasks.isNotEmpty) { | |
1048 _FilesReferencingNameTask task = _referencingNameTasks.first; | |
1049 bool isDone = await task.perform(); | |
1050 if (isDone) { | |
1051 _referencingNameTasks.remove(task); | |
1052 } | |
1053 return; | |
1054 } | |
1055 | |
1056 // Compute top-level declarations. | |
1057 if (_topLevelNameDeclarationsTasks.isNotEmpty) { | |
1058 _TopLevelNameDeclarationsTask task = _topLevelNameDeclarationsTasks.first; | |
1059 bool isDone = await task.perform(); | |
1060 if (isDone) { | |
1061 _topLevelNameDeclarationsTasks.remove(task); | |
1062 } | |
1063 return; | |
1064 } | |
1065 | |
1066 // Analyze a priority file. | |
1067 if (_priorityFiles.isNotEmpty) { | |
1068 for (String path in _priorityFiles) { | |
1069 if (_fileTracker.isFilePending(path)) { | |
1070 try { | |
1071 AnalysisResult result = | |
1072 _computeAnalysisResult(path, withUnit: true); | |
1073 if (result == null) { | |
1074 _partsToAnalyze.add(path); | |
1075 } else { | |
1076 _resultController.add(result); | |
1077 } | |
1078 } catch (exception, stackTrace) { | |
1079 _reportException(path, exception, stackTrace); | |
1080 } finally { | |
1081 _fileTracker.fileWasAnalyzed(path); | |
1082 } | |
1083 return; | |
1084 } | |
1085 } | |
1086 } | |
1087 | |
1088 // Analyze a general file. | |
1089 if (_fileTracker.hasPendingFiles) { | |
1090 String path = _fileTracker.anyPendingFile; | |
1091 try { | |
1092 AnalysisResult result = _computeAnalysisResult(path, | |
1093 withUnit: false, skipIfSameSignature: true); | |
1094 if (result == null) { | |
1095 _partsToAnalyze.add(path); | |
1096 } else if (result == AnalysisResult._UNCHANGED) { | |
1097 // We found that the set of errors is the same as we produced the | |
1098 // last time, so we don't need to produce it again now. | |
1099 } else { | |
1100 _resultController.add(result); | |
1101 _lastProducedSignatures[result.path] = result._signature; | |
1102 } | |
1103 } catch (exception, stackTrace) { | |
1104 _reportException(path, exception, stackTrace); | |
1105 } finally { | |
1106 _fileTracker.fileWasAnalyzed(path); | |
1107 } | |
1108 return; | |
1109 } | |
1110 | |
1111 // Analyze a requested part file. | |
1112 if (_requestedParts.isNotEmpty) { | |
1113 String path = _requestedParts.keys.first; | |
1114 try { | |
1115 AnalysisResult result = _computeAnalysisResult(path, | |
1116 withUnit: true, asIsIfPartWithoutLibrary: true); | |
1117 // Notify the completers. | |
1118 _requestedParts.remove(path).forEach((completer) { | |
1119 completer.complete(result); | |
1120 }); | |
1121 // Remove from to be analyzed and produce it now. | |
1122 _partsToAnalyze.remove(path); | |
1123 _resultController.add(result); | |
1124 } catch (exception, stackTrace) { | |
1125 _partsToAnalyze.remove(path); | |
1126 _requestedParts.remove(path).forEach((completer) { | |
1127 completer.completeError(exception, stackTrace); | |
1128 }); | |
1129 } | |
1130 return; | |
1131 } | |
1132 | |
1133 // Analyze a general part. | |
1134 if (_partsToAnalyze.isNotEmpty) { | |
1135 String path = _partsToAnalyze.first; | |
1136 _partsToAnalyze.remove(path); | |
1137 try { | |
1138 AnalysisResult result = _computeAnalysisResult(path, | |
1139 withUnit: _priorityFiles.contains(path), | |
1140 asIsIfPartWithoutLibrary: true); | |
1141 _resultController.add(result); | |
1142 } catch (exception, stackTrace) { | |
1143 _reportException(path, exception, stackTrace); | |
1144 } | |
1145 return; | |
1146 } | |
1147 } | |
1148 | |
1149 void _reportException(String path, exception, StackTrace stackTrace) { | 1205 void _reportException(String path, exception, StackTrace stackTrace) { |
1150 String contextKey = null; | 1206 String contextKey = null; |
1151 if (exception is _ExceptionState) { | 1207 if (exception is _ExceptionState) { |
1152 var state = exception as _ExceptionState; | 1208 var state = exception as _ExceptionState; |
1153 exception = state.exception; | 1209 exception = state.exception; |
1154 stackTrace = state.stackTrace; | 1210 stackTrace = state.stackTrace; |
1155 contextKey = state.contextKey; | 1211 contextKey = state.contextKey; |
1156 } | 1212 } |
1157 CaughtException caught = new CaughtException(exception, stackTrace); | 1213 CaughtException caught = new CaughtException(exception, stackTrace); |
1158 _exceptionController.add(new ExceptionResult(path, caught, contextKey)); | 1214 _exceptionController.add(new ExceptionResult(path, caught, contextKey)); |
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1297 bool get _hasFilesToAnalyze { | 1353 bool get _hasFilesToAnalyze { |
1298 for (AnalysisDriverGeneric driver in _drivers) { | 1354 for (AnalysisDriverGeneric driver in _drivers) { |
1299 if (driver.hasFilesToAnalyze) { | 1355 if (driver.hasFilesToAnalyze) { |
1300 return true; | 1356 return true; |
1301 } | 1357 } |
1302 } | 1358 } |
1303 return false; | 1359 return false; |
1304 } | 1360 } |
1305 | 1361 |
1306 /** | 1362 /** |
| 1363 * Add the given [driver] and schedule it to perform its work. |
| 1364 */ |
| 1365 void add(AnalysisDriverGeneric driver) { |
| 1366 _drivers.add(driver); |
| 1367 _hasWork.notify(); |
| 1368 } |
| 1369 |
| 1370 /** |
1307 * Notify that there is a change to the [driver], it it might need to | 1371 * Notify that there is a change to the [driver], it it might need to |
1308 * perform some work. | 1372 * perform some work. |
1309 */ | 1373 */ |
1310 void notify(AnalysisDriverGeneric driver) { | 1374 void notify(AnalysisDriverGeneric driver) { |
1311 _hasWork.notify(); | 1375 _hasWork.notify(); |
1312 _statusSupport.preTransitionToAnalyzing(); | 1376 _statusSupport.preTransitionToAnalyzing(); |
1313 } | 1377 } |
1314 | 1378 |
1315 /** | 1379 /** |
1316 * Start the scheduler, so that any [AnalysisDriver] created before or | 1380 * Start the scheduler, so that any [AnalysisDriver] created before or |
1317 * after will be asked to perform work. | 1381 * after will be asked to perform work. |
1318 */ | 1382 */ |
1319 void start() { | 1383 void start() { |
1320 if (_started) { | 1384 if (_started) { |
1321 throw new StateError('The scheduler has already been started.'); | 1385 throw new StateError('The scheduler has already been started.'); |
1322 } | 1386 } |
1323 _started = true; | 1387 _started = true; |
1324 _run(); | 1388 _run(); |
1325 } | 1389 } |
1326 | 1390 |
1327 /** | 1391 /** |
1328 * Return a future that will be completed the next time the status is idle. | 1392 * Return a future that will be completed the next time the status is idle. |
1329 * | 1393 * |
1330 * If the status is currently idle, the returned future will be signaled | 1394 * If the status is currently idle, the returned future will be signaled |
1331 * immediately. | 1395 * immediately. |
1332 */ | 1396 */ |
1333 Future<Null> waitForIdle() => _statusSupport.waitForIdle(); | 1397 Future<Null> waitForIdle() => _statusSupport.waitForIdle(); |
1334 | 1398 |
1335 /** | 1399 /** |
1336 * Add the given [driver] and schedule it to perform its work. | |
1337 */ | |
1338 void add(AnalysisDriverGeneric driver) { | |
1339 _drivers.add(driver); | |
1340 _hasWork.notify(); | |
1341 } | |
1342 | |
1343 /** | |
1344 * Remove the given [driver] from the scheduler, so that it will not be | 1400 * Remove the given [driver] from the scheduler, so that it will not be |
1345 * asked to perform any new work. | 1401 * asked to perform any new work. |
1346 */ | 1402 */ |
1347 void _remove(AnalysisDriverGeneric driver) { | 1403 void _remove(AnalysisDriverGeneric driver) { |
1348 _drivers.remove(driver); | 1404 _drivers.remove(driver); |
1349 _hasWork.notify(); | 1405 _hasWork.notify(); |
1350 } | 1406 } |
1351 | 1407 |
1352 /** | 1408 /** |
1353 * Run infinitely analysis cycle, selecting the drivers with the highest | 1409 * Run infinitely analysis cycle, selecting the drivers with the highest |
(...skipping 574 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1928 libraryDeclarations.add(new TopLevelDeclarationInSource( | 1984 libraryDeclarations.add(new TopLevelDeclarationInSource( |
1929 file.source, declaration, isExported)); | 1985 file.source, declaration, isExported)); |
1930 } | 1986 } |
1931 } | 1987 } |
1932 } | 1988 } |
1933 | 1989 |
1934 // We're not done yet. | 1990 // We're not done yet. |
1935 return false; | 1991 return false; |
1936 } | 1992 } |
1937 } | 1993 } |
OLD | NEW |