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

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

Issue 2990843002: Removed fixed dependencies (Closed)
Patch Set: Created 3 years, 5 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
« no previous file with comments | « packages/analyzer/lib/task/html.dart ('k') | packages/analyzer/lib/task/yaml.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: packages/analyzer/lib/task/model.dart
diff --git a/packages/analyzer/lib/task/model.dart b/packages/analyzer/lib/task/model.dart
index 7b70f8ec7a39d879596877154b87af857c488c63..2a6f6c55df2f66c61ed98822f39966c8b1eaab3e 100644
--- a/packages/analyzer/lib/task/model.dart
+++ b/packages/analyzer/lib/task/model.dart
@@ -7,9 +7,9 @@ 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/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';
@@ -35,6 +35,14 @@ typedef AnalysisTask BuildTask(AnalysisContext context, AnalysisTarget target);
*/
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
@@ -52,6 +60,9 @@ class AnalysisContextTarget implements AnalysisTarget {
AnalysisContextTarget(this.context);
+ @override
+ Source get librarySource => null;
+
@override
Source get source => null;
}
@@ -64,6 +75,12 @@ class AnalysisContextTarget implements AnalysisTarget {
* required to correctly implement [==] and [hashCode].
*/
abstract class AnalysisTarget {
+ /**
+ * If this target is associated with a library, return the source of the
+ * library's defining compilation unit; otherwise return `null`.
+ */
+ Source get librarySource;
+
/**
* Return the source associated with this target, or `null` if this target is
* not associated with a source.
@@ -78,6 +95,11 @@ abstract class AnalysisTarget {
* 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.
@@ -157,15 +179,26 @@ abstract class AnalysisTask {
*/
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.
*/
- Object getRequiredInput(String name) {
+ Object/*=E*/ getRequiredInput/*<E>*/(String name) {
if (inputs == null || !inputs.containsKey(name)) {
throw new AnalysisException("Could not $description: missing $name");
}
- return inputs[name];
+ return inputs[name] as Object/*=E*/;
}
/**
@@ -206,13 +239,58 @@ abstract class AnalysisTask {
} on AnalysisException catch (exception, stackTrace) {
caughtException = new CaughtException(exception, stackTrace);
AnalysisEngine.instance.logger
- .logInformation("Task failed: ${description}", caughtException);
+ .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].
@@ -221,6 +299,11 @@ abstract class AnalysisTask {
*/
void _safelyPerform() {
try {
+ //
+ // Store task description for diagnostics.
+ //
+ LAST_TASKS.add(description);
+
//
// Report that this task is being performed.
//
@@ -250,7 +333,8 @@ abstract class AnalysisTask {
//
try {
if (dependencyCycle != null && !handlesDependencyCycles) {
- throw new InfiniteTaskLoopException(this, dependencyCycle);
+ throw new InfiniteTaskLoopException(
+ this, dependencyCycle, _findCyclicPath(dependencyCycle));
}
internalPerform();
} finally {
@@ -261,6 +345,8 @@ abstract class AnalysisTask {
// }
} on AnalysisException {
rethrow;
+ } on ModificationTimeMismatchError {
+ rethrow;
} catch (exception, stackTrace) {
throw new AnalysisException(
'Unexpected exception while performing $description',
@@ -282,8 +368,8 @@ 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, {bool flushOnAccess: false});
@@ -295,34 +381,41 @@ abstract class ListResultDescriptor<E> implements ResultDescriptor<List<E>> {
*
* Clients may not extend, implement or mix-in this class.
*/
-abstract class ListTaskInput<E> extends TaskInput<List<E>> {
+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(UnaryFunction<E, dynamic /*<V>*/ > mapper);
+ ListTaskInput/*<V>*/ toList/*<V>*/(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);
+ 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, dynamic /*V*/ > toMap(
- UnaryFunction<E, dynamic /*<V>*/ > mapper);
+ MapTaskInput<E, dynamic/*=V*/ > toMap/*<V>*/(
+ 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);
+ MapTaskInput<AnalysisTarget, dynamic/*=V*/ > toMapOf/*<V>*/(
+ ResultDescriptor/*<V>*/ valueResult);
}
/**
@@ -330,15 +423,27 @@ abstract class ListTaskInput<E> extends TaskInput<List<E>> {
*
* Clients may not extend, implement or mix-in this class.
*/
-abstract class MapTaskInput<K, V> extends TaskInput<Map<K, V>> {
+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(
- BinaryFunction<K, dynamic /*element of V*/, dynamic /*<E>*/ > mapper);
+ TaskInput<List/*<E>*/ > toFlattenList/*<E>*/(
+ BinaryFunction<K, dynamic /*element of V*/, dynamic/*=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);
}
/**
@@ -375,6 +480,13 @@ abstract class ResultCachingPolicy<T> {
* 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].
@@ -384,7 +496,7 @@ abstract class ResultDescriptor<V> {
* never evicted from the cache, and removed only when they are invalidated.
*/
factory ResultDescriptor(String name, V defaultValue,
- {ResultCachingPolicy<V> cachingPolicy}) = ResultDescriptorImpl;
+ {ResultCachingPolicy<V> cachingPolicy}) = ResultDescriptorImpl<V>;
/**
* Return the caching policy for results described by this descriptor.
@@ -460,14 +572,14 @@ 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.
+ * 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) = TaskDescriptorImpl;
+ 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.
@@ -490,6 +602,11 @@ abstract class TaskDescriptor {
*/
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);
}
/**
@@ -508,7 +625,7 @@ abstract class TaskInput<V> {
* 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));
+ ListTaskInput/*<E>*/ mappedToList/*<E>*/(List/*<E>*/ mapper(V value));
}
/**
@@ -587,6 +704,11 @@ abstract class TaskInputBuilder<V> {
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.
*
« no previous file with comments | « packages/analyzer/lib/task/html.dart ('k') | packages/analyzer/lib/task/yaml.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698