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

import com.github.javaparser.Position;
Javier Costa's avatar
Javier Costa committed
import com.github.javaparser.ast.stmt.EmptyStmt;
import com.github.javaparser.ast.stmt.Statement;
import edg.graphlib.Arrow;
Javier Costa's avatar
Javier Costa committed
import edg.graphlib.Vertex;
import edg.graphlib.Visitor;
Javier Costa's avatar
Javier Costa committed
import tfm.arcs.Arc;
import tfm.arcs.cfg.ControlFlowArc;
Javier Costa's avatar
Javier Costa committed
import tfm.arcs.data.ArcData;
Javier Costa's avatar
Javier Costa committed
import tfm.arcs.pdg.ControlDependencyArc;
import tfm.arcs.pdg.DataDependencyArc;
import tfm.nodes.CFGNode;
Javier Costa's avatar
Javier Costa committed
import tfm.nodes.PDGNode;
import tfm.nodes.Node;
import tfm.utils.Logger;
Javier Costa's avatar
Javier Costa committed
import tfm.variables.*;
import tfm.variables.actions.VariableDeclaration;
import tfm.variables.actions.VariableUse;
import tfm.variables.actions.VariableDefinition;
Javier Costa's avatar
Javier Costa committed

Javier Costa's avatar
Javier Costa committed
import javax.swing.plaf.nimbus.State;
Javier Costa's avatar
Javier Costa committed
import java.util.*;
import java.util.stream.Collectors;
Javier Costa's avatar
Javier Costa committed
import java.util.stream.Stream;
Javier Costa's avatar
Javier Costa committed

public class PDGGraph extends Graph<PDGNode> {
Javier Costa's avatar
Javier Costa committed

    public PDGGraph() {
Javier Costa's avatar
Javier Costa committed
        setRootVertex(new PDGNode(getNextVertexId(), getRootNodeData(), new EmptyStmt()));
Javier Costa's avatar
Javier Costa committed
    }

    protected String getRootNodeData() {
        return "Entry";
    }
Javier Costa's avatar
Javier Costa committed

Javier Costa's avatar
Javier Costa committed
    public <N extends Node> PDGNode addNode(N node) {
        PDGNode vertex = new PDGNode(getNextVertexId(), node);
        super.addVertex(vertex);

        return vertex;
    }

Javier Costa's avatar
Javier Costa committed
    @Override
Javier Costa's avatar
Javier Costa committed
    public PDGNode addNode(String instruction, Statement statement) {
Javier Costa's avatar
Javier Costa committed
        PDGNode vertex = new PDGNode(getNextVertexId(), instruction, statement);
Javier Costa's avatar
Javier Costa committed
        super.addVertex(vertex);

        return vertex;
    }

    @SuppressWarnings("unchecked")
    private void addArc(Arc arc) {
        super.addEdge(arc);
    }

Javier Costa's avatar
Javier Costa committed
    public void addControlDependencyArc(PDGNode from, PDGNode to) {
Javier Costa's avatar
Javier Costa committed
        ControlDependencyArc controlDependencyArc = new ControlDependencyArc(from, to);

        this.addArc(controlDependencyArc);
    }

Javier Costa's avatar
Javier Costa committed
    public void addDataDependencyArc(PDGNode from, PDGNode to, String variable) {
Javier Costa's avatar
Javier Costa committed
        DataDependencyArc dataDataDependencyArc = new DataDependencyArc(from, to, variable);

        this.addArc(dataDataDependencyArc);
    }

Javier Costa's avatar
Javier Costa committed
    public List<PDGNode> getNodesAtLevel(int level) {
        return getVerticies().stream()
                .map(vertex -> (PDGNode) vertex)
                .filter(node -> node.getLevel() == level)
                .collect(Collectors.toList());
    }

    public int getLevels() {
        return getVerticies().stream()
                .map(vertex -> (PDGNode) vertex)
                .max(Comparator.comparingInt(PDGNode::getLevel))
                .map(PDGNode::getLevel)
                .get() + 1;
    }

Javier Costa's avatar
Javier Costa committed
    @Override
    public String toGraphvizRepresentation() {
        String lineSep = System.lineSeparator();

Javier Costa's avatar
Javier Costa committed
        String nodesDeclaration = getNodes().stream()
                .sorted(Comparator.comparingInt(Node::getId))
                .map(Node::toGraphvizRepresentation)
Javier Costa's avatar
Javier Costa committed
                .collect(Collectors.joining(lineSep));

Javier Costa's avatar
Javier Costa committed
        StringBuilder rankedNodes = new StringBuilder();

        // No level 0 is needed (only one node)
        for (int i = 0; i < getLevels(); i++) {
            List<PDGNode> levelNodes = getNodesAtLevel(i);

            if (levelNodes.size() <= 1) {
                continue;
            }

            // rank same
            rankedNodes.append("{ rank = same; ")
                    .append(levelNodes.stream()
                        .map(node -> String.valueOf(node.getId()))
                        .collect(Collectors.joining(";")))
                    .append(" }")
                    .append(lineSep);

            // invisible arrows for ordering
            rankedNodes.append(levelNodes.stream()
                        .sorted(Comparator.comparingInt(PDGNode::getId))
                        .map(node -> String.valueOf(node.getId()))
                        .collect(Collectors.joining(" -> ")))
                    .append("[style = invis];")
                    .append(lineSep);
        }

Javier Costa's avatar
Javier Costa committed
        String arrows =
Javier Costa's avatar
Javier Costa committed
                getArcs().stream()
Javier Costa's avatar
Javier Costa committed
                        .sorted(Comparator.comparingInt(arrow -> ((Node) arrow.getFrom()).getId()))
Javier Costa's avatar
Javier Costa committed
                        .map(Arc::toGraphvizRepresentation)
Javier Costa's avatar
Javier Costa committed
                        .collect(Collectors.joining(lineSep));


        return "digraph g{" + lineSep +
                "splines=true;" + lineSep +
                nodesDeclaration + lineSep +
                arrows + lineSep +
                rankedNodes.toString() +
Javier Costa's avatar
Javier Costa committed
                "}";
    }

    @Override
    public Set<PDGNode> slice(String variable, int lineNumber) {
        PDGNode sliceNode = null;

        // find node by line number
        for (PDGNode node : getNodes()) {
            Statement statement = node.getAstNode();

            if (!statement.getBegin().isPresent() || !statement.getEnd().isPresent())
                continue;

            int begin = statement.getBegin().get().line;
            int end = statement.getEnd().get().line;

            Logger.format("begin %s end %s", begin, end);

            if (lineNumber == begin || lineNumber == end) {
                sliceNode = node;
                break;
            }
        }

        if (sliceNode == null) {
            Logger.format("Warning: Slicing node not found for slicing criterion: (%s, %s)", variable, lineNumber);
            return new HashSet<>();
        }

        Logger.log("Slice node: " + sliceNode);

        return getSliceNodes(new HashSet<>(), sliceNode);
    }

    private Set<PDGNode> getSliceNodes(Set<PDGNode> visited, PDGNode root) {
        visited.add(root);

        for (Arrow arrow : root.getIncomingArrows()) {
            Arc arc = (Arc) arrow;

            PDGNode from = (PDGNode) arc.getFromNode();

            Logger.log("Arrow from node: " + from);

            if (visited.contains(from)) {
                Logger.log("It's already visited. Continuing...");
                continue;
            }

            getSliceNodes(visited, from);
        }

        Logger.format("Done with node %s", root.getId());

        return visited;
    }
Javier Costa's avatar
Javier Costa committed
}