| Index: pkg/analyzer/lib/src/context/cache.dart
|
| diff --git a/pkg/analyzer/lib/src/context/cache.dart b/pkg/analyzer/lib/src/context/cache.dart
|
| index 08c7c58978773e10eab5c931099aa68f855c6af3..4ef2814a792dabf89efce162db140f8391556782 100644
|
| --- a/pkg/analyzer/lib/src/context/cache.dart
|
| +++ b/pkg/analyzer/lib/src/context/cache.dart
|
| @@ -13,6 +13,7 @@ import 'package:analyzer/src/generated/html.dart';
|
| import 'package:analyzer/src/generated/java_engine.dart';
|
| import 'package:analyzer/src/generated/source.dart';
|
| import 'package:analyzer/src/generated/utilities_collection.dart';
|
| +import 'package:analyzer/src/generated/utilities_general.dart';
|
| import 'package:analyzer/task/model.dart';
|
|
|
| /**
|
| @@ -134,6 +135,8 @@ class AnalysisCache {
|
| * Associate the given [entry] with the given [target].
|
| */
|
| void put(AnalysisTarget target, CacheEntry entry) {
|
| + entry._cache = this;
|
| + entry._target = target;
|
| entry.fixExceptionState();
|
| int count = _partitions.length;
|
| for (int i = 0; i < count; i++) {
|
| @@ -213,6 +216,18 @@ class AnalysisCache {
|
| }
|
| }
|
| }
|
| +
|
| + ResultData _getDataFor(TargetedResult result) {
|
| + AnalysisTarget target = result.target;
|
| + int count = _partitions.length;
|
| + for (int i = 0; i < count; i++) {
|
| + if (_partitions[i].contains(target)) {
|
| + CacheEntry entry = _partitions[i].get(target);
|
| + return entry._getResultData(result.result);
|
| + }
|
| + }
|
| + return null;
|
| + }
|
| }
|
|
|
| /**
|
| @@ -227,6 +242,16 @@ class CacheEntry {
|
| static int _EXPLICITLY_ADDED_FLAG = 0;
|
|
|
| /**
|
| + * The cache that contains this entry.
|
| + */
|
| + AnalysisCache _cache;
|
| +
|
| + /**
|
| + * The target this entry is about.
|
| + */
|
| + AnalysisTarget _target;
|
| +
|
| + /**
|
| * The most recent time at which the state of the target matched the state
|
| * represented by this entry.
|
| */
|
| @@ -363,9 +388,9 @@ class CacheEntry {
|
| getState(descriptor) == CacheState.VALID;
|
|
|
| /**
|
| - * Set the [CacheState.ERROR] state for given [descriptors], their values to
|
| - * the corresponding default values, and remember the [exception] that caused
|
| - * this state.
|
| + * For each of the given [descriptors], set their states to
|
| + * [CacheState.ERROR], their values to the corresponding default values, and
|
| + * remember the [exception] that caused this state.
|
| */
|
| void setErrorState(
|
| CaughtException exception, List<ResultDescriptor> descriptors) {
|
| @@ -378,8 +403,8 @@ class CacheEntry {
|
| this._exception = exception;
|
| for (ResultDescriptor descriptor in descriptors) {
|
| ResultData data = _getResultData(descriptor);
|
| - data.state = CacheState.ERROR;
|
| - data.value = descriptor.defaultValue;
|
| + TargetedResult thisResult = new TargetedResult(_target, descriptor);
|
| + data.invalidate(_cache, thisResult, CacheState.ERROR);
|
| }
|
| }
|
|
|
| @@ -396,7 +421,11 @@ class CacheEntry {
|
| }
|
| _validateStateChange(descriptor, state);
|
| if (state == CacheState.INVALID) {
|
| - _resultMap.remove(descriptor);
|
| + ResultData data = _resultMap[descriptor];
|
| + if (data != null) {
|
| + TargetedResult thisResult = new TargetedResult(_target, descriptor);
|
| + data.invalidate(_cache, thisResult, CacheState.INVALID);
|
| + }
|
| } else {
|
| ResultData data = _getResultData(descriptor);
|
| data.state = state;
|
| @@ -415,9 +444,14 @@ class CacheEntry {
|
| * given [value].
|
| */
|
| /*<V>*/ void setValue(ResultDescriptor /*<V>*/ descriptor, dynamic /*V*/
|
| - value) {
|
| + value, List<TargetedResult> dependedOn) {
|
| _validateStateChange(descriptor, CacheState.VALID);
|
| ResultData data = _getResultData(descriptor);
|
| + {
|
| + TargetedResult thisResult = new TargetedResult(_target, descriptor);
|
| + data.invalidate(_cache, thisResult, CacheState.INVALID);
|
| + data.setDependedOnResults(_cache, thisResult, dependedOn);
|
| + }
|
| data.state = CacheState.VALID;
|
| data.value = value == null ? descriptor.defaultValue : value;
|
| }
|
| @@ -771,6 +805,11 @@ class DefaultRetentionPolicy implements CacheRetentionPolicy {
|
| // can be typed.
|
| class ResultData {
|
| /**
|
| + * The [ResultDescriptor] this result is for.
|
| + */
|
| + final ResultDescriptor descriptor;
|
| +
|
| + /**
|
| * The state of the cached value.
|
| */
|
| CacheState state;
|
| @@ -782,13 +821,78 @@ class ResultData {
|
| Object value;
|
|
|
| /**
|
| + * A list of the results on which this result depends.
|
| + */
|
| + List<TargetedResult> dependedOnResults = <TargetedResult>[];
|
| +
|
| + /**
|
| + * A list of the results that depend on this result.
|
| + */
|
| + List<TargetedResult> dependentResults = <TargetedResult>[];
|
| +
|
| + /**
|
| * Initialize a newly created result holder to represent the value of data
|
| * described by the given [descriptor].
|
| */
|
| - ResultData(ResultDescriptor descriptor) {
|
| + ResultData(this.descriptor) {
|
| state = CacheState.INVALID;
|
| value = descriptor.defaultValue;
|
| }
|
| +
|
| + /**
|
| + * Add the given [result] to the list of dependent results.
|
| + */
|
| + void addDependentResult(TargetedResult result) {
|
| + dependentResults.add(result);
|
| + }
|
| +
|
| + /**
|
| + * Invalidate this [ResultData] that corresponds to [thisResult] and
|
| + * propagate invalidation to the results that depend on this one.
|
| + */
|
| + void invalidate(
|
| + AnalysisCache cache, TargetedResult thisResult, CacheState newState) {
|
| + // Invalidate this result.
|
| + state = newState;
|
| + value = descriptor.defaultValue;
|
| + // Stop depending on other results.
|
| + List<TargetedResult> dependedOnResults = this.dependedOnResults;
|
| + this.dependedOnResults = <TargetedResult>[];
|
| + dependedOnResults.forEach((TargetedResult dependedOnResult) {
|
| + ResultData data = cache._getDataFor(dependedOnResult);
|
| + data.removeDependentResult(thisResult);
|
| + });
|
| + // Invalidate results that depend on this result.
|
| + List<TargetedResult> dependentResults = this.dependentResults;
|
| + this.dependentResults = <TargetedResult>[];
|
| + dependentResults.forEach((TargetedResult dependentResult) {
|
| + ResultData data = cache._getDataFor(dependentResult);
|
| + data.invalidate(cache, dependentResult, newState);
|
| + });
|
| + }
|
| +
|
| + /**
|
| + * Remove the given [result] from the list of dependent results.
|
| + */
|
| + void removeDependentResult(TargetedResult result) {
|
| + dependentResults.remove(result);
|
| + }
|
| +
|
| + /**
|
| + * Set the [dependedOn] on which this result depends.
|
| + */
|
| + void setDependedOnResults(AnalysisCache cache, TargetedResult thisResult,
|
| + List<TargetedResult> dependedOn) {
|
| + dependedOnResults.forEach((TargetedResult dependedOnResult) {
|
| + ResultData data = cache._getDataFor(dependedOnResult);
|
| + data.removeDependentResult(thisResult);
|
| + });
|
| + dependedOnResults = dependedOn;
|
| + dependedOnResults.forEach((TargetedResult dependentResult) {
|
| + ResultData data = cache._getDataFor(dependentResult);
|
| + data.addDependentResult(thisResult);
|
| + });
|
| + }
|
| }
|
|
|
| /**
|
| @@ -811,6 +915,46 @@ class SdkCachePartition extends CachePartition {
|
| }
|
|
|
| /**
|
| + * A specification of a specific result computed for a specific target.
|
| + */
|
| +class TargetedResult {
|
| + /**
|
| + * An empty list of results.
|
| + */
|
| + static final List<TargetedResult> EMPTY_LIST = const <TargetedResult>[];
|
| +
|
| + /**
|
| + * The target with which the result is associated.
|
| + */
|
| + final AnalysisTarget target;
|
| +
|
| + /**
|
| + * The result associated with the target.
|
| + */
|
| + final ResultDescriptor result;
|
| +
|
| + /**
|
| + * Initialize a new targeted result.
|
| + */
|
| + TargetedResult(this.target, this.result);
|
| +
|
| + @override
|
| + int get hashCode {
|
| + return JenkinsSmiHash.combine(target.hashCode, result.hashCode);
|
| + }
|
| +
|
| + @override
|
| + bool operator ==(other) {
|
| + return other is TargetedResult &&
|
| + other.target == target &&
|
| + other.result == result;
|
| + }
|
| +
|
| + @override
|
| + String toString() => '$result for $target';
|
| +}
|
| +
|
| +/**
|
| * A cache partition that contains all targets not contained in other partitions.
|
| */
|
| class UniversalCachePartition extends CachePartition {
|
|
|