use of com.google.javascript.jscomp.ControlFlowGraph.Branch in project closure-compiler by google.
the class TypeInference method branchedFlowThrough.
@Override
@SuppressWarnings({ "fallthrough", "incomplete-switch" })
List<FlowScope> branchedFlowThrough(Node source, FlowScope input) {
// NOTE(nicksantos): Right now, we just treat ON_EX edges like UNCOND
// edges. If we wanted to be perfect, we'd actually JOIN all the out
// lattices of this flow with the in lattice, and then make that the out
// lattice for the ON_EX edge. But it's probably too expensive to be
// worthwhile.
FlowScope output = flowThrough(source, input);
Node condition = null;
FlowScope conditionFlowScope = null;
BooleanOutcomePair conditionOutcomes = null;
List<DiGraphEdge<Node, Branch>> branchEdges = getCfg().getOutEdges(source);
List<FlowScope> result = new ArrayList<>(branchEdges.size());
for (DiGraphEdge<Node, Branch> branchEdge : branchEdges) {
Branch branch = branchEdge.getValue();
FlowScope newScope = output;
switch(branch) {
case ON_TRUE:
if (source.isForIn() || source.isForOf()) {
Node item = source.getFirstChild();
Node obj = item.getNext();
FlowScope informed = traverse(obj, output.createChildFlowScope());
if (item.isVar()) {
item = item.getFirstChild();
}
if (source.isForIn()) {
// item is assigned a property name, so its type should be string.
if (item.isName()) {
JSType iterKeyType = getNativeType(STRING_TYPE);
ObjectType objType = getJSType(obj).dereference();
JSType objIndexType = objType == null ? null : objType.getTemplateTypeMap().getResolvedTemplateType(registry.getObjectIndexKey());
if (objIndexType != null && !objIndexType.isUnknownType()) {
JSType narrowedKeyType = iterKeyType.getGreatestSubtype(objIndexType);
if (!narrowedKeyType.isEmptyType()) {
iterKeyType = narrowedKeyType;
}
}
redeclareSimpleVar(informed, item, iterKeyType);
}
} else {
// for/of. The type of `item` is the type parameter of the Iterable type.
ObjectType objType = getJSType(obj).dereference();
if (objType.isSubtypeOf(getNativeType(JSTypeNative.ITERABLE_TYPE))) {
if (objType.isTemplatizedType()) {
JSType newType = objType.getTemplateTypeMap().getResolvedTemplateType(registry.getIterableTemplate());
redeclareSimpleVar(informed, item, newType);
}
}
}
newScope = informed;
break;
}
case ON_FALSE:
if (condition == null) {
condition = NodeUtil.getConditionExpression(source);
if (condition == null && source.isCase()) {
condition = source;
// of the loop.
if (conditionFlowScope == null) {
conditionFlowScope = traverse(condition.getFirstChild(), output.createChildFlowScope());
}
}
}
if (condition != null) {
if (condition.isAnd() || condition.isOr()) {
// of the loop.
if (conditionOutcomes == null) {
conditionOutcomes = condition.isAnd() ? traverseAnd(condition, output.createChildFlowScope()) : traverseOr(condition, output.createChildFlowScope());
}
newScope = reverseInterpreter.getPreciserScopeKnowingConditionOutcome(condition, conditionOutcomes.getOutcomeFlowScope(condition.getToken(), branch == Branch.ON_TRUE), branch == Branch.ON_TRUE);
} else {
// of the loop.
if (conditionFlowScope == null) {
conditionFlowScope = traverse(condition, output.createChildFlowScope());
}
newScope = reverseInterpreter.getPreciserScopeKnowingConditionOutcome(condition, conditionFlowScope, branch == Branch.ON_TRUE);
}
}
break;
default:
break;
}
result.add(newScope.optimize());
}
return result;
}
use of com.google.javascript.jscomp.ControlFlowGraph.Branch 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);
}
use of com.google.javascript.jscomp.ControlFlowGraph.Branch in project closure-compiler by google.
the class LiveVariablesAnalysis method flowThrough.
@Override
LiveVariableLattice flowThrough(Node node, LiveVariableLattice input) {
final BitSet gen = new BitSet(input.liveSet.size());
final BitSet kill = new BitSet(input.liveSet.size());
// Make kills conditional if the node can end abruptly by an exception.
boolean conditional = false;
List<? extends DiGraphEdge<Node, Branch>> edgeList = getCfg().getOutEdges(node);
for (DiGraphEdge<Node, Branch> edge : edgeList) {
if (Branch.ON_EX.equals(edge.getValue())) {
conditional = true;
}
}
computeGenKill(node, gen, kill, conditional);
LiveVariableLattice result = new LiveVariableLattice(input);
// L_in = L_out - Kill + Gen
result.liveSet.andNot(kill);
result.liveSet.or(gen);
return result;
}
use of com.google.javascript.jscomp.ControlFlowGraph.Branch in project closure-compiler by google.
the class DotFormatter method traverseNodes.
private void traverseNodes(Node parent) throws IOException {
// key
int keyParent = key(parent);
// edges
for (Node child = parent.getFirstChild(); child != null; child = child.getNext()) {
int keyChild = key(child);
builder.append(INDENT);
builder.append(formatNodeName(keyParent));
builder.append(ARROW);
builder.append(formatNodeName(keyChild));
builder.append(" [weight=1];\n");
traverseNodes(child);
}
// Flow Edges
if (cfg != null && cfg.hasNode(parent)) {
List<? extends DiGraphEdge<Node, Branch>> outEdges = cfg.getOutEdges(parent);
String[] edgeList = new String[outEdges.size()];
for (int i = 0; i < edgeList.length; i++) {
DiGraphEdge<Node, ControlFlowGraph.Branch> edge = outEdges.get(i);
DiGraphNode<Node, Branch> succ = edge.getDestination();
String toNode = null;
if (succ == cfg.getImplicitReturn()) {
toNode = "RETURN";
} else {
int keySucc = key(succ.getValue());
toNode = formatNodeName(keySucc);
}
edgeList[i] = formatNodeName(keyParent) + ARROW + toNode + " [label=\"" + edge.getValue() + "\", " + "fontcolor=\"red\", " + "weight=0.01, color=\"red\"];\n";
}
Arrays.sort(edgeList);
for (String element : edgeList) {
builder.append(INDENT);
builder.append(element);
}
}
}
use of com.google.javascript.jscomp.ControlFlowGraph.Branch in project closure-compiler by google.
the class ControlFlowAnalysisTest method assertNodeOrder.
/**
* Asserts the priority order of CFG nodes.
*
* Checks that the node type of the highest-priority node matches the
* first element of the list, the type of the second node matches the
* second element of the list, and so on.
*
* @param cfg The control flow graph.
* @param nodeTypes The expected node types, in order.
*/
private void assertNodeOrder(ControlFlowGraph<Node> cfg, List<Token> nodeTypes) {
List<? extends DiGraphNode<Node, Branch>> cfgNodes = Ordering.from(cfg.getOptionalNodeComparator(true)).sortedCopy(cfg.getNodes());
// IMPLICIT RETURN must always be last.
Node implicitReturn = cfgNodes.remove(cfgNodes.size() - 1).getValue();
assertWithMessage(implicitReturn == null ? "null" : implicitReturn.toStringTree()).that(implicitReturn).isNull();
assertThat(cfgNodes.stream().map(DiGraphNode::getValue).map(Node::getToken).collect(Collectors.toList())).isEqualTo(nodeTypes);
}
Aggregations