| 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.
|
| */
|
|
|