| Index: pkg/analyzer/lib/src/generated/utilities_collection.dart
|
| diff --git a/pkg/analyzer/lib/src/generated/utilities_collection.dart b/pkg/analyzer/lib/src/generated/utilities_collection.dart
|
| index 85d6a76354b0c71e484dfe79127ce98c6662d537..0ba35d329f2fafa59ef01cf354b00a8ac6b7a10e 100644
|
| --- a/pkg/analyzer/lib/src/generated/utilities_collection.dart
|
| +++ b/pkg/analyzer/lib/src/generated/utilities_collection.dart
|
| @@ -134,11 +134,23 @@ class DirectedGraph<N> {
|
| }
|
|
|
| /**
|
| - * Return a list of nodes that form a cycle, or `null` if there are no cycles in this graph.
|
| - *
|
| - * @return a list of nodes that form a cycle
|
| + * Run a topological sort of the graph. Since the graph may contain cycles, this results in a list
|
| + * of strongly connected components rather than a list of nodes. The nodes in each strongly
|
| + * connected components only have edges that point to nodes in the same component or earlier
|
| + * components.
|
| */
|
| - List<N> findCycle() => null;
|
| + List<List<N>> computeTopologicalSort() {
|
| + DirectedGraph_SccFinder<N> finder = new DirectedGraph_SccFinder<N>(this);
|
| + return finder.computeTopologicalSort();
|
| + }
|
| +
|
| + /**
|
| + * Return true if the graph contains at least one path from `source` to `destination`.
|
| + */
|
| + bool containsPath(N source, N destination) {
|
| + Set<N> nodesVisited = new Set<N>();
|
| + return _containsPathInternal(source, destination, nodesVisited);
|
| + }
|
|
|
| /**
|
| * Return a list of nodes that form a cycle containing the given node. If the node is not part of
|
| @@ -162,6 +174,11 @@ class DirectedGraph<N> {
|
| int get nodeCount => _edges.length;
|
|
|
| /**
|
| + * Return a set of all nodes in the graph.
|
| + */
|
| + Set<N> get nodes => _edges.keys.toSet();
|
| +
|
| + /**
|
| * Return a set containing the tails of edges that have the given node as their head. The set will
|
| * be empty if there are no such edges or if the node is not part of the graph. Clients must not
|
| * modify the returned set.
|
| @@ -243,6 +260,24 @@ class DirectedGraph<N> {
|
| return sink;
|
| }
|
|
|
| + bool _containsPathInternal(N source, N destination, Set<N> nodesVisited) {
|
| + if (identical(source, destination)) {
|
| + return true;
|
| + }
|
| + Set<N> tails = _edges[source];
|
| + if (tails != null) {
|
| + nodesVisited.add(source);
|
| + for (N tail in tails) {
|
| + if (!nodesVisited.contains(tail)) {
|
| + if (_containsPathInternal(tail, destination, nodesVisited)) {
|
| + return true;
|
| + }
|
| + }
|
| + }
|
| + }
|
| + return false;
|
| + }
|
| +
|
| /**
|
| * Return one node that has no outgoing edges (that is, for which there are no edges that have
|
| * that node as the head of the edge), or `null` if there are no such nodes.
|
| @@ -323,6 +358,13 @@ class DirectedGraph_SccFinder<N> {
|
| Map<N, DirectedGraph_NodeInfo<N>> _nodeMap = new Map<N, DirectedGraph_NodeInfo<N>>();
|
|
|
| /**
|
| + * A list of all strongly connected components found, in topological sort order (each node in a
|
| + * strongly connected component only has edges that point to nodes in the same component or
|
| + * earlier components).
|
| + */
|
| + List<List<N>> _allComponents = new List<List<N>>();
|
| +
|
| + /**
|
| * Initialize a newly created finder.
|
| */
|
| DirectedGraph_SccFinder(this._graph) : super();
|
| @@ -338,6 +380,21 @@ class DirectedGraph_SccFinder<N> {
|
| List<N> componentContaining(N node) => _strongConnect(node).component;
|
|
|
| /**
|
| + * Run Tarjan's algorithm and return the resulting list of strongly connected components. The
|
| + * list is in topological sort order (each node in a strongly connected component only has edges
|
| + * that point to nodes in the same component or earlier components).
|
| + */
|
| + List<List<N>> computeTopologicalSort() {
|
| + for (N node in _graph._edges.keys.toSet()) {
|
| + DirectedGraph_NodeInfo<N> nodeInfo = _nodeMap[node];
|
| + if (nodeInfo == null) {
|
| + _strongConnect(node);
|
| + }
|
| + }
|
| + return _allComponents;
|
| + }
|
| +
|
| + /**
|
| * Remove and return the top-most element from the stack.
|
| *
|
| * @return the element that was removed
|
| @@ -400,6 +457,7 @@ class DirectedGraph_SccFinder<N> {
|
| component.add(w);
|
| _nodeMap[w].component = component;
|
| } while (!identical(w, v));
|
| + _allComponents.add(component);
|
| }
|
| return vInfo;
|
| }
|
|
|