All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.checkerframework.dataflow.cfg.ControlFlowGraph Maven / Gradle / Ivy

package org.checkerframework.dataflow.cfg;

/*>>>
import org.checkerframework.checker.nullness.qual.Nullable;
*/

import com.sun.source.tree.ClassTree;
import com.sun.source.tree.MethodTree;
import com.sun.source.tree.Tree;
import com.sun.source.tree.UnaryTree;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Deque;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Queue;
import java.util.Set;
import org.checkerframework.dataflow.cfg.block.Block;
import org.checkerframework.dataflow.cfg.block.Block.BlockType;
import org.checkerframework.dataflow.cfg.block.ConditionalBlock;
import org.checkerframework.dataflow.cfg.block.ExceptionBlock;
import org.checkerframework.dataflow.cfg.block.SingleSuccessorBlock;
import org.checkerframework.dataflow.cfg.block.SpecialBlock;
import org.checkerframework.dataflow.cfg.block.SpecialBlockImpl;
import org.checkerframework.dataflow.cfg.node.AssignmentNode;
import org.checkerframework.dataflow.cfg.node.Node;
import org.checkerframework.dataflow.cfg.node.ReturnNode;

/**
 * A control flow graph (CFG for short) of a single method.
 *
 * @author Stefan Heule
 */
public class ControlFlowGraph {

    /** The entry block of the control flow graph. */
    protected final SpecialBlock entryBlock;

    /** The regular exit block of the control flow graph. */
    protected final SpecialBlock regularExitBlock;

    /** The exceptional exit block of the control flow graph. */
    protected final SpecialBlock exceptionalExitBlock;

    /** The AST this CFG corresponds to. */
    protected UnderlyingAST underlyingAST;

    /**
     * Maps from AST {@link Tree}s to {@link Node}s. Every Tree that produces a value will have at
     * least one corresponding Node. Trees that undergo conversions, such as boxing or unboxing, can
     * map to two distinct Nodes. The Node for the pre-conversion value is stored in treeLookup,
     * while the Node for the post-conversion value is stored in convertedTreeLookup.
     */
    protected IdentityHashMap treeLookup;

    /** Map from AST {@link Tree}s to post-conversion {@link Node}s. */
    protected IdentityHashMap convertedTreeLookup;

    /** Map from AST {@link UnaryTree}s to corresponding {@link AssignmentNode}s. */
    protected IdentityHashMap unaryAssignNodeLookup;

    /**
     * All return nodes (if any) encountered. Only includes return statements that actually return
     * something
     */
    protected final List returnNodes;

    /** Map from AST {@link Tree}s to generated {@link Tree}s. */
    protected final IdentityHashMap> generatedTreesLookupMap;

    public ControlFlowGraph(
            SpecialBlock entryBlock,
            SpecialBlockImpl regularExitBlock,
            SpecialBlockImpl exceptionalExitBlock,
            UnderlyingAST underlyingAST,
            IdentityHashMap treeLookup,
            IdentityHashMap convertedTreeLookup,
            IdentityHashMap unaryAssignNodeLookup,
            List returnNodes,
            IdentityHashMap> generatedTreesLookupMap) {
        super();
        this.entryBlock = entryBlock;
        this.underlyingAST = underlyingAST;
        this.treeLookup = treeLookup;
        this.unaryAssignNodeLookup = unaryAssignNodeLookup;
        this.convertedTreeLookup = convertedTreeLookup;
        this.regularExitBlock = regularExitBlock;
        this.exceptionalExitBlock = exceptionalExitBlock;
        this.returnNodes = returnNodes;
        this.generatedTreesLookupMap = generatedTreesLookupMap;
    }

    /** @return the {@link Node} to which the {@link Tree} {@code t} corresponds. */
    public Node getNodeCorrespondingToTree(Tree t) {
        if (convertedTreeLookup.containsKey(t)) {
            return convertedTreeLookup.get(t);
        } else {
            return treeLookup.get(t);
        }
    }

    /** @return the entry block of the control flow graph. */
    public SpecialBlock getEntryBlock() {
        return entryBlock;
    }

    public List getReturnNodes() {
        return returnNodes;
    }

    public SpecialBlock getRegularExitBlock() {
        return regularExitBlock;
    }

    public SpecialBlock getExceptionalExitBlock() {
        return exceptionalExitBlock;
    }

    /** @return the AST this CFG corresponds to. */
    public UnderlyingAST getUnderlyingAST() {
        return underlyingAST;
    }

    /** @return the set of all basic block in this control flow graph */
    public Set getAllBlocks() {
        Set visited = new HashSet<>();
        Queue worklist = new ArrayDeque<>();
        Block cur = entryBlock;
        visited.add(entryBlock);

        // traverse the whole control flow graph
        while (true) {
            if (cur == null) {
                break;
            }

            Queue 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 exceptionSuccSet : ecur.getExceptionalSuccessors().values()) {
                    succs.addAll(exceptionSuccSet);
                }
            }

            for (Block b : succs) {
                if (!visited.contains(b)) {
                    visited.add(b);
                    worklist.add(b);
                }
            }

            cur = worklist.poll();
        }

        return visited;
    }

    /**
     * @return the list of all basic block in this control flow graph in reversed depth-first
     *     postorder sequence.
     *     

Blocks may appear more than once in the sequence. */ public List getDepthFirstOrderedBlocks() { List dfsOrderResult = new ArrayList<>(); Set visited = new HashSet<>(); Deque worklist = new ArrayDeque<>(); worklist.add(entryBlock); while (!worklist.isEmpty()) { Block cur = worklist.getLast(); if (visited.contains(cur)) { dfsOrderResult.add(cur); worklist.removeLast(); } else { visited.add(cur); Deque successors = getSuccessors(cur); successors.removeAll(visited); worklist.addAll(successors); } } Collections.reverse(dfsOrderResult); return dfsOrderResult; } /** * Get a list of all successor Blocks for cur * * @return a Deque of successor Blocks */ private Deque getSuccessors(Block cur) { Deque 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 exceptionSuccSet : ecur.getExceptionalSuccessors().values()) { succs.addAll(exceptionSuccSet); } } return succs; } /** @return the copied tree-lookup map */ public IdentityHashMap getTreeLookup() { return new IdentityHashMap<>(treeLookup); } /** @return the copied lookup-map of the assign node for unary operation */ public IdentityHashMap getUnaryAssignNodeLookup() { return new IdentityHashMap<>(unaryAssignNodeLookup); } /** @return the copied map to lookup generated {@link Tree}s from {@link Tree} */ public IdentityHashMap> getGeneratedTreesLookup() { return new IdentityHashMap<>(generatedTreesLookupMap); } /** * Get the {@link MethodTree} of the CFG if the argument {@link Tree} maps to a {@link Node} in * the CFG or null otherwise. */ public /*@Nullable*/ MethodTree getContainingMethod(Tree t) { if (treeLookup.containsKey(t)) { if (underlyingAST.getKind() == UnderlyingAST.Kind.METHOD) { UnderlyingAST.CFGMethod cfgMethod = (UnderlyingAST.CFGMethod) underlyingAST; return cfgMethod.getMethod(); } } return null; } /** * Get the {@link ClassTree} of the CFG if the argument {@link Tree} maps to a {@link Node} in * the CFG or null otherwise. */ public /*@Nullable*/ ClassTree getContainingClass(Tree t) { if (treeLookup.containsKey(t)) { if (underlyingAST.getKind() == UnderlyingAST.Kind.METHOD) { UnderlyingAST.CFGMethod cfgMethod = (UnderlyingAST.CFGMethod) underlyingAST; return cfgMethod.getClassTree(); } } return null; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy