use of org.checkerframework.dataflow.cfg.node.MarkerNode in project checker-framework by typetools.
the class CFGTranslationPhaseOne method visitTry.
@Override
public Node visitTry(TryTree tree, Void p) {
List<? extends CatchTree> catches = tree.getCatches();
BlockTree finallyBlock = tree.getFinallyBlock();
extendWithNode(new MarkerNode(tree, "start of try statement #" + TreeUtils.treeUids.get(tree), env.getTypeUtils()));
List<Pair<TypeMirror, Label>> catchLabels = CollectionsPlume.mapList((CatchTree c) -> {
return Pair.of(TreeUtils.typeOf(c.getParameter().getType()), new Label());
}, catches);
// Store return/break/continue labels, just in case we need them for a finally block.
TryFinallyScopeCell oldReturnTargetL = returnTargetL;
TryFinallyScopeCell oldBreakTargetL = breakTargetL;
Map<Name, Label> oldBreakLabels = breakLabels;
TryFinallyScopeCell oldContinueTargetL = continueTargetL;
Map<Name, Label> oldContinueLabels = continueLabels;
Label finallyLabel = null;
Label exceptionalFinallyLabel = null;
if (finallyBlock != null) {
finallyLabel = new Label();
exceptionalFinallyLabel = new Label();
tryStack.pushFrame(new TryFinallyFrame(exceptionalFinallyLabel));
returnTargetL = new TryFinallyScopeCell();
breakTargetL = new TryFinallyScopeCell();
breakLabels = new TryFinallyScopeMap();
continueTargetL = new TryFinallyScopeCell();
continueLabels = new TryFinallyScopeMap();
}
Label doneLabel = new Label();
tryStack.pushFrame(new TryCatchFrame(types, catchLabels));
// Must scan the resources *after* we push frame to tryStack. Otherwise we can lose catch
// blocks.
// TODO: Should we handle try-with-resources blocks by also generating code for automatically
// closing the resources?
List<? extends Tree> resources = tree.getResources();
for (Tree resource : resources) {
scan(resource, p);
}
extendWithNode(new MarkerNode(tree, "start of try block #" + TreeUtils.treeUids.get(tree), env.getTypeUtils()));
scan(tree.getBlock(), p);
extendWithNode(new MarkerNode(tree, "end of try block #" + TreeUtils.treeUids.get(tree), env.getTypeUtils()));
extendWithExtendedNode(new UnconditionalJump(CFGBuilder.firstNonNull(finallyLabel, doneLabel)));
tryStack.popFrame();
int catchIndex = 0;
for (CatchTree c : catches) {
addLabelForNextNode(catchLabels.get(catchIndex).second);
extendWithNode(new MarkerNode(tree, "start of catch block for " + c.getParameter().getType() + " #" + TreeUtils.treeUids.get(tree), env.getTypeUtils()));
scan(c, p);
extendWithNode(new MarkerNode(tree, "end of catch block for " + c.getParameter().getType() + " #" + TreeUtils.treeUids.get(tree), env.getTypeUtils()));
catchIndex++;
extendWithExtendedNode(new UnconditionalJump(CFGBuilder.firstNonNull(finallyLabel, doneLabel)));
}
if (finallyLabel != null) {
// Reset values before analyzing the finally block!
tryStack.popFrame();
{
// Scan 'finallyBlock' for only 'finallyLabel' (a successful path)
addLabelForNextNode(finallyLabel);
extendWithNode(new MarkerNode(tree, "start of finally block #" + TreeUtils.treeUids.get(tree), env.getTypeUtils()));
scan(finallyBlock, p);
extendWithNode(new MarkerNode(tree, "end of finally block #" + TreeUtils.treeUids.get(tree), env.getTypeUtils()));
extendWithExtendedNode(new UnconditionalJump(doneLabel));
}
if (hasExceptionalPath(exceptionalFinallyLabel)) {
// If an exceptional path exists, scan 'finallyBlock' for 'exceptionalFinallyLabel', and
// scan copied 'finallyBlock' for 'finallyLabel' (a successful path). If there is no
// successful path, it will be removed in later phase.
// TODO: Don't we need a separate finally block for each kind of exception?
addLabelForNextNode(exceptionalFinallyLabel);
extendWithNode(new MarkerNode(tree, "start of finally block for Throwable #" + TreeUtils.treeUids.get(tree), env.getTypeUtils()));
scan(finallyBlock, p);
NodeWithExceptionsHolder throwing = extendWithNodeWithException(new MarkerNode(tree, "end of finally block for Throwable #" + TreeUtils.treeUids.get(tree), env.getTypeUtils()), throwableType);
throwing.setTerminatesExecution(true);
}
if (returnTargetL.wasAccessed()) {
addLabelForNextNode(returnTargetL.peekLabel());
returnTargetL = oldReturnTargetL;
extendWithNode(new MarkerNode(tree, "start of finally block for return #" + TreeUtils.treeUids.get(tree), env.getTypeUtils()));
scan(finallyBlock, p);
extendWithNode(new MarkerNode(tree, "end of finally block for return #" + TreeUtils.treeUids.get(tree), env.getTypeUtils()));
extendWithExtendedNode(new UnconditionalJump(returnTargetL.accessLabel()));
} else {
returnTargetL = oldReturnTargetL;
}
if (breakTargetL.wasAccessed()) {
addLabelForNextNode(breakTargetL.peekLabel());
breakTargetL = oldBreakTargetL;
extendWithNode(new MarkerNode(tree, "start of finally block for break #" + TreeUtils.treeUids.get(tree), env.getTypeUtils()));
scan(finallyBlock, p);
extendWithNode(new MarkerNode(tree, "end of finally block for break #" + TreeUtils.treeUids.get(tree), env.getTypeUtils()));
extendWithExtendedNode(new UnconditionalJump(breakTargetL.accessLabel()));
} else {
breakTargetL = oldBreakTargetL;
}
Map<Name, Label> accessedBreakLabels = ((TryFinallyScopeMap) breakLabels).getAccessedNames();
if (!accessedBreakLabels.isEmpty()) {
breakLabels = oldBreakLabels;
for (Map.Entry<Name, Label> access : accessedBreakLabels.entrySet()) {
addLabelForNextNode(access.getValue());
extendWithNode(new MarkerNode(tree, "start of finally block for break label " + access.getKey() + " #" + TreeUtils.treeUids.get(tree), env.getTypeUtils()));
scan(finallyBlock, p);
extendWithNode(new MarkerNode(tree, "end of finally block for break label " + access.getKey() + " #" + TreeUtils.treeUids.get(tree), env.getTypeUtils()));
extendWithExtendedNode(new UnconditionalJump(breakLabels.get(access.getKey())));
}
} else {
breakLabels = oldBreakLabels;
}
if (continueTargetL.wasAccessed()) {
addLabelForNextNode(continueTargetL.peekLabel());
continueTargetL = oldContinueTargetL;
extendWithNode(new MarkerNode(tree, "start of finally block for continue #" + TreeUtils.treeUids.get(tree), env.getTypeUtils()));
scan(finallyBlock, p);
extendWithNode(new MarkerNode(tree, "end of finally block for continue #" + TreeUtils.treeUids.get(tree), env.getTypeUtils()));
extendWithExtendedNode(new UnconditionalJump(continueTargetL.accessLabel()));
} else {
continueTargetL = oldContinueTargetL;
}
Map<Name, Label> accessedContinueLabels = ((TryFinallyScopeMap) continueLabels).getAccessedNames();
if (!accessedContinueLabels.isEmpty()) {
continueLabels = oldContinueLabels;
for (Map.Entry<Name, Label> access : accessedContinueLabels.entrySet()) {
addLabelForNextNode(access.getValue());
extendWithNode(new MarkerNode(tree, "start of finally block for continue label " + access.getKey() + " #" + TreeUtils.treeUids.get(tree), env.getTypeUtils()));
scan(finallyBlock, p);
extendWithNode(new MarkerNode(tree, "end of finally block for continue label " + access.getKey() + " #" + TreeUtils.treeUids.get(tree), env.getTypeUtils()));
extendWithExtendedNode(new UnconditionalJump(continueLabels.get(access.getKey())));
}
} else {
continueLabels = oldContinueLabels;
}
}
addLabelForNextNode(doneLabel);
return null;
}
Aggregations