| Index: mojo/public/dart/third_party/analyzer/lib/task/model.dart
|
| diff --git a/mojo/public/dart/third_party/analyzer/lib/task/model.dart b/mojo/public/dart/third_party/analyzer/lib/task/model.dart
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..93755761dcba13a21af0a03cbacee4e42b62522f
|
| --- /dev/null
|
| +++ b/mojo/public/dart/third_party/analyzer/lib/task/model.dart
|
| @@ -0,0 +1,647 @@
|
| +// 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.
|
| +
|
| +library analyzer.task.model;
|
| +
|
| +import 'dart:collection';
|
| +
|
| +import 'package:analyzer/src/generated/engine.dart' hide AnalysisTask;
|
| +import 'package:analyzer/src/generated/error.dart' show AnalysisError;
|
| +import 'package:analyzer/src/generated/java_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';
|
| +
|
| +/**
|
| + * 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 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 source => null;
|
| +}
|
| +
|
| +/**
|
| + * An object with which an analysis result can be associated.
|
| + *
|
| + * Clients are allowed to subtype this class when creating new kinds of targets.
|
| + * Instances of this type are used in hashed data structures, so subtypes are
|
| + * required to correctly implement [==] and [hashCode].
|
| + */
|
| +abstract class AnalysisTarget {
|
| + /**
|
| + * Return the source associated with this target, or `null` if this target is
|
| + * not associated with a source.
|
| + */
|
| + Source get source;
|
| +}
|
| +
|
| +/**
|
| + * An object used to compute one or more analysis results associated with a
|
| + * single target.
|
| + *
|
| + * Clients are expected to extend this class when creating new tasks.
|
| + */
|
| +abstract class AnalysisTask {
|
| + /**
|
| + * 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 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]. Throw an exception if
|
| + * the input value is not defined.
|
| + */
|
| + Object getRequiredInput(String name) {
|
| + if (inputs == null || !inputs.containsKey(name)) {
|
| + throw new AnalysisException("Could not $description: missing $name");
|
| + }
|
| + return inputs[name];
|
| + }
|
| +
|
| + /**
|
| + * 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 should not override this method.
|
| + */
|
| + void perform() {
|
| + try {
|
| + _safelyPerform();
|
| + } on AnalysisException catch (exception, stackTrace) {
|
| + caughtException = new CaughtException(exception, stackTrace);
|
| + AnalysisEngine.instance.logger.logInformation(
|
| + "Task failed: ${description}", caughtException);
|
| + }
|
| + }
|
| +
|
| + @override
|
| + String toString() => description;
|
| +
|
| + /**
|
| + * Perform this analysis task, ensuring that all exceptions are wrapped in an
|
| + * [AnalysisException].
|
| + *
|
| + * Clients should not override this method.
|
| + */
|
| + void _safelyPerform() {
|
| + try {
|
| + //
|
| + // 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;
|
| + Stopwatch stopwatch = stopwatchMap[runtimeType];
|
| + if (stopwatch == null) {
|
| + stopwatch = new Stopwatch();
|
| + stopwatchMap[runtimeType] = stopwatch;
|
| + }
|
| + stopwatch.start();
|
| + //
|
| + // Actually perform the task.
|
| + //
|
| + try {
|
| + if (dependencyCycle != null && !handlesDependencyCycles) {
|
| + throw new InfiniteTaskLoopException(this, dependencyCycle);
|
| + }
|
| + internalPerform();
|
| + } finally {
|
| + stopwatch.stop();
|
| + }
|
| + } on AnalysisException {
|
| + 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 are not expected to subtype 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<List<E>> cachingPolicy}) = ListResultDescriptorImpl<E>;
|
| +
|
| + @override
|
| + ListTaskInput<E> of(AnalysisTarget target);
|
| +}
|
| +
|
| +/**
|
| + * A description of an input to an [AnalysisTask] that can be used to compute
|
| + * that input.
|
| + *
|
| + * Clients are not expected to subtype this class.
|
| + */
|
| +abstract class ListTaskInput<E> extends TaskInput<List<E>> {
|
| + /**
|
| + * 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(UnaryFunction<E, dynamic /*<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(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, dynamic /*V*/ > toMap(
|
| + UnaryFunction<E, dynamic /*<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, dynamic /*V*/ > toMapOf(
|
| + ResultDescriptor /*<V>*/ valueResult);
|
| +}
|
| +
|
| +/**
|
| + * A description of an input with a [Map] based values.
|
| + *
|
| + * Clients are not expected to subtype this class.
|
| + */
|
| +abstract class MapTaskInput<K, V> extends 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(
|
| + BinaryFunction<K, dynamic /*element of V*/, dynamic /*<E>*/ > mapper);
|
| +}
|
| +
|
| +/**
|
| + * 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.
|
| + */
|
| +abstract class ResultCachingPolicy<T> {
|
| + /**
|
| + * 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(T object);
|
| +}
|
| +
|
| +/**
|
| + * A description of an analysis result that can be computed by an [AnalysisTask].
|
| + *
|
| + * Clients are not expected to subtype this class.
|
| + */
|
| +abstract class ResultDescriptor<V> {
|
| + /**
|
| + * 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<V> cachingPolicy}) = ResultDescriptorImpl;
|
| +
|
| + /**
|
| + * Return the caching policy for results described by this descriptor.
|
| + */
|
| + ResultCachingPolicy<V> 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].
|
| + */
|
| + TaskInput<V> of(AnalysisTarget target);
|
| +}
|
| +
|
| +/**
|
| + * A specification of the given [result] for the given [target].
|
| + *
|
| + * Clients are not expected to subtype 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].
|
| + */
|
| +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] will be used to create
|
| + * the instance of [AnalysisTask] thusly described.
|
| + */
|
| + factory TaskDescriptor(String name, BuildTask buildTask,
|
| + CreateTaskInputs inputBuilder,
|
| + List<ResultDescriptor> results) = 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);
|
| +}
|
| +
|
| +/**
|
| + * A description of an input to an [AnalysisTask] that can be used to compute
|
| + * that input.
|
| + *
|
| + * Clients are not expected to subtype 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(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 are not expected to subtype 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 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();
|
| +}
|
| +
|
| +/**
|
| + * [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.
|
| + */
|
| +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.
|
| + */
|
| + 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
|
| +}
|
|
|