| Index: pkg/analyzer/lib/task/model.dart
|
| diff --git a/pkg/analyzer/lib/task/model.dart b/pkg/analyzer/lib/task/model.dart
|
| index 8f65f8bb1badbcc0421ad79b2d05a7f89f25425b..8672a18c453500e15fbd1886b6874bfc0d81b272 100644
|
| --- a/pkg/analyzer/lib/task/model.dart
|
| +++ b/pkg/analyzer/lib/task/model.dart
|
| @@ -9,6 +9,7 @@ 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/driver.dart';
|
| import 'package:analyzer/src/task/model.dart';
|
|
|
| /**
|
| @@ -116,6 +117,14 @@ abstract class AnalysisTask {
|
| 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].
|
| */
|
| @@ -132,6 +141,14 @@ abstract class AnalysisTask {
|
| 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.
|
| */
|
| @@ -219,6 +236,9 @@ abstract class AnalysisTask {
|
| // Actually perform the task.
|
| //
|
| try {
|
| + if (dependencyCycle != null && !handlesDependencyCycles) {
|
| + throw new InfiniteTaskLoopException(this, dependencyCycle);
|
| + }
|
| internalPerform();
|
| } finally {
|
| stopwatch.stop();
|
| @@ -461,10 +481,21 @@ abstract class TaskInputBuilder<V> {
|
| *
|
| * 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.
|
|
|