| Index: packages/analyzer/lib/task/model.dart
|
| diff --git a/analyzer/lib/task/model.dart b/packages/analyzer/lib/task/model.dart
|
| similarity index 77%
|
| rename from analyzer/lib/task/model.dart
|
| rename to packages/analyzer/lib/task/model.dart
|
| index 0a457661e8283f191e7ce78fd6e46a0ac4fd6bcf..9d949c308f836f0ec532fef3850f5e63d5bb39ff 100644
|
| --- a/analyzer/lib/task/model.dart
|
| +++ b/packages/analyzer/lib/task/model.dart
|
| @@ -5,10 +5,13 @@
|
| library analyzer.task.model;
|
|
|
| import 'dart:collection';
|
| +import 'dart:developer';
|
|
|
| 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';
|
|
|
| @@ -82,6 +85,12 @@ abstract class AnalysisTask {
|
| 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.
|
| */
|
| @@ -196,8 +205,8 @@ abstract class AnalysisTask {
|
| _safelyPerform();
|
| } on AnalysisException catch (exception, stackTrace) {
|
| caughtException = new CaughtException(exception, stackTrace);
|
| - AnalysisEngine.instance.logger.logInformation(
|
| - "Task failed: ${description}", caughtException);
|
| + AnalysisEngine.instance.logger
|
| + .logInformation("Task failed: ${description}", caughtException);
|
| }
|
| }
|
|
|
| @@ -219,18 +228,22 @@ abstract class AnalysisTask {
|
| if (contextName == null) {
|
| contextName = 'unnamed';
|
| }
|
| - AnalysisEngine.instance.instrumentationService.logAnalysisTask(
|
| - contextName, this);
|
| + 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.
|
| @@ -243,6 +256,9 @@ abstract class AnalysisTask {
|
| } finally {
|
| stopwatch.stop();
|
| }
|
| +// } finally {
|
| +// previousTag.makeCurrent();
|
| +// }
|
| } on AnalysisException {
|
| rethrow;
|
| } catch (exception, stackTrace) {
|
| @@ -266,10 +282,11 @@ abstract class ListResultDescriptor<E> implements ResultDescriptor<List<E>> {
|
| * values associated with this result will remain in the cache.
|
| */
|
| factory ListResultDescriptor(String name, List<E> defaultValue,
|
| - {ResultCachingPolicy<List<E>> cachingPolicy}) = ListResultDescriptorImpl<E>;
|
| + {ResultCachingPolicy<List<E>> cachingPolicy}) = ListResultDescriptorImpl<
|
| + E>;
|
|
|
| @override
|
| - ListTaskInput<E> of(AnalysisTarget target);
|
| + ListTaskInput<E> of(AnalysisTarget target, {bool flushOnAccess: false});
|
| }
|
|
|
| /**
|
| @@ -384,9 +401,52 @@ abstract class ResultDescriptor<V> {
|
|
|
| /**
|
| * Return a task input that can be used to compute this result for the given
|
| - * [target].
|
| + * [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);
|
| + TaskInput<V> of(AnalysisTarget target, {bool flushOnAccess: false});
|
| +}
|
| +
|
| +/**
|
| + * 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';
|
| }
|
|
|
| /**
|
| @@ -399,7 +459,9 @@ abstract class TaskDescriptor {
|
| * and produces the given [results]. The [buildTask] will be used to create
|
| * the instance of [AnalysisTask] thusly described.
|
| */
|
| - factory TaskDescriptor(String name, BuildTask buildTask,
|
| + factory TaskDescriptor(
|
| + String name,
|
| + BuildTask buildTask,
|
| CreateTaskInputs inputBuilder,
|
| List<ResultDescriptor> results) = TaskDescriptorImpl;
|
|
|
| @@ -483,6 +545,12 @@ abstract class TaskInputBuilder<V> {
|
| 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
|
| @@ -514,3 +582,95 @@ abstract class TaskInputBuilder<V> {
|
| */
|
| 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.
|
| + *
|
| + * 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
|
| +}
|
|
|