| 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
 | 
| +}
 | 
| 
 |