Index: pkg/analyzer/lib/src/dart/analysis/driver.dart |
diff --git a/pkg/analyzer/lib/src/dart/analysis/driver.dart b/pkg/analyzer/lib/src/dart/analysis/driver.dart |
index fd2e61b1011cac59cd8b34c933002ddaf1becf9b..c013c6f0f6a54848f496b0dc58b84c36ad6bb724 100644 |
--- a/pkg/analyzer/lib/src/dart/analysis/driver.dart |
+++ b/pkg/analyzer/lib/src/dart/analysis/driver.dart |
@@ -8,7 +8,8 @@ import 'dart:typed_data'; |
import 'package:analyzer/context/declared_variables.dart'; |
import 'package:analyzer/dart/ast/ast.dart'; |
-import 'package:analyzer/dart/element/element.dart' show CompilationUnitElement; |
+import 'package:analyzer/dart/element/element.dart' |
+ show CompilationUnitElement, LibraryElement; |
import 'package:analyzer/error/error.dart'; |
import 'package:analyzer/error/listener.dart'; |
import 'package:analyzer/exception/exception.dart'; |
@@ -29,6 +30,7 @@ import 'package:analyzer/src/services/lint.dart'; |
import 'package:analyzer/src/summary/api_signature.dart'; |
import 'package:analyzer/src/summary/format.dart'; |
import 'package:analyzer/src/summary/idl.dart'; |
+import 'package:analyzer/src/summary/package_bundle_reader.dart'; |
import 'package:meta/meta.dart'; |
/** |
@@ -109,6 +111,11 @@ class AnalysisDriver implements AnalysisDriverGeneric { |
final ByteStore _byteStore; |
/** |
+ * TODO(scheglov) document |
+ */ |
+ final SummaryDataStore externalSummaries; |
+ |
+ /** |
* This [ContentCache] is consulted for a file content before reading |
* the content from the file. |
*/ |
@@ -236,6 +243,8 @@ class AnalysisDriver implements AnalysisDriverGeneric { |
*/ |
FileTracker _fileTracker; |
+ final _cachedResults = {}; |
+ |
/** |
* Create a new instance of [AnalysisDriver]. |
* |
@@ -252,10 +261,12 @@ class AnalysisDriver implements AnalysisDriverGeneric { |
SourceFactory sourceFactory, |
this._analysisOptions, |
{PackageBundle sdkBundle, |
- this.analyzeWithoutTasks: true}) |
+ this.analyzeWithoutTasks: true, |
+ SummaryDataStore externalSummaries}) |
: _logger = logger, |
_sourceFactory = sourceFactory.clone(), |
- _sdkBundle = sdkBundle { |
+ _sdkBundle = sdkBundle, |
+ externalSummaries = externalSummaries { |
_testView = new AnalysisDriverTestView(this); |
_createFileTracker(logger); |
_scheduler.add(this); |
@@ -544,6 +555,13 @@ class AnalysisDriver implements AnalysisDriverGeneric { |
return completer.future; |
} |
+ ApiSignature getResolvedUnitKeyByPath(String path) { |
+ ApiSignature signature = getUnitKeyByPath(path); |
+ var file = fsState.getFileForPath(path); |
+ signature.addString(file.contentHash); |
+ return signature; |
+ } |
+ |
/** |
* Return a [Future] that completes with a [AnalysisResult] for the Dart |
* file with the given [path]. If the file is not a Dart file or cannot |
@@ -647,6 +665,14 @@ class AnalysisDriver implements AnalysisDriverGeneric { |
return completer.future; |
} |
+ ApiSignature getUnitKeyByPath(String path) { |
+ var file = fsState.getFileForPath(path); |
+ ApiSignature signature = new ApiSignature(); |
+ signature.addUint32List(_salt); |
+ signature.addString(file.transitiveSignature); |
+ return signature; |
+ } |
+ |
/** |
* Return a [Future] that completes with a [ParseResult] for the file |
* with the given [path]. |
@@ -668,6 +694,186 @@ class AnalysisDriver implements AnalysisDriverGeneric { |
} |
/** |
+ * Perform a single chunk of work and produce [results]. |
+ */ |
+ Future<Null> performWork() async { |
+ if (_fileTracker.verifyChangedFilesIfNeeded()) { |
+ return; |
+ } |
+ |
+ // Analyze a requested file. |
+ if (_requestedFiles.isNotEmpty) { |
+ String path = _requestedFiles.keys.first; |
+ try { |
+ AnalysisResult result = _computeAnalysisResult(path, withUnit: true); |
+ // If a part without a library, delay its analysis. |
+ if (result == null) { |
+ _requestedParts |
+ .putIfAbsent(path, () => []) |
+ .addAll(_requestedFiles.remove(path)); |
+ return; |
+ } |
+ // Notify the completers. |
+ _requestedFiles.remove(path).forEach((completer) { |
+ completer.complete(result); |
+ }); |
+ // Remove from to be analyzed and produce it now. |
+ _fileTracker.fileWasAnalyzed(path); |
+ _resultController.add(result); |
+ } catch (exception, stackTrace) { |
+ _fileTracker.fileWasAnalyzed(path); |
+ _requestedFiles.remove(path).forEach((completer) { |
+ completer.completeError(exception, stackTrace); |
+ }); |
+ } |
+ return; |
+ } |
+ |
+ // Process an index request. |
+ if (_indexRequestedFiles.isNotEmpty) { |
+ String path = _indexRequestedFiles.keys.first; |
+ AnalysisDriverUnitIndex index = _computeIndex(path); |
+ _indexRequestedFiles.remove(path).forEach((completer) { |
+ completer.complete(index); |
+ }); |
+ return; |
+ } |
+ |
+ // Process a unit element key request. |
+ if (_unitElementSignatureRequests.isNotEmpty) { |
+ String path = _unitElementSignatureRequests.keys.first; |
+ String signature = _computeUnitElementSignature(path); |
+ _unitElementSignatureRequests.remove(path).forEach((completer) { |
+ completer.complete(signature); |
+ }); |
+ return; |
+ } |
+ |
+ // Process a unit element request. |
+ if (_unitElementRequestedFiles.isNotEmpty) { |
+ String path = _unitElementRequestedFiles.keys.first; |
+ UnitElementResult result = _computeUnitElement(path); |
+ _unitElementRequestedFiles.remove(path).forEach((completer) { |
+ completer.complete(result); |
+ }); |
+ return; |
+ } |
+ |
+ // Compute files defining a name. |
+ if (_definingClassMemberNameTasks.isNotEmpty) { |
+ _FilesDefiningClassMemberNameTask task = |
+ _definingClassMemberNameTasks.first; |
+ bool isDone = await task.perform(); |
+ if (isDone) { |
+ _definingClassMemberNameTasks.remove(task); |
+ } |
+ return; |
+ } |
+ |
+ // Compute files referencing a name. |
+ if (_referencingNameTasks.isNotEmpty) { |
+ _FilesReferencingNameTask task = _referencingNameTasks.first; |
+ bool isDone = await task.perform(); |
+ if (isDone) { |
+ _referencingNameTasks.remove(task); |
+ } |
+ return; |
+ } |
+ |
+ // Compute top-level declarations. |
+ if (_topLevelNameDeclarationsTasks.isNotEmpty) { |
+ _TopLevelNameDeclarationsTask task = _topLevelNameDeclarationsTasks.first; |
+ bool isDone = await task.perform(); |
+ if (isDone) { |
+ _topLevelNameDeclarationsTasks.remove(task); |
+ } |
+ return; |
+ } |
+ |
+ // Analyze a priority file. |
+ if (_priorityFiles.isNotEmpty) { |
+ for (String path in _priorityFiles) { |
+ if (_fileTracker.isFilePending(path)) { |
+ try { |
+ AnalysisResult result = |
+ _computeAnalysisResult(path, withUnit: true); |
+ if (result == null) { |
+ _partsToAnalyze.add(path); |
+ } else { |
+ _resultController.add(result); |
+ } |
+ } catch (exception, stackTrace) { |
+ _reportException(path, exception, stackTrace); |
+ } finally { |
+ _fileTracker.fileWasAnalyzed(path); |
+ } |
+ return; |
+ } |
+ } |
+ } |
+ |
+ // Analyze a general file. |
+ if (_fileTracker.hasPendingFiles) { |
+ String path = _fileTracker.anyPendingFile; |
+ try { |
+ AnalysisResult result = _computeAnalysisResult(path, |
+ withUnit: false, skipIfSameSignature: true); |
+ if (result == null) { |
+ _partsToAnalyze.add(path); |
+ } else if (result == AnalysisResult._UNCHANGED) { |
+ // We found that the set of errors is the same as we produced the |
+ // last time, so we don't need to produce it again now. |
+ } else { |
+ _resultController.add(result); |
+ _lastProducedSignatures[result.path] = result._signature; |
+ } |
+ } catch (exception, stackTrace) { |
+ _reportException(path, exception, stackTrace); |
+ } finally { |
+ _fileTracker.fileWasAnalyzed(path); |
+ } |
+ return; |
+ } |
+ |
+ // Analyze a requested part file. |
+ if (_requestedParts.isNotEmpty) { |
+ String path = _requestedParts.keys.first; |
+ try { |
+ AnalysisResult result = _computeAnalysisResult(path, |
+ withUnit: true, asIsIfPartWithoutLibrary: true); |
+ // Notify the completers. |
+ _requestedParts.remove(path).forEach((completer) { |
+ completer.complete(result); |
+ }); |
+ // Remove from to be analyzed and produce it now. |
+ _partsToAnalyze.remove(path); |
+ _resultController.add(result); |
+ } catch (exception, stackTrace) { |
+ _partsToAnalyze.remove(path); |
+ _requestedParts.remove(path).forEach((completer) { |
+ completer.completeError(exception, stackTrace); |
+ }); |
+ } |
+ return; |
+ } |
+ |
+ // Analyze a general part. |
+ if (_partsToAnalyze.isNotEmpty) { |
+ String path = _partsToAnalyze.first; |
+ _partsToAnalyze.remove(path); |
+ try { |
+ AnalysisResult result = _computeAnalysisResult(path, |
+ withUnit: _priorityFiles.contains(path), |
+ asIsIfPartWithoutLibrary: true); |
+ _resultController.add(result); |
+ } catch (exception, stackTrace) { |
+ _reportException(path, exception, stackTrace); |
+ } |
+ return; |
+ } |
+ } |
+ |
+ /** |
* Remove the file with the given [path] from the list of files to analyze. |
* |
* The [path] must be absolute and normalized. |
@@ -682,6 +888,19 @@ class AnalysisDriver implements AnalysisDriverGeneric { |
} |
/** |
+ * TODO(scheglov) document |
+ */ |
+ Future<LibraryElement> resynthesizeLibrary(String uri) async { |
+ if (externalSummaries.hasUnlinkedUnit(uri)) { |
+ return LibraryContext.resynthesizeLibrary(analysisOptions, |
+ declaredVariables, sourceFactory, externalSummaries, uri); |
+ } |
+ Source source = sourceFactory.resolveUri(null, uri); |
+ var unitResult = await getUnitElement(source.fullName); |
+ return unitResult.element.library; |
+ } |
+ |
+ /** |
* Handles a notification from the [FileTracker] that there has been a change |
* of state. |
*/ |
@@ -711,6 +930,25 @@ class AnalysisDriver implements AnalysisDriverGeneric { |
bool skipIfSameSignature: false}) { |
FileState file = _fileTracker.fsState.getFileForPath(path); |
+ { |
+ UnitAnalysisResult unitResult = _cachedResults[file]; |
+ if (unitResult != null) { |
+ return new AnalysisResult( |
+ this, |
+ sourceFactory, |
+ path, |
+ file.uri, |
+ file.exists, |
+ file.content, |
+ file.contentHash, |
+ file.lineInfo, |
+ null, |
+ unitResult.unit, |
+ unitResult.errors, |
+ null); |
+ } |
+ } |
+ |
// Prepare the library - the file itself, or the known library. |
FileState library = file.isPart ? file.library : file; |
if (library == null) { |
@@ -757,6 +995,7 @@ class AnalysisDriver implements AnalysisDriverGeneric { |
libraryContext.store, |
library); |
Map<FileState, UnitAnalysisResult> results = analyzer.analyze(); |
+ _cachedResults.addAll(results); |
for (FileState unitFile in results.keys) { |
UnitAnalysisResult unitResult = results[unitFile]; |
List<int> unitBytes = |
@@ -810,6 +1049,9 @@ class AnalysisDriver implements AnalysisDriverGeneric { |
UnitElementResult _computeUnitElement(String path) { |
FileState file = _fileTracker.fsState.getFileForPath(path); |
+ if (path.startsWith('dart:')) { |
+ file = _fileTracker.fsState.getFileForUri(Uri.parse(path)); |
+ } |
FileState library = file.library ?? file; |
// Create the AnalysisContext to resynthesize elements in. |
@@ -840,8 +1082,16 @@ class AnalysisDriver implements AnalysisDriverGeneric { |
*/ |
void _createFileTracker(PerformanceLog logger) { |
_fillSalt(); |
- _fileTracker = new FileTracker(logger, _byteStore, _contentOverlay, |
- _resourceProvider, sourceFactory, _analysisOptions, _salt, _changeHook); |
+ _fileTracker = new FileTracker( |
+ logger, |
+ _byteStore, |
+ _contentOverlay, |
+ _resourceProvider, |
+ sourceFactory, |
+ _analysisOptions, |
+ _salt, |
+ externalSummaries, |
+ _changeHook); |
} |
/** |
@@ -856,6 +1106,7 @@ class AnalysisDriver implements AnalysisDriverGeneric { |
_analysisOptions, |
declaredVariables, |
_sourceFactory, |
+ externalSummaries, |
_fileTracker); |
/** |
@@ -933,21 +1184,6 @@ class AnalysisDriver implements AnalysisDriverGeneric { |
return signature.toHex(); |
} |
- ApiSignature getUnitKeyByPath(String path) { |
- var file = fsState.getFileForPath(path); |
- ApiSignature signature = new ApiSignature(); |
- signature.addUint32List(_salt); |
- signature.addString(file.transitiveSignature); |
- return signature; |
- } |
- |
- ApiSignature getResolvedUnitKeyByPath(String path) { |
- ApiSignature signature = getUnitKeyByPath(path); |
- var file = fsState.getFileForPath(path); |
- signature.addString(file.contentHash); |
- return signature; |
- } |
- |
/** |
* Return the lint code with the given [errorName], or `null` if there is no |
* lint registered with that name or the lint is not enabled in the analysis |
@@ -966,186 +1202,6 @@ class AnalysisDriver implements AnalysisDriverGeneric { |
return null; |
} |
- /** |
- * Perform a single chunk of work and produce [results]. |
- */ |
- Future<Null> performWork() async { |
- if (_fileTracker.verifyChangedFilesIfNeeded()) { |
- return; |
- } |
- |
- // Analyze a requested file. |
- if (_requestedFiles.isNotEmpty) { |
- String path = _requestedFiles.keys.first; |
- try { |
- AnalysisResult result = _computeAnalysisResult(path, withUnit: true); |
- // If a part without a library, delay its analysis. |
- if (result == null) { |
- _requestedParts |
- .putIfAbsent(path, () => []) |
- .addAll(_requestedFiles.remove(path)); |
- return; |
- } |
- // Notify the completers. |
- _requestedFiles.remove(path).forEach((completer) { |
- completer.complete(result); |
- }); |
- // Remove from to be analyzed and produce it now. |
- _fileTracker.fileWasAnalyzed(path); |
- _resultController.add(result); |
- } catch (exception, stackTrace) { |
- _fileTracker.fileWasAnalyzed(path); |
- _requestedFiles.remove(path).forEach((completer) { |
- completer.completeError(exception, stackTrace); |
- }); |
- } |
- return; |
- } |
- |
- // Process an index request. |
- if (_indexRequestedFiles.isNotEmpty) { |
- String path = _indexRequestedFiles.keys.first; |
- AnalysisDriverUnitIndex index = _computeIndex(path); |
- _indexRequestedFiles.remove(path).forEach((completer) { |
- completer.complete(index); |
- }); |
- return; |
- } |
- |
- // Process a unit element key request. |
- if (_unitElementSignatureRequests.isNotEmpty) { |
- String path = _unitElementSignatureRequests.keys.first; |
- String signature = _computeUnitElementSignature(path); |
- _unitElementSignatureRequests.remove(path).forEach((completer) { |
- completer.complete(signature); |
- }); |
- return; |
- } |
- |
- // Process a unit element request. |
- if (_unitElementRequestedFiles.isNotEmpty) { |
- String path = _unitElementRequestedFiles.keys.first; |
- UnitElementResult result = _computeUnitElement(path); |
- _unitElementRequestedFiles.remove(path).forEach((completer) { |
- completer.complete(result); |
- }); |
- return; |
- } |
- |
- // Compute files defining a name. |
- if (_definingClassMemberNameTasks.isNotEmpty) { |
- _FilesDefiningClassMemberNameTask task = |
- _definingClassMemberNameTasks.first; |
- bool isDone = await task.perform(); |
- if (isDone) { |
- _definingClassMemberNameTasks.remove(task); |
- } |
- return; |
- } |
- |
- // Compute files referencing a name. |
- if (_referencingNameTasks.isNotEmpty) { |
- _FilesReferencingNameTask task = _referencingNameTasks.first; |
- bool isDone = await task.perform(); |
- if (isDone) { |
- _referencingNameTasks.remove(task); |
- } |
- return; |
- } |
- |
- // Compute top-level declarations. |
- if (_topLevelNameDeclarationsTasks.isNotEmpty) { |
- _TopLevelNameDeclarationsTask task = _topLevelNameDeclarationsTasks.first; |
- bool isDone = await task.perform(); |
- if (isDone) { |
- _topLevelNameDeclarationsTasks.remove(task); |
- } |
- return; |
- } |
- |
- // Analyze a priority file. |
- if (_priorityFiles.isNotEmpty) { |
- for (String path in _priorityFiles) { |
- if (_fileTracker.isFilePending(path)) { |
- try { |
- AnalysisResult result = |
- _computeAnalysisResult(path, withUnit: true); |
- if (result == null) { |
- _partsToAnalyze.add(path); |
- } else { |
- _resultController.add(result); |
- } |
- } catch (exception, stackTrace) { |
- _reportException(path, exception, stackTrace); |
- } finally { |
- _fileTracker.fileWasAnalyzed(path); |
- } |
- return; |
- } |
- } |
- } |
- |
- // Analyze a general file. |
- if (_fileTracker.hasPendingFiles) { |
- String path = _fileTracker.anyPendingFile; |
- try { |
- AnalysisResult result = _computeAnalysisResult(path, |
- withUnit: false, skipIfSameSignature: true); |
- if (result == null) { |
- _partsToAnalyze.add(path); |
- } else if (result == AnalysisResult._UNCHANGED) { |
- // We found that the set of errors is the same as we produced the |
- // last time, so we don't need to produce it again now. |
- } else { |
- _resultController.add(result); |
- _lastProducedSignatures[result.path] = result._signature; |
- } |
- } catch (exception, stackTrace) { |
- _reportException(path, exception, stackTrace); |
- } finally { |
- _fileTracker.fileWasAnalyzed(path); |
- } |
- return; |
- } |
- |
- // Analyze a requested part file. |
- if (_requestedParts.isNotEmpty) { |
- String path = _requestedParts.keys.first; |
- try { |
- AnalysisResult result = _computeAnalysisResult(path, |
- withUnit: true, asIsIfPartWithoutLibrary: true); |
- // Notify the completers. |
- _requestedParts.remove(path).forEach((completer) { |
- completer.complete(result); |
- }); |
- // Remove from to be analyzed and produce it now. |
- _partsToAnalyze.remove(path); |
- _resultController.add(result); |
- } catch (exception, stackTrace) { |
- _partsToAnalyze.remove(path); |
- _requestedParts.remove(path).forEach((completer) { |
- completer.completeError(exception, stackTrace); |
- }); |
- } |
- return; |
- } |
- |
- // Analyze a general part. |
- if (_partsToAnalyze.isNotEmpty) { |
- String path = _partsToAnalyze.first; |
- _partsToAnalyze.remove(path); |
- try { |
- AnalysisResult result = _computeAnalysisResult(path, |
- withUnit: _priorityFiles.contains(path), |
- asIsIfPartWithoutLibrary: true); |
- _resultController.add(result); |
- } catch (exception, stackTrace) { |
- _reportException(path, exception, stackTrace); |
- } |
- return; |
- } |
- } |
- |
void _reportException(String path, exception, StackTrace stackTrace) { |
String contextKey = null; |
if (exception is _ExceptionState) { |
@@ -1304,6 +1360,14 @@ class AnalysisDriverScheduler { |
} |
/** |
+ * Add the given [driver] and schedule it to perform its work. |
+ */ |
+ void add(AnalysisDriverGeneric driver) { |
+ _drivers.add(driver); |
+ _hasWork.notify(); |
+ } |
+ |
+ /** |
* Notify that there is a change to the [driver], it it might need to |
* perform some work. |
*/ |
@@ -1333,14 +1397,6 @@ class AnalysisDriverScheduler { |
Future<Null> waitForIdle() => _statusSupport.waitForIdle(); |
/** |
- * Add the given [driver] and schedule it to perform its work. |
- */ |
- void add(AnalysisDriverGeneric driver) { |
- _drivers.add(driver); |
- _hasWork.notify(); |
- } |
- |
- /** |
* Remove the given [driver] from the scheduler, so that it will not be |
* asked to perform any new work. |
*/ |