Skip to content
CFG.java 2.39 KiB
Newer Older
Javier Costa's avatar
Javier Costa committed
package tfm.graphs;
Javier Costa's avatar
Javier Costa committed

Javier Costa's avatar
Javier Costa committed
import com.github.javaparser.ast.body.MethodDeclaration;
Javier Costa's avatar
Javier Costa committed
import tfm.arcs.Arc;
Javier Costa's avatar
Javier Costa committed
import tfm.arcs.cfg.ControlFlowArc;
Javier Costa's avatar
Javier Costa committed
import tfm.nodes.GraphNode;
Javier Costa's avatar
Javier Costa committed
import tfm.utils.NodeNotFoundException;
Javier Costa's avatar
Javier Costa committed

Javier Costa's avatar
Javier Costa committed
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
Javier Costa's avatar
Javier Costa committed

/**
 * The <b>Control Flow Graph</b> represents the statements of a method in
 * a graph, displaying the connections between each statement and the ones that
 * may follow it. You can build one manually or use the {@link CFGBuilder CFGBuilder}.
 * The variations of the CFG are implemented as child classes.
 * @see ControlFlowArc
 */
public class CFG extends GraphWithRootNode<MethodDeclaration> {
    private boolean built = false;
Javier Costa's avatar
Javier Costa committed

    public CFG() {
Javier Costa's avatar
Javier Costa committed
        super();
Javier Costa's avatar
Javier Costa committed

    public void addControlFlowEdge(GraphNode<?> from, GraphNode<?> to) {
        addControlFlowEdge(from, to, new ControlFlowArc());
    protected void addControlFlowEdge(GraphNode<?> from, GraphNode<?> to, ControlFlowArc arc) {
        super.addEdge(from, to, arc);
Javier Costa's avatar
Javier Costa committed
    }
Javier Costa's avatar
Javier Costa committed
    public Set<GraphNode<?>> findLastDefinitionsFrom(GraphNode<?> startNode, String variable) {
        if (!this.containsVertex(startNode))
Javier Costa's avatar
Javier Costa committed
            throw new NodeNotFoundException(startNode, this);
        return findLastDefinitionsFrom(new HashSet<>(), startNode, startNode, variable);
    }

    private Set<GraphNode<?>> findLastDefinitionsFrom(Set<Integer> visited, GraphNode<?> startNode, GraphNode<?> currentNode, String variable) {
        visited.add(currentNode.getId());

        Set<GraphNode<?>> res = new HashSet<>();

Javier Costa's avatar
Javier Costa committed
        for (Arc arc : incomingEdgesOf(currentNode)) {
Carlos Galindo's avatar
Carlos Galindo committed
            if (!arc.isExecutableControlFlowArc())
                continue;
            GraphNode<?> from = getEdgeSource(arc);
Javier Costa's avatar
Javier Costa committed

            if (!Objects.equals(startNode, from) && visited.contains(from.getId())) {
                continue;
            }

            if (from.getDefinedVariables().contains(variable)) {
                res.add(from);
            } else {
                res.addAll(findLastDefinitionsFrom(visited, startNode, from, variable));
            }
        }
        return res;
    }
    @Override
    public void build(MethodDeclaration method) {
        method.accept(newCFGBuilder(), null);
        built = true;
    }

    @Override
    public boolean isBuilt() {
        return built;
    }

    protected CFGBuilder newCFGBuilder() {
        return new CFGBuilder(this);
Javier Costa's avatar
Javier Costa committed
}