| Index: pkg/analyzer/lib/src/context/context.dart
|
| diff --git a/pkg/analyzer/lib/src/context/context.dart b/pkg/analyzer/lib/src/context/context.dart
|
| index 6467bfb18ca417f466b3810c7312d13eb803464d..52ab424cb7f83e9e331cdc5b2a166229551f11ce 100644
|
| --- a/pkg/analyzer/lib/src/context/context.dart
|
| +++ b/pkg/analyzer/lib/src/context/context.dart
|
| @@ -608,8 +608,9 @@ class AnalysisContextImpl implements InternalAnalysisContext {
|
| !AnalysisEngine.isDartFileName(librarySource.shortName)) {
|
| return new CancelableFuture.error(new AnalysisNotScheduledError());
|
| }
|
| + var unitTarget = new LibrarySpecificUnit(librarySource, unitSource);
|
| return new _AnalysisFutureHelper<CompilationUnit>(this).computeAsync(
|
| - new LibrarySpecificUnit(librarySource, unitSource), (CacheEntry entry) {
|
| + unitTarget, (CacheEntry entry) {
|
| CacheState state = entry.getState(RESOLVED_UNIT);
|
| if (state == CacheState.ERROR) {
|
| throw entry.exception;
|
| @@ -617,6 +618,8 @@ class AnalysisContextImpl implements InternalAnalysisContext {
|
| return null;
|
| }
|
| return entry.getValue(RESOLVED_UNIT);
|
| + }, () {
|
| + dartWorkManager.addPriorityResult(unitTarget, RESOLVED_UNIT);
|
| });
|
| }
|
|
|
| @@ -899,13 +902,6 @@ class AnalysisContextImpl implements InternalAnalysisContext {
|
| return builder.createPublicNamespaceForLibrary(library);
|
| }
|
|
|
| - /**
|
| - * Return the cache entry associated with the given [target], or `null` if
|
| - * there is no entry associated with the target.
|
| - */
|
| - CacheEntry getReadableSourceEntryOrNull(AnalysisTarget target) =>
|
| - _cache.get(target);
|
| -
|
| @override
|
| CompilationUnit getResolvedCompilationUnit(
|
| Source unitSource, LibraryElement library) {
|
| @@ -1045,6 +1041,7 @@ class AnalysisContextImpl implements InternalAnalysisContext {
|
| @override
|
| AnalysisResult performAnalysisTask() {
|
| return PerformanceStatistics.performAnaysis.makeCurrentWhile(() {
|
| + _evaluatePendingFutures();
|
| bool done = !driver.performAnalysisTask();
|
| if (done) {
|
| done = !_validateCacheConsistency();
|
| @@ -1061,6 +1058,20 @@ class AnalysisContextImpl implements InternalAnalysisContext {
|
| });
|
| }
|
|
|
| + void _evaluatePendingFutures() {
|
| + for (AnalysisTarget target in _pendingFutureTargets.keys) {
|
| + CacheEntry cacheEntry = _cache.get(target);
|
| + List<PendingFuture> pendingFutures = _pendingFutureTargets[target];
|
| + for (int i = 0; i < pendingFutures.length;) {
|
| + if (pendingFutures[i].evaluate(cacheEntry)) {
|
| + pendingFutures.removeAt(i);
|
| + } else {
|
| + i++;
|
| + }
|
| + }
|
| + }
|
| + }
|
| +
|
| @override
|
| void recordLibraryElements(Map<Source, LibraryElement> elementMap) {
|
| elementMap.forEach((Source librarySource, LibraryElement library) {
|
| @@ -1926,8 +1937,8 @@ class SdkAnalysisContext extends AnalysisContextImpl {
|
| }
|
|
|
| /**
|
| - * A helper class used to create futures for AnalysisContextImpl. Using a helper
|
| - * class allows us to preserve the generic parameter T.
|
| + * A helper class used to create futures for [AnalysisContextImpl].
|
| + * Using a helper class allows us to preserve the generic parameter T.
|
| */
|
| class _AnalysisFutureHelper<T> {
|
| final AnalysisContextImpl _context;
|
| @@ -1936,11 +1947,13 @@ class _AnalysisFutureHelper<T> {
|
|
|
| /**
|
| * Return a future that will be completed with the result of calling
|
| - * [computeValue]. If [computeValue] returns non-`null`, the future will be
|
| - * completed immediately with the resulting value. If it returns `null`, then
|
| - * it will be re-executed in the future, after the next time the cached
|
| - * information for [target] has changed. If [computeValue] throws an
|
| - * exception, the future will fail with that exception.
|
| + * [computeValue]. If [computeValue] returns non-`null`, the future will be
|
| + * completed immediately with the resulting value. If it returns `null`, then
|
| + * [scheduleComputation] is invoked to schedule analysis that will produce
|
| + * the required result, and [computeValue] will be re-executed in the future,
|
| + * after the next time the cached information for [target] has changed. If
|
| + * [computeValue] throws an exception, the future will fail with that
|
| + * exception.
|
| *
|
| * If the [computeValue] still returns `null` after there is no further
|
| * analysis to be done for [target], then the future will be completed with
|
| @@ -1950,23 +1963,21 @@ class _AnalysisFutureHelper<T> {
|
| * updated, it should be free of side effects so that it doesn't cause
|
| * reentrant changes to the analysis state.
|
| */
|
| - CancelableFuture<T> computeAsync(
|
| - AnalysisTarget target, T computeValue(CacheEntry entry)) {
|
| + CancelableFuture<T> computeAsync(AnalysisTarget target,
|
| + T computeValue(CacheEntry entry), void scheduleComputation()) {
|
| if (_context.isDisposed) {
|
| // No further analysis is expected, so return a future that completes
|
| // immediately with AnalysisNotScheduledError.
|
| return new CancelableFuture.error(new AnalysisNotScheduledError());
|
| }
|
| - CacheEntry entry = _context.getReadableSourceEntryOrNull(target);
|
| - if (entry == null) {
|
| - return new CancelableFuture.error(new AnalysisNotScheduledError());
|
| - }
|
| + CacheEntry entry = _context.getCacheEntry(target);
|
| PendingFuture pendingFuture =
|
| new PendingFuture<T>(_context, target, computeValue);
|
| if (!pendingFuture.evaluate(entry)) {
|
| _context._pendingFutureTargets
|
| .putIfAbsent(target, () => <PendingFuture>[])
|
| .add(pendingFuture);
|
| + scheduleComputation();
|
| }
|
| return pendingFuture.future;
|
| }
|
|
|