/**
   * Verify that some non-looping paths from {@code a} to {@code b} pass through at least one node
   * where {@code nodePredicate} is true.
   */
  private boolean checkSomePathsWithoutBackEdges(DiGraphNode<N, E> a, DiGraphNode<N, E> b) {
    if (nodePredicate.apply(a.getValue()) && (inclusive || (a != start && a != end))) {
      return true;
    }
    if (a == b) {
      return false;
    }
    for (DiGraphEdge<N, E> e : a.getOutEdges()) {
      // Once we visited that edge once, we no longer need to
      // re-visit it again.
      if (e.getAnnotation() == VISITED_EDGE) {
        continue;
      }
      e.setAnnotation(VISITED_EDGE);

      if (ignoreEdge(e)) {
        continue;
      }
      if (e.getAnnotation() == BACK_EDGE) {
        continue;
      }

      DiGraphNode<N, E> next = e.getDestination();
      if (checkSomePathsWithoutBackEdges(next, b)) {
        return true;
      }
    }
    return false;
  }
 /**
  * Gets all the edges of the graph.
  */
 private static List<DiGraphEdge<Node, Branch>> getAllEdges(
     ControlFlowGraph<Node> cfg) {
   List<DiGraphEdge<Node, Branch>> edges = new ArrayList<>();
   for (DiGraphNode<Node, Branch> n : cfg.getDirectedGraphNodes()) {
     edges.addAll(cfg.getOutEdges(n.getValue()));
   }
   return edges;
 }
    /** @return true if all paths from block must exit with an explicit return. */
    private boolean allPathsReturn(Node function) {
      // Computes the control flow graph.
      ControlFlowAnalysis cfa = new ControlFlowAnalysis(compiler, false, false);
      cfa.process(null, function);
      ControlFlowGraph<Node> cfg = cfa.getCfg();

      Node returnPathsParent = cfg.getImplicitReturn().getValue();
      for (DiGraphNode<Node, Branch> pred : cfg.getDirectedPredNodes(returnPathsParent)) {
        Node n = pred.getValue();
        if (!n.isReturn()) {
          return false;
        }
      }
      return true;
    }
  @Override
  public void process(Node externs, Node root) {
    this.root = root;
    astPositionCounter = 0;
    astPosition = Maps.newHashMap();
    nodePriorities = Maps.newHashMap();
    cfg = new AstControlFlowGraph(computeFallThrough(root), nodePriorities);
    NodeTraversal.traverse(compiler, root, this);
    astPosition.put(null, ++astPositionCounter); // the implicit return is last.

    // Now, generate the priority of nodes by doing a depth-first
    // search on the CFG.
    priorityCounter = 0;
    DiGraphNode<Node, Branch> entry = cfg.getEntry();
    prioritizeFromEntryNode(entry);

    if (shouldTraverseFunctions) {
      // If we're traversing inner functions, we need to rank the
      // priority of them too.
      for (DiGraphNode<Node, Branch> candidate : cfg.getDirectedGraphNodes()) {
        Node value = candidate.getValue();
        if (value != null && value.getType() == Token.FUNCTION) {
          Preconditions.checkState(!nodePriorities.containsKey(candidate) || candidate == entry);
          prioritizeFromEntryNode(candidate);
        }
      }
    }

    // At this point, all reachable nodes have been given a priority, but
    // unreachable nodes have not been given a priority. Put them last.
    // Presumably, it doesn't really matter what priority they get, since
    // this shouldn't happen in real code.
    for (DiGraphNode<Node, Branch> candidate : cfg.getDirectedGraphNodes()) {
      if (!nodePriorities.containsKey(candidate)) {
        nodePriorities.put(candidate, ++priorityCounter);
      }
    }

    // Again, the implicit return node is always last.
    nodePriorities.put(cfg.getImplicitReturn(), ++priorityCounter);
  }
 private void discoverBackEdges(DiGraphNode<N, E> u) {
   u.setAnnotation(GRAY);
   for (DiGraphEdge<N, E> e : u.getOutEdges()) {
     if (ignoreEdge(e)) {
       continue;
     }
     DiGraphNode<N, E> v = e.getDestination();
     if (v.getAnnotation() == WHITE) {
       discoverBackEdges(v);
     } else if (v.getAnnotation() == GRAY) {
       e.setAnnotation(BACK_EDGE);
     }
   }
   u.setAnnotation(BLACK);
 }
 @Override
 public int compare(DiGraphNode<Node, Branch> a, DiGraphNode<Node, Branch> b) {
   return astPosition.get(a.getValue()) - astPosition.get(b.getValue());
 }