Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1707)

Unified Diff: pkg/analyzer/lib/task/model.dart

Issue 812733004: Initial task support (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: pkg/analyzer/lib/task/model.dart
diff --git a/pkg/analyzer/lib/task/model.dart b/pkg/analyzer/lib/task/model.dart
new file mode 100644
index 0000000000000000000000000000000000000000..c450782c9947324d1f7ee26986eaea3c556276b5
--- /dev/null
+++ b/pkg/analyzer/lib/task/model.dart
@@ -0,0 +1,309 @@
+// 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/java_engine.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/task/model.dart';
+
+/**
+ * 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);
Paul Berry 2015/01/20 23:34:53 Consider renaming to "TaskBuilder" so that the typ
+
+/**
+ * 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);
Paul Berry 2015/01/20 23:34:53 Similarly, consider renaming to "InputBuilder".
+
+/**
+ * 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 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 thrownException;
Paul Berry 2015/01/20 23:34:53 I'm not sure the word "thrown" adds any meaning he
Brian Wilkerson 2015/01/26 04:54:51 Done
+
+ /**
+ * 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 source associated with this task's target, or `null` if the
+ * target is not associated with a source.
+ */
+ Source get source => target.source;
Paul Berry 2015/01/20 23:34:53 Consider removing this getter. It doesn't add a h
Brian Wilkerson 2015/01/26 04:54:51 Done
+
+ /**
+ * 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 [thrownException] should be set.
+ *
+ * Clients should not override this method.
+ */
+ void perform() {
+ try {
+ safelyPerform();
+ } on AnalysisException catch (exception, stackTrace) {
+ thrownException = new CaughtException(exception, stackTrace);
+ AnalysisEngine.instance.logger.logInformation(
+ "Task failed: ${description}",
+ thrownException);
+ }
+ }
+
+ /**
+ * Perform this analysis task, ensuring that all exceptions are wrapped in an
+ * [AnalysisException].
+ *
+ * Clients should not override this method.
+ */
+ void safelyPerform() {
Paul Berry 2015/01/20 23:34:53 Is this method ever meant to be called by clients,
Brian Wilkerson 2015/01/26 04:54:51 It also changes what is being measures by the stop
+ try {
+ Stopwatch stopwatch = stopwatchMap[runtimeType];
+ if (stopwatch == null) {
+ stopwatch = new Stopwatch();
+ stopwatchMap[runtimeType] = stopwatch;
+ }
+ stopwatch.start();
+ try {
+ internalPerform();
+ } finally {
+ stopwatch.stop();
+ }
+ } on AnalysisException catch (exception) {
+ rethrow;
+ } catch (exception, stackTrace) {
+ throw new AnalysisException(
+ 'Unexpected exception while performing $description',
+ new CaughtException(exception, stackTrace));
+ }
+ }
+
+ @override
+ String toString() => description;
+}
+
+/**
+ * A [ResultDescriptor] that denotes an analysis result that is a union of
+ * one or more other results.
+ *
+ * Clients are not expected to subtype this class.
+ */
+abstract class ContributionPoint<V> extends ResultDescriptor<V> {
Paul Berry 2015/01/20 23:34:53 As discussed in person, consider making Contributi
Brian Wilkerson 2015/01/26 04:54:51 I like the idea, but it leads to a type warning th
+ /**
+ * Initialize a newly created contribution point to have the given [name].
+ */
+ factory ContributionPoint(String name) = ContributionPointImpl;
+
+ /**
+ * Return a list containing the descriptors of the results that are unioned
+ * together to comprise the value of this result.
+ *
+ * Clients must not modify the returned list.
+ */
+ List<ResultDescriptor<V>> get contributors;
+}
+
+/**
+ * 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]. If a
+ * contribution point is specified, then this result will contribute to it.
+ */
+ factory ResultDescriptor(String name, {ContributionPoint contributesTo}) =
+ ResultDescriptorImpl;
+
+ /**
+ * Return a task input that can be used to compute this result for the given
+ * [target].
+ */
+ TaskInput<V> inputFor(AnalysisTarget 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 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();
+}
+
+/**
+ * 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`.
+ */
+ V get inputValue;
+
+ /**
+ * 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();
+}

Powered by Google App Engine
This is Rietveld 408576698