Search in sources :

Example 1 with ExceptionBlock

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();
}
Also used : ExceptionBlock(org.checkerframework.dataflow.cfg.block.ExceptionBlock) Set(java.util.Set) HashSet(java.util.HashSet) LinkedList(java.util.LinkedList) ConditionalBlock(org.checkerframework.dataflow.cfg.block.ConditionalBlock) SingleSuccessorBlock(org.checkerframework.dataflow.cfg.block.SingleSuccessorBlock) TypeMirror(javax.lang.model.type.TypeMirror) RegularBlock(org.checkerframework.dataflow.cfg.block.RegularBlock) ExceptionBlock(org.checkerframework.dataflow.cfg.block.ExceptionBlock) SingleSuccessorBlock(org.checkerframework.dataflow.cfg.block.SingleSuccessorBlock) SpecialBlock(org.checkerframework.dataflow.cfg.block.SpecialBlock) Block(org.checkerframework.dataflow.cfg.block.Block) ConditionalBlock(org.checkerframework.dataflow.cfg.block.ConditionalBlock) ArrayList(java.util.ArrayList) List(java.util.List) LinkedList(java.util.LinkedList) HashSet(java.util.HashSet)

Example 2 with ExceptionBlock

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;
    }
}
Also used : ExceptionBlock(org.checkerframework.dataflow.cfg.block.ExceptionBlock) AssignmentNode(org.checkerframework.dataflow.cfg.node.AssignmentNode) Node(org.checkerframework.dataflow.cfg.node.Node) RegularBlock(org.checkerframework.dataflow.cfg.block.RegularBlock) ExceptionBlock(org.checkerframework.dataflow.cfg.block.ExceptionBlock) Block(org.checkerframework.dataflow.cfg.block.Block) RegularBlock(org.checkerframework.dataflow.cfg.block.RegularBlock)

Example 3 with ExceptionBlock

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;
}
Also used : ExceptionBlock(org.checkerframework.dataflow.cfg.block.ExceptionBlock) ConditionalBlock(org.checkerframework.dataflow.cfg.block.ConditionalBlock) SingleSuccessorBlock(org.checkerframework.dataflow.cfg.block.SingleSuccessorBlock) ExceptionBlock(org.checkerframework.dataflow.cfg.block.ExceptionBlock) SingleSuccessorBlock(org.checkerframework.dataflow.cfg.block.SingleSuccessorBlock) SpecialBlock(org.checkerframework.dataflow.cfg.block.SpecialBlock) Block(org.checkerframework.dataflow.cfg.block.Block) ConditionalBlock(org.checkerframework.dataflow.cfg.block.ConditionalBlock) ArrayDeque(java.util.ArrayDeque)

Example 4 with ExceptionBlock

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;
}
Also used : ExceptionBlock(org.checkerframework.dataflow.cfg.block.ExceptionBlock) CFStore(org.checkerframework.framework.flow.CFStore) AnnotatedTypeMirror(org.checkerframework.framework.type.AnnotatedTypeMirror) TypeMirror(javax.lang.model.type.TypeMirror) LinkedHashMap(java.util.LinkedHashMap)

Example 5 with ExceptionBlock

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);
            }
        }
    }
}
Also used : ExceptionBlock(org.checkerframework.dataflow.cfg.block.ExceptionBlock) LinkedHashSet(java.util.LinkedHashSet) Set(java.util.Set) ConditionalBlock(org.checkerframework.dataflow.cfg.block.ConditionalBlock) SingleSuccessorBlock(org.checkerframework.dataflow.cfg.block.SingleSuccessorBlock) TypeMirror(javax.lang.model.type.TypeMirror) ExceptionBlock(org.checkerframework.dataflow.cfg.block.ExceptionBlock) SpecialBlock(org.checkerframework.dataflow.cfg.block.SpecialBlock) Block(org.checkerframework.dataflow.cfg.block.Block) SingleSuccessorBlock(org.checkerframework.dataflow.cfg.block.SingleSuccessorBlock) ConditionalBlock(org.checkerframework.dataflow.cfg.block.ConditionalBlock) Map(java.util.Map) IdentityHashMap(java.util.IdentityHashMap)

Aggregations

ExceptionBlock (org.checkerframework.dataflow.cfg.block.ExceptionBlock)16 Block (org.checkerframework.dataflow.cfg.block.Block)14 TypeMirror (javax.lang.model.type.TypeMirror)10 ConditionalBlock (org.checkerframework.dataflow.cfg.block.ConditionalBlock)10 SpecialBlock (org.checkerframework.dataflow.cfg.block.SpecialBlock)10 RegularBlock (org.checkerframework.dataflow.cfg.block.RegularBlock)8 SingleSuccessorBlock (org.checkerframework.dataflow.cfg.block.SingleSuccessorBlock)8 Node (org.checkerframework.dataflow.cfg.node.Node)7 Set (java.util.Set)5 ReturnNode (org.checkerframework.dataflow.cfg.node.ReturnNode)5 HashSet (java.util.HashSet)4 AssignmentNode (org.checkerframework.dataflow.cfg.node.AssignmentNode)4 LocalVariableNode (org.checkerframework.dataflow.cfg.node.LocalVariableNode)4 LinkedHashSet (java.util.LinkedHashSet)3 LinkedList (java.util.LinkedList)3 List (java.util.List)3 Map (java.util.Map)3 AnnotatedTypeMirror (org.checkerframework.framework.type.AnnotatedTypeMirror)3 ArrayDeque (java.util.ArrayDeque)2 IdentityHashMap (java.util.IdentityHashMap)2