|  | // Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file | 
|  | // for details. All rights reserved. Use of this source code is governed by a | 
|  | // BSD-style license that can be found in the LICENSE file. | 
|  |  | 
|  | import 'dart:collection'; | 
|  | import 'dart:developer'; | 
|  |  | 
|  | import 'package:analyzer/error/error.dart' show AnalysisError; | 
|  | import 'package:analyzer/exception/exception.dart'; | 
|  | import 'package:analyzer/src/generated/engine.dart'; | 
|  | import 'package:analyzer/src/generated/source.dart'; | 
|  | import 'package:analyzer/src/generated/utilities_general.dart'; | 
|  | import 'package:analyzer/src/task/driver.dart'; | 
|  | import 'package:analyzer/src/task/model.dart'; | 
|  | import 'package:front_end/src/base/analysis_target.dart'; | 
|  |  | 
|  | export 'package:front_end/src/base/analysis_target.dart' show AnalysisTarget; | 
|  |  | 
|  | /** | 
|  | * A function that converts the given [key] and [value] into a [TaskInput]. | 
|  | */ | 
|  | typedef TaskInput<E> BinaryFunction<K, V, E>(K key, V value); | 
|  |  | 
|  | /** | 
|  | * A function that takes an analysis [context] and an analysis [target] and | 
|  | * returns an analysis task. Such functions are passed to a [TaskDescriptor] to | 
|  | * be used to create the described task. | 
|  | */ | 
|  | typedef AnalysisTask BuildTask(AnalysisContext context, AnalysisTarget target); | 
|  |  | 
|  | /** | 
|  | * A function that takes the target for which a task will produce results and | 
|  | * returns a map from input names to descriptions of the analysis results needed | 
|  | * by the task in order for the task to be performed. Such functions are passed | 
|  | * to a [TaskDescriptor] to be used to determine the inputs needed by the task. | 
|  | */ | 
|  | typedef Map<String, TaskInput> CreateTaskInputs(AnalysisTarget target); | 
|  |  | 
|  | /** | 
|  | * A function that takes the target for which a task will produce results and | 
|  | * returns an indication of how suitable the task is for the target. Such | 
|  | * functions are passed to a [TaskDescriptor] to be used to determine their | 
|  | * suitability for computing results. | 
|  | */ | 
|  | typedef TaskSuitability SuitabilityFor(AnalysisTarget target); | 
|  |  | 
|  | /** | 
|  | * A function that converts an object of the type [B] into a [TaskInput]. | 
|  | * This is used, for example, by a [ListTaskInput] to create task inputs | 
|  | * for each value in a list of values. | 
|  | */ | 
|  | typedef TaskInput<E> UnaryFunction<B, E>(B object); | 
|  |  | 
|  | /** | 
|  | * An [AnalysisTarget] wrapper for an [AnalysisContext]. | 
|  | */ | 
|  | class AnalysisContextTarget implements AnalysisTarget { | 
|  | static final AnalysisContextTarget request = new AnalysisContextTarget(null); | 
|  |  | 
|  | final AnalysisContext context; | 
|  |  | 
|  | AnalysisContextTarget(this.context); | 
|  |  | 
|  | @override | 
|  | Source get librarySource => null; | 
|  |  | 
|  | @override | 
|  | Source get source => null; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * An object used to compute one or more analysis results associated with a | 
|  | * single target. | 
|  | * | 
|  | * Clients must extend this class when creating new tasks. | 
|  | */ | 
|  | abstract class AnalysisTask { | 
|  | /** | 
|  | * A queue storing the last 10 task descriptions for diagnostic purposes. | 
|  | */ | 
|  | static final LimitedQueue<String> LAST_TASKS = new LimitedQueue<String>(10); | 
|  |  | 
|  | /** | 
|  | * A table mapping the types of analysis tasks to the number of times each | 
|  | * kind of task has been performed. | 
|  | */ | 
|  | static final Map<Type, int> countMap = new HashMap<Type, int>(); | 
|  |  | 
|  | /** | 
|  | * A table mapping the types of analysis tasks to user tags used to collect | 
|  | * timing data for the Observatory. | 
|  | */ | 
|  | static Map<Type, UserTag> tagMap = new HashMap<Type, UserTag>(); | 
|  |  | 
|  | /** | 
|  | * A table mapping the types of analysis tasks to stopwatches used to compute | 
|  | * how much time was spent executing each kind of task. | 
|  | */ | 
|  | static final Map<Type, Stopwatch> stopwatchMap = | 
|  | new HashMap<Type, Stopwatch>(); | 
|  |  | 
|  | /** | 
|  | * The context in which the task is to be performed. | 
|  | */ | 
|  | final AnalysisContext context; | 
|  |  | 
|  | /** | 
|  | * The target for which result values are being produced. | 
|  | */ | 
|  | final AnalysisTarget target; | 
|  |  | 
|  | /** | 
|  | * A table mapping input names to input values. | 
|  | */ | 
|  | Map<String, dynamic> inputs; | 
|  |  | 
|  | /** | 
|  | * A table mapping result descriptors whose values are produced by this task | 
|  | * to the values that were produced. | 
|  | */ | 
|  | Map<ResultDescriptor, dynamic> outputs = | 
|  | new HashMap<ResultDescriptor, dynamic>(); | 
|  |  | 
|  | /** | 
|  | * The exception that was thrown while performing this task, or `null` if the | 
|  | * task completed successfully. | 
|  | */ | 
|  | CaughtException caughtException; | 
|  |  | 
|  | /** | 
|  | * If a dependency cycle was found while computing the inputs for the task, | 
|  | * the set of [WorkItem]s contained in the cycle (if there are overlapping | 
|  | * cycles, this is the set of all [WorkItem]s in the entire strongly | 
|  | * connected component).  Otherwise, `null`. | 
|  | */ | 
|  | List<WorkItem> dependencyCycle; | 
|  |  | 
|  | /** | 
|  | * Initialize a newly created task to perform analysis within the given | 
|  | * [context] in order to produce results for the given [target]. | 
|  | */ | 
|  | AnalysisTask(this.context, this.target); | 
|  |  | 
|  | /** | 
|  | * Return a textual description of this task. | 
|  | */ | 
|  | String get description; | 
|  |  | 
|  | /** | 
|  | * Return the descriptor that describes this task. | 
|  | */ | 
|  | TaskDescriptor get descriptor; | 
|  |  | 
|  | /** | 
|  | * Indicates whether the task is capable of handling dependency cycles.  A | 
|  | * task that overrides this getter to return `true` must be prepared for the | 
|  | * possibility that it will be invoked with a non-`null` value of | 
|  | * [dependencyCycle], and with not all of its inputs computed. | 
|  | */ | 
|  | bool get handlesDependencyCycles => false; | 
|  |  | 
|  | /** | 
|  | * Return the value of the input with the given [name], or `null` if the input | 
|  | * value is not defined. | 
|  | */ | 
|  | Object getOptionalInput(String name) { | 
|  | if (inputs == null || !inputs.containsKey(name)) { | 
|  | return null; | 
|  | } | 
|  | return inputs[name]; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Return the value of the input with the given [name]. Throw an exception if | 
|  | * the input value is not defined. | 
|  | */ | 
|  | E getRequiredInput<E>(String name) { | 
|  | if (inputs == null || !inputs.containsKey(name)) { | 
|  | throw new AnalysisException("Could not $description: missing $name"); | 
|  | } | 
|  | if (inputs[name] is! E) { | 
|  | throw new AnalysisException( | 
|  | "Could not $description: $name is a ${inputs[name].runtimeType} rather than a $E"); | 
|  | } | 
|  | return inputs[name] as E; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Return the source associated with the target. Throw an exception if | 
|  | * the target is not associated with a source. | 
|  | */ | 
|  | Source getRequiredSource() { | 
|  | Source source = target.source; | 
|  | if (source == null) { | 
|  | throw new AnalysisException("Could not $description: missing source"); | 
|  | } | 
|  | return source; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Perform this analysis task, protected by an exception handler. | 
|  | * | 
|  | * This method should throw an [AnalysisException] if an exception occurs | 
|  | * while performing the task. If other kinds of exceptions are thrown they | 
|  | * will be wrapped in an [AnalysisException]. | 
|  | * | 
|  | * If no exception is thrown, this method must fully populate the [outputs] | 
|  | * map (have a key/value pair for each result that this task is expected to | 
|  | * produce). | 
|  | */ | 
|  | void internalPerform(); | 
|  |  | 
|  | /** | 
|  | * Perform this analysis task. When this method returns, either the [outputs] | 
|  | * map should be fully populated (have a key/value pair for each result that | 
|  | * this task is expected to produce) or the [caughtException] should be set. | 
|  | * | 
|  | * Clients may not override this method. | 
|  | */ | 
|  | void perform() { | 
|  | try { | 
|  | _safelyPerform(); | 
|  | } on AnalysisException catch (exception, stackTrace) { | 
|  | caughtException = new CaughtException(exception, stackTrace); | 
|  | AnalysisEngine.instance.logger | 
|  | .logError("Task failed: $description", caughtException); | 
|  | } | 
|  | } | 
|  |  | 
|  | @override | 
|  | String toString() => description; | 
|  |  | 
|  | /** | 
|  | * Given a strongly connected component, find and return a list of | 
|  | * [TargetedResult]s that describes a cyclic path within the cycle.  Returns | 
|  | * null if no cyclic path is found. | 
|  | */ | 
|  | List<TargetedResult> _findCyclicPath(List<WorkItem> cycle) { | 
|  | WorkItem findInCycle(AnalysisTarget target, ResultDescriptor descriptor) { | 
|  | for (WorkItem item in cycle) { | 
|  | if (target == item.target && descriptor == item.spawningResult) { | 
|  | return item; | 
|  | } | 
|  | } | 
|  | return null; | 
|  | } | 
|  |  | 
|  | HashSet<WorkItem> active = new HashSet<WorkItem>(); | 
|  | List<TargetedResult> path = null; | 
|  | bool traverse(WorkItem item) { | 
|  | if (!active.add(item)) { | 
|  | // We've found a cycle | 
|  | path = <TargetedResult>[]; | 
|  | return true; | 
|  | } | 
|  | for (TargetedResult result in item.inputTargetedResults) { | 
|  | WorkItem item = findInCycle(result.target, result.result); | 
|  | // Ignore edges that leave the cycle. | 
|  | if (item != null) { | 
|  | if (traverse(item)) { | 
|  | // This edge is in a cycle (or leads to a cycle) so add it to the | 
|  | // path | 
|  | path.add(result); | 
|  | return true; | 
|  | } | 
|  | } | 
|  | } | 
|  | // There was no cycle. | 
|  | return false; | 
|  | } | 
|  |  | 
|  | if (cycle.length > 0) { | 
|  | traverse(cycle[0]); | 
|  | } | 
|  | return path; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Perform this analysis task, ensuring that all exceptions are wrapped in an | 
|  | * [AnalysisException]. | 
|  | * | 
|  | * Clients may not override this method. | 
|  | */ | 
|  | void _safelyPerform() { | 
|  | try { | 
|  | // | 
|  | // Store task description for diagnostics. | 
|  | // | 
|  | LAST_TASKS.add(description); | 
|  |  | 
|  | // | 
|  | // Report that this task is being performed. | 
|  | // | 
|  | String contextName = context.name; | 
|  | if (contextName == null) { | 
|  | contextName = 'unnamed'; | 
|  | } | 
|  | AnalysisEngine.instance.instrumentationService | 
|  | .logAnalysisTask(contextName, this); | 
|  | // | 
|  | // Gather statistics on the performance of the task. | 
|  | // | 
|  | int count = countMap[runtimeType]; | 
|  | countMap[runtimeType] = count == null ? 1 : count + 1; | 
|  | //      UserTag tag = tagMap.putIfAbsent( | 
|  | //          runtimeType, () => new UserTag(runtimeType.toString())); | 
|  | Stopwatch stopwatch = stopwatchMap[runtimeType]; | 
|  | if (stopwatch == null) { | 
|  | stopwatch = new Stopwatch(); | 
|  | stopwatchMap[runtimeType] = stopwatch; | 
|  | } | 
|  | //      UserTag previousTag = tag.makeCurrent(); | 
|  | //      try { | 
|  | stopwatch.start(); | 
|  | // | 
|  | // Actually perform the task. | 
|  | // | 
|  | try { | 
|  | if (dependencyCycle != null && !handlesDependencyCycles) { | 
|  | throw new InfiniteTaskLoopException( | 
|  | this, dependencyCycle, _findCyclicPath(dependencyCycle)); | 
|  | } | 
|  | internalPerform(); | 
|  | } finally { | 
|  | stopwatch.stop(); | 
|  | } | 
|  | //      } finally { | 
|  | //        previousTag.makeCurrent(); | 
|  | //      } | 
|  | } on AnalysisException { | 
|  | rethrow; | 
|  | } on ModificationTimeMismatchError { | 
|  | rethrow; | 
|  | } catch (exception, stackTrace) { | 
|  | throw new AnalysisException( | 
|  | 'Unexpected exception while performing $description', | 
|  | new CaughtException(exception, stackTrace)); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * A description of a [List]-based analysis result that can be computed by an | 
|  | * [AnalysisTask]. | 
|  | * | 
|  | * Clients may not extend, implement or mix-in this class. | 
|  | */ | 
|  | abstract class ListResultDescriptor<E> implements ResultDescriptor<List<E>> { | 
|  | /** | 
|  | * Initialize a newly created analysis result to have the given [name] and | 
|  | * [defaultValue]. If a [cachingPolicy] is provided, it will control how long | 
|  | * values associated with this result will remain in the cache. | 
|  | */ | 
|  | factory ListResultDescriptor(String name, List<E> defaultValue, | 
|  | {ResultCachingPolicy cachingPolicy}) = ListResultDescriptorImpl<E>; | 
|  |  | 
|  | @override | 
|  | ListTaskInput<E> of(AnalysisTarget target, {bool flushOnAccess: false}); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * A description of an input to an [AnalysisTask] that can be used to compute | 
|  | * that input. | 
|  | * | 
|  | * Clients may not extend, implement or mix-in this class. | 
|  | */ | 
|  | abstract class ListTaskInput<E> implements TaskInput<List<E>> { | 
|  | /** | 
|  | * Return a task input that can be used to compute a flatten list whose | 
|  | * elements are combined [subListResult]'s associated with those elements. | 
|  | */ | 
|  | ListTaskInput<V> toFlattenListOf<V>(ListResultDescriptor<V> subListResult); | 
|  |  | 
|  | /** | 
|  | * Return a task input that can be used to compute a list whose elements are | 
|  | * the result of passing the elements of this input to the [mapper] function. | 
|  | */ | 
|  | ListTaskInput<V> toList<V>(UnaryFunction<E, V> mapper); | 
|  |  | 
|  | /** | 
|  | * Return a task input that can be used to compute a list whose elements are | 
|  | * [valueResult]'s associated with those elements. | 
|  | */ | 
|  | ListTaskInput<V> toListOf<V>(ResultDescriptor<V> valueResult); | 
|  |  | 
|  | /** | 
|  | * Return a task input that can be used to compute a map whose keys are the | 
|  | * elements of this input and whose values are the result of passing the | 
|  | * corresponding key to the [mapper] function. | 
|  | */ | 
|  | MapTaskInput<E, V> toMap<V>(UnaryFunction<E, V> mapper); | 
|  |  | 
|  | /** | 
|  | * Return a task input that can be used to compute a map whose keys are the | 
|  | * elements of this input and whose values are the [valueResult]'s associated | 
|  | * with those elements. | 
|  | */ | 
|  | MapTaskInput<AnalysisTarget, V> toMapOf<V>(ResultDescriptor<V> valueResult); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * A description of an input with a [Map] based values. | 
|  | * | 
|  | * Clients may not extend, implement or mix-in this class. | 
|  | */ | 
|  | abstract class MapTaskInput<K, V> implements TaskInput<Map<K, V>> { | 
|  | /** | 
|  | * [V] must be a [List]. | 
|  | * Return a task input that can be used to compute a list whose elements are | 
|  | * the result of passing keys [K] and the corresponding elements of [V] to | 
|  | * the [mapper] function. | 
|  | */ | 
|  | TaskInput<List<E>> toFlattenList<E>( | 
|  | BinaryFunction<K, dynamic /*element of V*/, E> mapper); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Instances of this class are thrown when a task detects that the modification | 
|  | * time of a cache entry is not the same as the actual modification time.  This | 
|  | * means that any analysis results based on the content of the target cannot be | 
|  | * used anymore and must be invalidated. | 
|  | */ | 
|  | class ModificationTimeMismatchError { | 
|  | final Source source; | 
|  |  | 
|  | ModificationTimeMismatchError(this.source); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * A policy object that can compute sizes of results and provide the maximum | 
|  | * active and idle sizes that can be kept in the cache. | 
|  | * | 
|  | * All the [ResultDescriptor]s with the same [ResultCachingPolicy] instance | 
|  | * share the same total size in a cache. | 
|  | * | 
|  | * Clients may implement this class when implementing plugins. | 
|  | */ | 
|  | abstract class ResultCachingPolicy { | 
|  | /** | 
|  | * Return the maximum total size of results that can be kept in the cache | 
|  | * while analysis is in progress. | 
|  | */ | 
|  | int get maxActiveSize; | 
|  |  | 
|  | /** | 
|  | * Return the maximum total size of results that can be kept in the cache | 
|  | * while analysis is idle. | 
|  | */ | 
|  | int get maxIdleSize; | 
|  |  | 
|  | /** | 
|  | * Return the size of the given [object]. | 
|  | */ | 
|  | int measure(Object object); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * A description of an analysis result that can be computed by an [AnalysisTask]. | 
|  | * | 
|  | * Clients may not extend, implement or mix-in this class. | 
|  | */ | 
|  | abstract class ResultDescriptor<V> { | 
|  | /** | 
|  | * A comparator that can be used to sort result descriptors by their name. | 
|  | */ | 
|  | static final Comparator<ResultDescriptor> SORT_BY_NAME = | 
|  | (ResultDescriptor first, ResultDescriptor second) => | 
|  | first.name.compareTo(second.name); | 
|  |  | 
|  | /** | 
|  | * Initialize a newly created analysis result to have the given [name] and | 
|  | * [defaultValue]. | 
|  | * | 
|  | * The given [cachingPolicy] is used to limit the total size of results | 
|  | * described by this descriptor. If no policy is specified, the results are | 
|  | * never evicted from the cache, and removed only when they are invalidated. | 
|  | */ | 
|  | factory ResultDescriptor(String name, V defaultValue, | 
|  | {ResultCachingPolicy cachingPolicy}) = ResultDescriptorImpl<V>; | 
|  |  | 
|  | /** | 
|  | * Return the caching policy for results described by this descriptor. | 
|  | */ | 
|  | ResultCachingPolicy get cachingPolicy; | 
|  |  | 
|  | /** | 
|  | * Return the default value for results described by this descriptor. | 
|  | */ | 
|  | V get defaultValue; | 
|  |  | 
|  | /** | 
|  | * Return the name of this descriptor. | 
|  | */ | 
|  | String get name; | 
|  |  | 
|  | /** | 
|  | * Return a task input that can be used to compute this result for the given | 
|  | * [target]. If [flushOnAccess] is `true` then the value of this result that | 
|  | * is associated with the [target] will be flushed when it is accessed. | 
|  | */ | 
|  | TaskInput<V> of(AnalysisTarget target, {bool flushOnAccess: false}); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * A specification of the given [result] for the given [target]. | 
|  | * | 
|  | * Clients may not extend, implement or mix-in this class. | 
|  | */ | 
|  | 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 description of an [AnalysisTask]. | 
|  | * | 
|  | * Clients may not extend, implement or mix-in this class. | 
|  | */ | 
|  | abstract class TaskDescriptor { | 
|  | /** | 
|  | * Initialize a newly created task descriptor to have the given [name] and to | 
|  | * describe a task that takes the inputs built using the given [inputBuilder], | 
|  | * and produces the given [results]. The [buildTask] function will be used to | 
|  | * create the instance of [AnalysisTask] being described. If provided, the | 
|  | * [isAppropriateFor] function will be used to determine whether the task can | 
|  | * be used on a specific target. | 
|  | */ | 
|  | factory TaskDescriptor(String name, BuildTask buildTask, | 
|  | CreateTaskInputs inputBuilder, List<ResultDescriptor> results, | 
|  | {SuitabilityFor suitabilityFor}) = TaskDescriptorImpl; | 
|  |  | 
|  | /** | 
|  | * Return the builder used to build the inputs to the task. | 
|  | */ | 
|  | CreateTaskInputs get createTaskInputs; | 
|  |  | 
|  | /** | 
|  | * Return the name of the task being described. | 
|  | */ | 
|  | String get name; | 
|  |  | 
|  | /** | 
|  | * Return a list of the analysis results that will be computed by this task. | 
|  | */ | 
|  | List<ResultDescriptor> get results; | 
|  |  | 
|  | /** | 
|  | * Create and return a task that is described by this descriptor that can be | 
|  | * used to compute results based on the given [inputs]. | 
|  | */ | 
|  | AnalysisTask createTask(AnalysisContext context, AnalysisTarget target, | 
|  | Map<String, dynamic> inputs); | 
|  |  | 
|  | /** | 
|  | * Return an indication of how suitable this task is for the given [target]. | 
|  | */ | 
|  | TaskSuitability suitabilityFor(AnalysisTarget target); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * A description of an input to an [AnalysisTask] that can be used to compute | 
|  | * that input. | 
|  | * | 
|  | * Clients may not extend, implement or mix-in this class. | 
|  | */ | 
|  | abstract class TaskInput<V> { | 
|  | /** | 
|  | * Create and return a builder that can be used to build this task input. | 
|  | */ | 
|  | TaskInputBuilder<V> createBuilder(); | 
|  |  | 
|  | /** | 
|  | * Return a task input that can be used to compute a list whose elements are | 
|  | * the result of passing the result of this input to the [mapper] function. | 
|  | */ | 
|  | ListTaskInput<E> mappedToList<E>(List<E> mapper(V value)); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * An object used to build the value associated with a single [TaskInput]. | 
|  | * | 
|  | * All builders work by requesting one or more results (each result being | 
|  | * associated with a target). The interaction pattern is modeled after the class | 
|  | * [Iterator], in which the method [moveNext] is invoked to move from one result | 
|  | * request to the next. The getters [currentResult] and [currentTarget] are used | 
|  | * to get the result and target of the current request. The value of the result | 
|  | * must be supplied using the [currentValue] setter before [moveNext] can be | 
|  | * invoked to move to the next request. When [moveNext] returns `false`, | 
|  | * indicating that there are no more requests, the method [inputValue] can be | 
|  | * used to access the value of the input that was built. | 
|  | * | 
|  | * Clients may not extend, implement or mix-in this class. | 
|  | */ | 
|  | abstract class TaskInputBuilder<V> { | 
|  | /** | 
|  | * Return the result that needs to be computed, or `null` if [moveNext] has | 
|  | * not been invoked or if the last invocation of [moveNext] returned `false`. | 
|  | */ | 
|  | ResultDescriptor get currentResult; | 
|  |  | 
|  | /** | 
|  | * Return the target for which the result needs to be computed, or `null` if | 
|  | * [moveNext] has not been invoked or if the last invocation of [moveNext] | 
|  | * returned `false`. | 
|  | */ | 
|  | AnalysisTarget get currentTarget; | 
|  |  | 
|  | /** | 
|  | * Set the [value] that was computed for the current result. | 
|  | * | 
|  | * Throws a [StateError] if [moveNext] has not been invoked or if the last | 
|  | * invocation of [moveNext] returned `false`. | 
|  | */ | 
|  | void set currentValue(Object value); | 
|  |  | 
|  | /** | 
|  | * Return `true` if the value accessed by this input builder should be flushed | 
|  | * from the cache at the time it is retrieved. | 
|  | */ | 
|  | bool get flushOnAccess; | 
|  |  | 
|  | /** | 
|  | * Return the [value] that was computed by this builder. | 
|  | * | 
|  | * Throws a [StateError] if [moveNext] has not been invoked or if the last | 
|  | * invocation of [moveNext] returned `true`. | 
|  | * | 
|  | * Returns `null` if no value could be computed due to a circular dependency. | 
|  | */ | 
|  | V get inputValue; | 
|  |  | 
|  | /** | 
|  | * Record that no value is available for the current result, due to a | 
|  | * circular dependency. | 
|  | * | 
|  | * Throws a [StateError] if [moveNext] has not been invoked or if the last | 
|  | * invocation of [moveNext] returned `false`. | 
|  | */ | 
|  | void currentValueNotAvailable(); | 
|  |  | 
|  | /** | 
|  | * Move to the next result that needs to be computed in order to build the | 
|  | * inputs for a task. Return `true` if there is another result that needs to | 
|  | * be computed, or `false` if the inputs have been computed. | 
|  | * | 
|  | * It is safe to invoke [moveNext] after it has returned `false`. In this case | 
|  | * [moveNext] has no effect and will again return `false`. | 
|  | * | 
|  | * Throws a [StateError] if the value of the current result has not been | 
|  | * provided using [currentValue]. | 
|  | */ | 
|  | bool moveNext(); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * An indication of how suitable a task is for a given target. | 
|  | */ | 
|  | enum TaskSuitability { NONE, LOWEST, HIGHEST } | 
|  |  | 
|  | /** | 
|  | * [WorkManager]s are used to drive analysis. | 
|  | * | 
|  | * They know specific of the targets and results they care about, | 
|  | * so they can request analysis results in optimal order. | 
|  | * | 
|  | * Clients may implement this class when implementing plugins. | 
|  | */ | 
|  | abstract class WorkManager { | 
|  | /** | 
|  | * Notifies the manager about changes in the explicit source list. | 
|  | */ | 
|  | void applyChange(List<Source> addedSources, List<Source> changedSources, | 
|  | List<Source> removedSources); | 
|  |  | 
|  | /** | 
|  | * Notifies the managers that the given set of priority [targets] was set. | 
|  | */ | 
|  | void applyPriorityTargets(List<AnalysisTarget> targets); | 
|  |  | 
|  | /** | 
|  | * Return a list of all of the errors associated with the given [source]. | 
|  | * The list of errors will be empty if the source is not known to the context | 
|  | * or if there are no errors in the source. The errors contained in the list | 
|  | * can be incomplete. | 
|  | */ | 
|  | List<AnalysisError> getErrors(Source source); | 
|  |  | 
|  | /** | 
|  | * Return the next [TargetedResult] that this work manager wants to be | 
|  | * computed, or `null` if this manager doesn't need any new results. | 
|  | * | 
|  | * Note, that it is not guaranteed that this result will be computed, it is | 
|  | * up to the work manager to check whether the result is already computed | 
|  | * (for example during the next [getNextResult] invocation) or computation | 
|  | * of the same result should be requested again. | 
|  | */ | 
|  | TargetedResult getNextResult(); | 
|  |  | 
|  | /** | 
|  | * Return the priority if the next work order this work manager want to be | 
|  | * computed. The [AnalysisDriver] will perform the work order with | 
|  | * the highest priority. | 
|  | * | 
|  | * Even if the returned value is [WorkOrderPriority.NONE], it still does not | 
|  | * guarantee that [getNextResult] will return not `null`. | 
|  | */ | 
|  | WorkOrderPriority getNextResultPriority(); | 
|  |  | 
|  | /** | 
|  | * Notifies the manager about analysis options changes. | 
|  | */ | 
|  | void onAnalysisOptionsChanged(); | 
|  |  | 
|  | /** | 
|  | * Notifies the manager about [SourceFactory] changes. | 
|  | */ | 
|  | void onSourceFactoryChanged(); | 
|  |  | 
|  | /** | 
|  | * Notifies the manager that the given [outputs] were produced for | 
|  | * the given [target]. | 
|  | */ | 
|  | void resultsComputed( | 
|  | AnalysisTarget target, Map<ResultDescriptor, dynamic> outputs); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * The priorities of work orders returned by [WorkManager]s. | 
|  | * | 
|  | * New priorities may be added with time, clients need to tolerate this. | 
|  | */ | 
|  | enum WorkOrderPriority { | 
|  | /** | 
|  | * Responding to an user's action. | 
|  | */ | 
|  | INTERACTIVE, | 
|  |  | 
|  | /** | 
|  | * Computing information for priority sources. | 
|  | */ | 
|  | PRIORITY, | 
|  |  | 
|  | /** | 
|  | * A work should be done, but without any special urgency. | 
|  | */ | 
|  | NORMAL, | 
|  |  | 
|  | /** | 
|  | * Nothing to do. | 
|  | */ | 
|  | NONE | 
|  | } |