Search in sources :

Example 6 with DiGraphNode

use of com.google.javascript.jscomp.graph.DiGraph.DiGraphNode in project closure-compiler by google.

the class ControlFlowAnalysisTest method assertReturnEdge.

/**
 * Assert that there exists a control flow edge of the given type
 * from some node with the first token to the return node.
 */
private static void assertReturnEdge(ControlFlowGraph<Node> cfg, Token startToken) {
    List<DiGraphEdge<Node, Branch>> edges = getAllEdges(cfg);
    for (DiGraphEdge<Node, Branch> edge : edges) {
        Node source = edge.getSource().getValue();
        DiGraphNode<Node, Branch> dest = edge.getDestination();
        if (source.getToken() == startToken && cfg.isImplicitReturn(dest)) {
            return;
        }
    }
    assertWithMessage("No return edge found").fail();
}
Also used : DiGraphEdge(com.google.javascript.jscomp.graph.DiGraph.DiGraphEdge) Branch(com.google.javascript.jscomp.ControlFlowGraph.Branch) DiGraphNode(com.google.javascript.jscomp.graph.DiGraph.DiGraphNode) Node(com.google.javascript.rhino.Node)

Example 7 with DiGraphNode

use of com.google.javascript.jscomp.graph.DiGraph.DiGraphNode in project closure-compiler by google.

the class NewTypeInference method analyzeConditionalStmFwd.

private void analyzeConditionalStmFwd(DiGraphNode<Node, ControlFlowGraph.Branch> stm, Node cond, TypeEnv inEnv) {
    for (DiGraphEdge<Node, ControlFlowGraph.Branch> outEdge : stm.getOutEdges()) {
        JSType specializedType;
        switch(outEdge.getValue()) {
            case ON_TRUE:
                specializedType = TRUTHY;
                break;
            case ON_FALSE:
                specializedType = FALSY;
                break;
            case ON_EX:
                specializedType = UNKNOWN;
                break;
            default:
                throw new RuntimeException("Condition with an unexpected edge type: " + outEdge.getValue());
        }
        envs.put(outEdge, analyzeExprFwd(cond, inEnv, UNKNOWN, specializedType).env);
    }
}
Also used : JSType(com.google.javascript.jscomp.newtypes.JSType) Node(com.google.javascript.rhino.Node) DiGraphNode(com.google.javascript.jscomp.graph.DiGraph.DiGraphNode)

Example 8 with DiGraphNode

use of com.google.javascript.jscomp.graph.DiGraph.DiGraphNode in project closure-compiler by google.

the class NewTypeInference method getInEnv.

private TypeEnv getInEnv(DiGraphNode<Node, ControlFlowGraph.Branch> dn) {
    List<DiGraphEdge<Node, ControlFlowGraph.Branch>> inEdges = dn.getInEdges();
    // True for code considered dead in the CFG
    if (inEdges.isEmpty()) {
        return getEntryTypeEnv();
    }
    if (inEdges.size() == 1) {
        return envs.get(inEdges.get(0));
    }
    Set<TypeEnv> envSet = new LinkedHashSet<>();
    for (DiGraphEdge<Node, ControlFlowGraph.Branch> de : inEdges) {
        TypeEnv env = envs.get(de);
        if (env != null) {
            envSet.add(env);
        }
    }
    if (envSet.isEmpty()) {
        return null;
    }
    return TypeEnv.join(envSet);
}
Also used : LinkedHashSet(java.util.LinkedHashSet) DiGraphEdge(com.google.javascript.jscomp.graph.DiGraph.DiGraphEdge) Node(com.google.javascript.rhino.Node) DiGraphNode(com.google.javascript.jscomp.graph.DiGraph.DiGraphNode) TypeEnv(com.google.javascript.jscomp.newtypes.TypeEnv)

Example 9 with DiGraphNode

use of com.google.javascript.jscomp.graph.DiGraph.DiGraphNode in project closure-compiler by google.

the class NewTypeInference method analyzeFunctionFwd.

private void analyzeFunctionFwd(NTIWorkset workset) {
    for (DiGraphNode<Node, ControlFlowGraph.Branch> dn : workset.forward()) {
        Node n = dn.getValue();
        Node parent = n.getParent();
        checkState(n != null, "Implicit return should not be in workset.");
        TypeEnv inEnv = getInEnv(dn);
        TypeEnv outEnv = null;
        if (parent.isScript() || (parent.isNormalBlock() && parent.getParent().isFunction())) {
            // All joins have merged; forget changes
            inEnv = inEnv.clearChangeLog();
        }
        println("\tFWD Statment: ", n);
        println("\t\tinEnv: ", inEnv);
        boolean conditional = false;
        switch(n.getToken()) {
            case BLOCK:
            case ROOT:
            case BREAK:
            case CONTINUE:
            case DEFAULT_CASE:
            case DEBUGGER:
            case EMPTY:
            case FUNCTION:
            case SCRIPT:
            case TRY:
            case // We don't typecheck WITH, we just avoid crashing.
            WITH:
                outEnv = inEnv;
                break;
            case CATCH:
                Node catchVar = n.getFirstChild();
                String catchVarname = catchVar.getString();
                outEnv = envPutType(inEnv, catchVarname, UNKNOWN);
                maybeSetTypeI(catchVar, UNKNOWN);
                break;
            case EXPR_RESULT:
                println("\tsemi ", n.getFirstChild().getToken());
                if (n.getBooleanProp(Node.ANALYZED_DURING_GTI)) {
                    n.removeProp(Node.ANALYZED_DURING_GTI);
                    outEnv = inEnv;
                } else {
                    outEnv = analyzeExprFwd(n.getFirstChild(), inEnv, UNKNOWN).env;
                }
                break;
            case RETURN:
                outEnv = analyzeReturnFwd(n, inEnv);
                break;
            case DO:
            case IF:
            case FOR:
            case WHILE:
                conditional = true;
                analyzeConditionalStmFwd(dn, NodeUtil.getConditionExpression(n), inEnv);
                break;
            case FOR_IN:
                outEnv = analyzeForInFwd(n, inEnv);
                break;
            case FOR_OF:
                outEnv = analyzeForOfFwd(n, inEnv);
                break;
            case CASE:
                {
                    conditional = true;
                    // See analyzeExprFwd#Token.CASE for how to handle this precisely
                    analyzeConditionalStmFwd(dn, n, inEnv);
                    break;
                }
            case VAR:
                outEnv = inEnv;
                if (NodeUtil.isTypedefDecl(n)) {
                    maybeSetTypeI(n.getFirstChild(), UNDEFINED);
                    break;
                }
                for (Node nameNode : n.children()) {
                    outEnv = analyzeVarDeclFwd(nameNode, outEnv);
                }
                break;
            case SWITCH:
                outEnv = analyzeExprFwd(n.getFirstChild(), inEnv).env;
                break;
            case THROW:
                {
                    outEnv = analyzeExprFwd(n.getFirstChild(), inEnv).env;
                    exitEnvs.add(outEnv);
                    break;
                }
            default:
                if (NodeUtil.isStatement(n)) {
                    throw new RuntimeException("Unhandled statement type: " + n.getToken());
                } else {
                    outEnv = analyzeExprFwd(n, inEnv, UNKNOWN).env;
                    break;
                }
        }
        if (!conditional) {
            println("\t\toutEnv: ", outEnv);
            setOutEnv(dn, outEnv);
        }
    }
}
Also used : Node(com.google.javascript.rhino.Node) DiGraphNode(com.google.javascript.jscomp.graph.DiGraph.DiGraphNode) TypeEnv(com.google.javascript.jscomp.newtypes.TypeEnv)

Example 10 with DiGraphNode

use of com.google.javascript.jscomp.graph.DiGraph.DiGraphNode in project closure-compiler by google.

the class ControlFlowAnalysis method process.

@Override
public void process(Node externs, Node root) {
    Preconditions.checkArgument(NodeUtil.isValidCfgRoot(root), "Unexpected control flow graph root %s", root);
    this.root = root;
    astPositionCounter = 0;
    astPosition = new HashMap<>();
    nodePriorities = new HashMap<>();
    cfg = new AstControlFlowGraph(computeFallThrough(root), nodePriorities, edgeAnnotations);
    NodeTraversal.traverse(compiler, root, this);
    // the implicit return is last.
    astPosition.put(null, ++astPositionCounter);
    // 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) {
        // priority of them too.
        for (DiGraphNode<Node, Branch> candidate : cfg.getNodes()) {
            Node value = candidate.getValue();
            if (value != null && value.isFunction()) {
                prioritizeFromEntryNode(candidate);
            }
        }
    }
    // this shouldn't happen in real code.
    for (DiGraphNode<Node, Branch> candidate : cfg.getNodes()) {
        nodePriorities.computeIfAbsent(candidate, k -> ++priorityCounter);
    }
    // Again, the implicit return node is always last.
    nodePriorities.put(cfg.getImplicitReturn(), ++priorityCounter);
}
Also used : Branch(com.google.javascript.jscomp.ControlFlowGraph.Branch) DiGraphNode(com.google.javascript.jscomp.graph.DiGraph.DiGraphNode) Node(com.google.javascript.rhino.Node)

Aggregations

DiGraphNode (com.google.javascript.jscomp.graph.DiGraph.DiGraphNode)12 Node (com.google.javascript.rhino.Node)12 Branch (com.google.javascript.jscomp.ControlFlowGraph.Branch)7 DiGraphEdge (com.google.javascript.jscomp.graph.DiGraph.DiGraphEdge)4 TypeEnv (com.google.javascript.jscomp.newtypes.TypeEnv)4 LiveVariableLattice (com.google.javascript.jscomp.LiveVariablesAnalysis.LiveVariableLattice)2 JSType (com.google.javascript.jscomp.newtypes.JSType)2 LinkedHashSet (java.util.LinkedHashSet)2 GraphNode (com.google.javascript.jscomp.graph.GraphNode)1 GraphvizNode (com.google.javascript.jscomp.graph.GraphvizGraph.GraphvizNode)1 BitSet (java.util.BitSet)1