From bca373cc5361ff5539bb8f2e6e47e41593687880 Mon Sep 17 00:00:00 2001 From: Javier Costa Date: Sun, 19 Jan 2020 20:31:59 +0100 Subject: [PATCH 1/9] JGraphT without visitors --- .gitignore | 1 + src/main/java/tfm/arcs/Arc.java | 65 +++---- .../java/tfm/arcs/cfg/ControlFlowArc.java | 10 +- src/main/java/tfm/arcs/data/ArcData.java | 8 - .../java/tfm/arcs/data/VariableArcData.java | 37 ---- src/main/java/tfm/arcs/data/VoidArcData.java | 18 -- .../tfm/arcs/pdg/ControlDependencyArc.java | 14 +- .../java/tfm/arcs/pdg/DataDependencyArc.java | 33 +--- src/main/java/tfm/graphs/CFGGraph.java | 21 +- src/main/java/tfm/graphs/Graph.java | 137 +++++-------- src/main/java/tfm/graphs/JGraph.java | 12 -- src/main/java/tfm/graphs/PDGGraph.java | 78 +++----- src/main/java/tfm/graphs/SDGGraph.java | 18 +- src/main/java/tfm/nodes/CFGNode.java | 26 --- src/main/java/tfm/nodes/GraphNode.java | 95 +++------ src/main/java/tfm/nodes/JNode.java | 135 ------------- src/main/java/tfm/nodes/MethodCallNode.java | 7 +- src/main/java/tfm/nodes/PDGNode.java | 92 --------- src/main/java/tfm/nodes/SDGNode.java | 28 --- src/main/java/tfm/scopes/IfElseScope.java | 64 ------ src/main/java/tfm/scopes/Scope.java | 46 ----- src/main/java/tfm/scopes/ScopeHolder.java | 183 ------------------ src/main/java/tfm/scopes/VariableScope.java | 156 --------------- 23 files changed, 154 insertions(+), 1130 deletions(-) delete mode 100644 src/main/java/tfm/arcs/data/ArcData.java delete mode 100644 src/main/java/tfm/arcs/data/VariableArcData.java delete mode 100644 src/main/java/tfm/arcs/data/VoidArcData.java delete mode 100644 src/main/java/tfm/graphs/JGraph.java delete mode 100644 src/main/java/tfm/nodes/CFGNode.java delete mode 100644 src/main/java/tfm/nodes/JNode.java delete mode 100644 src/main/java/tfm/nodes/PDGNode.java delete mode 100644 src/main/java/tfm/nodes/SDGNode.java delete mode 100644 src/main/java/tfm/scopes/IfElseScope.java delete mode 100644 src/main/java/tfm/scopes/Scope.java delete mode 100644 src/main/java/tfm/scopes/ScopeHolder.java delete mode 100644 src/main/java/tfm/scopes/VariableScope.java diff --git a/.gitignore b/.gitignore index d947638..77901fe 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ .idea/ target/ out/ +.settings \ No newline at end of file diff --git a/src/main/java/tfm/arcs/Arc.java b/src/main/java/tfm/arcs/Arc.java index 5c13d31..8a2be34 100644 --- a/src/main/java/tfm/arcs/Arc.java +++ b/src/main/java/tfm/arcs/Arc.java @@ -1,15 +1,21 @@ package tfm.arcs; -import tfm.arcs.data.ArcData; +import org.jgrapht.graph.DefaultEdge;; import tfm.nodes.GraphNode; import java.util.Objects; +import java.util.Optional; -public abstract class Arc extends edg.graphlib.Arrow { +public abstract class Arc extends DefaultEdge { - @SuppressWarnings("unchecked") - public Arc(GraphNode from, GraphNode to) { - super((edg.graphlib.Vertex) from, (edg.graphlib.Vertex) to); + private String variable; + + public Arc() { + + } + + public Arc(String variable) { + this.variable = variable; } public abstract boolean isControlFlowArrow(); @@ -18,18 +24,14 @@ public abstract class Arc extends edg.graphlib.Arrow %s}", - getData(), - getFrom(), - getTo() - ); + public Optional getVariable() { + return Optional.ofNullable(this.variable); } - public String toGraphvizRepresentation() { - GraphNode from = (GraphNode) getFrom(); - GraphNode to = (GraphNode) getTo(); + @Override + public String toString() { + GraphNode from = (GraphNode) getSource(); + GraphNode to = (GraphNode) getTarget(); return String.format("%s -> %s", from.getId(), @@ -37,36 +39,21 @@ public abstract class Arc extends edg.graphlib.Arrow getFromNode() { - return (GraphNode) super.getFrom(); - } - - public GraphNode getToNode() { - return (GraphNode) super.getTo(); - } - - @Override - public int hashCode() { - return Objects.hashCode(getData()) + getFrom().hashCode() + getTo().hashCode(); + public String toGraphvizRepresentation() { + return toString(); } @Override public boolean equals(Object o) { - if (this == o) - return true; - - if (!(o instanceof Arc)) + if (this != o) { return false; + } - Arc arc = (Arc) o; - - GraphNode from = (GraphNode) arc.getFrom(); - GraphNode from2 = (GraphNode) getFrom(); - GraphNode to = (GraphNode) getTo(); - GraphNode to2 = (GraphNode) arc.getTo(); + return Objects.equals(variable, ((Arc) o).variable); + } - return Objects.equals(arc.getData(), getData()) && - Objects.equals(from.getId(), from2.getId()) && - Objects.equals(to.getId(), to2.getId()); + @Override + public int hashCode() { + return Objects.hash(variable, getSource(), getTarget()); } } diff --git a/src/main/java/tfm/arcs/cfg/ControlFlowArc.java b/src/main/java/tfm/arcs/cfg/ControlFlowArc.java index f51233c..8cd15b0 100644 --- a/src/main/java/tfm/arcs/cfg/ControlFlowArc.java +++ b/src/main/java/tfm/arcs/cfg/ControlFlowArc.java @@ -4,10 +4,9 @@ import tfm.arcs.Arc; import tfm.arcs.data.VoidArcData; import tfm.nodes.GraphNode; -public class ControlFlowArc extends Arc { +public class ControlFlowArc extends Arc { - public ControlFlowArc(GraphNode from, GraphNode to) { - super(from, to); + public ControlFlowArc() { } @Override @@ -27,10 +26,7 @@ public class ControlFlowArc extends Arc { @Override public String toString() { - return String.format("ControlFlowArc{%s -> %s}", - getFromNode().getId(), - getToNode().getId() - ); + return String.format("ControlFlowArc{%s}", super.toString()); } } diff --git a/src/main/java/tfm/arcs/data/ArcData.java b/src/main/java/tfm/arcs/data/ArcData.java deleted file mode 100644 index a20b654..0000000 --- a/src/main/java/tfm/arcs/data/ArcData.java +++ /dev/null @@ -1,8 +0,0 @@ -package tfm.arcs.data; - -public abstract class ArcData { - - public abstract boolean isVoid(); - - public abstract boolean isVariable(); -} diff --git a/src/main/java/tfm/arcs/data/VariableArcData.java b/src/main/java/tfm/arcs/data/VariableArcData.java deleted file mode 100644 index 0ce2e49..0000000 --- a/src/main/java/tfm/arcs/data/VariableArcData.java +++ /dev/null @@ -1,37 +0,0 @@ -package tfm.arcs.data; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; - -public class VariableArcData extends ArcData { - private List variables; - - public VariableArcData(String... variables) { - this(Arrays.asList(variables)); - } - - public VariableArcData(Collection variables) { - this.variables = new ArrayList<>(variables); - } - - public List getVariables() { - return variables; - } - - @Override - public boolean isVoid() { - return false; - } - - @Override - public boolean isVariable() { - return true; - } - - @Override - public String toString() { - return variables.toString(); - } -} diff --git a/src/main/java/tfm/arcs/data/VoidArcData.java b/src/main/java/tfm/arcs/data/VoidArcData.java deleted file mode 100644 index de5d824..0000000 --- a/src/main/java/tfm/arcs/data/VoidArcData.java +++ /dev/null @@ -1,18 +0,0 @@ -package tfm.arcs.data; - -public class VoidArcData extends ArcData { - @Override - public boolean isVoid() { - return true; - } - - @Override - public boolean isVariable() { - return false; - } - - @Override - public String toString() { - return "void"; - } -} diff --git a/src/main/java/tfm/arcs/pdg/ControlDependencyArc.java b/src/main/java/tfm/arcs/pdg/ControlDependencyArc.java index 6d7c79b..501e5f4 100644 --- a/src/main/java/tfm/arcs/pdg/ControlDependencyArc.java +++ b/src/main/java/tfm/arcs/pdg/ControlDependencyArc.java @@ -4,10 +4,13 @@ import tfm.arcs.Arc; import tfm.arcs.data.ArcData; import tfm.nodes.GraphNode; -public class ControlDependencyArc extends Arc { +public class ControlDependencyArc extends Arc { - public ControlDependencyArc(GraphNode from, GraphNode to) { - super(from, to); + public ControlDependencyArc(String variable) { + super(variable); + } + + public ControlDependencyArc() { } @Override @@ -27,9 +30,6 @@ public class ControlDependencyArc extends Arc { @Override public String toString() { - return String.format("ControlDependencyArc{%s -> %s}", - ((GraphNode) getFrom()).getId(), - ((GraphNode) getTo()).getId() - ); + return String.format("ControlDependencyArc{%s}", super.toString()); } } diff --git a/src/main/java/tfm/arcs/pdg/DataDependencyArc.java b/src/main/java/tfm/arcs/pdg/DataDependencyArc.java index 11e8ac0..80b0996 100644 --- a/src/main/java/tfm/arcs/pdg/DataDependencyArc.java +++ b/src/main/java/tfm/arcs/pdg/DataDependencyArc.java @@ -1,26 +1,13 @@ package tfm.arcs.pdg; import tfm.arcs.Arc; -import tfm.arcs.data.VariableArcData; -import tfm.nodes.GraphNode; +public class DataDependencyArc extends Arc { -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -public class DataDependencyArc extends Arc { - - public DataDependencyArc(GraphNode from, GraphNode to, String variable, String... variables) { - super(from, to); - - List variablesList = new ArrayList<>(variables.length + 1); - - variablesList.add(variable); - variablesList.addAll(Arrays.asList(variables)); - - VariableArcData variableArcData = new VariableArcData(variablesList); + public DataDependencyArc() { + } - setData(variableArcData); + public DataDependencyArc(String variable) { + super(variable); } @Override @@ -40,15 +27,15 @@ public class DataDependencyArc extends Arc { @Override public String toString() { - return String.format("DataDependencyArc{%s, %s -> %s}", - getData(), - getFromNode().getId(), - getToNode().getId()); + return String.format("DataDependencyArc{%s}", super.toString()); } @Override public String toGraphvizRepresentation() { - return String.format("%s [style=dashed, color=red, label=\"%s\"];", super.toGraphvizRepresentation(), getData().toString()); + return String.format("%s [style=dashed, color=red%s];", + super.toGraphvizRepresentation(), + getVariable().map(variable -> String.format(", label=\"%s\"", variable)).orElse("") + ); } } diff --git a/src/main/java/tfm/graphs/CFGGraph.java b/src/main/java/tfm/graphs/CFGGraph.java index 8faf9e3..f1e7acb 100644 --- a/src/main/java/tfm/graphs/CFGGraph.java +++ b/src/main/java/tfm/graphs/CFGGraph.java @@ -1,7 +1,6 @@ package tfm.graphs; import com.github.javaparser.ast.Node; -import com.github.javaparser.ast.stmt.EmptyStmt; import edg.graphlib.Arrow; import tfm.arcs.Arc; import tfm.arcs.cfg.ControlFlowArc; @@ -19,7 +18,6 @@ public class CFGGraph extends Graph { public CFGGraph() { super(); - setRootVertex(new GraphNode<>(getNextVertexId(), getRootNodeData(), new EmptyStmt())); } @Override @@ -30,14 +28,9 @@ public class CFGGraph extends Graph { return vertex; } - - protected String getRootNodeData() { - return "Start"; - } - @SuppressWarnings("unchecked") - public void addControlFlowEdge(GraphNode from, GraphNode to) { - super.addEdge((Arrow) new ControlFlowArc(from, to)); + public void addControlFlowEdge(GraphNode from, GraphNode to) { + super.addEdge(from, to); } @Override @@ -50,9 +43,9 @@ public class CFGGraph extends Graph { .collect(Collectors.joining(lineSep)); String arrows = - getArrows().stream() - .sorted(Comparator.comparingInt(arrow -> ((GraphNode) arrow.getFrom()).getId())) - .map(arrow -> ((Arc) arrow).toGraphvizRepresentation()) + getArcs().stream() + .sorted(Comparator.comparingInt(arc -> this.getEdgeSource(arc).getId())) + .map(Arc::toGraphvizRepresentation) .collect(Collectors.joining(lineSep)); return "digraph g{" + lineSep + @@ -86,10 +79,10 @@ public class CFGGraph extends Graph { Set> res = new HashSet<>(); - for (Arc arc : currentNode.getIncomingArcs()) { + for (Arc arc : incomingEdgesOf(currentNode)) { ControlFlowArc controlFlowArc = (ControlFlowArc) arc; - GraphNode from = controlFlowArc.getFromNode(); + GraphNode from = this.getEdgeSource(controlFlowArc); // Logger.log("Arrow from node: " + from); diff --git a/src/main/java/tfm/graphs/Graph.java b/src/main/java/tfm/graphs/Graph.java index 5ab503d..e337690 100644 --- a/src/main/java/tfm/graphs/Graph.java +++ b/src/main/java/tfm/graphs/Graph.java @@ -1,10 +1,8 @@ package tfm.graphs; import com.github.javaparser.ast.Node; -import edg.graphlib.Arrow; -import edg.graphlib.Vertex; +import org.jgrapht.graph.DefaultDirectedGraph; import tfm.arcs.Arc; -import tfm.arcs.data.ArcData; import tfm.nodes.GraphNode; import tfm.slicing.SlicingCriterion; @@ -12,82 +10,63 @@ import java.util.*; import java.util.stream.Collectors; /** - * A graphlib Graph without cost and data in arcs + * * */ -public abstract class Graph extends edg.graphlib.Graph { +public abstract class Graph extends DefaultDirectedGraph, Arc> { private int nextVertexId = 0; -// public final static class NodeId { -// private static int nextVertexId = 0; -// -// private int id; -// -// private NodeId(int id) { -// this.id = id; -// } -// -// static synchronized NodeId getVertexId() { -// return new NodeId(nextVertexId++); -// } -// -// public int getId() { -// return id; -// } -// -// @Override -// public String toString() { -// return String.valueOf(id); -// } -// } - public Graph() { - super(); + super(null, null, false); + } + + private GraphNode addNode(GraphNode node) { + this.addVertex(node); + + return node; + } + + private GraphNode addNode(int id, String instruction, ASTNode node) { + GraphNode newNode = new GraphNode<>(id, instruction, node); + + return this.addNode(newNode); + } + + public GraphNode addNode(String instruction, ASTNode node) { + return this.addNode(getNextVertexId(), instruction, node); } /** - Library fix: if a node had an edge to itself resulted in 2 outgoing nodes instead of 1 outgoing and 1 incoming + * Adds the given node to the graph. + * + * One must be careful with this method, as the given node will have + * an id and arcs corresponding to the graph in which it was created, and may not fit + * in the current graph. + * + * @param node the node to add to the graph + * @param copyId whether to copy the id node or not + * @param copyArcs whether to copy the arcs of the node or not + * @return the node instance added to the graph */ - @Override - public boolean addEdge(Arrow arrow) { - Vertex from = arrow.getFrom(); - Vertex to = arrow.getTo(); - int cost = arrow.getCost(); - ArcData data = arrow.getData(); - - if (!verticies.contains(from)) - throw new IllegalArgumentException(String.format("from (%s) is not in graph", from)); - if (!verticies.contains(to)) - throw new IllegalArgumentException(String.format("to (%s) is not in graph", to)); - - List> es2 = from.findEdges(to); - - for (Arrow e2 : es2) { - if (e2 != null && cost == e2.getCost() && - ((data == null && e2.getData() == null) || - (data != null && data.equals(e2.getData())))) - return false; - } - - // FIX - if (Objects.equals(from, to)) { - from.getOutgoingArrows().add(arrow); - from.getIncomingArrows().add(arrow); + public GraphNode addNode(GraphNode node, boolean copyId, boolean copyArcs) { + GraphNode res = node; + + if (copyId && copyArcs) { + this.addVertex(node); + } else if (copyId) { + res = this.addNode(node.getId(), node.getInstruction(), node.getAstNode()); + } else if (copyArcs) { + res = new GraphNode<>(node); + res.setId(getNextVertexId()); + + this.addVertex(res); } else { - from.addEdge(arrow); - to.addEdge(arrow); + res = this.addNode(node.getInstruction(), node.getAstNode()); } - edges.add(arrow); - return true; - } - @SuppressWarnings("unchecked") - public GraphNode getRootNode() { - return (GraphNode) super.getRootVertex(); + return res; } - public abstract GraphNode addNode(String instruction, ASTNode node); - @SuppressWarnings("unchecked") public Optional> findNodeByASTNode(ASTNode astNode) { return getNodes().stream() @@ -102,17 +81,12 @@ public abstract class Graph extends edg.graphlib.Graph { .findFirst(); } - @SuppressWarnings("unchecked") public Set> getNodes() { - return getVerticies().stream() - .map(vertex -> (GraphNode) vertex) - .collect(Collectors.toSet()); + return vertexSet(); } - public Set> getArcs() { - return getArrows().stream() - .map(arrow -> (Arc) arrow) - .collect(Collectors.toSet()); + public Set getArcs() { + return edgeSet(); } public String toString() { @@ -129,26 +103,13 @@ public abstract class Graph extends edg.graphlib.Graph { } public boolean contains(GraphNode graphNode) { - return getNodes().stream() - .anyMatch(node -> Objects.equals(node, graphNode)); + return super.containsVertex(graphNode); } public abstract Graph slice(SlicingCriterion slicingCriterion); - /** - * Deprecated for incorrect behaviour. Use removeNode instead - */ - @Override - @Deprecated - public boolean removeVertex(Vertex vertex) { - throw new UnsupportedOperationException("Deprecated method. Use removeNode instead"); - } - public void removeNode(GraphNode node) { - verticies.remove(node); - - edges.removeAll(node.getOutgoingArcs()); - edges.removeAll(node.getIncomingArcs()); + removeVertex(node); } public List> findDeclarationsOfVariable(String variable) { diff --git a/src/main/java/tfm/graphs/JGraph.java b/src/main/java/tfm/graphs/JGraph.java deleted file mode 100644 index 5fe88f8..0000000 --- a/src/main/java/tfm/graphs/JGraph.java +++ /dev/null @@ -1,12 +0,0 @@ -package tfm.graphs; - -import org.jgrapht.graph.DefaultDirectedGraph; -import tfm.arcs.Arc; -import tfm.nodes.JNode; - -public class JGraph extends DefaultDirectedGraph, Arc> { - - public JGraph() { - super(null, null, false); - } -} diff --git a/src/main/java/tfm/graphs/PDGGraph.java b/src/main/java/tfm/graphs/PDGGraph.java index 7cd03b4..d163a8f 100644 --- a/src/main/java/tfm/graphs/PDGGraph.java +++ b/src/main/java/tfm/graphs/PDGGraph.java @@ -2,7 +2,6 @@ package tfm.graphs; import com.github.javaparser.ast.Node; import com.github.javaparser.ast.body.MethodDeclaration; -import com.github.javaparser.ast.stmt.EmptyStmt; import edg.graphlib.Arrow; import org.jetbrains.annotations.NotNull; import tfm.arcs.Arc; @@ -15,10 +14,7 @@ import tfm.utils.Logger; import tfm.utils.NodeNotFoundException; import tfm.visitors.pdg.PDGBuilder; -import java.util.Comparator; -import java.util.HashSet; -import java.util.Optional; -import java.util.Set; +import java.util.*; import java.util.stream.Collectors; public class PDGGraph extends Graph { @@ -26,64 +22,40 @@ public class PDGGraph extends Graph { private CFGGraph cfgGraph; public PDGGraph() { - setRootVertex(new GraphNode<>(getNextVertexId(), getRootNodeData(), new MethodDeclaration())); + super(); } public PDGGraph(CFGGraph cfgGraph) { - this(); + super(); this.cfgGraph = cfgGraph; } - protected String getRootNodeData() { - return "Entry"; - } - - public GraphNode addNode(GraphNode node) { - GraphNode vertex = new GraphNode<>(node); - super.addVertex(vertex); - - return vertex; - } - - @Override - public GraphNode addNode(String instruction, ASTNode node) { - return addNode(getNextVertexId(), instruction, node); - } + public GraphNode getRootNode() { + Iterator> iterator = this.getNodesAtLevel(0).iterator(); - public GraphNode addNode(int id, String instruction, ASTNode node) { - GraphNode vertex = new GraphNode<>(id, instruction, node); - super.addVertex(vertex); - - return vertex; - } + if (iterator.hasNext()) { + return iterator.next(); + } - @SuppressWarnings("unchecked") - private void addArc(Arc arc) { - super.addEdge(arc); + return null; } - public void addControlDependencyArc(GraphNode from, GraphNode to) { - ControlDependencyArc controlDependencyArc = new ControlDependencyArc(from, to); - - this.addArc(controlDependencyArc); + public void addControlDependencyArc(GraphNode from, GraphNode to) { + this.addEdge(from, to); } - public void addDataDependencyArc(GraphNode from, GraphNode to, String variable) { - DataDependencyArc dataDataDependencyArc = new DataDependencyArc(from, to, variable); - - this.addArc(dataDataDependencyArc); + public void addDataDependencyArc(GraphNode from, GraphNode to, String variable) { + this.addEdge(from, to, new DataDependencyArc(variable)); } - public Set getNodesAtLevel(int level) { - return getVerticies().stream() - .map(vertex -> (GraphNode) vertex) + public Set> getNodesAtLevel(int level) { + return getNodes().stream() .filter(node -> getLevelOf(node) == level) .collect(Collectors.toSet()); } public int getLevels() { - return getVerticies().stream() - .map(vertex -> (GraphNode) vertex) + return getNodes().stream() .max(Comparator.comparingInt(this::getLevelOf)) .map(node -> getLevelOf(node) + 1) .orElse(0); @@ -96,7 +68,7 @@ public class PDGGraph extends Graph { } public int getLevelOf(@NotNull GraphNode node) { - Optional optionalControlDependencyArc = node.getIncomingArcs().stream() + Optional optionalControlDependencyArc = incomingEdgesOf(node).stream() .filter(Arc::isControlDependencyArrow) .findFirst() .map(arc -> (ControlDependencyArc) arc); @@ -105,7 +77,7 @@ public class PDGGraph extends Graph { return 0; } - GraphNode parent = optionalControlDependencyArc.get().getFromNode(); + GraphNode parent = this.getEdgeSource(optionalControlDependencyArc.get()); return 1 + getLevelOf(parent); } @@ -127,7 +99,7 @@ public class PDGGraph extends Graph { // No level 0 is needed (only one node) for (int i = 0; i < getLevels(); i++) { - Set levelNodes = getNodesAtLevel(i); + Set> levelNodes = getNodesAtLevel(i); if (levelNodes.size() <= 1) { continue; @@ -152,7 +124,7 @@ public class PDGGraph extends Graph { String arrows = getArcs().stream() - .sorted(Comparator.comparingInt(arrow -> ((GraphNode) arrow.getFrom()).getId())) + .sorted(Comparator.comparingInt(arc -> this.getEdgeSource(arc).getId())) .map(Arc::toGraphvizRepresentation) .collect(Collectors.joining(lineSep)); @@ -197,9 +169,9 @@ public class PDGGraph extends Graph { Node astCopy = ASTUtils.cloneAST(node.getAstNode()); - astCopy.accept(new PDGBuilder(sliceGraph), sliceGraph.getRootNode()); + astCopy.accept(new PDGBuilder(sliceGraph), sliceGraph.getNodesAtLevel(0).iterator().next()); - for (GraphNode sliceNode : sliceGraph.getNodes()) { + for (GraphNode sliceNode : sliceGraph.getNodes()) { if (!sliceNodes.contains(sliceNode.getId())) { Logger.log("Removing node " + sliceNode.getId()); sliceNode.getAstNode().removeForced(); @@ -230,10 +202,8 @@ public class PDGGraph extends Graph { private Set getSliceNodes(Set visited, GraphNode root) { visited.add(root.getId()); - for (Arrow arrow : root.getIncomingArcs()) { - Arc arc = (Arc) arrow; - - GraphNode from = (GraphNode) arc.getFromNode(); + for (Arc arc : incomingEdgesOf(root)) { + GraphNode from = this.getEdgeSource(arc); if (visited.contains(from.getId())) { continue; diff --git a/src/main/java/tfm/graphs/SDGGraph.java b/src/main/java/tfm/graphs/SDGGraph.java index ec4692b..4aa8752 100644 --- a/src/main/java/tfm/graphs/SDGGraph.java +++ b/src/main/java/tfm/graphs/SDGGraph.java @@ -19,14 +19,6 @@ public class SDGGraph extends Graph { this.contextPDGGraphMap = new HashMap<>(); } - @Override - public GraphNode addNode(String instruction, ASTNode node) { - GraphNode sdgNode = new GraphNode<>(getNextVertexId(), instruction, node); - super.addVertex(sdgNode); - - return sdgNode; - } - @Override public String toGraphvizRepresentation() { return contextPDGGraphMap.values().stream() @@ -59,10 +51,6 @@ public class SDGGraph extends Graph { @Deprecated public void addPDG(PDGGraph pdgGraph, MethodDeclaration methodDeclaration) { - if (this.rootVertex == null) { - this.setRootVertex(new GraphNode<>(getNextVertexId(), methodDeclaration.getNameAsString(), methodDeclaration)); - } - for (Parameter parameter : methodDeclaration.getParameters()) { GraphNode sdgNode = new GraphNode<>( getNextVertexId(), @@ -74,13 +62,11 @@ public class SDGGraph extends Graph { } for (GraphNode node : pdgGraph.getNodes()) { - if (!this.verticies.contains(node)) { + if (!this.contains(node)) { GraphNode sdgNode = new GraphNode<>( getNextVertexId(), - node.getData(), + node.getInstruction(), node.getAstNode(), - node.getIncomingArcs(), - node.getOutgoingArcs(), node.getDeclaredVariables(), node.getDefinedVariables(), node.getUsedVariables() diff --git a/src/main/java/tfm/nodes/CFGNode.java b/src/main/java/tfm/nodes/CFGNode.java deleted file mode 100644 index 75e4b1c..0000000 --- a/src/main/java/tfm/nodes/CFGNode.java +++ /dev/null @@ -1,26 +0,0 @@ -package tfm.nodes; - -import com.github.javaparser.ast.Node; - -import java.util.stream.Collectors; - -@Deprecated -public class CFGNode extends GraphNode { - - public > CFGNode(N1 node) { - super(node); - } - - public CFGNode(int nextVertexId, String rootNodeData, N node) { - super(nextVertexId, rootNodeData, node); - } - - @Override - public String toString() { - return String.format("CFGNode{id: %s, in: %s, out: %s", - getId(), - getIncomingArcs().stream().map(arc -> arc.getFromNode().getId()).collect(Collectors.toList()), - getOutgoingArcs().stream().map(arc -> arc.getToNode().getId()).collect(Collectors.toList()) - ); - } -} diff --git a/src/main/java/tfm/nodes/GraphNode.java b/src/main/java/tfm/nodes/GraphNode.java index 133b4cf..b1ed794 100644 --- a/src/main/java/tfm/nodes/GraphNode.java +++ b/src/main/java/tfm/nodes/GraphNode.java @@ -2,21 +2,17 @@ package tfm.nodes; import com.github.javaparser.ast.Node; import com.github.javaparser.ast.stmt.Statement; -import edg.graphlib.Arrow; -import edg.graphlib.Vertex; import org.checkerframework.checker.nullness.qual.NonNull; import org.jetbrains.annotations.NotNull; -import tfm.arcs.Arc; -import tfm.arcs.data.ArcData; import tfm.utils.Utils; import tfm.variables.VariableExtractor; import java.util.*; -import java.util.stream.Collectors; -public class GraphNode extends Vertex { +public class GraphNode { private int id; + private String instruction; protected N astNode; @@ -27,23 +23,19 @@ public class GraphNode extends Vertex { public > GraphNode(N1 node) { this( node.getId(), - node.getData(), + node.getInstruction(), node.getAstNode(), - node.getIncomingArcs(), - node.getOutgoingArcs(), node.getDeclaredVariables(), node.getDefinedVariables(), node.getUsedVariables() ); } - public GraphNode(int id, String representation, @NotNull N astNode) { + public GraphNode(int id, String instruction, @NotNull N astNode) { this( id, - representation, + instruction, astNode, - Utils.emptyList(), - Utils.emptyList(), Utils.emptySet(), Utils.emptySet(), Utils.emptySet() @@ -52,27 +44,20 @@ public class GraphNode extends Vertex { public GraphNode( int id, - String representation, + String instruction, @NonNull N astNode, - Collection> incomingArcs, - Collection> outgoingArcs, Set declaredVariables, Set definedVariables, Set usedVariables ) { - super(null, representation); - this.id = id; - + this.instruction = instruction; this.astNode = astNode; this.declaredVariables = declaredVariables; this.definedVariables = definedVariables; this.usedVariables = usedVariables; - this.setIncomingArcs(incomingArcs); - this.setOutgoingArcs(outgoingArcs); - if (astNode instanceof Statement) { extractVariables((Statement) astNode); } @@ -95,11 +80,10 @@ public class GraphNode extends Vertex { } public String toString() { - return String.format("GraphNode{id: %s, data: '%s', in: %s, out: %s}", + return String.format("GraphNode{id: %s, instruction: '%s'}", getId(), - getData(), - getIncomingArcs().stream().map(arc -> arc.getFromNode().getId()).collect(Collectors.toList()), - getOutgoingArcs().stream().map(arc -> arc.getToNode().getId()).collect(Collectors.toList())); + getInstruction() + ); } public N getAstNode() { @@ -135,17 +119,20 @@ public class GraphNode extends Vertex { if (!(o instanceof GraphNode)) return false; - GraphNode other = (GraphNode) o; + GraphNode other = (GraphNode) o; - return Objects.equals(getData(), other.getData()) + return Objects.equals(getId(), other.getId()) + && Objects.equals(getInstruction(), other.getInstruction()) && Objects.equals(astNode, other.astNode); -// && Objects.equals(getIncomingArrows(), other.getIncomingArrows()) -// && Objects.equals(getOutgoingArrows(), other.getOutgoingArrows()) -// && Objects.equals(getName(), other.getName()) ID IS ALWAYS UNIQUE, SO IT WILL NEVER BE THE SAME + } + + @Override + public int hashCode() { + return Objects.hash(getId(), getInstruction(), getAstNode()); } public String toGraphvizRepresentation() { - String text = getData().replace("\\", "\\\\") + String text = getInstruction().replace("\\", "\\\\") .replace("\"", "\\\""); return String.format("%s[label=\"%s: %s\"];", getId(), getId(), text); } @@ -162,47 +149,11 @@ public class GraphNode extends Vertex { return usedVariables; } - public List> getIncomingArcs() { - return super.getIncomingArrows().stream() - .map(arrow -> (Arc) arrow) - .collect(Collectors.toList()); + public String getInstruction() { + return instruction; } - public List> getOutgoingArcs() { - return super.getOutgoingArrows().stream() - .map(arrow -> (Arc) arrow) - .collect(Collectors.toList()); - } - - public , C extends Collection> void setIncomingArcs(C arcs) { - for (A arc : arcs) { - this.addIncomingEdge(arc.getFrom(), arc.getCost()); - } - } - - public , C extends Collection> void setOutgoingArcs(C arcs) { - for (A arc : arcs) { - this.addOutgoingEdge(arc.getTo(), arc.getCost()); - } - } - - /** - * Deprecated. Use getIncomingArcs instead - * @throws UnsupportedOperationException - */ - @Deprecated - @Override - public List> getIncomingArrows() { - return super.getIncomingArrows(); - } - - /** - * Deprecated. Use getOutgoingArcs instead - * @throws UnsupportedOperationException - */ - @Deprecated - @Override - public List> getOutgoingArrows() { - return super.getOutgoingArrows(); + public void setInstruction(String instruction) { + this.instruction = instruction; } } diff --git a/src/main/java/tfm/nodes/JNode.java b/src/main/java/tfm/nodes/JNode.java deleted file mode 100644 index 534f433..0000000 --- a/src/main/java/tfm/nodes/JNode.java +++ /dev/null @@ -1,135 +0,0 @@ -package tfm.nodes; - -import com.github.javaparser.ast.Node; -import org.checkerframework.checker.nullness.qual.NonNull; -import tfm.utils.Utils; -import tfm.variables.VariableExtractor; - -import java.util.Objects; -import java.util.Optional; -import java.util.Set; - -public class JNode { - - public int getId() { - return id; - } - - public void setId(int id) { - this.id = id; - } - - public String getRepresentation() { - return representation; - } - - public void setRepresentation(String representation) { - this.representation = representation; - } - - public ASTNode getAstNode() { - return astNode; - } - - public void setAstNode(ASTNode astNode) { - this.astNode = astNode; - } - - public Set getDeclaredVariables() { - return declaredVariables; - } - - public Set getDefinedVariables() { - return definedVariables; - } - - public Set getUsedVariables() { - return usedVariables; - } - - private int id; - private String representation; - - protected ASTNode astNode; - protected Set declaredVariables; - protected Set definedVariables; - protected Set usedVariables; - - - public JNode(@NonNull JNode node) { - this(node.id, node.representation, node.astNode, node.declaredVariables, node.definedVariables, node.usedVariables); - } - - public JNode(int id, @NonNull String representation, @NonNull ASTNode astNode) { - this(id, representation, astNode, Utils.emptySet(), Utils.emptySet(), Utils.emptySet()); - - extractVariables(astNode); - } - - public JNode(int id, @NonNull String representation, @NonNull ASTNode astNode, Set declaredVariables, Set definedVariables, Set usedVariables) { - this.id = id; - this.representation = representation; - this.astNode = astNode; - this.declaredVariables = declaredVariables; - this.definedVariables = definedVariables; - this.usedVariables = usedVariables; - } - - private void extractVariables(ASTNode astNode) { - new VariableExtractor() - .setOnVariableDeclarationListener(variable -> this.declaredVariables.add(variable)) - .setOnVariableDefinitionListener(variable -> this.definedVariables.add(variable)) - .setOnVariableUseListener(variable -> this.usedVariables.add(variable)) - .visit(astNode); - } - - public void addDeclaredVariable(String variable) { - declaredVariables.add(variable); - } - - public void addDefinedVariable(String variable) { - definedVariables.add(variable); - } - - public void addUsedVariable(String variable) { - usedVariables.add(variable); - } - - public Optional getFileLineNumber() { - return astNode.getBegin() - .map(begin -> begin.line); - } - - @Override - public int hashCode() { - return id + astNode.hashCode(); - } - - @Override - public boolean equals(Object obj) { - if (obj == this) { - return true; - } - - if (!(obj instanceof JNode)) { - return false; - } - - JNode jNode = (JNode) obj; - - return jNode.id == id && Objects.equals(jNode.astNode, astNode); - } - - @Override - public String toString() { - return String.format("JNode{id: %s, repr: %s, astNodeClass: %s}", - id, - representation, - astNode.getClass().getName() - ); - } - - public String toGraphvizRepresentation() { - return String.format("%s[label=\"%s: %s\"];", getId(), getId(), getRepresentation()); - } -} diff --git a/src/main/java/tfm/nodes/MethodCallNode.java b/src/main/java/tfm/nodes/MethodCallNode.java index b241c5c..89ff4af 100644 --- a/src/main/java/tfm/nodes/MethodCallNode.java +++ b/src/main/java/tfm/nodes/MethodCallNode.java @@ -1,12 +1,9 @@ package tfm.nodes; import com.github.javaparser.ast.stmt.ExpressionStmt; -import edg.graphlib.Arrow; import org.checkerframework.checker.nullness.qual.NonNull; -import tfm.arcs.data.ArcData; import java.util.ArrayList; -import java.util.Collection; import java.util.List; import java.util.Set; @@ -30,8 +27,8 @@ public class MethodCallNode extends GraphNode { this.outParameters = new ArrayList<>(); } - public MethodCallNode(int id, String representation, @NonNull ExpressionStmt node, Collection> incomingArcs, Collection> outgoingArcs, Set declaredVariables, Set definedVariables, Set usedVariables) { - super(id, representation, node, incomingArcs, outgoingArcs, declaredVariables, definedVariables, usedVariables); + public MethodCallNode(int id, String representation, @NonNull ExpressionStmt node, Set declaredVariables, Set definedVariables, Set usedVariables) { + super(id, representation, node, declaredVariables, definedVariables, usedVariables); this.inParameters = new ArrayList<>(); this.outParameters = new ArrayList<>(); diff --git a/src/main/java/tfm/nodes/PDGNode.java b/src/main/java/tfm/nodes/PDGNode.java deleted file mode 100644 index fe8c5be..0000000 --- a/src/main/java/tfm/nodes/PDGNode.java +++ /dev/null @@ -1,92 +0,0 @@ -package tfm.nodes; - -import com.github.javaparser.ast.Node; -import edg.graphlib.Arrow; -import org.checkerframework.checker.nullness.qual.NonNull; -import tfm.arcs.Arc; -import tfm.arcs.data.ArcData; -import tfm.arcs.pdg.ControlDependencyArc; -import tfm.utils.Logger; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; - -@Deprecated -public class PDGNode extends GraphNode { - - public PDGNode(int id, String data, N node) { - super(id, data, node); - } - - public PDGNode(int id, String representation, @NonNull N node, Collection> incomingArcs, Collection> outgoingArcs, Set declaredVariables, Set definedVariables, Set usedVariables) { - super(id, representation, node, incomingArcs, outgoingArcs, declaredVariables, definedVariables, usedVariables); - } - - public > PDGNode(N1 node) { - super(node); - } - - public String toString() { - List dataFrom = new ArrayList<>(); - List dataTo = new ArrayList<>(); - List controlFrom = new ArrayList<>(); - List controlTo = new ArrayList<>(); - - getIncomingArcs().forEach(arrow -> { - Logger.log(arrow); - Arc arc = (Arc) arrow; - GraphNode from = (GraphNode) arc.getFrom(); - - if (arc.isDataDependencyArrow()) { - dataFrom.add(from.getId()); - } else if (arc.isControlDependencyArrow()) { - controlFrom.add(from.getId()); - } - - }); - - getOutgoingArcs().forEach(arrow -> { - Arc arc = (Arc) arrow; - GraphNode to = (GraphNode) arc.getTo(); - - if (arc.isDataDependencyArrow()) { - dataTo.add(to.getId()); - } else if (arc.isControlDependencyArrow()) { - controlTo.add(to.getId()); - } - - }); - - return String.format("PDGNode{id: %s, data: %s, dataFrom: %s, dataTo: %s, controlFrom: %s, controlTo: %s}", - getId(), - getData(), - dataFrom, - dataTo, - controlFrom, - controlTo - ); - } - - public List getControlDependencies() { - return getIncomingArcs().stream() - .filter(arrow -> ((Arc) arrow).isControlDependencyArrow()) - .map(arc -> (ControlDependencyArc) arc) - .collect(Collectors.toList()); - } - - public int getLevel() { - return getLevel(this); - } - - private int getLevel(PDGNode node) { - List dependencies = node.getControlDependencies(); - - if (dependencies.isEmpty()) - return 0; - - return 1 + getLevel((PDGNode) dependencies.get(0).getFrom()); - } -} diff --git a/src/main/java/tfm/nodes/SDGNode.java b/src/main/java/tfm/nodes/SDGNode.java deleted file mode 100644 index 79a4120..0000000 --- a/src/main/java/tfm/nodes/SDGNode.java +++ /dev/null @@ -1,28 +0,0 @@ -package tfm.nodes; - -import com.github.javaparser.ast.Node; -import edg.graphlib.Arrow; -import org.checkerframework.checker.nullness.qual.NonNull; -import tfm.arcs.data.ArcData; - -import java.util.Collection; -import java.util.Set; - -@Deprecated -public class SDGNode extends GraphNode { - - public > SDGNode(N1 node) { - super(node); - } - - public SDGNode(int id, String representation, N node) { - super(id, representation, node); - } - public SDGNode(int id, String representation, @NonNull N node, Collection> incomingArcs, Collection> outgoingArcs, Set declaredVariables, Set definedVariables, Set usedVariables) { - super(id, representation, node, incomingArcs, outgoingArcs, declaredVariables, definedVariables, usedVariables); - } - - public String toString() { - return String.format("SDGNode{id: %s, data: %s, "); - } -} diff --git a/src/main/java/tfm/scopes/IfElseScope.java b/src/main/java/tfm/scopes/IfElseScope.java deleted file mode 100644 index 765b7f0..0000000 --- a/src/main/java/tfm/scopes/IfElseScope.java +++ /dev/null @@ -1,64 +0,0 @@ -package tfm.scopes; - -import tfm.nodes.GraphNode; -import tfm.variables.actions.VariableDefinition; - -import java.util.List; -import java.util.stream.Collectors; - -public class IfElseScope extends ScopeHolder { - - private VariableScope expressionScope; - private ScopeHolder thenScope; - private ScopeHolder elseScope; - - public IfElseScope(N node) { - super(node); - - this.expressionScope = new VariableScope<>(node); - this.thenScope = new ScopeHolder<>(node); - this.elseScope = new ScopeHolder<>(node); - - addSubscope(expressionScope); // expression - addSubscope(thenScope); // then - addSubscope(elseScope); // else - } - - public VariableScope getExpressionScope() { - return expressionScope; - } - - public ScopeHolder getThenScope() { - return thenScope; - } - - public ScopeHolder getElseScope() { - return elseScope; - } - - @Override - public void addVariableUse(String variable, N node) { - getExpressionScope().addVariableUse(variable, node); - } - - @Override - public List> getFirstDefinitions(String variable) { - return getSubscopes().stream() - .flatMap(scope -> scope.getFirstDefinitions(variable).stream()) - .collect(Collectors.toList()); - } - - @Override - public List> getLastDefinitions(String variable) { - return getSubscopes().stream() - .flatMap(scope -> scope.getLastDefinitions(variable).stream()) - .collect(Collectors.toList()); - } - - @Override - public List> getLastDefinitionsBeforeNode(String variable, N node) { - return getSubscopes().stream() - .flatMap(scope -> scope.getLastDefinitionsBeforeNode(variable, node).stream()) - .collect(Collectors.toList()); - } -} diff --git a/src/main/java/tfm/scopes/Scope.java b/src/main/java/tfm/scopes/Scope.java deleted file mode 100644 index 9d56e90..0000000 --- a/src/main/java/tfm/scopes/Scope.java +++ /dev/null @@ -1,46 +0,0 @@ -package tfm.scopes; - -import tfm.nodes.GraphNode; -import tfm.variables.actions.VariableDeclaration; -import tfm.variables.actions.VariableDefinition; -import tfm.variables.actions.VariableUse; - -import java.util.List; -import java.util.Set; - -public abstract class Scope { - - protected N root; - - protected Scope(N root) { - this.root = root; - } - - public N getRoot() { - return root; - } - - public abstract void addVariableDeclaration(String variable, N context); - public abstract void addVariableDefinition(String variable, N context); - public abstract void addVariableUse(String variable, N context); - - public abstract boolean isVariableDeclared(String variable); - public abstract boolean isVariableDefined(String variable); - public abstract boolean isVariableUsed(String variable); - - public abstract List> getVariableDeclarations(String variable); - public abstract List> getVariableDefinitions(String variable); - public abstract List> getVariableUses(String variable); - - public abstract Set getDeclaredVariables(); - public abstract Set getDefinedVariables(); - public abstract Set getUsedVariables(); - - - public abstract List> getVariableUsesBeforeNode(String variable, N node); - - public abstract List> getFirstDefinitions(String variable); - public abstract List> getLastDefinitions(String variable); - public abstract List> getLastDefinitionsBeforeNode(String variable, N node); -} - diff --git a/src/main/java/tfm/scopes/ScopeHolder.java b/src/main/java/tfm/scopes/ScopeHolder.java deleted file mode 100644 index a5a4780..0000000 --- a/src/main/java/tfm/scopes/ScopeHolder.java +++ /dev/null @@ -1,183 +0,0 @@ -package tfm.scopes; - -import tfm.nodes.GraphNode; -import tfm.variables.actions.VariableDeclaration; -import tfm.variables.actions.VariableDefinition; -import tfm.variables.actions.VariableUse; - -import java.util.*; -import java.util.stream.Collectors; - -public class ScopeHolder extends Scope { - - private Queue> subscopes; - - public ScopeHolder(N root) { - super(root); - - subscopes = Collections.asLifoQueue(new ArrayDeque<>()); - } - - private Optional> getLastScope() { - if (subscopes.isEmpty()) - return Optional.empty(); - - return Optional.of(subscopes.peek()); - } - - @Override - public void addVariableDeclaration(String variable, N context) { - Optional> optionalScope = getLastScope(); - - boolean newScope = !optionalScope.isPresent(); - - Scope scope = optionalScope.orElse(new VariableScope<>(context)); - - scope.addVariableDeclaration(variable, context); - - if (newScope) { - addSubscope(scope); - } - } - - @Override - public void addVariableDefinition(String variable, N context) { - Optional> optionalScope = getLastScope(); - - boolean newScope = !optionalScope.isPresent(); - - Scope scope = optionalScope.orElse(new VariableScope<>(context)); - - scope.addVariableDefinition(variable, context); - - if (newScope) { - addSubscope(scope); - } - } - - @Override - public void addVariableUse(String variable, N context) { - Optional> optionalScope = getLastScope(); - - boolean newScope = !optionalScope.isPresent(); - - Scope scope = optionalScope.orElse(new VariableScope<>(context)); - - scope.addVariableUse(variable, context); - - if (newScope) { - addSubscope(scope); - } - } - - public Queue> getSubscopes() { - return subscopes; - } - - public void addSubscope(Scope subscope) { - subscopes.add(subscope); - } - - @Override - public boolean isVariableDeclared(String variable) { - return subscopes.stream().anyMatch(subscope -> subscope.isVariableDeclared(variable)); - } - - @Override - public boolean isVariableDefined(String variable) { - return subscopes.stream().anyMatch(subscope -> subscope.isVariableDefined(variable)); - } - - @Override - public boolean isVariableUsed(String variable) { - return subscopes.stream().anyMatch(subscope -> subscope.isVariableUsed(variable)); - } - - @Override - public List> getVariableDeclarations(String variable) { - return subscopes.stream() - .flatMap(scope -> scope.getVariableDeclarations(variable).stream()) - .collect(Collectors.toList()); - } - - @Override - public List> getVariableDefinitions(String variable) { - return subscopes.stream() - .flatMap(scope -> scope.getVariableDefinitions(variable).stream()) - .collect(Collectors.toList()); - } - - @Override - public List> getVariableUses(String variable) { - return subscopes.stream() - .flatMap(scope -> scope.getVariableUses(variable).stream()) - .collect(Collectors.toList()); - } - - @Override - public Set getDeclaredVariables() { - return subscopes.stream() - .flatMap(scope -> scope.getDeclaredVariables().stream()) - .collect(Collectors.toSet()); - } - - @Override - public Set getDefinedVariables() { - return subscopes.stream() - .flatMap(scope -> scope.getDefinedVariables().stream()) - .collect(Collectors.toSet()); - } - - @Override - public Set getUsedVariables() { - return subscopes.stream() - .flatMap(scope -> scope.getUsedVariables().stream()) - .collect(Collectors.toSet()); - } - - @Override - public List> getVariableUsesBeforeNode(String variable, N node) { - return subscopes.stream() - .filter(_scope -> _scope.isVariableUsed(variable) && _scope.root.getId() <= node.getId()) - .flatMap(scope -> scope.getVariableUsesBeforeNode(variable, node).stream()) - .collect(Collectors.toList()); - } - - @Override - public List> getFirstDefinitions(String variable) { - Optional> scope = subscopes.stream() - .filter(_scope -> _scope.isVariableDefined(variable)) - .reduce((first, second) -> second); - - if (!scope.isPresent()) - return new ArrayList<>(0); - - return scope.get().getFirstDefinitions(variable); - } - - @Override - public List> getLastDefinitions(String variable) { - Optional> scope = subscopes.stream() - .filter(_scope -> _scope.isVariableDefined(variable)) - .findFirst(); - - if (!scope.isPresent()) - return new ArrayList<>(0); - - return scope.get().getLastDefinitions(variable); - } - - @Override - public List> getLastDefinitionsBeforeNode(String variable, N node) { - Optional> scope = subscopes.stream() - .filter(_scope -> _scope.isVariableDefined(variable) && _scope.root.getId() <= node.getId()) - .findFirst(); - - if (!scope.isPresent()) - return new ArrayList<>(0); - - return scope.get().getLastDefinitions(variable); - } - - -} diff --git a/src/main/java/tfm/scopes/VariableScope.java b/src/main/java/tfm/scopes/VariableScope.java deleted file mode 100644 index d8af5df..0000000 --- a/src/main/java/tfm/scopes/VariableScope.java +++ /dev/null @@ -1,156 +0,0 @@ -package tfm.scopes; - -import tfm.nodes.GraphNode; -import tfm.variables.actions.VariableAction; -import tfm.variables.actions.VariableDeclaration; -import tfm.variables.actions.VariableDefinition; -import tfm.variables.actions.VariableUse; - -import java.util.*; - -public class VariableScope extends Scope { - - private Map>> variableDeclarations; - private Map>> variableDefinitions; - private Map>> variableUses; - - public VariableScope(N root) { - super(root); - - variableDeclarations = new HashMap<>(); - variableDefinitions = new HashMap<>(); - variableUses = new HashMap<>(); - } - - @Override - public boolean isVariableDeclared(String variable) { - return variableDeclarations.containsKey(variable); - } - - @Override - public boolean isVariableDefined(String variable) { - return variableDefinitions.containsKey(variable); - } - - @Override - public boolean isVariableUsed(String variable) { - return variableUses.containsKey(variable); - } - - @Override - public List> getVariableDeclarations(String variable) { - return new ArrayList<>(variableDeclarations.getOrDefault(variable, new ArrayList<>())); - } - - @Override - public List> getVariableDefinitions(String variable) { - return new ArrayList<>(variableDefinitions.getOrDefault(variable, new ArrayList<>())); - } - - @Override - public List> getVariableUses(String variable) { - return new ArrayList<>(variableUses.getOrDefault(variable, new ArrayList<>())); - } - - @Override - public Set getDeclaredVariables() { - return new HashSet<>(variableDeclarations.keySet()); - } - - @Override - public Set getDefinedVariables() { - return new HashSet<>(variableDefinitions.keySet()); - } - - @Override - public Set getUsedVariables() { - return new HashSet<>(variableUses.keySet()); - } - - @Override - public List> getVariableUsesBeforeNode(String variable, N node) { - List> res = getVariableUses(variable); - - if (res.isEmpty()) - return res; - - return res.stream() - .filter(variableUse -> variableUse.getNode().getId() <= node.getId()) - .max(Comparator.comparingInt(variableUse -> variableUse.getNode().getId())) - .map(variableUse -> new ArrayList<>(Collections.singletonList(variableUse))) - .orElseGet(ArrayList::new); - } - - @Override - public List> getFirstDefinitions(String variable) { - List> res = getVariableDefinitions(variable); - - if (res.isEmpty()) - return res; - - return res.subList(0, 1); - } - - @Override - public List> getLastDefinitions(String variable) { - List> res = getVariableDefinitions(variable); - - if (res.isEmpty()) - return res; - - return res.subList(res.size() - 1, res.size()); - } - - @Override - public List> getLastDefinitionsBeforeNode(String variable, N node) { - List> res = getVariableDefinitions(variable); - - if (res.isEmpty()) - return res; - - return res.stream() - .filter(variableDefinition -> variableDefinition.getNode().getId() <= node.getId()) - .max(Comparator.comparingInt(variableDefinition -> variableDefinition.getNode().getId())) - .map(variableDefinition -> new ArrayList<>(Collections.singletonList(variableDefinition))) - .orElseGet(ArrayList::new); - } - - @Override - public void addVariableDeclaration(String variable, N context) { - appendValue(variableDeclarations, variable, new VariableDeclaration<>(variable, context)); - } - - @Override - public void addVariableDefinition(String variable, N context) { - appendValue(variableDefinitions, variable, new VariableDefinition<>(variable, context)); - } - - @Override - public void addVariableUse(String variable, N context) { - appendValue(variableUses, variable, new VariableUse<>(variable, context)); - } - - private > void appendValue(Map> map, String variable, E action) { - List value = map.getOrDefault(variable, new ArrayList<>()); - - boolean exists = !value.isEmpty(); - - value.add(action); - - if (!exists) { - map.put(variable, value); - } - } - - private > void appendValues(Map> map, String variable, List actions) { - List value = map.getOrDefault(variable, new ArrayList<>()); - - boolean exists = !value.isEmpty(); - - value.addAll(actions); - - if (!exists) { - map.put(variable, value); - } - } -} -- GitLab From 95abb1585df67b161f3f330f46aaf0b6d78ec7a1 Mon Sep 17 00:00:00 2001 From: Javier Costa Date: Mon, 20 Jan 2020 02:53:03 +0100 Subject: [PATCH 2/9] Using JGraphT, removed all graphlib + cleaned + improved API --- pom.xml | 6 + src/main/java/tfm/arcs/Arc.java | 14 +- .../java/tfm/arcs/cfg/ControlFlowArc.java | 2 - .../tfm/arcs/pdg/ControlDependencyArc.java | 2 - src/main/java/tfm/exec/GraphLog.java | 24 +- src/main/java/tfm/exec/Main.java | 6 +- src/main/java/tfm/exec/PDGLog.java | 2 +- src/main/java/tfm/exec/SDGLog.java | 2 - .../java/tfm/graphbuilding/GraphOptions.java | 2 +- src/main/java/tfm/graphs/CFGGraph.java | 14 +- src/main/java/tfm/graphs/Graph.java | 140 ++++++++-- .../java/tfm/graphs/GraphWithRootNode.java | 32 +++ src/main/java/tfm/graphs/PDGGraph.java | 22 +- src/main/java/tfm/graphs/SDGGraph.java | 6 +- src/main/java/tfm/nodes/GraphNode.java | 72 ++--- src/main/java/tfm/nodes/MethodCallNode.java | 2 +- src/main/java/tfm/slicing/Slice.java | 2 +- src/main/java/tfm/utils/ASTUtils.java | 1 - src/main/java/tfm/utils/NodeFactory.java | 61 +++++ .../java/tfm/validation/PDGValidator.java | 2 +- .../java/tfm/visitors/cfg/CFGBuilder.java | 58 ++-- .../pdg/ControlDependencyBuilder.java | 21 +- .../java/tfm/visitors/pdg/PDGBuilder.java | 22 +- .../java/tfm/visitors/pdg/PDGVisitor.java | 253 ------------------ .../tfm/visitors/sdg/MethodCallReplacer.java | 3 - .../java/tfm/visitors/sdg/NewSDGBuilder.java | 1 - .../java/tfm/visitors/sdg/SDGBuilder.java | 12 +- 27 files changed, 343 insertions(+), 441 deletions(-) create mode 100644 src/main/java/tfm/graphs/GraphWithRootNode.java create mode 100644 src/main/java/tfm/utils/NodeFactory.java delete mode 100644 src/main/java/tfm/visitors/pdg/PDGVisitor.java diff --git a/pom.xml b/pom.xml index 2963592..c0aa410 100644 --- a/pom.xml +++ b/pom.xml @@ -41,5 +41,11 @@ 1.3.0 + + org.jgrapht + jgrapht-io + 1.3.0 + + \ No newline at end of file diff --git a/src/main/java/tfm/arcs/Arc.java b/src/main/java/tfm/arcs/Arc.java index 8a2be34..3f35cf5 100644 --- a/src/main/java/tfm/arcs/Arc.java +++ b/src/main/java/tfm/arcs/Arc.java @@ -1,6 +1,6 @@ package tfm.arcs; -import org.jgrapht.graph.DefaultEdge;; +import org.jgrapht.graph.DefaultEdge; import tfm.nodes.GraphNode; import java.util.Objects; @@ -30,6 +30,10 @@ public abstract class Arc extends DefaultEdge { @Override public String toString() { + return toGraphvizRepresentation(); + } + + public String toGraphvizRepresentation() { GraphNode from = (GraphNode) getSource(); GraphNode to = (GraphNode) getTarget(); @@ -39,14 +43,10 @@ public abstract class Arc extends DefaultEdge { ); } - public String toGraphvizRepresentation() { - return toString(); - } - @Override public boolean equals(Object o) { - if (this != o) { - return false; + if (this == o) { + return true; } return Objects.equals(variable, ((Arc) o).variable); diff --git a/src/main/java/tfm/arcs/cfg/ControlFlowArc.java b/src/main/java/tfm/arcs/cfg/ControlFlowArc.java index 8cd15b0..ff78a8d 100644 --- a/src/main/java/tfm/arcs/cfg/ControlFlowArc.java +++ b/src/main/java/tfm/arcs/cfg/ControlFlowArc.java @@ -1,8 +1,6 @@ package tfm.arcs.cfg; import tfm.arcs.Arc; -import tfm.arcs.data.VoidArcData; -import tfm.nodes.GraphNode; public class ControlFlowArc extends Arc { diff --git a/src/main/java/tfm/arcs/pdg/ControlDependencyArc.java b/src/main/java/tfm/arcs/pdg/ControlDependencyArc.java index 501e5f4..85a233a 100644 --- a/src/main/java/tfm/arcs/pdg/ControlDependencyArc.java +++ b/src/main/java/tfm/arcs/pdg/ControlDependencyArc.java @@ -1,8 +1,6 @@ package tfm.arcs.pdg; import tfm.arcs.Arc; -import tfm.arcs.data.ArcData; -import tfm.nodes.GraphNode; public class ControlDependencyArc extends Arc { diff --git a/src/main/java/tfm/exec/GraphLog.java b/src/main/java/tfm/exec/GraphLog.java index a3d38fa..d08b499 100644 --- a/src/main/java/tfm/exec/GraphLog.java +++ b/src/main/java/tfm/exec/GraphLog.java @@ -1,11 +1,20 @@ package tfm.exec; import com.github.javaparser.ast.Node; +import org.jgrapht.io.ComponentNameProvider; +import org.jgrapht.io.DOTExporter; +import org.jgrapht.io.ExportException; +import org.jgrapht.io.GraphExporter; +import tfm.arcs.Arc; import tfm.graphs.Graph; +import tfm.nodes.GraphNode; import tfm.utils.FileUtil; import tfm.utils.Logger; -import java.io.*; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.Writer; public abstract class GraphLog { public enum Format { @@ -73,8 +82,19 @@ public abstract class GraphLog { generated = true; File tmpDot = File.createTempFile("graph-source-", ".dot"); tmpDot.deleteOnExit(); + try (Writer w = new FileWriter(tmpDot)) { - w.write(graph.toGraphvizRepresentation()); +// w.write(graph.toGraphvizRepresentation()); + + // JGraphT DOT export + GraphExporter, Arc> exporter = new DOTExporter<>( + component -> String.valueOf(component.getId()), + GraphNode::getInstruction, + component -> component.getVariable().orElse("")); + + exporter.exportGraph(graph, w); + } catch (ExportException e) { + e.printStackTrace(); } ProcessBuilder pb = new ProcessBuilder("dot", tmpDot.getAbsolutePath(), "-T" + format.getExt(), diff --git a/src/main/java/tfm/exec/Main.java b/src/main/java/tfm/exec/Main.java index 9532105..963e00f 100644 --- a/src/main/java/tfm/exec/Main.java +++ b/src/main/java/tfm/exec/Main.java @@ -13,7 +13,7 @@ import java.util.Optional; public class Main { - public static final String PROGRAM = Utils.PROGRAMS_FOLDER + "sdg/Example1.java"; + public static final String PROGRAM = Utils.PROGRAMS_FOLDER + "cfg/Eval_4.java"; public static final String GRAPH = GraphLog.SDG; public static final String METHOD = "main"; @@ -45,6 +45,10 @@ public class Main { long tt = tf - t0; + graphLog.graph.modifyNode(12, node -> { + node.setInstruction("hahhdh"); + }); + graphLog.log(); graphLog.openVisualRepresentation(); diff --git a/src/main/java/tfm/exec/PDGLog.java b/src/main/java/tfm/exec/PDGLog.java index a712abe..099daa6 100644 --- a/src/main/java/tfm/exec/PDGLog.java +++ b/src/main/java/tfm/exec/PDGLog.java @@ -29,7 +29,7 @@ public class PDGLog extends GraphLog { public void visit(com.github.javaparser.ast.Node node) { this.graph = new PDGGraph(); - node.accept(new PDGBuilder(graph), this.graph.getRootNode()); + node.accept(new PDGBuilder(graph), null); if (cfgLog == null) { cfgLog = new CFGLog(graph.getCfgGraph()); diff --git a/src/main/java/tfm/exec/SDGLog.java b/src/main/java/tfm/exec/SDGLog.java index b88de54..16978ae 100644 --- a/src/main/java/tfm/exec/SDGLog.java +++ b/src/main/java/tfm/exec/SDGLog.java @@ -4,8 +4,6 @@ import com.github.javaparser.ast.Node; import tfm.graphs.SDGGraph; import tfm.visitors.sdg.SDGBuilder; -import java.io.IOException; - public class SDGLog extends GraphLog { @Override diff --git a/src/main/java/tfm/graphbuilding/GraphOptions.java b/src/main/java/tfm/graphbuilding/GraphOptions.java index 2884f49..b7d2486 100644 --- a/src/main/java/tfm/graphbuilding/GraphOptions.java +++ b/src/main/java/tfm/graphbuilding/GraphOptions.java @@ -45,7 +45,7 @@ class PDGOptions extends GraphOptions { @Override protected void buildGraphWithSpecificVisitor(PDGGraph emptyGraph, Node node) { - node.accept(new PDGBuilder(emptyGraph), emptyGraph.getRootNode()); + node.accept(new PDGBuilder(emptyGraph), null); } } diff --git a/src/main/java/tfm/graphs/CFGGraph.java b/src/main/java/tfm/graphs/CFGGraph.java index f1e7acb..fb706e0 100644 --- a/src/main/java/tfm/graphs/CFGGraph.java +++ b/src/main/java/tfm/graphs/CFGGraph.java @@ -1,7 +1,7 @@ package tfm.graphs; import com.github.javaparser.ast.Node; -import edg.graphlib.Arrow; +import com.github.javaparser.ast.stmt.EmptyStmt; import tfm.arcs.Arc; import tfm.arcs.cfg.ControlFlowArc; import tfm.nodes.GraphNode; @@ -14,23 +14,19 @@ import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; -public class CFGGraph extends Graph { +public class CFGGraph extends GraphWithRootNode { public CFGGraph() { super(); } @Override - public GraphNode addNode(String instruction, ASTNode node) { - GraphNode vertex = new GraphNode<>(getNextVertexId(), instruction, node); - this.addVertex(vertex); - - return vertex; + protected GraphNode buildRootNode() { + return new GraphNode<>(getNextVertexId(), "Start", new EmptyStmt()); } - @SuppressWarnings("unchecked") public void addControlFlowEdge(GraphNode from, GraphNode to) { - super.addEdge(from, to); + super.addEdge(from, to, new ControlFlowArc()); } @Override diff --git a/src/main/java/tfm/graphs/Graph.java b/src/main/java/tfm/graphs/Graph.java index e337690..2c820ef 100644 --- a/src/main/java/tfm/graphs/Graph.java +++ b/src/main/java/tfm/graphs/Graph.java @@ -1,12 +1,17 @@ package tfm.graphs; import com.github.javaparser.ast.Node; +import com.github.javaparser.ast.stmt.Statement; +import org.checkerframework.checker.nullness.qual.NonNull; import org.jgrapht.graph.DefaultDirectedGraph; import tfm.arcs.Arc; import tfm.nodes.GraphNode; import tfm.slicing.SlicingCriterion; +import tfm.utils.NodeFactory; +import tfm.variables.VariableExtractor; import java.util.*; +import java.util.function.Consumer; import java.util.stream.Collectors; /** @@ -27,7 +32,7 @@ public abstract class Graph extends DefaultDirectedGraph, Arc> { } private GraphNode addNode(int id, String instruction, ASTNode node) { - GraphNode newNode = new GraphNode<>(id, instruction, node); + GraphNode newNode = NodeFactory.graphNode(id, instruction, node); return this.addNode(newNode); } @@ -40,31 +45,26 @@ public abstract class Graph extends DefaultDirectedGraph, Arc> { * Adds the given node to the graph. * * One must be careful with this method, as the given node will have - * an id and arcs corresponding to the graph in which it was created, and may not fit + * an id corresponding to the graph in which it was created, and may not fit * in the current graph. * * @param node the node to add to the graph - * @param copyId whether to copy the id node or not - * @param copyArcs whether to copy the arcs of the node or not + * @param copyId whether to copy the node id or generate a new one * @return the node instance added to the graph */ - public GraphNode addNode(GraphNode node, boolean copyId, boolean copyArcs) { - GraphNode res = node; - - if (copyId && copyArcs) { - this.addVertex(node); - } else if (copyId) { - res = this.addNode(node.getId(), node.getInstruction(), node.getAstNode()); - } else if (copyArcs) { - res = new GraphNode<>(node); - res.setId(getNextVertexId()); - - this.addVertex(res); - } else { - res = this.addNode(node.getInstruction(), node.getAstNode()); - } - - return res; + public GraphNode addNode(GraphNode node, boolean copyId) { + GraphNode copy = NodeFactory.computedGraphNode( + copyId ? node.getId() : getNextVertexId(), + node.getInstruction(), + node.getAstNode(), + node.getDeclaredVariables(), + node.getDefinedVariables(), + node.getUsedVariables() + ); + + this.addVertex(copy); + + return copy; } @SuppressWarnings("unchecked") @@ -117,4 +117,102 @@ public abstract class Graph extends DefaultDirectedGraph, Arc> { .filter(node -> node.getDeclaredVariables().contains(variable)) .collect(Collectors.toList()); } + + public boolean isEmpty() { + return this.getNodes().size() == 0; + } + + /** + * Modifies a current node in the graph by the changes done in the MutableGraphNode instance + * inside the function passed as parameter + * + * @param id the id of the node to be modified + * @param modifyFn a consumer which takes a MutableGraphNode as parameter + */ + public void modifyNode(int id, Consumer> modifyFn) { + this.findNodeById(id).ifPresent(node -> { + Set incomingArcs = new HashSet<>(incomingEdgesOf(node)); + Set outgoingArcs = new HashSet<>(outgoingEdgesOf(node)); + + this.removeNode(node); + + MutableGraphNode modifiedNode = new MutableGraphNode<>((GraphNode) node); + + modifyFn.accept(modifiedNode); + + GraphNode newNode = modifiedNode.toGraphNode(); + + this.addVertex(newNode); + + for (Arc incomingArc : incomingArcs) { + GraphNode from = getEdgeSource(incomingArc); + this.addEdge(from, newNode, incomingArc); + } + + for (Arc outgoingArc : outgoingArcs) { + GraphNode to = getEdgeTarget(outgoingArc); + this.addEdge(newNode, to, outgoingArc); + } + }); + } + + public static class MutableGraphNode { + private int id; + private String instruction; + private ASTNode astNode; + private Set declaredVariables; + private Set definedVariables; + private Set usedVariables; + + private boolean mustCompute; + + MutableGraphNode(GraphNode node) { + this.id = node.getId(); + this.instruction = node.getInstruction(); + this.astNode = node.getAstNode(); + this.declaredVariables = node.getDeclaredVariables(); + this.definedVariables = node.getDefinedVariables(); + this.usedVariables = node.getUsedVariables(); + } + + GraphNode toGraphNode() { + return mustCompute + ? NodeFactory.graphNode(id, instruction, astNode) + : NodeFactory.computedGraphNode( + id, + instruction, + astNode, + declaredVariables, + definedVariables, + usedVariables + ); + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getInstruction() { + return instruction; + } + + public void setInstruction(String instruction) { + this.instruction = instruction; + } + + public ASTNode getAstNode() { + return astNode; + } + + public void setAstNode(ASTNode astNode) { + this.astNode = astNode; + + // If the AST node changes, we need to compute all variables for it + mustCompute = true; + } + } } diff --git a/src/main/java/tfm/graphs/GraphWithRootNode.java b/src/main/java/tfm/graphs/GraphWithRootNode.java new file mode 100644 index 0000000..d80c776 --- /dev/null +++ b/src/main/java/tfm/graphs/GraphWithRootNode.java @@ -0,0 +1,32 @@ +package tfm.graphs; + +import tfm.nodes.GraphNode; + +import java.util.Objects; + +public abstract class GraphWithRootNode extends Graph { + + protected GraphNode rootNode; + + public GraphWithRootNode() { + super(); + + this.rootNode = buildRootNode(); + this.addVertex(rootNode); + } + + protected abstract GraphNode buildRootNode(); + + public GraphNode getRootNode() { + return rootNode; + } + + @Override + public boolean removeVertex(GraphNode graphNode) { + if (Objects.equals(graphNode, rootNode)) { + return false; + } + + return super.removeVertex(graphNode); + } +} diff --git a/src/main/java/tfm/graphs/PDGGraph.java b/src/main/java/tfm/graphs/PDGGraph.java index d163a8f..3e90520 100644 --- a/src/main/java/tfm/graphs/PDGGraph.java +++ b/src/main/java/tfm/graphs/PDGGraph.java @@ -2,7 +2,6 @@ package tfm.graphs; import com.github.javaparser.ast.Node; import com.github.javaparser.ast.body.MethodDeclaration; -import edg.graphlib.Arrow; import org.jetbrains.annotations.NotNull; import tfm.arcs.Arc; import tfm.arcs.pdg.ControlDependencyArc; @@ -17,7 +16,7 @@ import tfm.visitors.pdg.PDGBuilder; import java.util.*; import java.util.stream.Collectors; -public class PDGGraph extends Graph { +public class PDGGraph extends GraphWithRootNode { private CFGGraph cfgGraph; @@ -25,23 +24,18 @@ public class PDGGraph extends Graph { super(); } + @Override + protected GraphNode buildRootNode() { + return new GraphNode<>(getNextVertexId(), "ENTER", new MethodDeclaration()); + } + public PDGGraph(CFGGraph cfgGraph) { super(); this.cfgGraph = cfgGraph; } - public GraphNode getRootNode() { - Iterator> iterator = this.getNodesAtLevel(0).iterator(); - - if (iterator.hasNext()) { - return iterator.next(); - } - - return null; - } - public void addControlDependencyArc(GraphNode from, GraphNode to) { - this.addEdge(from, to); + this.addEdge(from, to, new ControlDependencyArc()); } public void addDataDependencyArc(GraphNode from, GraphNode to, String variable) { @@ -169,7 +163,7 @@ public class PDGGraph extends Graph { Node astCopy = ASTUtils.cloneAST(node.getAstNode()); - astCopy.accept(new PDGBuilder(sliceGraph), sliceGraph.getNodesAtLevel(0).iterator().next()); + astCopy.accept(new PDGBuilder(sliceGraph), null); for (GraphNode sliceNode : sliceGraph.getNodes()) { if (!sliceNodes.contains(sliceNode.getId())) { diff --git a/src/main/java/tfm/graphs/SDGGraph.java b/src/main/java/tfm/graphs/SDGGraph.java index 4aa8752..1167e1a 100644 --- a/src/main/java/tfm/graphs/SDGGraph.java +++ b/src/main/java/tfm/graphs/SDGGraph.java @@ -1,6 +1,5 @@ package tfm.graphs; -import com.github.javaparser.ast.Node; import com.github.javaparser.ast.body.MethodDeclaration; import com.github.javaparser.ast.body.Parameter; import com.github.javaparser.ast.stmt.EmptyStmt; @@ -8,7 +7,10 @@ import tfm.nodes.GraphNode; import tfm.slicing.SlicingCriterion; import tfm.utils.Context; -import java.util.*; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; import java.util.stream.Collectors; public class SDGGraph extends Graph { diff --git a/src/main/java/tfm/nodes/GraphNode.java b/src/main/java/tfm/nodes/GraphNode.java index b1ed794..a92cdf6 100644 --- a/src/main/java/tfm/nodes/GraphNode.java +++ b/src/main/java/tfm/nodes/GraphNode.java @@ -9,27 +9,20 @@ import tfm.variables.VariableExtractor; import java.util.*; +/** + * Immutable class that represents an AST node inside a CFG, PDG or SDG. + * + * @param the AST node that represents + */ public class GraphNode { - private int id; - private String instruction; + private final int id; + private final String instruction; + private final N astNode; - protected N astNode; - - protected Set declaredVariables; - protected Set definedVariables; - protected Set usedVariables; - - public > GraphNode(N1 node) { - this( - node.getId(), - node.getInstruction(), - node.getAstNode(), - node.getDeclaredVariables(), - node.getDefinedVariables(), - node.getUsedVariables() - ); - } + private final Set declaredVariables; + private final Set definedVariables; + private final Set usedVariables; public GraphNode(int id, String instruction, @NotNull N astNode) { this( @@ -40,49 +33,46 @@ public class GraphNode { Utils.emptySet(), Utils.emptySet() ); + + if (astNode instanceof Statement) { + extractVariables((Statement) astNode); + } } public GraphNode( int id, String instruction, @NonNull N astNode, - Set declaredVariables, - Set definedVariables, - Set usedVariables + Collection declaredVariables, + Collection definedVariables, + Collection usedVariables ) { this.id = id; this.instruction = instruction; this.astNode = astNode; - this.declaredVariables = declaredVariables; - this.definedVariables = definedVariables; - this.usedVariables = usedVariables; - - if (astNode instanceof Statement) { - extractVariables((Statement) astNode); - } + this.declaredVariables = new HashSet<>(declaredVariables); + this.definedVariables = new HashSet<>(definedVariables); + this.usedVariables = new HashSet<>(usedVariables); } private void extractVariables(@NonNull Statement statement) { new VariableExtractor() - .setOnVariableDeclarationListener(variable -> this.declaredVariables.add(variable)) - .setOnVariableDefinitionListener(variable -> this.definedVariables.add(variable)) - .setOnVariableUseListener(variable -> this.usedVariables.add(variable)) + .setOnVariableDeclarationListener(this.declaredVariables::add) + .setOnVariableDefinitionListener(this.definedVariables::add) + .setOnVariableUseListener(this.usedVariables::add) .visit(statement); } - public void setId(int id) { - this.id = id; - } - public int getId() { return id; } public String toString() { - return String.format("GraphNode{id: %s, instruction: '%s'}", + return String.format("GraphNode{id: %s, instruction: '%s', astNodeType: %s}", getId(), - getInstruction() + getInstruction(), + getAstNode().getClass().getSimpleName() ); } @@ -90,10 +80,6 @@ public class GraphNode { return astNode; } - public void setAstNode(N node) { - this.astNode = node; - } - public Optional getFileLineNumber() { return astNode.getBegin() .map(begin -> begin.line); @@ -152,8 +138,4 @@ public class GraphNode { public String getInstruction() { return instruction; } - - public void setInstruction(String instruction) { - this.instruction = instruction; - } } diff --git a/src/main/java/tfm/nodes/MethodCallNode.java b/src/main/java/tfm/nodes/MethodCallNode.java index 89ff4af..95f0479 100644 --- a/src/main/java/tfm/nodes/MethodCallNode.java +++ b/src/main/java/tfm/nodes/MethodCallNode.java @@ -14,7 +14,7 @@ public class MethodCallNode extends GraphNode { private List outParameters; public > MethodCallNode(N1 node) { - super(node); + super(node.getId(), node.getInstruction(), node.getAstNode()); this.inParameters = new ArrayList<>(); this.outParameters = new ArrayList<>(); diff --git a/src/main/java/tfm/slicing/Slice.java b/src/main/java/tfm/slicing/Slice.java index dca9284..15b4f50 100644 --- a/src/main/java/tfm/slicing/Slice.java +++ b/src/main/java/tfm/slicing/Slice.java @@ -22,7 +22,7 @@ public class Slice { PDGGraph pdgGraph = new PDGGraph(); - compilationUnit.accept(new PDGBuilder(pdgGraph), pdgGraph.getRootNode()); + compilationUnit.accept(new PDGBuilder(pdgGraph), null); Logger.log("=================="); Logger.log("= Starting slice ="); diff --git a/src/main/java/tfm/utils/ASTUtils.java b/src/main/java/tfm/utils/ASTUtils.java index a8e7031..0ec3b1b 100644 --- a/src/main/java/tfm/utils/ASTUtils.java +++ b/src/main/java/tfm/utils/ASTUtils.java @@ -1,6 +1,5 @@ package tfm.utils; -import com.github.javaparser.Position; import com.github.javaparser.ast.Node; import com.github.javaparser.ast.NodeList; import com.github.javaparser.ast.stmt.BlockStmt; diff --git a/src/main/java/tfm/utils/NodeFactory.java b/src/main/java/tfm/utils/NodeFactory.java new file mode 100644 index 0000000..585fea7 --- /dev/null +++ b/src/main/java/tfm/utils/NodeFactory.java @@ -0,0 +1,61 @@ +package tfm.utils; + +import com.github.javaparser.ast.Node; +import tfm.nodes.GraphNode; + +import java.util.Collection; + +public class NodeFactory { + + /** + * Returns a computed GraphNode (i.e. a GraphNode with computed the + * declared, defined and used variables in its AST node) + * + * @param id the id of the node + * @param instruction the instruction that represents + * @param node the node of the AST that represents + * @param declaredVariables the set of declared variables + * @param definedVariables the set of defined variables + * @param usedVariables the set of used variables + * @param the type of the AST node + * @return a new GraphNode + */ + public static GraphNode computedGraphNode( + int id, + String instruction, + ASTNode node, + Collection declaredVariables, + Collection definedVariables, + Collection usedVariables + ) { + return new GraphNode<>( + id, + instruction, + node, + declaredVariables, + definedVariables, + usedVariables + ); + } + + /** + * Returns a GraphNode computing the declared, defined and used variables in its AST node + * + * @param id the id of the node + * @param instruction the instruction that represents + * @param node the node of the AST that represents + * @param the type of the AST node + * @return a new GraphNode + */ + public static GraphNode graphNode( + int id, + String instruction, + ASTNode node + ) { + return new GraphNode<>( + id, + instruction, + node + ); + } +} diff --git a/src/main/java/tfm/validation/PDGValidator.java b/src/main/java/tfm/validation/PDGValidator.java index 48cb5d8..f4d3f20 100644 --- a/src/main/java/tfm/validation/PDGValidator.java +++ b/src/main/java/tfm/validation/PDGValidator.java @@ -65,7 +65,7 @@ public class PDGValidator { public static boolean generateAndCheck(MethodDeclaration methodDeclaration) { PDGGraph graph = new PDGGraph(); - methodDeclaration.accept(new PDGBuilder(graph), graph.getRootNode()); + methodDeclaration.accept(new PDGBuilder(graph), null); return check(methodDeclaration, graph); } diff --git a/src/main/java/tfm/visitors/cfg/CFGBuilder.java b/src/main/java/tfm/visitors/cfg/CFGBuilder.java index 633aad8..7c74b95 100644 --- a/src/main/java/tfm/visitors/cfg/CFGBuilder.java +++ b/src/main/java/tfm/visitors/cfg/CFGBuilder.java @@ -15,8 +15,8 @@ public class CFGBuilder extends VoidVisitorAdapter { private CFGGraph graph; - private Queue lastParentNodes; - private List bodyBreaks; + private Queue> lastParentNodes; + private List> bodyBreaks; public CFGBuilder(CFGGraph graph) { this.graph = graph; @@ -33,25 +33,14 @@ public class CFGBuilder extends VoidVisitorAdapter { public void visit(ExpressionStmt expressionStmt, Void arg) { String expression = expressionStmt.toString().replace("\"", "\\\""); - GraphNode nextNode = addNodeAndArcs(expression, expressionStmt); + GraphNode nextNode = addNodeAndArcs(expression, expressionStmt); lastParentNodes.add(nextNode); } -// @Override -// public void visit(VariableDeclarationExpr variableDeclarationExpr, Void arg) { -// GraphNode nextNode = addNodeAndArcs(variableDeclarationExpr.toString()); -// -// lastParentNodes.add(nextNode); -// -// Logger.log(variableDeclarationExpr); -// -// super.visit(variableDeclarationExpr, arg); -// } - @Override public void visit(IfStmt ifStmt, Void arg) { - GraphNode ifCondition = addNodeAndArcs( + GraphNode ifCondition = addNodeAndArcs( String.format("if (%s)", ifStmt.getCondition().toString()), ifStmt ); @@ -61,7 +50,7 @@ public class CFGBuilder extends VoidVisitorAdapter { // Visit "then" ifStmt.getThenStmt().accept(this, arg); - Queue lastThenNodes = new ArrayDeque<>(lastParentNodes); + Queue> lastThenNodes = new ArrayDeque<>(lastParentNodes); if (ifStmt.hasElseBranch()) { lastParentNodes.clear(); @@ -77,7 +66,7 @@ public class CFGBuilder extends VoidVisitorAdapter { @Override public void visit(WhileStmt whileStmt, Void arg) { - GraphNode whileCondition = addNodeAndArcs( + GraphNode whileCondition = addNodeAndArcs( String.format("while (%s)", whileStmt.getCondition().toString()), whileStmt ); @@ -101,7 +90,7 @@ public class CFGBuilder extends VoidVisitorAdapter { body.accept(this, arg); - GraphNode doWhileNode = addNodeAndArcs( + GraphNode doWhileNode = addNodeAndArcs( String.format("while (%s)", doStmt.getCondition()), doStmt ); @@ -120,19 +109,10 @@ public class CFGBuilder extends VoidVisitorAdapter { @Override public void visit(ForStmt forStmt, Void arg) { -// String inizialization = forStmt.getInitialization().stream() -// .map(GraphNode::toString) -// .collect(Collectors.joining(",")); -// -// String update = forStmt.getUpdate().stream() -// .map(GraphNode::toString) -// .collect(Collectors.joining(",")); - Expression comparison = forStmt.getCompare().orElse(new BooleanLiteralExpr(true)); -// forStmt.getInitialization().forEach(expression -> new ExpressionStmt(expression).accept(this, null)); - GraphNode forNode = addNodeAndArcs( + GraphNode forNode = addNodeAndArcs( String.format("for (;%s;)", comparison), forStmt ); @@ -156,7 +136,7 @@ public class CFGBuilder extends VoidVisitorAdapter { @Override public void visit(ForEachStmt forEachStmt, Void arg) { - GraphNode foreachNode = addNodeAndArcs( + GraphNode foreachNode = addNodeAndArcs( String.format("for (%s : %s)", forEachStmt.getVariable(), forEachStmt.getIterable()), forEachStmt ); @@ -176,23 +156,23 @@ public class CFGBuilder extends VoidVisitorAdapter { @Override public void visit(SwitchStmt switchStmt, Void arg) { - GraphNode switchNode = addNodeAndArcs( + GraphNode switchNode = addNodeAndArcs( String.format("switch (%s)", switchStmt.getSelector()), switchStmt ); lastParentNodes.add(switchNode); - List allEntryBreaks = new ArrayList<>(); + List> allEntryBreaks = new ArrayList<>(); - List lastEntryStatementsWithNoBreak = new ArrayList<>(); + List> lastEntryStatementsWithNoBreak = new ArrayList<>(); switchStmt.getEntries().forEach(switchEntryStmt -> { String label = switchEntryStmt.getLabel() .map(expression -> "case " + expression) .orElse("default"); - GraphNode switchEntryNode = addNodeAndArcs(label, switchEntryStmt); + GraphNode switchEntryNode = addNodeAndArcs(label, switchEntryStmt); lastParentNodes.add(switchEntryNode); lastParentNodes.addAll(lastEntryStatementsWithNoBreak); @@ -226,14 +206,14 @@ public class CFGBuilder extends VoidVisitorAdapter { public void visit(ContinueStmt continueStmt, Void arg) { Statement continuableStatement = ASTUtils.findFirstAncestorStatementFrom(continueStmt, ASTUtils::isLoop); - GraphNode continuableNode = graph.findNodeByASTNode(continuableStatement).get(); + GraphNode continuableNode = graph.findNodeByASTNode(continuableStatement).get(); lastParentNodes.forEach(parentNode -> graph.addControlFlowEdge(parentNode, continuableNode)); } @Override public void visit(ReturnStmt returnStmt, Void arg) { - GraphNode node = addNodeAndArcs( + GraphNode node = addNodeAndArcs( returnStmt.toString(), returnStmt ); @@ -243,7 +223,7 @@ public class CFGBuilder extends VoidVisitorAdapter { @Override public void visit(MethodDeclaration methodDeclaration, Void arg) { - if (!lastParentNodes.isEmpty() && Objects.equals(lastParentNodes.peek().getData(), "Stop")) { + if (!lastParentNodes.isEmpty() && Objects.equals(lastParentNodes.peek().getInstruction(), "Stop")) { throw new IllegalStateException("CFG is only allowed for one method, not multiple!"); } @@ -252,10 +232,10 @@ public class CFGBuilder extends VoidVisitorAdapter { lastParentNodes.add(addNodeAndArcs("Stop", new EmptyStmt())); } - private GraphNode addNodeAndArcs(String nodeData, Statement statement) { - GraphNode node = graph.addNode(nodeData, statement); + private GraphNode addNodeAndArcs(String nodeData, Statement statement) { + GraphNode node = graph.addNode(nodeData, statement); - GraphNode parent = lastParentNodes.poll(); // ALWAYS exists a parent + GraphNode parent = lastParentNodes.poll(); // ALWAYS exists a parent graph.addControlFlowEdge(parent, node); while (!lastParentNodes.isEmpty()) { diff --git a/src/main/java/tfm/visitors/pdg/ControlDependencyBuilder.java b/src/main/java/tfm/visitors/pdg/ControlDependencyBuilder.java index 7ceab66..4a267ec 100644 --- a/src/main/java/tfm/visitors/pdg/ControlDependencyBuilder.java +++ b/src/main/java/tfm/visitors/pdg/ControlDependencyBuilder.java @@ -5,10 +5,12 @@ import com.github.javaparser.ast.visitor.VoidVisitorAdapter; import tfm.graphs.CFGGraph; import tfm.graphs.PDGGraph; import tfm.nodes.GraphNode; +import tfm.utils.Logger; +import java.util.Objects; import java.util.stream.Collectors; -public class ControlDependencyBuilder extends VoidVisitorAdapter { +public class ControlDependencyBuilder extends VoidVisitorAdapter> { private CFGGraph cfgGraph; private PDGGraph pdgGraph; @@ -25,7 +27,7 @@ public class ControlDependencyBuilder extends VoidVisitorAdapter { @Override public void visit(IfStmt ifStmt, GraphNode parent) { - GraphNode node = addNodeAndControlDependency(ifStmt, parent); + GraphNode node = addNodeAndControlDependency(ifStmt, parent); ifStmt.getThenStmt().accept(this, node); @@ -34,7 +36,7 @@ public class ControlDependencyBuilder extends VoidVisitorAdapter { @Override public void visit(WhileStmt whileStmt, GraphNode parent) { - GraphNode node = addNodeAndControlDependency(whileStmt, parent); + GraphNode node = addNodeAndControlDependency(whileStmt, parent); whileStmt.getBody().accept(this, node); } @@ -54,7 +56,7 @@ public class ControlDependencyBuilder extends VoidVisitorAdapter { .orElse("true"); - GraphNode forNode = pdgGraph.addNode( + GraphNode forNode = pdgGraph.addNode( String.format("for (%s;%s;%s)", initialization, compare, update), forStmt ); @@ -66,29 +68,28 @@ public class ControlDependencyBuilder extends VoidVisitorAdapter { @Override public void visit(ForEachStmt forEachStmt, GraphNode parent) { - GraphNode node = addNodeAndControlDependency(forEachStmt, parent); + GraphNode node = addNodeAndControlDependency(forEachStmt, parent); forEachStmt.getBody().accept(this, node); } @Override public void visit(SwitchStmt switchStmt, GraphNode parent) { - GraphNode node = addNodeAndControlDependency(switchStmt, parent); + GraphNode node = addNodeAndControlDependency(switchStmt, parent); switchStmt.getEntries().accept(this, node); } @Override public void visit(SwitchEntryStmt switchEntryStmt, GraphNode parent) { - GraphNode node = addNodeAndControlDependency(switchEntryStmt, parent); + GraphNode node = addNodeAndControlDependency(switchEntryStmt, parent); switchEntryStmt.getStatements().accept(this, node); } - private GraphNode addNodeAndControlDependency(Statement statement, GraphNode parent) { + private GraphNode addNodeAndControlDependency(Statement statement, GraphNode parent) { GraphNode cfgNode = cfgGraph.findNodeByASTNode(statement).get(); - - GraphNode node = pdgGraph.addNode(cfgNode.getData(), cfgNode.getAstNode()); + GraphNode node = pdgGraph.addNode(cfgNode.getInstruction(), cfgNode.getAstNode()); pdgGraph.addControlDependencyArc(parent, node); return node; diff --git a/src/main/java/tfm/visitors/pdg/PDGBuilder.java b/src/main/java/tfm/visitors/pdg/PDGBuilder.java index 37aff8c..1e59487 100644 --- a/src/main/java/tfm/visitors/pdg/PDGBuilder.java +++ b/src/main/java/tfm/visitors/pdg/PDGBuilder.java @@ -1,26 +1,19 @@ package tfm.visitors.pdg; -import com.github.javaparser.ast.Node; import com.github.javaparser.ast.body.MethodDeclaration; import com.github.javaparser.ast.stmt.BlockStmt; import com.github.javaparser.ast.visitor.VoidVisitorAdapter; import tfm.graphs.CFGGraph; import tfm.graphs.PDGGraph; -import tfm.nodes.GraphNode; import tfm.visitors.cfg.CFGBuilder; -public class PDGBuilder extends VoidVisitorAdapter> { +public class PDGBuilder extends VoidVisitorAdapter { private PDGGraph pdgGraph; private CFGGraph cfgGraph; public PDGBuilder(PDGGraph pdgGraph) { - this(pdgGraph, new CFGGraph() { - @Override - protected String getRootNodeData() { - return "Start"; - } - }); + this(pdgGraph, new CFGGraph()); } public PDGBuilder(PDGGraph pdgGraph, CFGGraph cfgGraph) { @@ -30,12 +23,15 @@ public class PDGBuilder extends VoidVisitorAdapter> { this.pdgGraph.setCfgGraph(cfgGraph); } - public void visit(MethodDeclaration methodDeclaration, GraphNode parent) { + public void visit(MethodDeclaration methodDeclaration, Void empty) { if (!methodDeclaration.getBody().isPresent()) return; - // Assign the method declaration to the root node of the PDG graph - this.pdgGraph.getRootNode().setAstNode(methodDeclaration); + // Assign the method declaration to the root node of the PDG graph. Here parent will always be the root node + this.pdgGraph.modifyNode(pdgGraph.getRootNode().getId(), mutableGraphNode -> { + mutableGraphNode.setInstruction("ENTER " + methodDeclaration.getNameAsString()); + mutableGraphNode.setAstNode(methodDeclaration); + }); BlockStmt methodBody = methodDeclaration.getBody().get(); @@ -44,7 +40,7 @@ public class PDGBuilder extends VoidVisitorAdapter> { // Build control dependency ControlDependencyBuilder controlDependencyBuilder = new ControlDependencyBuilder(pdgGraph, cfgGraph); - methodBody.accept(controlDependencyBuilder, parent); + methodBody.accept(controlDependencyBuilder, pdgGraph.getRootNode()); // Build data dependency DataDependencyBuilder dataDependencyBuilder = new DataDependencyBuilder(pdgGraph, cfgGraph); diff --git a/src/main/java/tfm/visitors/pdg/PDGVisitor.java b/src/main/java/tfm/visitors/pdg/PDGVisitor.java deleted file mode 100644 index 6599e2e..0000000 --- a/src/main/java/tfm/visitors/pdg/PDGVisitor.java +++ /dev/null @@ -1,253 +0,0 @@ -package tfm.visitors.pdg; - -import com.github.javaparser.ast.visitor.VoidVisitorAdapter; -import tfm.nodes.GraphNode; -import tfm.scopes.ScopeHolder; - -@Deprecated -public class PDGVisitor extends VoidVisitorAdapter>> { - -// private VariableSet variableSet; - -// protected PDGGraph graph; -// protected ScopeHolder globalScope; -// -// public PDGVisitor(PDGGraph graph, ScopeHolder scopeHolder) { -// this.graph = graph; -// this.globalScope = scopeHolder; -// } -// -// @Override -// public void visit(ExpressionStmt n, ScopeHolder scope) { -// Expression expression = n.getExpression(); -// -// PDGNode expressionNode = graph.addNode(expression.toString(), n); -// -// graph.addControlDependencyArc(scope.getRoot(), expressionNode); -// -// VariableScope expressionScope = new VariableScope<>(expressionNode); -// -// new VariableExtractor() -// .setOnVariableDeclarationListener(variable -> -// expressionScope.addVariableDeclaration(variable, expressionNode) -// ).setOnVariableDefinitionListener(variable -> -// expressionScope.addVariableDefinition(variable, expressionNode) -// ).setOnVariableUseListener(variable -> { -// expressionScope.addVariableUse(variable, expressionNode); -// -// Scope searchScope = scope.isVariableDefined(variable) ? scope : globalScope; -// -// searchScope.getLastDefinitions(variable) -// .forEach(variableDefinition -> graph.addDataDependencyArc( -// variableDefinition.getNode(), -// expressionNode, -// variable -// )); -// }) -// .visit(expression); -// -// scope.addSubscope(expressionScope); -// } -// -// @Override -// public void visit(IfStmt ifStmt, ScopeHolder scope) { -// PDGNode ifNode = graph.addNode( -// String.format("if (%s)", ifStmt.getCondition().toString()), -// ifStmt -// ); -// -// graph.addControlDependencyArc(scope.getRoot(), ifNode); -// -// ScopeHolder ifScope = ifStmt.hasElseBranch() ? new IfElseScope<>(ifNode) : new ScopeHolder<>(ifNode); -// -// new VariableExtractor() -// .setOnVariableUseListener(variable -> { -// ifScope.addVariableUse(variable, ifNode); -// -// Scope searchScope = scope.isVariableDefined(variable) ? scope : globalScope; -// -// searchScope.getLastDefinitions(variable) -// .forEach(variableDefinition -> -// graph.addDataDependencyArc( -// variableDefinition.getNode(), -// ifNode, -// variable -// ) -// ); -// }) -// .visit(ifStmt.getCondition()); -// -// if (!ifStmt.hasElseBranch()) { -// ifStmt.getThenStmt().accept(this, ifScope); -// } else { -// @SuppressWarnings("unchecked") -// IfElseScope ifElseScope = (IfElseScope) ifScope; -// -// ifStmt.getThenStmt().accept(this, ifElseScope.getThenScope()); -// ifStmt.getElseStmt().get().accept(this, ifElseScope.getElseScope()); -// } -// -// scope.addSubscope(ifScope); -// } -// -// @Override -// public void visit(WhileStmt whileStmt, ScopeHolder scope) { -// // assert whileStmt.getBegin().isPresent(); -// -// PDGNode whileNode = graph.addNode( -// String.format("while (%s)", whileStmt.getCondition().toString()), -// whileStmt -// ); -// -// graph.addControlDependencyArc(scope.getRoot(), whileNode); -// -// ScopeHolder whileScope = new ScopeHolder<>(whileNode); -// -// new VariableExtractor() -// .setOnVariableUseListener(variable -> { -// whileScope.addVariableUse(variable, whileNode); -// -// Scope searchScope = scope.isVariableDefined(variable) ? scope : globalScope; -// -// searchScope.getLastDefinitions(variable) -// .forEach(variableDefinition -> graph.addDataDependencyArc( -// variableDefinition.getNode(), -// whileNode, -// variable -// )); -// }) -// .visit(whileStmt.getCondition()); -// -// whileStmt.getBody().accept(this, whileScope); -// -// buildLoopDataDependencies(whileScope); -// -// scope.addSubscope(whileScope); -// } -// -// private void buildLoopDataDependencies(ScopeHolder scope) { -// scope.getDefinedVariables() -// .forEach(variable -> { -// List> firstDef = scope.getFirstDefinitions(variable); -// List> lastDef = scope.getLastDefinitions(variable); -// -// Set usesFromLastDef = new HashSet<>(); -// -// firstDef.forEach(variableDefinition -> { -// scope.getVariableUsesBeforeNode(variable, variableDefinition.getNode()) -// .forEach(use -> { -// if (!usesFromLastDef.contains(use.getNode().getId())) { -// lastDef.forEach(def -> graph.addDataDependencyArc( -// def.getNode(), -// use.getNode(), -// variable) -// ); -// -// usesFromLastDef.add(use.getNode().getId()); -// } -// }); -// }); -// }); -// } - -// @Override -// public void visit(ForStmt forStmt, PDGNode node) { -// // Add initialization nodes -// forStmt.getInitialization().stream() -// .map(expression -> graph.addNode(expression.toString())) -// .forEach(pdgVertex -> graph.addControlDependencyArc(parent, pdgVertex)); -// -// // Add condition node -// Expression condition = forStmt.getCompare().orElse(new BooleanLiteralExpr(true)); -// PDGNode conditionNode = graph.addNode(condition.toString()); -// -// graph.addControlDependencyArc(parent, conditionNode); -// -// // Visit for -// super.visit(forStmt, conditionNode); -// -// // Add update vertex -// forStmt.getUpdate().stream() -// .map(expression -> graph.addNode(expression.toString())) -// .forEach(pdgVertex -> graph.addControlDependencyArc(conditionNode, pdgVertex)); -// } - -// @Override -// public void visit(ForEachStmt forEachStmt, ScopeHolder scope) { -// // Initializer -// VariableDeclarationExpr iterator = new VariableDeclarationExpr( -// new VariableDeclarator( -// JavaParser.parseClassOrInterfaceType("Iterator"), -// "iterator", -// new ConditionalExpr( -// new MethodCallExpr( -// new MethodCallExpr( -// forEachStmt.getIterable(), -// "getClass" -// ), -// "isArray" -// ), -// new MethodCallExpr( -// new NameExpr("Arrays"), -// "asList", -// new NodeList<>( -// forEachStmt.getIterable() -// ) -// ), -// new CastExpr( -// JavaParser.parseClassOrInterfaceType("Iterable"), -// new CastExpr( -// JavaParser.parseClassOrInterfaceType("Object"), -// forEachStmt.getIterable() -// ) -// ) -// ) -// ) -// ); -// -// // Compare -// MethodCallExpr iteratorHasNext = new MethodCallExpr( -// new NameExpr("iterator"), -// "hasNext" -// ); -// -// // Body -// Type variableType = forEachStmt.getVariable().getCommonType(); -// String variableName = forEachStmt.getVariable().getVariables().get(0).getNameAsString(); -// -// BlockStmt foreachBody = Utils.blockWrapper(forEachStmt.getBody()); -// foreachBody.getStatements().addFirst( -// new ExpressionStmt( -// new VariableDeclarationExpr( -// new VariableDeclarator( -// variableType, -// variableName, -// new CastExpr( -// variableType, -// new MethodCallExpr( -// new NameExpr("iterator"), -// "next" -// ) -// ) -// ) -// ) -// ) -// ); -// -// new ForStmt(new NodeList<>(iterator), iteratorHasNext, new NodeList<>(), foreachBody) -// .accept(this, parent); - - -// } - -// @Override -// public void visit(SwitchStmt switchStmt, PDGNode node) { -// PDGNode switchNode = graph.addNode(switchStmt.toString()); -// -// graph.addControlDependencyArc(parent, switchNode); -// -// switchStmt.getSelector().accept(this, parent); -// switchStmt.getEntries() -// .forEach(switchEntryStmt -> switchEntryStmt.accept(this, switchNode)); -// } -} diff --git a/src/main/java/tfm/visitors/sdg/MethodCallReplacer.java b/src/main/java/tfm/visitors/sdg/MethodCallReplacer.java index 01b853f..93137fd 100644 --- a/src/main/java/tfm/visitors/sdg/MethodCallReplacer.java +++ b/src/main/java/tfm/visitors/sdg/MethodCallReplacer.java @@ -1,9 +1,6 @@ package tfm.visitors.sdg; -import com.github.javaparser.ast.body.MethodDeclaration; -import tfm.graphs.PDGGraph; import tfm.graphs.SDGGraph; -import tfm.utils.Context; public class MethodCallReplacer { diff --git a/src/main/java/tfm/visitors/sdg/NewSDGBuilder.java b/src/main/java/tfm/visitors/sdg/NewSDGBuilder.java index 8938632..3e81151 100644 --- a/src/main/java/tfm/visitors/sdg/NewSDGBuilder.java +++ b/src/main/java/tfm/visitors/sdg/NewSDGBuilder.java @@ -4,7 +4,6 @@ import com.github.javaparser.ast.CompilationUnit; import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration; import com.github.javaparser.ast.body.MethodDeclaration; import com.github.javaparser.ast.visitor.VoidVisitorAdapter; -import javassist.expr.MethodCall; import tfm.graphbuilding.Graphs; import tfm.graphs.PDGGraph; import tfm.graphs.SDGGraph; diff --git a/src/main/java/tfm/visitors/sdg/SDGBuilder.java b/src/main/java/tfm/visitors/sdg/SDGBuilder.java index 9a51186..f2c85ff 100644 --- a/src/main/java/tfm/visitors/sdg/SDGBuilder.java +++ b/src/main/java/tfm/visitors/sdg/SDGBuilder.java @@ -46,13 +46,7 @@ public class SDGBuilder extends VoidVisitorAdapter { if (sdgGraph.isEmpty()) { - sdgGraph.setRootVertex( - new GraphNode<>( - 0, - "ENTER " + methodDeclaration.getNameAsString(), - methodDeclaration - ) - ); + sdgGraph.addNode("ENTER " + methodDeclaration.getNameAsString(), methodDeclaration); } else { // sdgGraph.addMethod(methodDeclaration); } @@ -61,7 +55,7 @@ public class SDGBuilder extends VoidVisitorAdapter { PDGBuilder PDGBuilder = new PDGBuilder(pdgGraph) { @Override - public void visit(MethodCallExpr methodCallExpr, GraphNode parent) { + public void visit(MethodCallExpr methodCallExpr, Void empty) { if (methodCallExpr.getScope().isPresent()) { String scopeName = methodCallExpr.getScope().get().toString(); @@ -117,7 +111,7 @@ public class SDGBuilder extends VoidVisitorAdapter { } }; - PDGBuilder.visit(methodDeclaration, pdgGraph.getRootNode()); + PDGBuilder.visit(methodDeclaration, null); sdgGraph.addNode(methodDeclaration.getNameAsString(), methodDeclaration); -- GitLab From 37705607f1e82ded8ee23046b805f004e5282c37 Mon Sep 17 00:00:00 2001 From: Carlos Galindo Date: Mon, 20 Jan 2020 12:45:57 +0100 Subject: [PATCH 3/9] Fix dot generation --- src/main/java/tfm/visitors/cfg/CFGBuilder.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main/java/tfm/visitors/cfg/CFGBuilder.java b/src/main/java/tfm/visitors/cfg/CFGBuilder.java index 7c74b95..25fa8c1 100644 --- a/src/main/java/tfm/visitors/cfg/CFGBuilder.java +++ b/src/main/java/tfm/visitors/cfg/CFGBuilder.java @@ -31,9 +31,7 @@ public class CFGBuilder extends VoidVisitorAdapter { @Override public void visit(ExpressionStmt expressionStmt, Void arg) { - String expression = expressionStmt.toString().replace("\"", "\\\""); - - GraphNode nextNode = addNodeAndArcs(expression, expressionStmt); + GraphNode nextNode = addNodeAndArcs(expressionStmt.toString(), expressionStmt); lastParentNodes.add(nextNode); } -- GitLab From 8f07088a63aebb9d35799f0b6e655a7070ce9048 Mon Sep 17 00:00:00 2001 From: Carlos Galindo Date: Mon, 20 Jan 2020 13:22:32 +0100 Subject: [PATCH 4/9] Fixes DOT generation implementation. * Adds API `asXArc` and `isXArc` to Arc. * Adds Sliceable interface for graphs. * Removed old DOT methods (toGraphvizRepresentation) * Removed representation-related methods from graphs. * Removed unnecessary methods. --- pom.xml | 6 + src/main/java/tfm/arcs/Arc.java | 68 ++++++---- .../java/tfm/arcs/cfg/ControlFlowArc.java | 22 --- .../tfm/arcs/pdg/ControlDependencyArc.java | 25 ---- .../java/tfm/arcs/pdg/DataDependencyArc.java | 41 +++--- src/main/java/tfm/exec/GraphLog.java | 40 ++---- src/main/java/tfm/exec/Main.java | 4 - src/main/java/tfm/exec/PDGLog.java | 2 +- src/main/java/tfm/graphs/CFGGraph.java | 52 +------- src/main/java/tfm/graphs/Graph.java | 47 +++---- src/main/java/tfm/graphs/PDGGraph.java | 126 +----------------- src/main/java/tfm/graphs/SDGGraph.java | 18 +-- src/main/java/tfm/graphs/Sliceable.java | 7 + src/main/java/tfm/nodes/GraphNode.java | 11 -- .../java/tfm/slicing/LineNumberCriterion.java | 2 +- .../java/tfm/validation/PDGValidator.java | 33 ++--- .../pdg/ControlDependencyBuilder.java | 2 - .../java/tfm/visitors/sdg/SDGBuilder.java | 2 +- 18 files changed, 137 insertions(+), 371 deletions(-) create mode 100644 src/main/java/tfm/graphs/Sliceable.java diff --git a/pom.xml b/pom.xml index c0aa410..b99904e 100644 --- a/pom.xml +++ b/pom.xml @@ -47,5 +47,11 @@ 1.3.0 + + org.junit.jupiter + junit-jupiter + 5.5.2 + test + \ No newline at end of file diff --git a/src/main/java/tfm/arcs/Arc.java b/src/main/java/tfm/arcs/Arc.java index 3f35cf5..143c900 100644 --- a/src/main/java/tfm/arcs/Arc.java +++ b/src/main/java/tfm/arcs/Arc.java @@ -1,59 +1,79 @@ package tfm.arcs; import org.jgrapht.graph.DefaultEdge; +import org.jgrapht.io.Attribute; +import tfm.arcs.cfg.ControlFlowArc; +import tfm.arcs.pdg.ControlDependencyArc; +import tfm.arcs.pdg.DataDependencyArc; import tfm.nodes.GraphNode; +import java.util.HashMap; +import java.util.Map; import java.util.Objects; -import java.util.Optional; public abstract class Arc extends DefaultEdge { - - private String variable; - public Arc() { } - public Arc(String variable) { - this.variable = variable; + public final boolean isControlFlowArc() { + return this instanceof ControlFlowArc; } - public abstract boolean isControlFlowArrow(); + public final ControlFlowArc asControlFlowArc() { + if (isControlFlowArc()) + return (ControlFlowArc) this; + throw new UnsupportedOperationException("Not a ControlFlowArc"); + } - public abstract boolean isControlDependencyArrow(); + public final boolean isControlDependencyArc() { + return this instanceof ControlDependencyArc; + } - public abstract boolean isDataDependencyArrow(); + public final ControlDependencyArc asControlDependencyArc() { + if (isControlDependencyArc()) + return (ControlDependencyArc) this; + throw new UnsupportedOperationException("Not a ControlDependencyArc"); + } - public Optional getVariable() { - return Optional.ofNullable(this.variable); + public final boolean isDataDependencyArc() { + return this instanceof DataDependencyArc; + } + + public final DataDependencyArc asDataDependencyArc() { + if (isDataDependencyArc()) + return (DataDependencyArc) this; + throw new UnsupportedOperationException("Not a DataDependencyArc"); } @Override public String toString() { - return toGraphvizRepresentation(); + return String.format("%s{%d -> %d}", getClass().getName(), + ((GraphNode) getSource()).getId(), ((GraphNode) getTarget()).getId()); } - public String toGraphvizRepresentation() { - GraphNode from = (GraphNode) getSource(); - GraphNode to = (GraphNode) getTarget(); + public String getLabel() { + return ""; + } - return String.format("%s -> %s", - from.getId(), - to.getId() - ); + public Map getDotAttributes() { + return new HashMap<>(); } @Override public boolean equals(Object o) { - if (this == o) { + if (this == o) return true; - } - - return Objects.equals(variable, ((Arc) o).variable); + if (o == null) + return false; + if (!o.getClass().equals(this.getClass())) + return false; + return Objects.equals(getSource(), ((Arc) o).getSource()) && + Objects.equals(getTarget(), ((Arc) o).getTarget()); } @Override public int hashCode() { - return Objects.hash(variable, getSource(), getTarget()); + return Objects.hash(getClass(), getSource(), getTarget()); } } diff --git a/src/main/java/tfm/arcs/cfg/ControlFlowArc.java b/src/main/java/tfm/arcs/cfg/ControlFlowArc.java index ff78a8d..5abdda3 100644 --- a/src/main/java/tfm/arcs/cfg/ControlFlowArc.java +++ b/src/main/java/tfm/arcs/cfg/ControlFlowArc.java @@ -3,28 +3,6 @@ package tfm.arcs.cfg; import tfm.arcs.Arc; public class ControlFlowArc extends Arc { - public ControlFlowArc() { } - - @Override - public boolean isControlFlowArrow() { - return true; - } - - @Override - public boolean isControlDependencyArrow() { - return false; - } - - @Override - public boolean isDataDependencyArrow() { - return false; - } - - @Override - public String toString() { - return String.format("ControlFlowArc{%s}", super.toString()); - } - } diff --git a/src/main/java/tfm/arcs/pdg/ControlDependencyArc.java b/src/main/java/tfm/arcs/pdg/ControlDependencyArc.java index 85a233a..914401e 100644 --- a/src/main/java/tfm/arcs/pdg/ControlDependencyArc.java +++ b/src/main/java/tfm/arcs/pdg/ControlDependencyArc.java @@ -3,31 +3,6 @@ package tfm.arcs.pdg; import tfm.arcs.Arc; public class ControlDependencyArc extends Arc { - - public ControlDependencyArc(String variable) { - super(variable); - } - public ControlDependencyArc() { } - - @Override - public boolean isControlFlowArrow() { - return false; - } - - @Override - public boolean isControlDependencyArrow() { - return true; - } - - @Override - public boolean isDataDependencyArrow() { - return false; - } - - @Override - public String toString() { - return String.format("ControlDependencyArc{%s}", super.toString()); - } } diff --git a/src/main/java/tfm/arcs/pdg/DataDependencyArc.java b/src/main/java/tfm/arcs/pdg/DataDependencyArc.java index 80b0996..9806f85 100644 --- a/src/main/java/tfm/arcs/pdg/DataDependencyArc.java +++ b/src/main/java/tfm/arcs/pdg/DataDependencyArc.java @@ -1,41 +1,30 @@ package tfm.arcs.pdg; +import org.jgrapht.io.Attribute; +import org.jgrapht.io.DefaultAttribute; import tfm.arcs.Arc; -public class DataDependencyArc extends Arc { - public DataDependencyArc() { - } +import java.util.Map; - public DataDependencyArc(String variable) { - super(variable); - } - - @Override - public boolean isControlFlowArrow() { - return false; - } - - @Override - public boolean isControlDependencyArrow() { - return false; - } +public class DataDependencyArc extends Arc { + private final String variable; - @Override - public boolean isDataDependencyArrow() { - return true; + public DataDependencyArc(String variable) { + super(); + this.variable = variable; } @Override - public String toString() { - return String.format("DataDependencyArc{%s}", super.toString()); + public String getLabel() { + return variable; } @Override - public String toGraphvizRepresentation() { - return String.format("%s [style=dashed, color=red%s];", - super.toGraphvizRepresentation(), - getVariable().map(variable -> String.format(", label=\"%s\"", variable)).orElse("") - ); + public Map getDotAttributes() { + Map map = super.getDotAttributes(); + map.put("style", DefaultAttribute.createAttribute("dashed")); + map.put("color", DefaultAttribute.createAttribute("red")); + return map; } } diff --git a/src/main/java/tfm/exec/GraphLog.java b/src/main/java/tfm/exec/GraphLog.java index d08b499..43f39ad 100644 --- a/src/main/java/tfm/exec/GraphLog.java +++ b/src/main/java/tfm/exec/GraphLog.java @@ -1,20 +1,11 @@ package tfm.exec; import com.github.javaparser.ast.Node; -import org.jgrapht.io.ComponentNameProvider; -import org.jgrapht.io.DOTExporter; -import org.jgrapht.io.ExportException; -import org.jgrapht.io.GraphExporter; -import tfm.arcs.Arc; import tfm.graphs.Graph; -import tfm.nodes.GraphNode; import tfm.utils.FileUtil; import tfm.utils.Logger; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.io.Writer; +import java.io.*; public abstract class GraphLog { public enum Format { @@ -64,8 +55,11 @@ public abstract class GraphLog { "* GRAPHVIZ *\n" + "****************************" ); - Logger.log(graph.toGraphvizRepresentation()); - Logger.log(); + try (StringWriter stringWriter = new StringWriter()) { + graph.getDOTExporter().exportGraph(graph, stringWriter); + stringWriter.append('\n'); + Logger.log(stringWriter.toString()); + } } public void generateImages() throws IOException { @@ -81,29 +75,21 @@ public abstract class GraphLog { this.format = format; generated = true; File tmpDot = File.createTempFile("graph-source-", ".dot"); - tmpDot.deleteOnExit(); + // Graph -> DOT -> file try (Writer w = new FileWriter(tmpDot)) { -// w.write(graph.toGraphvizRepresentation()); - - // JGraphT DOT export - GraphExporter, Arc> exporter = new DOTExporter<>( - component -> String.valueOf(component.getId()), - GraphNode::getInstruction, - component -> component.getVariable().orElse("")); - - exporter.exportGraph(graph, w); - } catch (ExportException e) { - e.printStackTrace(); + graph.getDOTExporter().exportGraph(graph, w); } + // Execute dot ProcessBuilder pb = new ProcessBuilder("dot", tmpDot.getAbsolutePath(), "-T" + format.getExt(), "-o", getImageFile().getAbsolutePath()); try { int result = pb.start().waitFor(); - if (result != 0) { - Logger.log("Image generation failed"); - } + if (result == 0) + tmpDot.deleteOnExit(); + else + Logger.log("Image generation failed, try running \"" + pb.toString() + "\" on your terminal."); } catch (InterruptedException e) { Logger.log("Image generation failed\n" + e.getMessage()); } diff --git a/src/main/java/tfm/exec/Main.java b/src/main/java/tfm/exec/Main.java index 963e00f..d604251 100644 --- a/src/main/java/tfm/exec/Main.java +++ b/src/main/java/tfm/exec/Main.java @@ -45,10 +45,6 @@ public class Main { long tt = tf - t0; - graphLog.graph.modifyNode(12, node -> { - node.setInstruction("hahhdh"); - }); - graphLog.log(); graphLog.openVisualRepresentation(); diff --git a/src/main/java/tfm/exec/PDGLog.java b/src/main/java/tfm/exec/PDGLog.java index 099daa6..d369fb5 100644 --- a/src/main/java/tfm/exec/PDGLog.java +++ b/src/main/java/tfm/exec/PDGLog.java @@ -41,7 +41,7 @@ public class PDGLog extends GraphLog { super.log(); Logger.log("Nodes with variable info"); - Logger.log(graph.getNodes().stream() + Logger.log(graph.vertexSet().stream() .sorted(Comparator.comparingInt(GraphNode::getId)) .map(node -> String.format("GraphNode { id: %s, declared: %s, defined: %s, used: %s }", diff --git a/src/main/java/tfm/graphs/CFGGraph.java b/src/main/java/tfm/graphs/CFGGraph.java index fb706e0..f21e4d8 100644 --- a/src/main/java/tfm/graphs/CFGGraph.java +++ b/src/main/java/tfm/graphs/CFGGraph.java @@ -1,18 +1,15 @@ package tfm.graphs; -import com.github.javaparser.ast.Node; import com.github.javaparser.ast.stmt.EmptyStmt; +import org.jgrapht.io.DOTExporter; import tfm.arcs.Arc; import tfm.arcs.cfg.ControlFlowArc; import tfm.nodes.GraphNode; -import tfm.slicing.SlicingCriterion; import tfm.utils.NodeNotFoundException; -import java.util.Comparator; import java.util.HashSet; import java.util.Objects; import java.util.Set; -import java.util.stream.Collectors; public class CFGGraph extends GraphWithRootNode { @@ -29,75 +26,32 @@ public class CFGGraph extends GraphWithRootNode { super.addEdge(from, to, new ControlFlowArc()); } - @Override - public String toGraphvizRepresentation() { - String lineSep = System.lineSeparator(); - - String nodes = getNodes().stream() - .sorted(Comparator.comparingInt(GraphNode::getId)) - .map(GraphNode::toGraphvizRepresentation) - .collect(Collectors.joining(lineSep)); - - String arrows = - getArcs().stream() - .sorted(Comparator.comparingInt(arc -> this.getEdgeSource(arc).getId())) - .map(Arc::toGraphvizRepresentation) - .collect(Collectors.joining(lineSep)); - - return "digraph g{" + lineSep + - nodes + lineSep + - arrows + lineSep + - "}"; - } - - @Override - public Graph slice(SlicingCriterion slicingCriterion) { - return this; - } - public Set> findLastDefinitionsFrom(GraphNode startNode, String variable) { -// Logger.log("======================================================="); -// Logger.log("Starting from " + startNode); -// Logger.log("Looking for variable " + variable); -// Logger.log(cfgGraph.toString()); - - if (!this.contains(startNode)) { + if (!this.containsVertex(startNode)) throw new NodeNotFoundException(startNode, this); - } - return findLastDefinitionsFrom(new HashSet<>(), startNode, startNode, variable); } private Set> findLastDefinitionsFrom(Set visited, GraphNode startNode, GraphNode currentNode, String variable) { visited.add(currentNode.getId()); -// Logger.log("On " + currentNode); - Set> res = new HashSet<>(); for (Arc arc : incomingEdgesOf(currentNode)) { - ControlFlowArc controlFlowArc = (ControlFlowArc) arc; + ControlFlowArc controlFlowArc = arc.asControlFlowArc(); GraphNode from = this.getEdgeSource(controlFlowArc); -// Logger.log("Arrow from node: " + from); - if (!Objects.equals(startNode, from) && visited.contains(from.getId())) { -// Logger.log("It's already visited. Continuing..."); continue; } if (from.getDefinedVariables().contains(variable)) { -// Logger.log("Contains defined variable: " + variable); res.add(from); } else { -// Logger.log("Doesn't contain the variable, searching inside it"); res.addAll(findLastDefinitionsFrom(visited, startNode, from, variable)); } } - -// Logger.format("Done with node %s", currentNode.getId()); - return res; } } diff --git a/src/main/java/tfm/graphs/Graph.java b/src/main/java/tfm/graphs/Graph.java index 2c820ef..fcd246e 100644 --- a/src/main/java/tfm/graphs/Graph.java +++ b/src/main/java/tfm/graphs/Graph.java @@ -1,14 +1,11 @@ package tfm.graphs; import com.github.javaparser.ast.Node; -import com.github.javaparser.ast.stmt.Statement; -import org.checkerframework.checker.nullness.qual.NonNull; import org.jgrapht.graph.DefaultDirectedGraph; +import org.jgrapht.io.DOTExporter; import tfm.arcs.Arc; import tfm.nodes.GraphNode; -import tfm.slicing.SlicingCriterion; import tfm.utils.NodeFactory; -import tfm.variables.VariableExtractor; import java.util.*; import java.util.function.Consumer; @@ -69,57 +66,47 @@ public abstract class Graph extends DefaultDirectedGraph, Arc> { @SuppressWarnings("unchecked") public Optional> findNodeByASTNode(ASTNode astNode) { - return getNodes().stream() + return vertexSet().stream() .filter(node -> Objects.equals(node.getAstNode(), astNode)) .findFirst() .map(node -> (GraphNode) node); } public Optional> findNodeById(int id) { - return getNodes().stream() + return vertexSet().stream() .filter(node -> Objects.equals(node.getId(), id)) .findFirst(); } - public Set> getNodes() { - return vertexSet(); - } - - public Set getArcs() { - return edgeSet(); - } - + @Override public String toString() { - return getNodes().stream() + return vertexSet().stream() .sorted(Comparator.comparingInt(GraphNode::getId)) .map(GraphNode::toString) .collect(Collectors.joining(System.lineSeparator())); } - public abstract String toGraphvizRepresentation(); - protected synchronized int getNextVertexId() { return nextVertexId++; } - public boolean contains(GraphNode graphNode) { - return super.containsVertex(graphNode); - } - - public abstract Graph slice(SlicingCriterion slicingCriterion); - - public void removeNode(GraphNode node) { - removeVertex(node); - } - public List> findDeclarationsOfVariable(String variable) { - return getNodes().stream() + return vertexSet().stream() .filter(node -> node.getDeclaredVariables().contains(variable)) .collect(Collectors.toList()); } public boolean isEmpty() { - return this.getNodes().size() == 0; + return this.vertexSet().isEmpty(); + } + + public DOTExporter, Arc> getDOTExporter() { + return new DOTExporter<>( + graphNode -> String.valueOf(graphNode.getId()), + GraphNode::getInstruction, + Arc::getLabel, + null, + Arc::getDotAttributes); } /** @@ -134,7 +121,7 @@ public abstract class Graph extends DefaultDirectedGraph, Arc> { Set incomingArcs = new HashSet<>(incomingEdgesOf(node)); Set outgoingArcs = new HashSet<>(outgoingEdgesOf(node)); - this.removeNode(node); + this.removeVertex(node); MutableGraphNode modifiedNode = new MutableGraphNode<>((GraphNode) node); diff --git a/src/main/java/tfm/graphs/PDGGraph.java b/src/main/java/tfm/graphs/PDGGraph.java index 3e90520..1cf2061 100644 --- a/src/main/java/tfm/graphs/PDGGraph.java +++ b/src/main/java/tfm/graphs/PDGGraph.java @@ -2,7 +2,7 @@ package tfm.graphs; import com.github.javaparser.ast.Node; import com.github.javaparser.ast.body.MethodDeclaration; -import org.jetbrains.annotations.NotNull; +import org.jgrapht.io.DOTExporter; import tfm.arcs.Arc; import tfm.arcs.pdg.ControlDependencyArc; import tfm.arcs.pdg.DataDependencyArc; @@ -14,9 +14,8 @@ import tfm.utils.NodeNotFoundException; import tfm.visitors.pdg.PDGBuilder; import java.util.*; -import java.util.stream.Collectors; -public class PDGGraph extends GraphWithRootNode { +public class PDGGraph extends GraphWithRootNode implements Sliceable { private CFGGraph cfgGraph; @@ -42,95 +41,10 @@ public class PDGGraph extends GraphWithRootNode { this.addEdge(from, to, new DataDependencyArc(variable)); } - public Set> getNodesAtLevel(int level) { - return getNodes().stream() - .filter(node -> getLevelOf(node) == level) - .collect(Collectors.toSet()); - } - - public int getLevels() { - return getNodes().stream() - .max(Comparator.comparingInt(this::getLevelOf)) - .map(node -> getLevelOf(node) + 1) - .orElse(0); - } - - public int getLevelOf(int nodeId) { - return findNodeById(nodeId) - .map(this::getLevelOf) - .orElseThrow(() -> new NodeNotFoundException("Node with id " + nodeId + " not found in PDG graph")); - } - - public int getLevelOf(@NotNull GraphNode node) { - Optional optionalControlDependencyArc = incomingEdgesOf(node).stream() - .filter(Arc::isControlDependencyArrow) - .findFirst() - .map(arc -> (ControlDependencyArc) arc); - - if (!optionalControlDependencyArc.isPresent()) { - return 0; - } - - GraphNode parent = this.getEdgeSource(optionalControlDependencyArc.get()); - - return 1 + getLevelOf(parent); - } - public void setCfgGraph(CFGGraph cfgGraph) { this.cfgGraph = cfgGraph; } - @Override - public String toGraphvizRepresentation() { - String lineSep = System.lineSeparator(); - - String nodesDeclaration = getNodes().stream() - .sorted(Comparator.comparingInt(GraphNode::getId)) - .map(GraphNode::toGraphvizRepresentation) - .collect(Collectors.joining(lineSep)); - - StringBuilder rankedNodes = new StringBuilder(); - - // No level 0 is needed (only one node) - for (int i = 0; i < getLevels(); i++) { - Set> 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(GraphNode::getId)) - .map(node -> String.valueOf(node.getId())) - .collect(Collectors.joining(" -> "))) - .append("[style = invis];") - .append(lineSep); - } - - String arrows = - getArcs().stream() - .sorted(Comparator.comparingInt(arc -> this.getEdgeSource(arc).getId())) - .map(Arc::toGraphvizRepresentation) - .collect(Collectors.joining(lineSep)); - - - return "digraph g{" + lineSep + - "splines=true;" + lineSep + - nodesDeclaration + lineSep + - arrows + lineSep + - rankedNodes.toString() + - "}"; - } - @Override public PDGGraph slice(SlicingCriterion slicingCriterion) { Optional> optionalGraphNode = slicingCriterion.findNode(this); @@ -141,21 +55,6 @@ public class PDGGraph extends GraphWithRootNode { GraphNode node = optionalGraphNode.get(); -// // DEPRECATED - Find CFGNode and find last definition of variable -// CFGNode cfgNode = this.cfgGraph.findNodeByASTNode(node.getAstNode()) -// .orElseThrow(() -> new NodeNotFoundException("CFGNode not found")); -// -// Set> definitionNodes = Utils.findLastDefinitionsFrom(cfgNode, slicingCriterion.getVariable()); -// -// Logger.format("Slicing node: %s", node); -// -// // Get slice nodes from definition nodes -// Set sliceNodes = definitionNodes.stream() -// .flatMap(definitionNode -> getSliceNodes(new HashSet<>(), this.findNodeByASTNode(definitionNode.getAstNode()).get()).stream()) -// .collect(Collectors.toSet()); -// -// sliceNodes.add(node.getId()); - // Simply get slice nodes from GraphNode Set sliceNodes = getSliceNodes(new HashSet<>(), node); @@ -165,31 +64,14 @@ public class PDGGraph extends GraphWithRootNode { astCopy.accept(new PDGBuilder(sliceGraph), null); - for (GraphNode sliceNode : sliceGraph.getNodes()) { + for (GraphNode sliceNode : sliceGraph.vertexSet()) { if (!sliceNodes.contains(sliceNode.getId())) { Logger.log("Removing node " + sliceNode.getId()); sliceNode.getAstNode().removeForced(); - sliceGraph.removeNode(sliceNode); + sliceGraph.removeVertex(sliceNode); } } -// for (Arc arc : getArcs()) { -// Optional fromOptional = sliceGraph.findNodeById(arc.getFromNode().getId()); -// Optional toOptional = sliceGraph.findNodeById(arc.getToNode().getId()); -// -// if (fromOptional.isPresent() && toOptional.isPresent()) { -// GraphNode from = fromOptional.get(); -// GraphNode to = toOptional.get(); -// -// if (arc.isControlDependencyArrow()) { -// sliceGraph.addControlDependencyArc(from, to); -// } else { -// DataDependencyArc dataDependencyArc = (DataDependencyArc) arc; -// sliceGraph.addDataDependencyArc(from, to, dataDependencyArc.getData().getVariables().get(0)); -// } -// } -// } - return sliceGraph; } diff --git a/src/main/java/tfm/graphs/SDGGraph.java b/src/main/java/tfm/graphs/SDGGraph.java index 1167e1a..66be5a0 100644 --- a/src/main/java/tfm/graphs/SDGGraph.java +++ b/src/main/java/tfm/graphs/SDGGraph.java @@ -3,6 +3,8 @@ package tfm.graphs; import com.github.javaparser.ast.body.MethodDeclaration; import com.github.javaparser.ast.body.Parameter; import com.github.javaparser.ast.stmt.EmptyStmt; +import org.jgrapht.io.DOTExporter; +import tfm.arcs.Arc; import tfm.nodes.GraphNode; import tfm.slicing.SlicingCriterion; import tfm.utils.Context; @@ -13,7 +15,7 @@ import java.util.Map; import java.util.Set; import java.util.stream.Collectors; -public class SDGGraph extends Graph { +public class SDGGraph extends Graph implements Sliceable { private Map contextPDGGraphMap; @@ -22,14 +24,8 @@ public class SDGGraph extends Graph { } @Override - public String toGraphvizRepresentation() { - return contextPDGGraphMap.values().stream() - .map(PDGGraph::toGraphvizRepresentation).collect(Collectors.joining("\n")); - } - - @Override - public Graph slice(SlicingCriterion slicingCriterion) { - return this; + public SDGGraph slice(SlicingCriterion slicingCriterion) { + throw new IllegalStateException("Not implemented (yet)"); } public Map getContextPDGGraphMap() { @@ -63,8 +59,8 @@ public class SDGGraph extends Graph { addVertex(sdgNode); } - for (GraphNode node : pdgGraph.getNodes()) { - if (!this.contains(node)) { + for (GraphNode node : pdgGraph.vertexSet()) { + if (!this.containsVertex(node)) { GraphNode sdgNode = new GraphNode<>( getNextVertexId(), node.getInstruction(), diff --git a/src/main/java/tfm/graphs/Sliceable.java b/src/main/java/tfm/graphs/Sliceable.java new file mode 100644 index 0000000..3edf64a --- /dev/null +++ b/src/main/java/tfm/graphs/Sliceable.java @@ -0,0 +1,7 @@ +package tfm.graphs; + +import tfm.slicing.SlicingCriterion; + +public interface Sliceable { + G slice(SlicingCriterion sc); +} diff --git a/src/main/java/tfm/nodes/GraphNode.java b/src/main/java/tfm/nodes/GraphNode.java index a92cdf6..5361195 100644 --- a/src/main/java/tfm/nodes/GraphNode.java +++ b/src/main/java/tfm/nodes/GraphNode.java @@ -80,11 +80,6 @@ public class GraphNode { return astNode; } - public Optional getFileLineNumber() { - return astNode.getBegin() - .map(begin -> begin.line); - } - public void addDeclaredVariable(String variable) { declaredVariables.add(variable); } @@ -117,12 +112,6 @@ public class GraphNode { return Objects.hash(getId(), getInstruction(), getAstNode()); } - public String toGraphvizRepresentation() { - String text = getInstruction().replace("\\", "\\\\") - .replace("\"", "\\\""); - return String.format("%s[label=\"%s: %s\"];", getId(), getId(), text); - } - public Set getDeclaredVariables() { return declaredVariables; } diff --git a/src/main/java/tfm/slicing/LineNumberCriterion.java b/src/main/java/tfm/slicing/LineNumberCriterion.java index 2b0c246..901bcc5 100644 --- a/src/main/java/tfm/slicing/LineNumberCriterion.java +++ b/src/main/java/tfm/slicing/LineNumberCriterion.java @@ -27,7 +27,7 @@ public class LineNumberCriterion extends SlicingCriterion { @Override public Optional> findNode(PDGGraph graph) { // find node by line number - return graph.getNodes().stream().filter(node -> { + return graph.vertexSet().stream().filter(node -> { Node astNode = node.getAstNode(); if (!astNode.getBegin().isPresent() || !astNode.getEnd().isPresent()) diff --git a/src/main/java/tfm/validation/PDGValidator.java b/src/main/java/tfm/validation/PDGValidator.java index f4d3f20..2679189 100644 --- a/src/main/java/tfm/validation/PDGValidator.java +++ b/src/main/java/tfm/validation/PDGValidator.java @@ -76,22 +76,25 @@ public class PDGValidator { return ProgramComparator.areEqual(methodDeclaration, generatedMethod); } + @Deprecated public static MethodDeclaration generateMethod(MethodDeclaration info, PDGGraph graph) { - MethodDeclaration methodDeclaration = new MethodDeclaration(); - - methodDeclaration.setName(info.getNameAsString()); - methodDeclaration.setModifiers(info.getModifiers()); - methodDeclaration.setType(info.getType()); - methodDeclaration.setParameters(info.getParameters()); - - BlockStmt methodBody = new BlockStmt(); - methodDeclaration.setBody(methodBody); - - graph.getNodesAtLevel(1).stream() - .sorted(Comparator.comparingInt(GraphNode::getId)) - .forEach(node -> methodBody.addStatement((Statement) node.getAstNode())); - - return methodDeclaration; + // TODO: this does not work properly, replace or remove + throw new IllegalStateException("Deprecated method"); +// MethodDeclaration methodDeclaration = new MethodDeclaration(); +// +// methodDeclaration.setName(info.getNameAsString()); +// methodDeclaration.setModifiers(info.getModifiers()); +// methodDeclaration.setType(info.getType()); +// methodDeclaration.setParameters(info.getParameters()); +// +// BlockStmt methodBody = new BlockStmt(); +// methodDeclaration.setBody(methodBody); +// +// graph.getNodesAtLevel(1).stream() +// .sorted(Comparator.comparingInt(GraphNode::getId)) +// .forEach(node -> methodBody.addStatement((Statement) node.getAstNode())); +// +// return methodDeclaration; } public static void printPDGProgram(String fileName, PDGGraph graph) throws FileNotFoundException { diff --git a/src/main/java/tfm/visitors/pdg/ControlDependencyBuilder.java b/src/main/java/tfm/visitors/pdg/ControlDependencyBuilder.java index 4a267ec..f4ee2b8 100644 --- a/src/main/java/tfm/visitors/pdg/ControlDependencyBuilder.java +++ b/src/main/java/tfm/visitors/pdg/ControlDependencyBuilder.java @@ -5,9 +5,7 @@ import com.github.javaparser.ast.visitor.VoidVisitorAdapter; import tfm.graphs.CFGGraph; import tfm.graphs.PDGGraph; import tfm.nodes.GraphNode; -import tfm.utils.Logger; -import java.util.Objects; import java.util.stream.Collectors; public class ControlDependencyBuilder extends VoidVisitorAdapter> { diff --git a/src/main/java/tfm/visitors/sdg/SDGBuilder.java b/src/main/java/tfm/visitors/sdg/SDGBuilder.java index f2c85ff..9662844 100644 --- a/src/main/java/tfm/visitors/sdg/SDGBuilder.java +++ b/src/main/java/tfm/visitors/sdg/SDGBuilder.java @@ -116,7 +116,7 @@ public class SDGBuilder extends VoidVisitorAdapter { sdgGraph.addNode(methodDeclaration.getNameAsString(), methodDeclaration); - pdgGraph.getNodes().stream().skip(1).forEach(pdgNode -> { + pdgGraph.vertexSet().stream().skip(1).forEach(pdgNode -> { Statement statement = (Statement) pdgNode.getAstNode(); if (statement.isExpressionStmt()) { -- GitLab From 6ed533e71fd264fefe5c864b856b5c40a58353bc Mon Sep 17 00:00:00 2001 From: Carlos Galindo Date: Mon, 20 Jan 2020 15:10:10 +0100 Subject: [PATCH 5/9] Remove graphlib.jar and graphlib from maven. --- lib/graphlib.jar | Bin 22438 -> 0 bytes pom.xml | 1 - 2 files changed, 1 deletion(-) delete mode 100644 lib/graphlib.jar diff --git a/lib/graphlib.jar b/lib/graphlib.jar deleted file mode 100644 index cf0e9844307d1dff58335a2e6f3500c532f7d58d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22438 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%0D8Lb!KHd(-7EB`>2aL*Ux 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 diff --git a/pom.xml b/pom.xml index b99904e..53b3a44 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,6 @@ - com.github.javaparser javaparser-symbol-solver-core -- GitLab From 6bb53029839b10359b2fef4d0db7588ddb677c01 Mon Sep 17 00:00:00 2001 From: Javier Costa Date: Wed, 22 Jan 2020 14:56:43 +0100 Subject: [PATCH 6/9] build root node on demand --- src/main/java/tfm/graphs/CFGGraph.java | 8 +--- src/main/java/tfm/graphs/Graph.java | 9 ++++- .../java/tfm/graphs/GraphWithRootNode.java | 38 ++++++++++++++----- src/main/java/tfm/graphs/PDGGraph.java | 7 +--- .../java/tfm/visitors/cfg/CFGBuilder.java | 12 +++--- .../java/tfm/visitors/pdg/PDGBuilder.java | 14 +++---- 6 files changed, 53 insertions(+), 35 deletions(-) diff --git a/src/main/java/tfm/graphs/CFGGraph.java b/src/main/java/tfm/graphs/CFGGraph.java index f21e4d8..445fcb4 100644 --- a/src/main/java/tfm/graphs/CFGGraph.java +++ b/src/main/java/tfm/graphs/CFGGraph.java @@ -1,5 +1,6 @@ package tfm.graphs; +import com.github.javaparser.ast.body.MethodDeclaration; import com.github.javaparser.ast.stmt.EmptyStmt; import org.jgrapht.io.DOTExporter; import tfm.arcs.Arc; @@ -11,17 +12,12 @@ import java.util.HashSet; import java.util.Objects; import java.util.Set; -public class CFGGraph extends GraphWithRootNode { +public class CFGGraph extends GraphWithRootNode { public CFGGraph() { super(); } - @Override - protected GraphNode buildRootNode() { - return new GraphNode<>(getNextVertexId(), "Start", new EmptyStmt()); - } - public void addControlFlowEdge(GraphNode from, GraphNode to) { super.addEdge(from, to, new ControlFlowArc()); } diff --git a/src/main/java/tfm/graphs/Graph.java b/src/main/java/tfm/graphs/Graph.java index fcd246e..7e2603c 100644 --- a/src/main/java/tfm/graphs/Graph.java +++ b/src/main/java/tfm/graphs/Graph.java @@ -16,10 +16,17 @@ import java.util.stream.Collectors; * */ public abstract class Graph extends DefaultDirectedGraph, Arc> { - private int nextVertexId = 0; + protected static final int DEFAULT_VERTEX_START_ID = 0; + + private int nextVertexId; public Graph() { + this(DEFAULT_VERTEX_START_ID); + } + + protected Graph(int vertexStartId) { super(null, null, false); + this.nextVertexId = vertexStartId; } private GraphNode addNode(GraphNode node) { diff --git a/src/main/java/tfm/graphs/GraphWithRootNode.java b/src/main/java/tfm/graphs/GraphWithRootNode.java index d80c776..9630a2b 100644 --- a/src/main/java/tfm/graphs/GraphWithRootNode.java +++ b/src/main/java/tfm/graphs/GraphWithRootNode.java @@ -1,24 +1,44 @@ package tfm.graphs; +import com.github.javaparser.ast.Node; import tfm.nodes.GraphNode; +import tfm.utils.NodeFactory; import java.util.Objects; +import java.util.Optional; -public abstract class GraphWithRootNode extends Graph { +public abstract class GraphWithRootNode extends Graph { - protected GraphNode rootNode; + protected final int ROOT_NODE_ID = 0; - public GraphWithRootNode() { - super(); + protected GraphNode rootNode; - this.rootNode = buildRootNode(); - this.addVertex(rootNode); + public GraphWithRootNode() { + super(1); } - protected abstract GraphNode buildRootNode(); + /** + * Builds the root node with the given instruction and AST node. + * If the root node already exists, just returns false + * + * @param instruction the instruction string + * @param rootNodeAst the AST node + * @return true if the root node is created, false otherwise + */ + public boolean buildRootNode(String instruction, ASTRootNode rootNodeAst) { + if (rootNode != null) { + return false; + } + + GraphNode root = NodeFactory.graphNode(ROOT_NODE_ID, instruction, rootNodeAst); + this.rootNode = root; + this.addVertex(root); + + return true; + } - public GraphNode getRootNode() { - return rootNode; + public Optional> getRootNode() { + return Optional.ofNullable(rootNode); } @Override diff --git a/src/main/java/tfm/graphs/PDGGraph.java b/src/main/java/tfm/graphs/PDGGraph.java index 1cf2061..a19a9c4 100644 --- a/src/main/java/tfm/graphs/PDGGraph.java +++ b/src/main/java/tfm/graphs/PDGGraph.java @@ -15,7 +15,7 @@ import tfm.visitors.pdg.PDGBuilder; import java.util.*; -public class PDGGraph extends GraphWithRootNode implements Sliceable { +public class PDGGraph extends GraphWithRootNode implements Sliceable { private CFGGraph cfgGraph; @@ -23,11 +23,6 @@ public class PDGGraph extends GraphWithRootNode implements Sliceable { super(); } - @Override - protected GraphNode buildRootNode() { - return new GraphNode<>(getNextVertexId(), "ENTER", new MethodDeclaration()); - } - public PDGGraph(CFGGraph cfgGraph) { super(); this.cfgGraph = cfgGraph; diff --git a/src/main/java/tfm/visitors/cfg/CFGBuilder.java b/src/main/java/tfm/visitors/cfg/CFGBuilder.java index 25fa8c1..c0ba5d5 100644 --- a/src/main/java/tfm/visitors/cfg/CFGBuilder.java +++ b/src/main/java/tfm/visitors/cfg/CFGBuilder.java @@ -20,11 +20,7 @@ public class CFGBuilder extends VoidVisitorAdapter { public CFGBuilder(CFGGraph graph) { this.graph = graph; - this.lastParentNodes = Collections.asLifoQueue( - new ArrayDeque<>( - Collections.singletonList(graph.getRootNode()) - ) - ); + this.lastParentNodes = Collections.asLifoQueue(new ArrayDeque<>()); this.bodyBreaks = new ArrayList<>(); } @@ -225,6 +221,12 @@ public class CFGBuilder extends VoidVisitorAdapter { throw new IllegalStateException("CFG is only allowed for one method, not multiple!"); } + this.graph.buildRootNode("Start", methodDeclaration); + + assert this.graph.getRootNode().isPresent(); + + lastParentNodes.add(this.graph.getRootNode().get()); + super.visit(methodDeclaration, arg); lastParentNodes.add(addNodeAndArcs("Stop", new EmptyStmt())); diff --git a/src/main/java/tfm/visitors/pdg/PDGBuilder.java b/src/main/java/tfm/visitors/pdg/PDGBuilder.java index 1e59487..09ad2f8 100644 --- a/src/main/java/tfm/visitors/pdg/PDGBuilder.java +++ b/src/main/java/tfm/visitors/pdg/PDGBuilder.java @@ -27,20 +27,18 @@ public class PDGBuilder extends VoidVisitorAdapter { if (!methodDeclaration.getBody().isPresent()) return; - // Assign the method declaration to the root node of the PDG graph. Here parent will always be the root node - this.pdgGraph.modifyNode(pdgGraph.getRootNode().getId(), mutableGraphNode -> { - mutableGraphNode.setInstruction("ENTER " + methodDeclaration.getNameAsString()); - mutableGraphNode.setAstNode(methodDeclaration); - }); + this.pdgGraph.buildRootNode("ENTER " + methodDeclaration.getNameAsString(), methodDeclaration); - BlockStmt methodBody = methodDeclaration.getBody().get(); + assert this.pdgGraph.getRootNode().isPresent(); // build CFG - methodBody.accept(new CFGBuilder(cfgGraph), null); + methodDeclaration.accept(new CFGBuilder(cfgGraph), null); + + BlockStmt methodBody = methodDeclaration.getBody().get(); // Build control dependency ControlDependencyBuilder controlDependencyBuilder = new ControlDependencyBuilder(pdgGraph, cfgGraph); - methodBody.accept(controlDependencyBuilder, pdgGraph.getRootNode()); + methodBody.accept(controlDependencyBuilder, pdgGraph.getRootNode().get()); // Build data dependency DataDependencyBuilder dataDependencyBuilder = new DataDependencyBuilder(pdgGraph, cfgGraph); -- GitLab From 9ba2e8d164dd2ea746b29207efb1e8c63769a8a8 Mon Sep 17 00:00:00 2001 From: Javier Costa Date: Wed, 22 Jan 2020 15:04:26 +0100 Subject: [PATCH 7/9] NodeFactory to create new nodes + GraphNode constructors package private --- src/main/java/tfm/graphs/Graph.java | 2 +- src/main/java/tfm/graphs/GraphWithRootNode.java | 2 +- src/main/java/tfm/graphs/SDGGraph.java | 7 ++++--- src/main/java/tfm/nodes/GraphNode.java | 4 ++-- src/main/java/tfm/{utils => nodes}/NodeFactory.java | 13 ++++++++++++- 5 files changed, 20 insertions(+), 8 deletions(-) rename src/main/java/tfm/{utils => nodes}/NodeFactory.java (73%) diff --git a/src/main/java/tfm/graphs/Graph.java b/src/main/java/tfm/graphs/Graph.java index 7e2603c..ce739be 100644 --- a/src/main/java/tfm/graphs/Graph.java +++ b/src/main/java/tfm/graphs/Graph.java @@ -5,7 +5,7 @@ import org.jgrapht.graph.DefaultDirectedGraph; import org.jgrapht.io.DOTExporter; import tfm.arcs.Arc; import tfm.nodes.GraphNode; -import tfm.utils.NodeFactory; +import tfm.nodes.NodeFactory; import java.util.*; import java.util.function.Consumer; diff --git a/src/main/java/tfm/graphs/GraphWithRootNode.java b/src/main/java/tfm/graphs/GraphWithRootNode.java index 9630a2b..76d01e6 100644 --- a/src/main/java/tfm/graphs/GraphWithRootNode.java +++ b/src/main/java/tfm/graphs/GraphWithRootNode.java @@ -2,7 +2,7 @@ package tfm.graphs; import com.github.javaparser.ast.Node; import tfm.nodes.GraphNode; -import tfm.utils.NodeFactory; +import tfm.nodes.NodeFactory; import java.util.Objects; import java.util.Optional; diff --git a/src/main/java/tfm/graphs/SDGGraph.java b/src/main/java/tfm/graphs/SDGGraph.java index 66be5a0..6da8faf 100644 --- a/src/main/java/tfm/graphs/SDGGraph.java +++ b/src/main/java/tfm/graphs/SDGGraph.java @@ -6,6 +6,7 @@ import com.github.javaparser.ast.stmt.EmptyStmt; import org.jgrapht.io.DOTExporter; import tfm.arcs.Arc; import tfm.nodes.GraphNode; +import tfm.nodes.NodeFactory; import tfm.slicing.SlicingCriterion; import tfm.utils.Context; @@ -50,7 +51,7 @@ public class SDGGraph extends Graph implements Sliceable { @Deprecated public void addPDG(PDGGraph pdgGraph, MethodDeclaration methodDeclaration) { for (Parameter parameter : methodDeclaration.getParameters()) { - GraphNode sdgNode = new GraphNode<>( + GraphNode sdgNode = NodeFactory.graphNode( getNextVertexId(), String.format("%s = %s_in", parameter.getNameAsString(), parameter.getNameAsString()), new EmptyStmt() @@ -61,7 +62,7 @@ public class SDGGraph extends Graph implements Sliceable { for (GraphNode node : pdgGraph.vertexSet()) { if (!this.containsVertex(node)) { - GraphNode sdgNode = new GraphNode<>( + GraphNode sdgNode = NodeFactory.computedGraphNode( getNextVertexId(), node.getInstruction(), node.getAstNode(), @@ -76,7 +77,7 @@ public class SDGGraph extends Graph implements Sliceable { } public void addMethod(MethodDeclaration methodDeclaration, PDGGraph pdgGraph) { - GraphNode methodRootNode = new GraphNode<>( + GraphNode methodRootNode = NodeFactory.graphNode( getNextVertexId(), "ENTER " + methodDeclaration.getDeclarationAsString(false, false, true), methodDeclaration diff --git a/src/main/java/tfm/nodes/GraphNode.java b/src/main/java/tfm/nodes/GraphNode.java index 5361195..1afa440 100644 --- a/src/main/java/tfm/nodes/GraphNode.java +++ b/src/main/java/tfm/nodes/GraphNode.java @@ -24,7 +24,7 @@ public class GraphNode { private final Set definedVariables; private final Set usedVariables; - public GraphNode(int id, String instruction, @NotNull N astNode) { + GraphNode(int id, String instruction, @NotNull N astNode) { this( id, instruction, @@ -39,7 +39,7 @@ public class GraphNode { } } - public GraphNode( + GraphNode( int id, String instruction, @NonNull N astNode, diff --git a/src/main/java/tfm/utils/NodeFactory.java b/src/main/java/tfm/nodes/NodeFactory.java similarity index 73% rename from src/main/java/tfm/utils/NodeFactory.java rename to src/main/java/tfm/nodes/NodeFactory.java index 585fea7..92047af 100644 --- a/src/main/java/tfm/utils/NodeFactory.java +++ b/src/main/java/tfm/nodes/NodeFactory.java @@ -1,9 +1,11 @@ -package tfm.utils; +package tfm.nodes; import com.github.javaparser.ast.Node; +import org.checkerframework.checker.nullness.qual.NonNull; import tfm.nodes.GraphNode; import java.util.Collection; +import java.util.Objects; public class NodeFactory { @@ -28,6 +30,12 @@ public class NodeFactory { Collection definedVariables, Collection usedVariables ) { + Objects.requireNonNull(instruction, "Instruction cannot be null!"); + Objects.requireNonNull(node, "AST Node cannot be null"); + Objects.requireNonNull(declaredVariables, "declared variables collection cannot be null!"); + Objects.requireNonNull(definedVariables, "defined variables collection cannot be null"); + Objects.requireNonNull(usedVariables, "Used variables collection cannot be null!"); + return new GraphNode<>( id, instruction, @@ -52,6 +60,9 @@ public class NodeFactory { String instruction, ASTNode node ) { + Objects.requireNonNull(instruction, "Instruction cannot be null!"); + Objects.requireNonNull(node, "AST Node cannot be null"); + return new GraphNode<>( id, instruction, -- GitLab From 0d6593ad93d34abeab8788ea4ca74f42223c5256 Mon Sep 17 00:00:00 2001 From: Carlos Galindo Date: Thu, 23 Jan 2020 14:42:59 +0100 Subject: [PATCH 8/9] Renamed graphs and replaced @NonNull with @NotNull Also optimized imports --- readme.md | 4 +-- src/main/java/tfm/exec/CFGLog.java | 8 ++--- src/main/java/tfm/exec/PDGLog.java | 19 +++++------ src/main/java/tfm/exec/SDGLog.java | 6 ++-- .../java/tfm/graphbuilding/GraphOptions.java | 30 ++++++++--------- src/main/java/tfm/graphbuilding/Graphs.java | 12 +++---- .../tfm/graphs/{CFGGraph.java => CFG.java} | 6 ++-- .../tfm/graphs/{PDGGraph.java => PDG.java} | 27 ++++++++-------- .../tfm/graphs/{SDGGraph.java => SDG.java} | 20 ++++++------ src/main/java/tfm/nodes/GraphNode.java | 10 +++--- src/main/java/tfm/nodes/NodeFactory.java | 2 -- src/main/java/tfm/readme.md | 4 +-- .../java/tfm/slicing/LineNumberCriterion.java | 12 +++---- src/main/java/tfm/slicing/Slice.java | 8 ++--- .../java/tfm/slicing/SlicingCriterion.java | 12 +++---- .../java/tfm/validation/PDGValidator.java | 14 +++----- .../java/tfm/visitors/cfg/CFGBuilder.java | 6 ++-- .../pdg/ControlDependencyBuilder.java | 24 +++++++------- .../visitors/pdg/DataDependencyBuilder.java | 30 ++++++++--------- .../java/tfm/visitors/pdg/PDGBuilder.java | 32 +++++++++---------- .../tfm/visitors/sdg/MethodCallReplacer.java | 10 +++--- .../sdg/MethodCallReplacerVisitor.java | 10 +++--- .../java/tfm/visitors/sdg/NewSDGBuilder.java | 16 +++++----- .../java/tfm/visitors/sdg/SDGBuilder.java | 32 +++++++++---------- 24 files changed, 174 insertions(+), 180 deletions(-) rename src/main/java/tfm/graphs/{CFGGraph.java => CFG.java} (89%) rename src/main/java/tfm/graphs/{PDGGraph.java => PDG.java} (79%) rename src/main/java/tfm/graphs/{SDGGraph.java => SDG.java} (81%) diff --git a/readme.md b/readme.md index 5ef10f6..9fd78a3 100644 --- a/readme.md +++ b/readme.md @@ -131,9 +131,9 @@ public PDGGraph getSlice(File program, SlicingCriterion slicingCriterion) { Node astRoot = JavaParser.parse(programFile); - PDGGraph pdgGraph = Graphs.PDG.fromASTNode(astRoot); + PDGGraph pdg = Graphs.PDG.fromASTNode(astRoot); - return pdgGraph.slice(slicingCriterion); + return pdg.slice(slicingCriterion); } ``` diff --git a/src/main/java/tfm/exec/CFGLog.java b/src/main/java/tfm/exec/CFGLog.java index e04a483..153728a 100644 --- a/src/main/java/tfm/exec/CFGLog.java +++ b/src/main/java/tfm/exec/CFGLog.java @@ -1,22 +1,22 @@ package tfm.exec; import com.github.javaparser.ast.Node; -import tfm.graphs.CFGGraph; +import tfm.graphs.CFG; import tfm.visitors.cfg.CFGBuilder; -public class CFGLog extends GraphLog { +public class CFGLog extends GraphLog { public CFGLog() { super(); } - public CFGLog(CFGGraph graph) { + public CFGLog(CFG graph) { super(graph); } @Override public void visit(Node node) { - this.graph = new CFGGraph(); + this.graph = new CFG(); node.accept(new CFGBuilder(graph), null); } } diff --git a/src/main/java/tfm/exec/PDGLog.java b/src/main/java/tfm/exec/PDGLog.java index d369fb5..991681d 100644 --- a/src/main/java/tfm/exec/PDGLog.java +++ b/src/main/java/tfm/exec/PDGLog.java @@ -1,6 +1,7 @@ package tfm.exec; -import tfm.graphs.PDGGraph; +import com.github.javaparser.ast.Node; +import tfm.graphs.PDG; import tfm.nodes.GraphNode; import tfm.utils.Logger; import tfm.visitors.pdg.PDGBuilder; @@ -9,7 +10,7 @@ import java.io.IOException; import java.util.Comparator; import java.util.stream.Collectors; -public class PDGLog extends GraphLog { +public class PDGLog extends GraphLog { private CFGLog cfgLog; @@ -17,22 +18,22 @@ public class PDGLog extends GraphLog { this(null); } - public PDGLog(PDGGraph pdgGraph) { - super(pdgGraph); + public PDGLog(PDG pdg) { + super(pdg); - if (graph != null && graph.getCfgGraph() != null) - cfgLog = new CFGLog(graph.getCfgGraph()); + if (graph != null && graph.getCfg() != null) + cfgLog = new CFGLog(graph.getCfg()); else cfgLog = null; } @Override - public void visit(com.github.javaparser.ast.Node node) { - this.graph = new PDGGraph(); + public void visit(Node node) { + this.graph = new PDG(); node.accept(new PDGBuilder(graph), null); if (cfgLog == null) { - cfgLog = new CFGLog(graph.getCfgGraph()); + cfgLog = new CFGLog(graph.getCfg()); } } diff --git a/src/main/java/tfm/exec/SDGLog.java b/src/main/java/tfm/exec/SDGLog.java index 16978ae..702e7c9 100644 --- a/src/main/java/tfm/exec/SDGLog.java +++ b/src/main/java/tfm/exec/SDGLog.java @@ -1,14 +1,14 @@ package tfm.exec; import com.github.javaparser.ast.Node; -import tfm.graphs.SDGGraph; +import tfm.graphs.SDG; import tfm.visitors.sdg.SDGBuilder; -public class SDGLog extends GraphLog { +public class SDGLog extends GraphLog { @Override public void visit(Node node) { - this.graph = new SDGGraph(); + this.graph = new SDG(); SDGBuilder sdgBuilder = new SDGBuilder(this.graph); node.accept(sdgBuilder, null); } diff --git a/src/main/java/tfm/graphbuilding/GraphOptions.java b/src/main/java/tfm/graphbuilding/GraphOptions.java index b7d2486..31e7fe7 100644 --- a/src/main/java/tfm/graphbuilding/GraphOptions.java +++ b/src/main/java/tfm/graphbuilding/GraphOptions.java @@ -1,10 +1,10 @@ package tfm.graphbuilding; import com.github.javaparser.ast.Node; -import tfm.graphs.CFGGraph; +import tfm.graphs.CFG; import tfm.graphs.Graph; -import tfm.graphs.PDGGraph; -import tfm.graphs.SDGGraph; +import tfm.graphs.PDG; +import tfm.graphs.SDG; import tfm.visitors.cfg.CFGBuilder; import tfm.visitors.pdg.PDGBuilder; import tfm.visitors.sdg.SDGBuilder; @@ -23,41 +23,41 @@ public abstract class GraphOptions { protected abstract void buildGraphWithSpecificVisitor(G emptyGraph, Node node); } -class CFGOptions extends GraphOptions { +class CFGOptions extends GraphOptions { @Override - public CFGGraph empty() { - return new CFGGraph(); + public CFG empty() { + return new CFG(); } @Override - protected void buildGraphWithSpecificVisitor(CFGGraph emptyGraph, Node node) { + protected void buildGraphWithSpecificVisitor(CFG emptyGraph, Node node) { node.accept(new CFGBuilder(emptyGraph), null); } } -class PDGOptions extends GraphOptions { +class PDGOptions extends GraphOptions { @Override - public PDGGraph empty() { - return new PDGGraph(); + public PDG empty() { + return new PDG(); } @Override - protected void buildGraphWithSpecificVisitor(PDGGraph emptyGraph, Node node) { + protected void buildGraphWithSpecificVisitor(PDG emptyGraph, Node node) { node.accept(new PDGBuilder(emptyGraph), null); } } -class SDGOptions extends GraphOptions { +class SDGOptions extends GraphOptions { @Override - public SDGGraph empty() { - return new SDGGraph(); + public SDG empty() { + return new SDG(); } @Override - protected void buildGraphWithSpecificVisitor(SDGGraph emptyGraph, Node node) { + protected void buildGraphWithSpecificVisitor(SDG emptyGraph, Node node) { node.accept(new SDGBuilder(emptyGraph), null); } } \ No newline at end of file diff --git a/src/main/java/tfm/graphbuilding/Graphs.java b/src/main/java/tfm/graphbuilding/Graphs.java index 235124c..548bfcd 100644 --- a/src/main/java/tfm/graphbuilding/Graphs.java +++ b/src/main/java/tfm/graphbuilding/Graphs.java @@ -1,13 +1,13 @@ package tfm.graphbuilding; -import tfm.graphs.CFGGraph; -import tfm.graphs.PDGGraph; -import tfm.graphs.SDGGraph; +import tfm.graphs.CFG; +import tfm.graphs.PDG; +import tfm.graphs.SDG; public class Graphs { - public static final GraphOptions CFG = new CFGOptions(); - public static final GraphOptions PDG = new PDGOptions(); - public static final GraphOptions SDG = new SDGOptions(); + public static final GraphOptions CFG = new CFGOptions(); + public static final GraphOptions PDG = new PDGOptions(); + public static final GraphOptions SDG = new SDGOptions(); } \ No newline at end of file diff --git a/src/main/java/tfm/graphs/CFGGraph.java b/src/main/java/tfm/graphs/CFG.java similarity index 89% rename from src/main/java/tfm/graphs/CFGGraph.java rename to src/main/java/tfm/graphs/CFG.java index 445fcb4..3677921 100644 --- a/src/main/java/tfm/graphs/CFGGraph.java +++ b/src/main/java/tfm/graphs/CFG.java @@ -1,8 +1,6 @@ package tfm.graphs; import com.github.javaparser.ast.body.MethodDeclaration; -import com.github.javaparser.ast.stmt.EmptyStmt; -import org.jgrapht.io.DOTExporter; import tfm.arcs.Arc; import tfm.arcs.cfg.ControlFlowArc; import tfm.nodes.GraphNode; @@ -12,9 +10,9 @@ import java.util.HashSet; import java.util.Objects; import java.util.Set; -public class CFGGraph extends GraphWithRootNode { +public class CFG extends GraphWithRootNode { - public CFGGraph() { + public CFG() { super(); } diff --git a/src/main/java/tfm/graphs/PDGGraph.java b/src/main/java/tfm/graphs/PDG.java similarity index 79% rename from src/main/java/tfm/graphs/PDGGraph.java rename to src/main/java/tfm/graphs/PDG.java index a19a9c4..98fad8e 100644 --- a/src/main/java/tfm/graphs/PDGGraph.java +++ b/src/main/java/tfm/graphs/PDG.java @@ -2,7 +2,6 @@ package tfm.graphs; import com.github.javaparser.ast.Node; import com.github.javaparser.ast.body.MethodDeclaration; -import org.jgrapht.io.DOTExporter; import tfm.arcs.Arc; import tfm.arcs.pdg.ControlDependencyArc; import tfm.arcs.pdg.DataDependencyArc; @@ -13,19 +12,21 @@ import tfm.utils.Logger; import tfm.utils.NodeNotFoundException; import tfm.visitors.pdg.PDGBuilder; -import java.util.*; +import java.util.HashSet; +import java.util.Optional; +import java.util.Set; -public class PDGGraph extends GraphWithRootNode implements Sliceable { +public class PDG extends GraphWithRootNode implements Sliceable { - private CFGGraph cfgGraph; + private CFG cfg; - public PDGGraph() { + public PDG() { super(); } - public PDGGraph(CFGGraph cfgGraph) { + public PDG(CFG cfg) { super(); - this.cfgGraph = cfgGraph; + this.cfg = cfg; } public void addControlDependencyArc(GraphNode from, GraphNode to) { @@ -36,12 +37,12 @@ public class PDGGraph extends GraphWithRootNode implements Sl this.addEdge(from, to, new DataDependencyArc(variable)); } - public void setCfgGraph(CFGGraph cfgGraph) { - this.cfgGraph = cfgGraph; + public void setCfg(CFG cfg) { + this.cfg = cfg; } @Override - public PDGGraph slice(SlicingCriterion slicingCriterion) { + public PDG slice(SlicingCriterion slicingCriterion) { Optional> optionalGraphNode = slicingCriterion.findNode(this); if (!optionalGraphNode.isPresent()) { @@ -53,7 +54,7 @@ public class PDGGraph extends GraphWithRootNode implements Sl // Simply get slice nodes from GraphNode Set sliceNodes = getSliceNodes(new HashSet<>(), node); - PDGGraph sliceGraph = new PDGGraph(); + PDG sliceGraph = new PDG(); Node astCopy = ASTUtils.cloneAST(node.getAstNode()); @@ -86,7 +87,7 @@ public class PDGGraph extends GraphWithRootNode implements Sl return visited; } - public CFGGraph getCfgGraph() { - return cfgGraph; + public CFG getCfg() { + return cfg; } } diff --git a/src/main/java/tfm/graphs/SDGGraph.java b/src/main/java/tfm/graphs/SDG.java similarity index 81% rename from src/main/java/tfm/graphs/SDGGraph.java rename to src/main/java/tfm/graphs/SDG.java index 6da8faf..6ba940e 100644 --- a/src/main/java/tfm/graphs/SDGGraph.java +++ b/src/main/java/tfm/graphs/SDG.java @@ -3,8 +3,6 @@ package tfm.graphs; import com.github.javaparser.ast.body.MethodDeclaration; import com.github.javaparser.ast.body.Parameter; import com.github.javaparser.ast.stmt.EmptyStmt; -import org.jgrapht.io.DOTExporter; -import tfm.arcs.Arc; import tfm.nodes.GraphNode; import tfm.nodes.NodeFactory; import tfm.slicing.SlicingCriterion; @@ -16,20 +14,20 @@ import java.util.Map; import java.util.Set; import java.util.stream.Collectors; -public class SDGGraph extends Graph implements Sliceable { +public class SDG extends Graph implements Sliceable { - private Map contextPDGGraphMap; + private Map contextPDGGraphMap; - public SDGGraph() { + public SDG() { this.contextPDGGraphMap = new HashMap<>(); } @Override - public SDGGraph slice(SlicingCriterion slicingCriterion) { + public SDG slice(SlicingCriterion slicingCriterion) { throw new IllegalStateException("Not implemented (yet)"); } - public Map getContextPDGGraphMap() { + public Map getContextPDGGraphMap() { return contextPDGGraphMap; } @@ -44,12 +42,12 @@ public class SDGGraph extends Graph implements Sliceable { .collect(Collectors.toSet()); } - public Collection getPDGs() { + public Collection getPDGs() { return contextPDGGraphMap.values(); } @Deprecated - public void addPDG(PDGGraph pdgGraph, MethodDeclaration methodDeclaration) { + public void addPDG(PDG pdg, MethodDeclaration methodDeclaration) { for (Parameter parameter : methodDeclaration.getParameters()) { GraphNode sdgNode = NodeFactory.graphNode( getNextVertexId(), @@ -60,7 +58,7 @@ public class SDGGraph extends Graph implements Sliceable { addVertex(sdgNode); } - for (GraphNode node : pdgGraph.vertexSet()) { + for (GraphNode node : pdg.vertexSet()) { if (!this.containsVertex(node)) { GraphNode sdgNode = NodeFactory.computedGraphNode( getNextVertexId(), @@ -76,7 +74,7 @@ public class SDGGraph extends Graph implements Sliceable { } } - public void addMethod(MethodDeclaration methodDeclaration, PDGGraph pdgGraph) { + public void addMethod(MethodDeclaration methodDeclaration, PDG pdg) { GraphNode methodRootNode = NodeFactory.graphNode( getNextVertexId(), "ENTER " + methodDeclaration.getDeclarationAsString(false, false, true), diff --git a/src/main/java/tfm/nodes/GraphNode.java b/src/main/java/tfm/nodes/GraphNode.java index 1afa440..c011359 100644 --- a/src/main/java/tfm/nodes/GraphNode.java +++ b/src/main/java/tfm/nodes/GraphNode.java @@ -2,12 +2,14 @@ package tfm.nodes; import com.github.javaparser.ast.Node; import com.github.javaparser.ast.stmt.Statement; -import org.checkerframework.checker.nullness.qual.NonNull; import org.jetbrains.annotations.NotNull; import tfm.utils.Utils; import tfm.variables.VariableExtractor; -import java.util.*; +import java.util.Collection; +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; /** * Immutable class that represents an AST node inside a CFG, PDG or SDG. @@ -42,7 +44,7 @@ public class GraphNode { GraphNode( int id, String instruction, - @NonNull N astNode, + @NotNull N astNode, Collection declaredVariables, Collection definedVariables, Collection usedVariables @@ -56,7 +58,7 @@ public class GraphNode { this.usedVariables = new HashSet<>(usedVariables); } - private void extractVariables(@NonNull Statement statement) { + private void extractVariables(@NotNull Statement statement) { new VariableExtractor() .setOnVariableDeclarationListener(this.declaredVariables::add) .setOnVariableDefinitionListener(this.definedVariables::add) diff --git a/src/main/java/tfm/nodes/NodeFactory.java b/src/main/java/tfm/nodes/NodeFactory.java index 92047af..7d4f96e 100644 --- a/src/main/java/tfm/nodes/NodeFactory.java +++ b/src/main/java/tfm/nodes/NodeFactory.java @@ -1,8 +1,6 @@ package tfm.nodes; import com.github.javaparser.ast.Node; -import org.checkerframework.checker.nullness.qual.NonNull; -import tfm.nodes.GraphNode; import java.util.Collection; import java.util.Objects; diff --git a/src/main/java/tfm/readme.md b/src/main/java/tfm/readme.md index 5ef10f6..9fd78a3 100644 --- a/src/main/java/tfm/readme.md +++ b/src/main/java/tfm/readme.md @@ -131,9 +131,9 @@ public PDGGraph getSlice(File program, SlicingCriterion slicingCriterion) { Node astRoot = JavaParser.parse(programFile); - PDGGraph pdgGraph = Graphs.PDG.fromASTNode(astRoot); + PDGGraph pdg = Graphs.PDG.fromASTNode(astRoot); - return pdgGraph.slice(slicingCriterion); + return pdg.slice(slicingCriterion); } ``` diff --git a/src/main/java/tfm/slicing/LineNumberCriterion.java b/src/main/java/tfm/slicing/LineNumberCriterion.java index 901bcc5..355398c 100644 --- a/src/main/java/tfm/slicing/LineNumberCriterion.java +++ b/src/main/java/tfm/slicing/LineNumberCriterion.java @@ -1,9 +1,9 @@ package tfm.slicing; import com.github.javaparser.ast.Node; -import tfm.graphs.CFGGraph; -import tfm.graphs.PDGGraph; -import tfm.graphs.SDGGraph; +import tfm.graphs.CFG; +import tfm.graphs.PDG; +import tfm.graphs.SDG; import tfm.nodes.GraphNode; import tfm.utils.Logger; @@ -20,12 +20,12 @@ public class LineNumberCriterion extends SlicingCriterion { } @Override - public Optional> findNode(CFGGraph graph) { + public Optional> findNode(CFG graph) { return Optional.empty(); } @Override - public Optional> findNode(PDGGraph graph) { + public Optional> findNode(PDG graph) { // find node by line number return graph.vertexSet().stream().filter(node -> { Node astNode = node.getAstNode(); @@ -43,7 +43,7 @@ public class LineNumberCriterion extends SlicingCriterion { } @Override - public Optional> findNode(SDGGraph graph) { + public Optional> findNode(SDG graph) { return Optional.empty(); } diff --git a/src/main/java/tfm/slicing/Slice.java b/src/main/java/tfm/slicing/Slice.java index 15b4f50..034c6ec 100644 --- a/src/main/java/tfm/slicing/Slice.java +++ b/src/main/java/tfm/slicing/Slice.java @@ -3,7 +3,7 @@ package tfm.slicing; import com.github.javaparser.JavaParser; import com.github.javaparser.ast.CompilationUnit; import tfm.exec.PDGLog; -import tfm.graphs.PDGGraph; +import tfm.graphs.PDG; import tfm.utils.Logger; import tfm.utils.Utils; import tfm.validation.PDGValidator; @@ -20,15 +20,15 @@ public class Slice { public static void main(String[] args) throws IOException { CompilationUnit compilationUnit = JavaParser.parse(new File(PROGRAM_FOLDER + PROGRAM_NAME + ".java")); - PDGGraph pdgGraph = new PDGGraph(); + PDG pdg = new PDG(); - compilationUnit.accept(new PDGBuilder(pdgGraph), null); + compilationUnit.accept(new PDGBuilder(pdg), null); Logger.log("=================="); Logger.log("= Starting slice ="); Logger.log("=================="); - PDGGraph sliced = pdgGraph.slice(new LineNumberCriterion(18, "x")); + PDG sliced = pdg.slice(new LineNumberCriterion(18, "x")); PDGLog pdgLog = new PDGLog(sliced); pdgLog.log(); diff --git a/src/main/java/tfm/slicing/SlicingCriterion.java b/src/main/java/tfm/slicing/SlicingCriterion.java index 2574071..b01c357 100644 --- a/src/main/java/tfm/slicing/SlicingCriterion.java +++ b/src/main/java/tfm/slicing/SlicingCriterion.java @@ -1,8 +1,8 @@ package tfm.slicing; -import tfm.graphs.CFGGraph; -import tfm.graphs.PDGGraph; -import tfm.graphs.SDGGraph; +import tfm.graphs.CFG; +import tfm.graphs.PDG; +import tfm.graphs.SDG; import tfm.nodes.GraphNode; import java.util.Optional; @@ -19,9 +19,9 @@ public abstract class SlicingCriterion { return variable; } - public abstract Optional> findNode(CFGGraph graph); - public abstract Optional> findNode(PDGGraph graph); - public abstract Optional> findNode(SDGGraph graph); + public abstract Optional> findNode(CFG graph); + public abstract Optional> findNode(PDG graph); + public abstract Optional> findNode(SDG graph); @Override public String toString() { diff --git a/src/main/java/tfm/validation/PDGValidator.java b/src/main/java/tfm/validation/PDGValidator.java index 2679189..43e0241 100644 --- a/src/main/java/tfm/validation/PDGValidator.java +++ b/src/main/java/tfm/validation/PDGValidator.java @@ -7,13 +7,10 @@ import com.github.javaparser.ast.NodeList; import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration; import com.github.javaparser.ast.body.MethodDeclaration; import com.github.javaparser.ast.body.Parameter; -import com.github.javaparser.ast.stmt.BlockStmt; -import com.github.javaparser.ast.stmt.Statement; import com.github.javaparser.ast.type.ArrayType; import com.github.javaparser.ast.type.VoidType; import com.github.javaparser.ast.visitor.VoidVisitorAdapter; -import tfm.graphs.PDGGraph; -import tfm.nodes.GraphNode; +import tfm.graphs.PDG; import tfm.utils.Logger; import tfm.utils.Utils; import tfm.visitors.pdg.PDGBuilder; @@ -21,7 +18,6 @@ import tfm.visitors.pdg.PDGBuilder; import java.io.File; import java.io.FileNotFoundException; import java.io.PrintWriter; -import java.util.Comparator; import java.util.Objects; import java.util.Optional; @@ -63,21 +59,21 @@ public class PDGValidator { } public static boolean generateAndCheck(MethodDeclaration methodDeclaration) { - PDGGraph graph = new PDGGraph(); + PDG graph = new PDG(); methodDeclaration.accept(new PDGBuilder(graph), null); return check(methodDeclaration, graph); } - public static boolean check(MethodDeclaration methodDeclaration, PDGGraph graph) { + public static boolean check(MethodDeclaration methodDeclaration, PDG graph) { MethodDeclaration generatedMethod = generateMethod(methodDeclaration, graph); return ProgramComparator.areEqual(methodDeclaration, generatedMethod); } @Deprecated - public static MethodDeclaration generateMethod(MethodDeclaration info, PDGGraph graph) { + public static MethodDeclaration generateMethod(MethodDeclaration info, PDG graph) { // TODO: this does not work properly, replace or remove throw new IllegalStateException("Deprecated method"); // MethodDeclaration methodDeclaration = new MethodDeclaration(); @@ -97,7 +93,7 @@ public class PDGValidator { // return methodDeclaration; } - public static void printPDGProgram(String fileName, PDGGraph graph) throws FileNotFoundException { + public static void printPDGProgram(String fileName, PDG graph) throws FileNotFoundException { CompilationUnit generatedProgram = new CompilationUnit(); ClassOrInterfaceDeclaration clazz = generatedProgram.addClass(fileName).setPublic(true); diff --git a/src/main/java/tfm/visitors/cfg/CFGBuilder.java b/src/main/java/tfm/visitors/cfg/CFGBuilder.java index c0ba5d5..b3ea34c 100644 --- a/src/main/java/tfm/visitors/cfg/CFGBuilder.java +++ b/src/main/java/tfm/visitors/cfg/CFGBuilder.java @@ -5,7 +5,7 @@ import com.github.javaparser.ast.expr.BooleanLiteralExpr; import com.github.javaparser.ast.expr.Expression; import com.github.javaparser.ast.stmt.*; import com.github.javaparser.ast.visitor.VoidVisitorAdapter; -import tfm.graphs.CFGGraph; +import tfm.graphs.CFG; import tfm.nodes.GraphNode; import tfm.utils.ASTUtils; @@ -13,12 +13,12 @@ import java.util.*; public class CFGBuilder extends VoidVisitorAdapter { - private CFGGraph graph; + private CFG graph; private Queue> lastParentNodes; private List> bodyBreaks; - public CFGBuilder(CFGGraph graph) { + public CFGBuilder(CFG graph) { this.graph = graph; this.lastParentNodes = Collections.asLifoQueue(new ArrayDeque<>()); diff --git a/src/main/java/tfm/visitors/pdg/ControlDependencyBuilder.java b/src/main/java/tfm/visitors/pdg/ControlDependencyBuilder.java index f4ee2b8..75c1b1e 100644 --- a/src/main/java/tfm/visitors/pdg/ControlDependencyBuilder.java +++ b/src/main/java/tfm/visitors/pdg/ControlDependencyBuilder.java @@ -2,20 +2,20 @@ package tfm.visitors.pdg; import com.github.javaparser.ast.stmt.*; import com.github.javaparser.ast.visitor.VoidVisitorAdapter; -import tfm.graphs.CFGGraph; -import tfm.graphs.PDGGraph; +import tfm.graphs.CFG; +import tfm.graphs.PDG; import tfm.nodes.GraphNode; import java.util.stream.Collectors; public class ControlDependencyBuilder extends VoidVisitorAdapter> { - private CFGGraph cfgGraph; - private PDGGraph pdgGraph; + private CFG cfg; + private PDG pdg; - public ControlDependencyBuilder(PDGGraph pdgGraph, CFGGraph cfgGraph) { - this.pdgGraph = pdgGraph; - this.cfgGraph = cfgGraph; + public ControlDependencyBuilder(PDG pdg, CFG cfg) { + this.pdg = pdg; + this.cfg = cfg; } @Override @@ -54,12 +54,12 @@ public class ControlDependencyBuilder extends VoidVisitorAdapter> { .orElse("true"); - GraphNode forNode = pdgGraph.addNode( + GraphNode forNode = pdg.addNode( String.format("for (%s;%s;%s)", initialization, compare, update), forStmt ); - pdgGraph.addControlDependencyArc(parent, forNode); + pdg.addControlDependencyArc(parent, forNode); forStmt.getBody().accept(this, forNode); } @@ -86,9 +86,9 @@ public class ControlDependencyBuilder extends VoidVisitorAdapter> { } private GraphNode addNodeAndControlDependency(Statement statement, GraphNode parent) { - GraphNode cfgNode = cfgGraph.findNodeByASTNode(statement).get(); - GraphNode node = pdgGraph.addNode(cfgNode.getInstruction(), cfgNode.getAstNode()); - pdgGraph.addControlDependencyArc(parent, node); + GraphNode cfgNode = cfg.findNodeByASTNode(statement).get(); + GraphNode node = pdg.addNode(cfgNode.getInstruction(), cfgNode.getAstNode()); + pdg.addControlDependencyArc(parent, node); return node; } diff --git a/src/main/java/tfm/visitors/pdg/DataDependencyBuilder.java b/src/main/java/tfm/visitors/pdg/DataDependencyBuilder.java index d7bd5f1..786abca 100644 --- a/src/main/java/tfm/visitors/pdg/DataDependencyBuilder.java +++ b/src/main/java/tfm/visitors/pdg/DataDependencyBuilder.java @@ -2,8 +2,8 @@ package tfm.visitors.pdg; import com.github.javaparser.ast.stmt.*; import com.github.javaparser.ast.visitor.VoidVisitorAdapter; -import tfm.graphs.CFGGraph; -import tfm.graphs.PDGGraph; +import tfm.graphs.CFG; +import tfm.graphs.PDG; import tfm.nodes.GraphNode; import tfm.variables.VariableExtractor; @@ -12,12 +12,12 @@ import java.util.Set; public class DataDependencyBuilder extends VoidVisitorAdapter { - private CFGGraph cfgGraph; - private PDGGraph pdgGraph; + private CFG cfg; + private PDG pdg; - public DataDependencyBuilder(PDGGraph pdgGraph, CFGGraph cfgGraph) { - this.pdgGraph = pdgGraph; - this.cfgGraph = cfgGraph; + public DataDependencyBuilder(PDG pdg, CFG cfg) { + this.pdg = pdg; + this.cfg = cfg; } @Override @@ -43,7 +43,7 @@ public class DataDependencyBuilder extends VoidVisitorAdapter { @Override public void visit(ForStmt forStmt, Void ignored) { - GraphNode forNode = pdgGraph.findNodeByASTNode(forStmt).get(); + GraphNode forNode = pdg.findNodeByASTNode(forStmt).get(); forStmt.getInitialization().stream() .map(ExpressionStmt::new) @@ -80,7 +80,7 @@ public class DataDependencyBuilder extends VoidVisitorAdapter { } private void buildDataDependency(Statement statement) { - buildDataDependency(pdgGraph.findNodeByASTNode(statement).get()); + buildDataDependency(pdg.findNodeByASTNode(statement).get()); } private void buildDataDependency(GraphNode node) { @@ -88,7 +88,7 @@ public class DataDependencyBuilder extends VoidVisitorAdapter { .setOnVariableUseListener(variable -> { node.addUsedVariable(variable); - Optional> nodeOptional = cfgGraph.findNodeByASTNode(node.getAstNode()); + Optional> nodeOptional = cfg.findNodeByASTNode(node.getAstNode()); if (!nodeOptional.isPresent()) { return; @@ -96,11 +96,11 @@ public class DataDependencyBuilder extends VoidVisitorAdapter { GraphNode cfgNode = nodeOptional.get(); - Set> lastDefinitions = cfgGraph.findLastDefinitionsFrom(cfgNode, variable); + Set> lastDefinitions = cfg.findLastDefinitionsFrom(cfgNode, variable); for (GraphNode definitionNode : lastDefinitions) { - pdgGraph.findNodeByASTNode(definitionNode.getAstNode()) - .ifPresent(pdgNode -> pdgGraph.addDataDependencyArc(pdgNode, node, variable)); + pdg.findNodeByASTNode(definitionNode.getAstNode()) + .ifPresent(pdgNode -> pdg.addDataDependencyArc(pdgNode, node, variable)); } }) .setOnVariableDefinitionListener(node::addDefinedVariable) @@ -114,13 +114,13 @@ public class DataDependencyBuilder extends VoidVisitorAdapter { .setOnVariableUseListener(variable -> { forNode.addUsedVariable(variable); - Optional> nodeOptional = cfgGraph.findNodeByASTNode(statement); + Optional> nodeOptional = cfg.findNodeByASTNode(statement); if (!nodeOptional.isPresent()) { return; } - pdgGraph.addDataDependencyArc(forNode, forNode, variable); + pdg.addDataDependencyArc(forNode, forNode, variable); }) .setOnVariableDefinitionListener(forNode::addDefinedVariable) .setOnVariableDeclarationListener(forNode::addDeclaredVariable) diff --git a/src/main/java/tfm/visitors/pdg/PDGBuilder.java b/src/main/java/tfm/visitors/pdg/PDGBuilder.java index 09ad2f8..104294a 100644 --- a/src/main/java/tfm/visitors/pdg/PDGBuilder.java +++ b/src/main/java/tfm/visitors/pdg/PDGBuilder.java @@ -3,45 +3,45 @@ package tfm.visitors.pdg; import com.github.javaparser.ast.body.MethodDeclaration; import com.github.javaparser.ast.stmt.BlockStmt; import com.github.javaparser.ast.visitor.VoidVisitorAdapter; -import tfm.graphs.CFGGraph; -import tfm.graphs.PDGGraph; +import tfm.graphs.CFG; +import tfm.graphs.PDG; import tfm.visitors.cfg.CFGBuilder; public class PDGBuilder extends VoidVisitorAdapter { - private PDGGraph pdgGraph; - private CFGGraph cfgGraph; + private PDG pdg; + private CFG cfg; - public PDGBuilder(PDGGraph pdgGraph) { - this(pdgGraph, new CFGGraph()); + public PDGBuilder(PDG pdg) { + this(pdg, new CFG()); } - public PDGBuilder(PDGGraph pdgGraph, CFGGraph cfgGraph) { - this.pdgGraph = pdgGraph; - this.cfgGraph = cfgGraph; + public PDGBuilder(PDG pdg, CFG cfg) { + this.pdg = pdg; + this.cfg = cfg; - this.pdgGraph.setCfgGraph(cfgGraph); + this.pdg.setCfg(cfg); } public void visit(MethodDeclaration methodDeclaration, Void empty) { if (!methodDeclaration.getBody().isPresent()) return; - this.pdgGraph.buildRootNode("ENTER " + methodDeclaration.getNameAsString(), methodDeclaration); + this.pdg.buildRootNode("ENTER " + methodDeclaration.getNameAsString(), methodDeclaration); - assert this.pdgGraph.getRootNode().isPresent(); + assert this.pdg.getRootNode().isPresent(); // build CFG - methodDeclaration.accept(new CFGBuilder(cfgGraph), null); + methodDeclaration.accept(new CFGBuilder(cfg), null); BlockStmt methodBody = methodDeclaration.getBody().get(); // Build control dependency - ControlDependencyBuilder controlDependencyBuilder = new ControlDependencyBuilder(pdgGraph, cfgGraph); - methodBody.accept(controlDependencyBuilder, pdgGraph.getRootNode().get()); + ControlDependencyBuilder controlDependencyBuilder = new ControlDependencyBuilder(pdg, cfg); + methodBody.accept(controlDependencyBuilder, pdg.getRootNode().get()); // Build data dependency - DataDependencyBuilder dataDependencyBuilder = new DataDependencyBuilder(pdgGraph, cfgGraph); + DataDependencyBuilder dataDependencyBuilder = new DataDependencyBuilder(pdg, cfg); methodBody.accept(dataDependencyBuilder, null); } } diff --git a/src/main/java/tfm/visitors/sdg/MethodCallReplacer.java b/src/main/java/tfm/visitors/sdg/MethodCallReplacer.java index 93137fd..4613134 100644 --- a/src/main/java/tfm/visitors/sdg/MethodCallReplacer.java +++ b/src/main/java/tfm/visitors/sdg/MethodCallReplacer.java @@ -1,17 +1,17 @@ package tfm.visitors.sdg; -import tfm.graphs.SDGGraph; +import tfm.graphs.SDG; public class MethodCallReplacer { - private SDGGraph sdgGraph; + private SDG sdg; - public MethodCallReplacer(SDGGraph sdgGraph) { - this.sdgGraph = sdgGraph; + public MethodCallReplacer(SDG sdg) { + this.sdg = sdg; } public void replace() { - this.sdgGraph.getContextPDGGraphMap() + this.sdg.getContextPDGGraphMap() .forEach((context, pdgGraph) -> { if (!context.getCurrentMethod().isPresent()) { return; // Should NOT happen diff --git a/src/main/java/tfm/visitors/sdg/MethodCallReplacerVisitor.java b/src/main/java/tfm/visitors/sdg/MethodCallReplacerVisitor.java index eb32ef0..1eec815 100644 --- a/src/main/java/tfm/visitors/sdg/MethodCallReplacerVisitor.java +++ b/src/main/java/tfm/visitors/sdg/MethodCallReplacerVisitor.java @@ -9,7 +9,7 @@ import com.github.javaparser.ast.expr.VariableDeclarationExpr; import com.github.javaparser.ast.stmt.ExpressionStmt; import com.github.javaparser.ast.type.Type; import com.github.javaparser.ast.visitor.VoidVisitorAdapter; -import tfm.graphs.PDGGraph; +import tfm.graphs.PDG; import tfm.nodes.GraphNode; import tfm.utils.Context; import tfm.utils.Logger; @@ -21,10 +21,10 @@ import java.util.stream.Collectors; public class MethodCallReplacerVisitor extends VoidVisitorAdapter { - private PDGGraph pdgGraph; + private PDG pdg; - public MethodCallReplacerVisitor(PDGGraph pdgGraph) { - this.pdgGraph = pdgGraph; + public MethodCallReplacerVisitor(PDG pdg) { + this.pdg = pdg; } @Override @@ -57,7 +57,7 @@ public class MethodCallReplacerVisitor extends VoidVisitorAdapter { if (!Objects.equals(scopeName, currentClass.getNameAsString())) { // Check if 'scopeName' is a variable - List> declarations = pdgGraph.findDeclarationsOfVariable(scopeName); + List> declarations = pdg.findDeclarationsOfVariable(scopeName); if (declarations.isEmpty()) { // It is a static method call of another class. We do nothing diff --git a/src/main/java/tfm/visitors/sdg/NewSDGBuilder.java b/src/main/java/tfm/visitors/sdg/NewSDGBuilder.java index 3e81151..bf510e0 100644 --- a/src/main/java/tfm/visitors/sdg/NewSDGBuilder.java +++ b/src/main/java/tfm/visitors/sdg/NewSDGBuilder.java @@ -5,16 +5,16 @@ import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration; import com.github.javaparser.ast.body.MethodDeclaration; import com.github.javaparser.ast.visitor.VoidVisitorAdapter; import tfm.graphbuilding.Graphs; -import tfm.graphs.PDGGraph; -import tfm.graphs.SDGGraph; +import tfm.graphs.PDG; +import tfm.graphs.SDG; import tfm.utils.Context; public class NewSDGBuilder extends VoidVisitorAdapter { - SDGGraph sdgGraph; + SDG sdg; - public NewSDGBuilder(SDGGraph sdgGraph) { - this.sdgGraph = sdgGraph; + public NewSDGBuilder(SDG sdg) { + this.sdg = sdg; } @Override @@ -26,9 +26,9 @@ public class NewSDGBuilder extends VoidVisitorAdapter { context.setCurrentMethod(methodDeclaration); // Build PDG and add to SDGGraph - PDGGraph pdgGraph = Graphs.PDG.fromASTNode(methodDeclaration); + PDG pdg = Graphs.PDG.fromASTNode(methodDeclaration); - sdgGraph.addMethod(methodDeclaration, pdgGraph); + sdg.addMethod(methodDeclaration, pdg); } @Override @@ -51,7 +51,7 @@ public class NewSDGBuilder extends VoidVisitorAdapter { // Once every PDG is built, expand method call nodes of each one // and link them to the corresponding method declaration node - MethodCallReplacer methodCallReplacer = new MethodCallReplacer(sdgGraph); + MethodCallReplacer methodCallReplacer = new MethodCallReplacer(sdg); methodCallReplacer.replace(); diff --git a/src/main/java/tfm/visitors/sdg/SDGBuilder.java b/src/main/java/tfm/visitors/sdg/SDGBuilder.java index 9662844..dabf2fd 100644 --- a/src/main/java/tfm/visitors/sdg/SDGBuilder.java +++ b/src/main/java/tfm/visitors/sdg/SDGBuilder.java @@ -11,8 +11,8 @@ import com.github.javaparser.ast.stmt.ExpressionStmt; import com.github.javaparser.ast.stmt.Statement; import com.github.javaparser.ast.type.Type; import com.github.javaparser.ast.visitor.VoidVisitorAdapter; -import tfm.graphs.PDGGraph; -import tfm.graphs.SDGGraph; +import tfm.graphs.PDG; +import tfm.graphs.SDG; import tfm.nodes.GraphNode; import tfm.visitors.pdg.PDGBuilder; @@ -28,15 +28,15 @@ import java.util.Optional; */ public class SDGBuilder extends VoidVisitorAdapter { - SDGGraph sdgGraph; - List pdgGraphs; + SDG sdg; + List pdgs; private ClassOrInterfaceDeclaration currentClass; private CompilationUnit currentCompilationUnit; - public SDGBuilder(SDGGraph sdgGraph) { - this.sdgGraph = sdgGraph; - this.pdgGraphs = new ArrayList<>(); + public SDGBuilder(SDG sdg) { + this.sdg = sdg; + this.pdgs = new ArrayList<>(); } @Override @@ -45,15 +45,15 @@ public class SDGBuilder extends VoidVisitorAdapter { return; - if (sdgGraph.isEmpty()) { - sdgGraph.addNode("ENTER " + methodDeclaration.getNameAsString(), methodDeclaration); + if (sdg.isEmpty()) { + sdg.addNode("ENTER " + methodDeclaration.getNameAsString(), methodDeclaration); } else { // sdgGraph.addMethod(methodDeclaration); } - PDGGraph pdgGraph = new PDGGraph(); + PDG pdg = new PDG(); - PDGBuilder PDGBuilder = new PDGBuilder(pdgGraph) { + PDGBuilder PDGBuilder = new PDGBuilder(pdg) { @Override public void visit(MethodCallExpr methodCallExpr, Void empty) { if (methodCallExpr.getScope().isPresent()) { @@ -65,7 +65,7 @@ public class SDGBuilder extends VoidVisitorAdapter { if (!Objects.equals(scopeName, currentClassName)) { // Check if 'scopeName' is a variable - List> declarations = sdgGraph.findDeclarationsOfVariable(scopeName); + List> declarations = sdg.findDeclarationsOfVariable(scopeName); if (declarations.isEmpty()) { // It is a static method call of another class. We don't do anything @@ -114,9 +114,9 @@ public class SDGBuilder extends VoidVisitorAdapter { PDGBuilder.visit(methodDeclaration, null); - sdgGraph.addNode(methodDeclaration.getNameAsString(), methodDeclaration); + sdg.addNode(methodDeclaration.getNameAsString(), methodDeclaration); - pdgGraph.vertexSet().stream().skip(1).forEach(pdgNode -> { + pdg.vertexSet().stream().skip(1).forEach(pdgNode -> { Statement statement = (Statement) pdgNode.getAstNode(); if (statement.isExpressionStmt()) { @@ -134,11 +134,11 @@ public class SDGBuilder extends VoidVisitorAdapter { - sdgGraph.addPDG(pdgGraph, methodDeclaration); + sdg.addPDG(pdg, methodDeclaration); methodDeclaration.accept(this, ignored); - pdgGraphs.add(pdgGraph); + pdgs.add(pdg); } @Override -- GitLab From 2b465f8db94b4c923d3eac9fb7c32eef103579e9 Mon Sep 17 00:00:00 2001 From: Carlos Galindo Date: Thu, 23 Jan 2020 14:55:32 +0100 Subject: [PATCH 9/9] Updated readme.md with the changes to the API Deleted copy of readme.md in ./src/main/java/tfm --- readme.md | 54 ++++++++----- src/main/java/tfm/readme.md | 153 ------------------------------------ 2 files changed, 35 insertions(+), 172 deletions(-) delete mode 100644 src/main/java/tfm/readme.md diff --git a/readme.md b/readme.md index 9fd78a3..357cd4e 100644 --- a/readme.md +++ b/readme.md @@ -34,9 +34,9 @@ Find `Slice` class (`tfm/slicing`), set the program path and execute. The sliced ## Structure -Graphs are built using a library called `graphlib`, located in `lib/graphlib.jar`. This library is old and has some issues I had to fix... +Graphs are built using a library called `JGraphT`. -The main class is the `Graph` class, which extends from `graphlib`'s `Graph` class. This class includes some behaviour fixes, and some general interest methods (like `toString`, `toGraphvizRepresentation`, etc.) +The main class is the `Graph` class, which extends from `JGraphT`'s `DefaultDirectedGraph` class. This class includes some general interest methods (like `toString`, etc.) Every graph has a set of nodes and arrows. `GraphNode` and `Arc` classes are used to represent them respectively. @@ -104,7 +104,7 @@ Forget about the `tfm/scopes` folder, it was an idea I had to discard and it has ### General -- Switch to a (much) better graph library like [JGraphT](https://jgrapht.org/). It also supports graph visualization +- Switch to a (much) better graph library like [JGraphT](https://jgrapht.org/). It also supports graph visualization (done). - Performance review - Make a test suite (test graph building, slicing, etc.) - Add support to more Java language features (lambdas, etc.) @@ -114,28 +114,44 @@ Forget about the `tfm/scopes` folder, it was an idea I had to discard and it has ### Build a CFG from a program ```java -public CFGGraph buildCFG(File programFile) { - JavaParser.getStaticConfiguration().setAttributeComments(false); // Always disable comments, just in case - - Node astRoot = JavaParser.parse(programFile); - - return Graphs.CFG.fromASTNode(astRoot); // Creates a new graph representing the program +public class Example { + public CFG buildCFG(File programFile) { + // Always disable attribution of comments, just in case + JavaParser.getStaticConfiguration().setAttributeComments(false); + + Node astRoot = JavaParser.parse(programFile); + Optional optMethod = astRoot.findFirst(MethodDeclaration.class); + if (!optMethod.isPresent) + throw new RuntimeException("No method could be found"); + + // Creates a new graph representing the program + CFG cfg = new CFG(); + cfg.build(optMethod.get()); + return cfg; + } } ``` ### Get a slice of the PDG of a program ```java -public PDGGraph getSlice(File program, SlicingCriterion slicingCriterion) { - JavaParser.getStaticConfiguration().setAttributeComments(false); // Always disable comments, just in case - - Node astRoot = JavaParser.parse(programFile); - - PDGGraph pdg = Graphs.PDG.fromASTNode(astRoot); - - return pdg.slice(slicingCriterion); +public class Example { + public PDGGraph getSlice(File program, SlicingCriterion slicingCriterion) { + // Always disable attribution of comments, just in case + JavaParser.getStaticConfiguration().setAttributeComments(false); + + Node astRoot = JavaParser.parse(programFile); + Optional optMethod = astRoot.findFirst(MethodDeclaration.class); + if (!optMethod.isPresent) + throw new RuntimeException("No method could be found"); + + // Creates a new graph representing the program + PDG pdg = new PDG(); + pdg.build(optMethod.get()); + // Slice PDG + return pdg.slice(slicingCriterion); + } } - ``` ## Workflow @@ -143,7 +159,7 @@ public PDGGraph getSlice(File program, SlicingCriterion slicingCriterion) { - Branches: - `master` (only for stable versions) - `develop` (main branch) - - `` + - `-name` 1. Discover a new feature/fix 2. Open an issue describing it and assign it diff --git a/src/main/java/tfm/readme.md b/src/main/java/tfm/readme.md deleted file mode 100644 index 9fd78a3..0000000 --- a/src/main/java/tfm/readme.md +++ /dev/null @@ -1,153 +0,0 @@ -# TFM - -- [TFM](#tfm) - - [Introduction](#introduction) - - [Quick start](#quick-start) - - [Build a graph](#build-a-graph) - - [Slice a program](#slice-a-program) - - [Structure](#structure) - - [Summary](#summary) - - [Current state](#current-state) - - [Graphs](#graphs) - - [Statements covered](#statements-covered) - - [To do list](#to-do-list) - - [SDG](#sdg) - - [General](#general) - - [Code samples](#code-samples) - - [Build a CFG from a program](#build-a-cfg-from-a-program) - - [Get a slice of the PDG of a program](#get-a-slice-of-the-pdg-of-a-program) - - [Workflow](#workflow) - -## Introduction - -The main goal of this work is to develop a Java slicer. This is done by building a System Dependence Graph of the program being sliced - -## Quick start - -### Build a graph - -Find `Main` class (`tfm/exec`), modify static fields of the class (the program being analyzed, the graph to build, etc.) and execute it. You will find the output in `tfm/out` as a png image - -### Slice a program - -Find `Slice` class (`tfm/slicing`), set the program path and execute. The sliced program will be in `tfm/out` - -## Structure - -Graphs are built using a library called `graphlib`, located in `lib/graphlib.jar`. This library is old and has some issues I had to fix... - -The main class is the `Graph` class, which extends from `graphlib`'s `Graph` class. This class includes some behaviour fixes, and some general interest methods (like `toString`, `toGraphvizRepresentation`, etc.) - -Every graph has a set of nodes and arrows. `GraphNode` and `Arc` classes are used to represent them respectively. - -A set of visitors is implemented for many things, such as graph building, data dependence building, etc... (available in `tfm/visitors`) - -A bunch of programs are written in `tfm/programs`, you can write more there. - -Some naive testing is implemented in the `tfm/validation` folder. Currently, a PDG can be compared with a program to check their equality. - -Some util methods are available in `tfm/utils` (such as AST utils, logger, etc.) - -Forget about the `tfm/scopes` folder, it was an idea I had to discard and it has to be deleted. - -### Summary - -- Graphs (`tfm/graphs`) - - CFGGraph - - PDGGraph - - SDGGraph - -- Nodes (`tfm/nodes`) - - ~~CFGNode, PDGNode, SDGNode~~ (_Deprecated_) - - GraphNode - - MethodCallNode (_idk if this is necessary, maybe it can be deleted_) - -- Arcs (`tfm/arcs`) - - ControlFlowArc - - DataDependencyArc - - ControlDependencyArc - -- Visitors (`tfm/visitors`) - - CFGBuilder - - ~~PDGVisitor~~ (_Deprecated, it was an intent to build a PDG with no CFG needed_) - - PDGBuilder - - ControlDependencyBuilder - - DataDependencyBuilder - - SDGBuilder (_Probably deprecated_) - - NewSDGBuilder -**Work in progress**- - - MethodCallReplacerVisitor (_Replaces method call nodes with in and out variable nodes_) -**Work in progress**- - -## Current state - -### Graphs - -- CFG: Done! -- PDG: Done! -- SDG: PDGs are built for each method - -### Statements covered - -- Expressions (ExpressionStmt) -- If (IfStmt) -- While, DoWhile (WhileStmt, DoStmt) -- For, Foreach (ForStmt, ForeachStmt) -- Switch (SwitchStmt, SwitchEntryStmt) -- Break (BreakStmt) -- Continue (ContinueStmt) - -## To do list - -### SDG - -- Replace method call nodes with in and out variables nodes and build arrows for them -- Build summary arrows - -### General - -- Switch to a (much) better graph library like [JGraphT](https://jgrapht.org/). It also supports graph visualization -- Performance review -- Make a test suite (test graph building, slicing, etc.) -- Add support to more Java language features (lambdas, etc.) - -## Code samples - -### Build a CFG from a program - -```java -public CFGGraph buildCFG(File programFile) { - JavaParser.getStaticConfiguration().setAttributeComments(false); // Always disable comments, just in case - - Node astRoot = JavaParser.parse(programFile); - - return Graphs.CFG.fromASTNode(astRoot); // Creates a new graph representing the program -} -``` - -### Get a slice of the PDG of a program - -```java -public PDGGraph getSlice(File program, SlicingCriterion slicingCriterion) { - JavaParser.getStaticConfiguration().setAttributeComments(false); // Always disable comments, just in case - - Node astRoot = JavaParser.parse(programFile); - - PDGGraph pdg = Graphs.PDG.fromASTNode(astRoot); - - return pdg.slice(slicingCriterion); -} - -``` - -## Workflow - -- Branches: - - `master` (only for stable versions) - - `develop` (main branch) - - `` - -1. Discover a new feature/fix -2. Open an issue describing it and assign it -4. Create a new branch from `develop` with the same name as the issue number (e.g. for issue #12 the new branch is called `12`) -5. Write the solution to the issue -6. Once resolved, open a pull request from the issue branch to `develop` branch -7. Finally, when pull request is merged, remove branch \ No newline at end of file -- GitLab