use of org.checkerframework.dataflow.cfg.block.ExceptionBlock in project bazel by bazelbuild.
the class CFGDOTVisualizer method visualize.
/**
* Output a graph description in the DOT language, representing the control
* flow graph starting at <code>entry</code>.
*
* @param entry
* The entry node of the control flow graph to be represented.
* @param analysis
* An analysis containing information about the program
* represented by the CFG. The information includes {@link Store}
* s that are valid at the beginning of basic blocks reachable
* from <code>entry</code> and per-node information for value
* producing {@link Node}s. Can also be <code>null</code> to
* indicate that this information should not be output.
* @param verbose
* Add more output to the CFG description.
* @return String representation of the graph in the DOT language.
*/
public static <A extends AbstractValue<A>, S extends Store<S>, T extends TransferFunction<A, S>> String visualize(ControlFlowGraph cfg, Block entry, /*@Nullable*/
Analysis<A, S, T> analysis, boolean verbose) {
StringBuilder sb1 = new StringBuilder();
StringBuilder sb2 = new StringBuilder();
Set<Block> visited = new HashSet<>();
Queue<Block> worklist = new LinkedList<>();
Block cur = entry;
visited.add(entry);
// header
sb1.append("digraph {\n");
sb1.append(" node [shape=rectangle];\n\n");
// traverse control flow graph and define all arrows
while (true) {
if (cur == null)
break;
if (cur.getType() == BlockType.CONDITIONAL_BLOCK) {
ConditionalBlock ccur = ((ConditionalBlock) cur);
Block thenSuccessor = ccur.getThenSuccessor();
sb2.append(" " + ccur.getId() + " -> " + thenSuccessor.getId());
sb2.append(" [label=\"then\\n" + ccur.getThenFlowRule() + "\"];\n");
if (!visited.contains(thenSuccessor)) {
visited.add(thenSuccessor);
worklist.add(thenSuccessor);
}
Block elseSuccessor = ccur.getElseSuccessor();
sb2.append(" " + ccur.getId() + " -> " + elseSuccessor.getId());
sb2.append(" [label=\"else\\n" + ccur.getElseFlowRule() + "\"];\n");
if (!visited.contains(elseSuccessor)) {
visited.add(elseSuccessor);
worklist.add(elseSuccessor);
}
} else {
assert cur instanceof SingleSuccessorBlock;
Block b = ((SingleSuccessorBlock) cur).getSuccessor();
if (b != null) {
sb2.append(" " + cur.getId() + " -> " + b.getId());
sb2.append(" [label=\"" + ((SingleSuccessorBlock) cur).getFlowRule() + "\"];\n");
if (!visited.contains(b)) {
visited.add(b);
worklist.add(b);
}
}
}
// exceptional edges
if (cur.getType() == BlockType.EXCEPTION_BLOCK) {
ExceptionBlock ecur = (ExceptionBlock) cur;
for (Entry<TypeMirror, Set<Block>> e : ecur.getExceptionalSuccessors().entrySet()) {
Set<Block> blocks = e.getValue();
TypeMirror cause = e.getKey();
String exception = cause.toString();
if (exception.startsWith("java.lang.")) {
exception = exception.replace("java.lang.", "");
}
for (Block b : blocks) {
sb2.append(" " + cur.getId() + " -> " + b.getId());
sb2.append(" [label=\"" + exception + "\"];\n");
if (!visited.contains(b)) {
visited.add(b);
worklist.add(b);
}
}
}
}
cur = worklist.poll();
}
IdentityHashMap<Block, List<Integer>> processOrder = getProcessOrder(cfg);
// definition of all nodes including their labels
for (Block v : visited) {
sb1.append(" " + v.getId() + " [");
if (v.getType() == BlockType.CONDITIONAL_BLOCK) {
sb1.append("shape=polygon sides=8 ");
} else if (v.getType() == BlockType.SPECIAL_BLOCK) {
sb1.append("shape=oval ");
}
sb1.append("label=\"");
if (verbose) {
sb1.append("Process order: " + processOrder.get(v).toString().replaceAll("[\\[\\]]", "") + "\\n");
}
sb1.append(visualizeContent(v, analysis, verbose).replace("\\n", "\\l") + " \",];\n");
}
sb1.append("\n");
sb1.append(sb2);
// footer
sb1.append("}\n");
return sb1.toString();
}
use of org.checkerframework.dataflow.cfg.block.ExceptionBlock in project checker-framework by typetools.
the class AnalysisResult method runAnalysisFor.
/**
* Runs the analysis again within the block of {@code node} and returns the store at the
* location of {@code node}. If {@code before} is true, then the store immediately before the
* {@link Node} {@code node} is returned. Otherwise, the store after {@code node} is returned.
* If {@code analysisCaches} is not null, this method uses a cache. {@code analysisCaches} is a
* map to a cache for analysis result from an input of the block of the node. If the cache for
* {@code transferInput} is not in {@code analysisCaches}, this method create new cache and
* store it in {@code analysisCaches}. The cache is a map from a node to the analysis result of
* the node.
*/
public static <A extends AbstractValue<A>, S extends Store<S>> S runAnalysisFor(Node node, boolean before, TransferInput<A, S> transferInput, Map<TransferInput<A, S>, IdentityHashMap<Node, TransferResult<A, S>>> analysisCaches) {
assert node != null;
Block block = node.getBlock();
assert transferInput != null;
Analysis<A, S, ?> analysis = transferInput.analysis;
Node oldCurrentNode = analysis.currentNode;
// Prepare cache
IdentityHashMap<Node, TransferResult<A, S>> cache;
if (analysisCaches != null) {
cache = analysisCaches.get(transferInput);
if (cache == null) {
cache = new IdentityHashMap<>();
analysisCaches.put(transferInput, cache);
}
} else {
cache = null;
}
if (analysis.isRunning) {
return analysis.currentInput.getRegularStore();
}
analysis.isRunning = true;
try {
switch(block.getType()) {
case REGULAR_BLOCK:
{
RegularBlock rb = (RegularBlock) block;
// Apply transfer function to contents until we found the node we are
// looking for.
TransferInput<A, S> store = transferInput;
TransferResult<A, S> transferResult = null;
for (Node n : rb.getContents()) {
analysis.currentNode = n;
if (n == node && before) {
return store.getRegularStore();
}
if (cache != null && cache.containsKey(n)) {
transferResult = cache.get(n);
} else {
// Copy the store not to change the state in the cache
transferResult = analysis.callTransferFunction(n, store.copy());
if (cache != null) {
cache.put(n, transferResult);
}
}
if (n == node) {
return transferResult.getRegularStore();
}
store = new TransferInput<>(n, analysis, transferResult);
}
// 'block', then 'node' must be part of the contents of 'block'.
assert false;
return null;
}
case EXCEPTION_BLOCK:
{
ExceptionBlock eb = (ExceptionBlock) block;
// apply transfer function to content
assert eb.getNode() == node;
if (before) {
return transferInput.getRegularStore();
}
analysis.currentNode = node;
TransferResult<A, S> transferResult = analysis.callTransferFunction(node, transferInput);
return transferResult.getRegularStore();
}
default:
// Only regular blocks and exceptional blocks can hold nodes.
assert false;
break;
}
return null;
} finally {
analysis.currentNode = oldCurrentNode;
analysis.isRunning = false;
}
}
use of org.checkerframework.dataflow.cfg.block.ExceptionBlock in project checker-framework by typetools.
the class ControlFlowGraph method getSuccessors.
/**
* Get a list of all successor Blocks for cur
*
* @return a Deque of successor Blocks
*/
private Deque<Block> getSuccessors(Block cur) {
Deque<Block> succs = new ArrayDeque<>();
if (cur.getType() == BlockType.CONDITIONAL_BLOCK) {
ConditionalBlock ccur = ((ConditionalBlock) cur);
succs.add(ccur.getThenSuccessor());
succs.add(ccur.getElseSuccessor());
} else {
assert cur instanceof SingleSuccessorBlock;
Block b = ((SingleSuccessorBlock) cur).getSuccessor();
if (b != null) {
succs.add(b);
}
}
if (cur.getType() == BlockType.EXCEPTION_BLOCK) {
ExceptionBlock ecur = (ExceptionBlock) cur;
for (Set<Block> exceptionSuccSet : ecur.getExceptionalSuccessors().values()) {
succs.addAll(exceptionSuccSet);
}
}
return succs;
}
use of org.checkerframework.dataflow.cfg.block.ExceptionBlock in project checker-framework by typetools.
the class CalledMethodsTransfer method makeExceptionalStores.
/**
* Create a set of stores for the exceptional paths out of the block containing {@code node}. This
* allows propagation, along those paths, of the fact that the method being invoked in {@code
* node} was definitely called.
*
* @param node a method invocation
* @param input the transfer input associated with the method invocation
* @return a map from types to stores. The keys are the same keys used by {@link
* ExceptionBlock#getExceptionalSuccessors()}. The values are copies of the regular store from
* {@code input}.
*/
private Map<TypeMirror, CFStore> makeExceptionalStores(MethodInvocationNode node, final TransferInput<CFValue, CFStore> input) {
if (!(node.getBlock() instanceof ExceptionBlock)) {
// see https://github.com/typetools/checker-framework/issues/3585
return Collections.emptyMap();
}
ExceptionBlock block = (ExceptionBlock) node.getBlock();
Map<TypeMirror, CFStore> result = new LinkedHashMap<>();
block.getExceptionalSuccessors().forEach((tm, b) -> result.put(tm, input.getRegularStore().copy()));
return result;
}
use of org.checkerframework.dataflow.cfg.block.ExceptionBlock in project checker-framework by typetools.
the class AbstractCFGVisualizer method handleSuccessorsHelper.
/**
* Outputs, to sbGraph, a visualization of a block's edges, but not the block itself. (The block
* itself is output elsewhere.) Also adds the successors of the block to the work list and the
* visited blocks list.
*
* @param cur the current block
* @param visited the set of blocks that have already been visited or are in the work list; side
* effected by this method
* @param workList the queue of blocks to be processed; side effected by this method
* @param sbGraph the {@link StringBuilder} to store the graph; side effected by this method
*/
protected void handleSuccessorsHelper(Block cur, Set<Block> visited, Queue<Block> workList, StringBuilder sbGraph) {
if (cur.getType() == Block.BlockType.CONDITIONAL_BLOCK) {
ConditionalBlock ccur = ((ConditionalBlock) cur);
Block thenSuccessor = ccur.getThenSuccessor();
sbGraph.append(visualizeEdge(ccur.getUid(), thenSuccessor.getUid(), ccur.getThenFlowRule().toString()));
sbGraph.append(lineSeparator);
addBlock(thenSuccessor, visited, workList);
Block elseSuccessor = ccur.getElseSuccessor();
sbGraph.append(visualizeEdge(ccur.getUid(), elseSuccessor.getUid(), ccur.getElseFlowRule().toString()));
sbGraph.append(lineSeparator);
addBlock(elseSuccessor, visited, workList);
} else {
SingleSuccessorBlock sscur = (SingleSuccessorBlock) cur;
Block succ = sscur.getSuccessor();
if (succ != null) {
sbGraph.append(visualizeEdge(cur.getUid(), succ.getUid(), sscur.getFlowRule().name()));
sbGraph.append(lineSeparator);
addBlock(succ, visited, workList);
}
}
if (cur.getType() == Block.BlockType.EXCEPTION_BLOCK) {
ExceptionBlock ecur = (ExceptionBlock) cur;
for (Map.Entry<TypeMirror, Set<Block>> e : ecur.getExceptionalSuccessors().entrySet()) {
TypeMirror cause = e.getKey();
String exception = cause.toString();
if (exception.startsWith("java.lang.")) {
exception = exception.replace("java.lang.", "");
}
for (Block b : e.getValue()) {
sbGraph.append(visualizeEdge(cur.getUid(), b.getUid(), exception));
sbGraph.append(lineSeparator);
addBlock(b, visited, workList);
}
}
}
}
Aggregations