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();
}
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);
}
}
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);
}
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);
}
}
}
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);
}
Aggregations