| 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 |