| Index: pkg/analyzer/lib/src/task/driver.dart
|
| diff --git a/pkg/analyzer/lib/src/task/driver.dart b/pkg/analyzer/lib/src/task/driver.dart
|
| index 77e7cff07055a0a8ce1e619be12e9d2cbcaf0e7f..87929c0cb2fb75ec6d10b1a4f2ce4b51ba7c449e 100644
|
| --- a/pkg/analyzer/lib/src/task/driver.dart
|
| +++ b/pkg/analyzer/lib/src/task/driver.dart
|
| @@ -348,7 +348,7 @@ abstract class CycleAwareDependencyWalker<Node> {
|
| * it. The client is expected to evaluate this component before calling
|
| * [getNextStronglyConnectedComponent] again.
|
| */
|
| - List<Node> getNextStronglyConnectedComponent() {
|
| + StronglyConnectedComponent<Node> getNextStronglyConnectedComponent() {
|
| while (_currentIndices.isNotEmpty) {
|
| Node nextUnevaluatedInput = getNextInput(_path[_currentIndices.last],
|
| _provisionalDependencies[_currentIndices.last]);
|
| @@ -394,11 +394,17 @@ abstract class CycleAwareDependencyWalker<Node> {
|
| // No more nodes in the current strongly connected component need to
|
| // have their indices examined. We can now yield this component to
|
| // the caller.
|
| - List<Node> component = _path.sublist(_contractedPath.last);
|
| + List<Node> nodes = _path.sublist(_contractedPath.last);
|
| + bool containsCycle = nodes.length > 1;
|
| + if (!containsCycle) {
|
| + if (_provisionalDependencies.last.isNotEmpty) {
|
| + containsCycle = true;
|
| + }
|
| + }
|
| _path.length = _contractedPath.last;
|
| _provisionalDependencies.length = _contractedPath.last;
|
| _contractedPath.removeLast();
|
| - return component;
|
| + return new StronglyConnectedComponent<Node>(nodes, containsCycle);
|
| } else {
|
| // At least one node in the current strongly connected component
|
| // still needs to have its inputs examined. So loop and allow the
|
| @@ -446,6 +452,27 @@ class InfiniteTaskLoopException extends AnalysisException {
|
| }
|
|
|
| /**
|
| + * Object used by CycleAwareDependencyWalker to report a single strongly
|
| + * connected component of nodes.
|
| + */
|
| +class StronglyConnectedComponent<Node> {
|
| + /**
|
| + * The nodes contained in the strongly connected component.
|
| + */
|
| + final List<Node> nodes;
|
| +
|
| + /**
|
| + * Indicates whether the strongly component contains any cycles. Note that
|
| + * if [nodes] has multiple elements, this will always be `true`. However, if
|
| + * [nodes] has exactly one element, this may be either `true` or `false`
|
| + * depending on whether the node has a dependency on itself.
|
| + */
|
| + final bool containsCycle;
|
| +
|
| + StronglyConnectedComponent(this.nodes, this.containsCycle);
|
| +}
|
| +
|
| +/**
|
| * A description of a single anaysis task that can be performed to advance
|
| * analysis.
|
| */
|
| @@ -695,11 +722,14 @@ class WorkOrder implements Iterator<WorkItem> {
|
| return true;
|
| } else {
|
| // Get a new strongly connected component.
|
| - currentItems = _dependencyWalker.getNextStronglyConnectedComponent();
|
| - if (currentItems == null) {
|
| + StronglyConnectedComponent<WorkItem> nextStronglyConnectedComponent =
|
| + _dependencyWalker.getNextStronglyConnectedComponent();
|
| + if (nextStronglyConnectedComponent == null) {
|
| + currentItems = null;
|
| return false;
|
| }
|
| - if (currentItems.length > 1) {
|
| + currentItems = nextStronglyConnectedComponent.nodes;
|
| + if (nextStronglyConnectedComponent.containsCycle) {
|
| // A cycle has been found.
|
| for (WorkItem item in currentItems) {
|
| item.dependencyCycle = currentItems.toList();
|
|
|