/** @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); }