diff --git a/.gitignore b/.gitignore
index d947638b907cb3c9a1e887d86071337d19dfaf8a..77901fe0104c73e4efa7d26cd2a376b950baabd9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,3 +2,4 @@
.idea/
target/
out/
+.settings
\ No newline at end of file
diff --git a/lib/graphlib.jar b/lib/graphlib.jar
deleted file mode 100644
index cf0e9844307d1dff58335a2e6f3500c532f7d58d..0000000000000000000000000000000000000000
Binary files a/lib/graphlib.jar and /dev/null differ
diff --git a/pom.xml b/pom.xml
index 296359213f1fac45fc9721e94940f196b7fe0c0c..53b3a44c9465fe535cdba60083353e07c194728a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -21,7 +21,6 @@
-
com.github.javaparser
javaparser-symbol-solver-core
@@ -41,5 +40,17 @@
1.3.0
+
+ org.jgrapht
+ jgrapht-io
+ 1.3.0
+
+
+
+ org.junit.jupiter
+ junit-jupiter
+ 5.5.2
+ test
+
\ No newline at end of file
diff --git a/readme.md b/readme.md
index 5ef10f60754416053c5d780b1ec52590789b430d..357cd4e0835b30c81e5bf09981eec872f2e84540 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 pdgGraph = Graphs.PDG.fromASTNode(astRoot);
-
- return pdgGraph.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/arcs/Arc.java b/src/main/java/tfm/arcs/Arc.java
index 5c13d3195c683795b099ee0c71ef090f2def7ace..143c900bff50fe3ad595d65285a5e9b454ccb8f8 100644
--- a/src/main/java/tfm/arcs/Arc.java
+++ b/src/main/java/tfm/arcs/Arc.java
@@ -1,72 +1,79 @@
package tfm.arcs;
-import tfm.arcs.data.ArcData;
+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;
-public abstract class Arc extends edg.graphlib.Arrow {
+public abstract class Arc extends DefaultEdge {
+ public Arc() {
- @SuppressWarnings("unchecked")
- public Arc(GraphNode> from, GraphNode> to) {
- super((edg.graphlib.Vertex) from, (edg.graphlib.Vertex) to);
}
- public abstract boolean isControlFlowArrow();
+ public final boolean isControlFlowArc() {
+ return this instanceof ControlFlowArc;
+ }
- public abstract boolean isControlDependencyArrow();
+ public final ControlFlowArc asControlFlowArc() {
+ if (isControlFlowArc())
+ return (ControlFlowArc) this;
+ throw new UnsupportedOperationException("Not a ControlFlowArc");
+ }
- public abstract boolean isDataDependencyArrow();
+ public final boolean isControlDependencyArc() {
+ return this instanceof ControlDependencyArc;
+ }
- @Override
- public String toString() {
- return String.format("Arc{data: %s, %s -> %s}",
- getData(),
- getFrom(),
- getTo()
- );
+ public final ControlDependencyArc asControlDependencyArc() {
+ if (isControlDependencyArc())
+ return (ControlDependencyArc) this;
+ throw new UnsupportedOperationException("Not a ControlDependencyArc");
}
- public String toGraphvizRepresentation() {
- GraphNode from = (GraphNode) getFrom();
- GraphNode to = (GraphNode) getTo();
+ public final boolean isDataDependencyArc() {
+ return this instanceof DataDependencyArc;
+ }
- return String.format("%s -> %s",
- from.getId(),
- to.getId()
- );
+ public final DataDependencyArc asDataDependencyArc() {
+ if (isDataDependencyArc())
+ return (DataDependencyArc) this;
+ throw new UnsupportedOperationException("Not a DataDependencyArc");
}
- public GraphNode> getFromNode() {
- return (GraphNode>) super.getFrom();
+ @Override
+ public String toString() {
+ return String.format("%s{%d -> %d}", getClass().getName(),
+ ((GraphNode>) getSource()).getId(), ((GraphNode>) getTarget()).getId());
}
- public GraphNode> getToNode() {
- return (GraphNode>) super.getTo();
+ public String getLabel() {
+ return "";
}
- @Override
- public int hashCode() {
- return Objects.hashCode(getData()) + getFrom().hashCode() + getTo().hashCode();
+ public Map getDotAttributes() {
+ return new HashMap<>();
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
-
- if (!(o instanceof Arc))
+ 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());
+ }
- 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(arc.getData(), getData()) &&
- Objects.equals(from.getId(), from2.getId()) &&
- Objects.equals(to.getId(), to2.getId());
+ @Override
+ public int hashCode() {
+ 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 f51233cfc1ad6f95d811b1fb3190f999ecd95724..5abdda3f513886e271dff195af4677b682beb99f 100644
--- a/src/main/java/tfm/arcs/cfg/ControlFlowArc.java
+++ b/src/main/java/tfm/arcs/cfg/ControlFlowArc.java
@@ -1,36 +1,8 @@
package tfm.arcs.cfg;
import tfm.arcs.Arc;
-import tfm.arcs.data.VoidArcData;
-import tfm.nodes.GraphNode;
-public class ControlFlowArc extends Arc {
-
- public ControlFlowArc(GraphNode from, GraphNode to) {
- super(from, to);
- }
-
- @Override
- public boolean isControlFlowArrow() {
- return true;
- }
-
- @Override
- public boolean isControlDependencyArrow() {
- return false;
+public class ControlFlowArc extends Arc {
+ public ControlFlowArc() {
}
-
- @Override
- public boolean isDataDependencyArrow() {
- return false;
- }
-
- @Override
- public String toString() {
- return String.format("ControlFlowArc{%s -> %s}",
- getFromNode().getId(),
- getToNode().getId()
- );
- }
-
}
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 a20b654f32f84d4001f8670146e64a33ad7eb82a..0000000000000000000000000000000000000000
--- 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 0ce2e49edb6b108f47270114d13caac8484908f5..0000000000000000000000000000000000000000
--- 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 extends String> 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 de5d824192d9bf4a9797fabf66b2796b9f6a7ba6..0000000000000000000000000000000000000000
--- 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 6d7c79bb40b562485c9e4a97353937689cbe6df1..914401e3c55ed3612cd757342b017088e0024d83 100644
--- a/src/main/java/tfm/arcs/pdg/ControlDependencyArc.java
+++ b/src/main/java/tfm/arcs/pdg/ControlDependencyArc.java
@@ -1,35 +1,8 @@
package tfm.arcs.pdg;
import tfm.arcs.Arc;
-import tfm.arcs.data.ArcData;
-import tfm.nodes.GraphNode;
-public class ControlDependencyArc extends Arc {
-
- public ControlDependencyArc(GraphNode from, GraphNode to) {
- super(from, to);
- }
-
- @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 -> %s}",
- ((GraphNode) getFrom()).getId(),
- ((GraphNode) getTo()).getId()
- );
+public class ControlDependencyArc extends Arc {
+ public ControlDependencyArc() {
}
}
diff --git a/src/main/java/tfm/arcs/pdg/DataDependencyArc.java b/src/main/java/tfm/arcs/pdg/DataDependencyArc.java
index 11e8ac030217f4905feb05b3609d39ed8841fe1d..9806f85847b6de54dc562192e57daa831d6c5e05 100644
--- a/src/main/java/tfm/arcs/pdg/DataDependencyArc.java
+++ b/src/main/java/tfm/arcs/pdg/DataDependencyArc.java
@@ -1,54 +1,30 @@
package tfm.arcs.pdg;
+import org.jgrapht.io.Attribute;
+import org.jgrapht.io.DefaultAttribute;
import tfm.arcs.Arc;
-import tfm.arcs.data.VariableArcData;
-import tfm.nodes.GraphNode;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
+import java.util.Map;
-public class DataDependencyArc extends Arc {
+public class DataDependencyArc extends Arc {
+ private final String variable;
- 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);
-
- setData(variableArcData);
- }
-
- @Override
- public boolean isControlFlowArrow() {
- return false;
- }
-
- @Override
- public boolean isControlDependencyArrow() {
- return false;
- }
-
- @Override
- public boolean isDataDependencyArrow() {
- return true;
+ public DataDependencyArc(String variable) {
+ super();
+ this.variable = variable;
}
@Override
- public String toString() {
- return String.format("DataDependencyArc{%s, %s -> %s}",
- getData(),
- getFromNode().getId(),
- getToNode().getId());
+ public String getLabel() {
+ return variable;
}
@Override
- public String toGraphvizRepresentation() {
- return String.format("%s [style=dashed, color=red, label=\"%s\"];", super.toGraphvizRepresentation(), getData().toString());
+ 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/CFGLog.java b/src/main/java/tfm/exec/CFGLog.java
index e04a483c0f2649c6a2854ed04f02130706e62a7a..153728ac6904b45ef18a3a1c66d8423fa7424024 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/GraphLog.java b/src/main/java/tfm/exec/GraphLog.java
index a3d38faef6a4800ec543f5d5b7769d65df18df0d..43f39ad966c51ee0700c71d8b9225d423f3b7372 100644
--- a/src/main/java/tfm/exec/GraphLog.java
+++ b/src/main/java/tfm/exec/GraphLog.java
@@ -55,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 {
@@ -72,18 +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());
+ 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 9532105800151a0c67f1c4322b80bb0711468341..d604251a8879e21867f51d98f966b5f36ae878d7 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";
diff --git a/src/main/java/tfm/exec/PDGLog.java b/src/main/java/tfm/exec/PDGLog.java
index a712abe2f2386ee9c6785f4bc02bd210b832f2ae..991681d74e9c288d67c400f5b4c7d2359fb555a1 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), this.graph.getRootNode());
+ node.accept(new PDGBuilder(graph), null);
if (cfgLog == null) {
- cfgLog = new CFGLog(graph.getCfgGraph());
+ cfgLog = new CFGLog(graph.getCfg());
}
}
@@ -41,7 +42,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/exec/SDGLog.java b/src/main/java/tfm/exec/SDGLog.java
index b88de5468eabb9f24dc36c4af1265714eae365a5..702e7c91b061754f6607ea7430d27cc8eb1fa32b 100644
--- a/src/main/java/tfm/exec/SDGLog.java
+++ b/src/main/java/tfm/exec/SDGLog.java
@@ -1,16 +1,14 @@
package tfm.exec;
import com.github.javaparser.ast.Node;
-import tfm.graphs.SDGGraph;
+import tfm.graphs.SDG;
import tfm.visitors.sdg.SDGBuilder;
-import java.io.IOException;
-
-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 2884f49981f1d6ae9df2c8c7acb2ca617547a0ad..31e7fe754ca26faf578c38baf666196b550935d1 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) {
- node.accept(new PDGBuilder(emptyGraph), emptyGraph.getRootNode());
+ 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 235124ca06360392507b42ea2b01df5c844c2612..548bfcdeec1ef9873db218a8fca751cf0367bb37 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/CFG.java b/src/main/java/tfm/graphs/CFG.java
new file mode 100644
index 0000000000000000000000000000000000000000..36779212eb7ec03c3aab6fd8d9735f8868db6203
--- /dev/null
+++ b/src/main/java/tfm/graphs/CFG.java
@@ -0,0 +1,51 @@
+package tfm.graphs;
+
+import com.github.javaparser.ast.body.MethodDeclaration;
+import tfm.arcs.Arc;
+import tfm.arcs.cfg.ControlFlowArc;
+import tfm.nodes.GraphNode;
+import tfm.utils.NodeNotFoundException;
+
+import java.util.HashSet;
+import java.util.Objects;
+import java.util.Set;
+
+public class CFG extends GraphWithRootNode {
+
+ public CFG() {
+ super();
+ }
+
+ public void addControlFlowEdge(GraphNode> from, GraphNode> to) {
+ super.addEdge(from, to, new ControlFlowArc());
+ }
+
+ public Set> findLastDefinitionsFrom(GraphNode> startNode, String variable) {
+ 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());
+
+ Set> res = new HashSet<>();
+
+ for (Arc arc : incomingEdgesOf(currentNode)) {
+ ControlFlowArc controlFlowArc = arc.asControlFlowArc();
+
+ GraphNode> from = this.getEdgeSource(controlFlowArc);
+
+ if (!Objects.equals(startNode, from) && visited.contains(from.getId())) {
+ continue;
+ }
+
+ if (from.getDefinedVariables().contains(variable)) {
+ res.add(from);
+ } else {
+ res.addAll(findLastDefinitionsFrom(visited, startNode, from, variable));
+ }
+ }
+ return res;
+ }
+}
diff --git a/src/main/java/tfm/graphs/CFGGraph.java b/src/main/java/tfm/graphs/CFGGraph.java
deleted file mode 100644
index 8faf9e31b4e356a9e32abbd94c67aa4fcb3a1466..0000000000000000000000000000000000000000
--- a/src/main/java/tfm/graphs/CFGGraph.java
+++ /dev/null
@@ -1,114 +0,0 @@
-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;
-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 Graph {
-
- public CFGGraph() {
- super();
- setRootVertex(new GraphNode<>(getNextVertexId(), getRootNodeData(), new EmptyStmt()));
- }
-
- @Override
- public GraphNode addNode(String instruction, ASTNode node) {
- GraphNode vertex = new GraphNode<>(getNextVertexId(), instruction, node);
- this.addVertex(vertex);
-
- return vertex;
- }
-
-
- protected String getRootNodeData() {
- return "Start";
- }
-
- @SuppressWarnings("unchecked")
- public void addControlFlowEdge(GraphNode from, GraphNode to) {
- super.addEdge((Arrow) new ControlFlowArc(from, to));
- }
-
- @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 =
- getArrows().stream()
- .sorted(Comparator.comparingInt(arrow -> ((GraphNode) arrow.getFrom()).getId()))
- .map(arrow -> ((Arc) arrow).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)) {
- 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 : currentNode.getIncomingArcs()) {
- ControlFlowArc controlFlowArc = (ControlFlowArc) arc;
-
- GraphNode> from = controlFlowArc.getFromNode();
-
-// 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 5ab503de87504e25013066d0da1e94836706ded5..ce739be90844293a7e80d941fb39d46afa030347 100644
--- a/src/main/java/tfm/graphs/Graph.java
+++ b/src/main/java/tfm/graphs/Graph.java
@@ -1,159 +1,212 @@
package tfm.graphs;
import com.github.javaparser.ast.Node;
-import edg.graphlib.Arrow;
-import edg.graphlib.Vertex;
+import org.jgrapht.graph.DefaultDirectedGraph;
+import org.jgrapht.io.DOTExporter;
import tfm.arcs.Arc;
-import tfm.arcs.data.ArcData;
import tfm.nodes.GraphNode;
-import tfm.slicing.SlicingCriterion;
+import tfm.nodes.NodeFactory;
import java.util.*;
+import java.util.function.Consumer;
import java.util.stream.Collectors;
/**
- * A graphlib Graph without cost and data in arcs
+ *
* */
-public abstract class Graph extends edg.graphlib.Graph {
-
- 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 abstract class Graph extends DefaultDirectedGraph, Arc> {
+
+ protected static final int DEFAULT_VERTEX_START_ID = 0;
+
+ private int nextVertexId;
public Graph() {
- super();
+ this(DEFAULT_VERTEX_START_ID);
}
- /**
- Library fix: if a node had an edge to itself resulted in 2 outgoing nodes instead of 1 outgoing and 1 incoming
- */
- @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;
- }
+ protected Graph(int vertexStartId) {
+ super(null, null, false);
+ this.nextVertexId = vertexStartId;
+ }
- // FIX
- if (Objects.equals(from, to)) {
- from.getOutgoingArrows().add(arrow);
- from.getIncomingArrows().add(arrow);
- } else {
- from.addEdge(arrow);
- to.addEdge(arrow);
- }
- edges.add(arrow);
- return true;
+ private GraphNode addNode(GraphNode node) {
+ this.addVertex(node);
+
+ return node;
}
- @SuppressWarnings("unchecked")
- public GraphNode getRootNode() {
- return (GraphNode) super.getRootVertex();
+ private GraphNode addNode(int id, String instruction, ASTNode node) {
+ GraphNode newNode = NodeFactory.graphNode(id, instruction, node);
+
+ return this.addNode(newNode);
}
- public abstract GraphNode addNode(String instruction, ASTNode node);
+ public GraphNode addNode(String instruction, ASTNode node) {
+ return this.addNode(getNextVertexId(), instruction, node);
+ }
+
+ /**
+ * Adds the given node to the graph.
+ *
+ * One must be careful with this method, as the given node will have
+ * 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 node id or generate a new one
+ * @return the node instance added to the graph
+ */
+ 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")
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();
}
- @SuppressWarnings("unchecked")
- public Set> getNodes() {
- return getVerticies().stream()
- .map(vertex -> (GraphNode>) vertex)
- .collect(Collectors.toSet());
- }
-
- public Set> getArcs() {
- return getArrows().stream()
- .map(arrow -> (Arc) arrow)
- .collect(Collectors.toSet());
- }
-
+ @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 getNodes().stream()
- .anyMatch(node -> Objects.equals(node, graphNode));
+ public List> findDeclarationsOfVariable(String variable) {
+ return vertexSet().stream()
+ .filter(node -> node.getDeclaredVariables().contains(variable))
+ .collect(Collectors.toList());
}
- public abstract Graph slice(SlicingCriterion slicingCriterion);
+ public boolean isEmpty() {
+ return this.vertexSet().isEmpty();
+ }
+
+ public DOTExporter, Arc> getDOTExporter() {
+ return new DOTExporter<>(
+ graphNode -> String.valueOf(graphNode.getId()),
+ GraphNode::getInstruction,
+ Arc::getLabel,
+ null,
+ Arc::getDotAttributes);
+ }
/**
- * Deprecated for incorrect behaviour. Use removeNode instead
+ * 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
*/
- @Override
- @Deprecated
- public boolean removeVertex(Vertex vertex) {
- throw new UnsupportedOperationException("Deprecated method. Use removeNode instead");
- }
+ 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.removeVertex(node);
+
+ MutableGraphNode modifiedNode = new MutableGraphNode<>((GraphNode) node);
+
+ modifyFn.accept(modifiedNode);
+
+ GraphNode newNode = modifiedNode.toGraphNode();
- public void removeNode(GraphNode> node) {
- verticies.remove(node);
+ this.addVertex(newNode);
- edges.removeAll(node.getOutgoingArcs());
- edges.removeAll(node.getIncomingArcs());
+ 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 List> findDeclarationsOfVariable(String variable) {
- return getNodes().stream()
- .filter(node -> node.getDeclaredVariables().contains(variable))
- .collect(Collectors.toList());
+ 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 0000000000000000000000000000000000000000..76d01e6ff992d5ce6a67a0bf17873369e3bc236c
--- /dev/null
+++ b/src/main/java/tfm/graphs/GraphWithRootNode.java
@@ -0,0 +1,52 @@
+package tfm.graphs;
+
+import com.github.javaparser.ast.Node;
+import tfm.nodes.GraphNode;
+import tfm.nodes.NodeFactory;
+
+import java.util.Objects;
+import java.util.Optional;
+
+public abstract class GraphWithRootNode extends Graph {
+
+ protected final int ROOT_NODE_ID = 0;
+
+ protected GraphNode rootNode;
+
+ public GraphWithRootNode() {
+ super(1);
+ }
+
+ /**
+ * 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 Optional> getRootNode() {
+ return Optional.ofNullable(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/JGraph.java b/src/main/java/tfm/graphs/JGraph.java
deleted file mode 100644
index 5fe88f8e2a4e69a6d478b9714dad39cdb9ed0c99..0000000000000000000000000000000000000000
--- 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/PDG.java b/src/main/java/tfm/graphs/PDG.java
new file mode 100644
index 0000000000000000000000000000000000000000..98fad8e52bde77353d41ca39fb91aee1d8c63d11
--- /dev/null
+++ b/src/main/java/tfm/graphs/PDG.java
@@ -0,0 +1,93 @@
+package tfm.graphs;
+
+import com.github.javaparser.ast.Node;
+import com.github.javaparser.ast.body.MethodDeclaration;
+import tfm.arcs.Arc;
+import tfm.arcs.pdg.ControlDependencyArc;
+import tfm.arcs.pdg.DataDependencyArc;
+import tfm.nodes.GraphNode;
+import tfm.slicing.SlicingCriterion;
+import tfm.utils.ASTUtils;
+import tfm.utils.Logger;
+import tfm.utils.NodeNotFoundException;
+import tfm.visitors.pdg.PDGBuilder;
+
+import java.util.HashSet;
+import java.util.Optional;
+import java.util.Set;
+
+public class PDG extends GraphWithRootNode implements Sliceable {
+
+ private CFG cfg;
+
+ public PDG() {
+ super();
+ }
+
+ public PDG(CFG cfg) {
+ super();
+ this.cfg = cfg;
+ }
+
+ public void addControlDependencyArc(GraphNode> from, GraphNode> to) {
+ this.addEdge(from, to, new ControlDependencyArc());
+ }
+
+ public void addDataDependencyArc(GraphNode> from, GraphNode> to, String variable) {
+ this.addEdge(from, to, new DataDependencyArc(variable));
+ }
+
+ public void setCfg(CFG cfg) {
+ this.cfg = cfg;
+ }
+
+ @Override
+ public PDG slice(SlicingCriterion slicingCriterion) {
+ Optional> optionalGraphNode = slicingCriterion.findNode(this);
+
+ if (!optionalGraphNode.isPresent()) {
+ throw new NodeNotFoundException(slicingCriterion);
+ }
+
+ GraphNode node = optionalGraphNode.get();
+
+ // Simply get slice nodes from GraphNode
+ Set sliceNodes = getSliceNodes(new HashSet<>(), node);
+
+ PDG sliceGraph = new PDG();
+
+ Node astCopy = ASTUtils.cloneAST(node.getAstNode());
+
+ astCopy.accept(new PDGBuilder(sliceGraph), null);
+
+ for (GraphNode> sliceNode : sliceGraph.vertexSet()) {
+ if (!sliceNodes.contains(sliceNode.getId())) {
+ Logger.log("Removing node " + sliceNode.getId());
+ sliceNode.getAstNode().removeForced();
+ sliceGraph.removeVertex(sliceNode);
+ }
+ }
+
+ return sliceGraph;
+ }
+
+ private Set getSliceNodes(Set visited, GraphNode> root) {
+ visited.add(root.getId());
+
+ for (Arc arc : incomingEdgesOf(root)) {
+ GraphNode> from = this.getEdgeSource(arc);
+
+ if (visited.contains(from.getId())) {
+ continue;
+ }
+
+ getSliceNodes(visited, from);
+ }
+
+ return visited;
+ }
+
+ public CFG getCfg() {
+ return cfg;
+ }
+}
diff --git a/src/main/java/tfm/graphs/PDGGraph.java b/src/main/java/tfm/graphs/PDGGraph.java
deleted file mode 100644
index 7cd03b498650efc04341f3d455effaf56aaaa4b5..0000000000000000000000000000000000000000
--- a/src/main/java/tfm/graphs/PDGGraph.java
+++ /dev/null
@@ -1,251 +0,0 @@
-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;
-import tfm.arcs.pdg.ControlDependencyArc;
-import tfm.arcs.pdg.DataDependencyArc;
-import tfm.nodes.GraphNode;
-import tfm.slicing.SlicingCriterion;
-import tfm.utils.ASTUtils;
-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.stream.Collectors;
-
-public class PDGGraph extends Graph {
-
- private CFGGraph cfgGraph;
-
- public PDGGraph() {
- setRootVertex(new GraphNode<>(getNextVertexId(), getRootNodeData(), new MethodDeclaration()));
- }
-
- public PDGGraph(CFGGraph cfgGraph) {
- this();
- 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 addNode(int id, String instruction, ASTNode node) {
- GraphNode vertex = new GraphNode<>(id, instruction, node);
- super.addVertex(vertex);
-
- return vertex;
- }
-
- @SuppressWarnings("unchecked")
- private void addArc(Arc arc) {
- super.addEdge(arc);
- }
-
- public void addControlDependencyArc(GraphNode from, GraphNode to) {
- ControlDependencyArc controlDependencyArc = new ControlDependencyArc(from, to);
-
- this.addArc(controlDependencyArc);
- }
-
- public void addDataDependencyArc(GraphNode from, GraphNode to, String variable) {
- DataDependencyArc dataDataDependencyArc = new DataDependencyArc(from, to, variable);
-
- this.addArc(dataDataDependencyArc);
- }
-
- public Set getNodesAtLevel(int level) {
- return getVerticies().stream()
- .map(vertex -> (GraphNode) vertex)
- .filter(node -> getLevelOf(node) == level)
- .collect(Collectors.toSet());
- }
-
- public int getLevels() {
- return getVerticies().stream()
- .map(vertex -> (GraphNode) vertex)
- .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 = node.getIncomingArcs().stream()
- .filter(Arc::isControlDependencyArrow)
- .findFirst()
- .map(arc -> (ControlDependencyArc) arc);
-
- if (!optionalControlDependencyArc.isPresent()) {
- return 0;
- }
-
- GraphNode> parent = optionalControlDependencyArc.get().getFromNode();
-
- 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(arrow -> ((GraphNode) arrow.getFrom()).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);
-
- if (!optionalGraphNode.isPresent()) {
- throw new NodeNotFoundException(slicingCriterion);
- }
-
- 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);
-
- PDGGraph sliceGraph = new PDGGraph();
-
- Node astCopy = ASTUtils.cloneAST(node.getAstNode());
-
- astCopy.accept(new PDGBuilder(sliceGraph), sliceGraph.getRootNode());
-
- for (GraphNode sliceNode : sliceGraph.getNodes()) {
- if (!sliceNodes.contains(sliceNode.getId())) {
- Logger.log("Removing node " + sliceNode.getId());
- sliceNode.getAstNode().removeForced();
- sliceGraph.removeNode(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;
- }
-
- 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();
-
- if (visited.contains(from.getId())) {
- continue;
- }
-
- getSliceNodes(visited, from);
- }
-
- return visited;
- }
-
- public CFGGraph getCfgGraph() {
- return cfgGraph;
- }
-}
diff --git a/src/main/java/tfm/graphs/SDGGraph.java b/src/main/java/tfm/graphs/SDG.java
similarity index 53%
rename from src/main/java/tfm/graphs/SDGGraph.java
rename to src/main/java/tfm/graphs/SDG.java
index ec4692bfd16c598ede2d0c624c44e3a771feb733..6ba940e5b95675a804330c7fd91f983ad83b0527 100644
--- a/src/main/java/tfm/graphs/SDGGraph.java
+++ b/src/main/java/tfm/graphs/SDG.java
@@ -1,44 +1,33 @@
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;
import tfm.nodes.GraphNode;
+import tfm.nodes.NodeFactory;
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 {
+public class SDG extends Graph implements Sliceable {
- private Map contextPDGGraphMap;
+ private Map contextPDGGraphMap;
- public SDGGraph() {
+ public SDG() {
this.contextPDGGraphMap = new HashMap<>();
}
@Override
- public GraphNode addNode(String instruction, ASTNode node) {
- GraphNode sdgNode = new GraphNode<>(getNextVertexId(), instruction, node);
- super.addVertex(sdgNode);
-
- return sdgNode;
+ public SDG slice(SlicingCriterion slicingCriterion) {
+ throw new IllegalStateException("Not implemented (yet)");
}
- @Override
- public String toGraphvizRepresentation() {
- return contextPDGGraphMap.values().stream()
- .map(PDGGraph::toGraphvizRepresentation).collect(Collectors.joining("\n"));
- }
-
- @Override
- public Graph slice(SlicingCriterion slicingCriterion) {
- return this;
- }
-
- public Map getContextPDGGraphMap() {
+ public Map getContextPDGGraphMap() {
return contextPDGGraphMap;
}
@@ -53,18 +42,14 @@ public class SDGGraph extends Graph {
.collect(Collectors.toSet());
}
- public Collection getPDGs() {
+ public Collection getPDGs() {
return contextPDGGraphMap.values();
}
@Deprecated
- public void addPDG(PDGGraph pdgGraph, MethodDeclaration methodDeclaration) {
- if (this.rootVertex == null) {
- this.setRootVertex(new GraphNode<>(getNextVertexId(), methodDeclaration.getNameAsString(), methodDeclaration));
- }
-
+ public void addPDG(PDG pdg, 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()
@@ -73,14 +58,12 @@ public class SDGGraph extends Graph {
addVertex(sdgNode);
}
- for (GraphNode> node : pdgGraph.getNodes()) {
- if (!this.verticies.contains(node)) {
- GraphNode> sdgNode = new GraphNode<>(
+ for (GraphNode> node : pdg.vertexSet()) {
+ if (!this.containsVertex(node)) {
+ GraphNode> sdgNode = NodeFactory.computedGraphNode(
getNextVertexId(),
- node.getData(),
+ node.getInstruction(),
node.getAstNode(),
- node.getIncomingArcs(),
- node.getOutgoingArcs(),
node.getDeclaredVariables(),
node.getDefinedVariables(),
node.getUsedVariables()
@@ -91,8 +74,8 @@ public class SDGGraph extends Graph {
}
}
- public void addMethod(MethodDeclaration methodDeclaration, PDGGraph pdgGraph) {
- GraphNode methodRootNode = new GraphNode<>(
+ public void addMethod(MethodDeclaration methodDeclaration, PDG pdg) {
+ GraphNode methodRootNode = NodeFactory.graphNode(
getNextVertexId(),
"ENTER " + methodDeclaration.getDeclarationAsString(false, false, true),
methodDeclaration
diff --git a/src/main/java/tfm/graphs/Sliceable.java b/src/main/java/tfm/graphs/Sliceable.java
new file mode 100644
index 0000000000000000000000000000000000000000..3edf64a944f069ab7ac72f34c2d07cfecdd6f61f
--- /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/CFGNode.java b/src/main/java/tfm/nodes/CFGNode.java
deleted file mode 100644
index 75e4b1cdfe69b22c71fe7b20be8973287cda3fe3..0000000000000000000000000000000000000000
--- 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 133b4cfbea085e8a68c0ee7e359af8d1e4e2f1b7..c0113599bc3221cc38bf5f8324a0f867349fdde6 100644
--- a/src/main/java/tfm/nodes/GraphNode.java
+++ b/src/main/java/tfm/nodes/GraphNode.java
@@ -2,119 +2,86 @@ 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;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Objects;
+import java.util.Set;
-public class GraphNode extends Vertex {
+/**
+ * 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 final int id;
+ private final String instruction;
+ private final N astNode;
- protected N astNode;
+ private final Set declaredVariables;
+ private final Set definedVariables;
+ private final Set usedVariables;
- protected Set declaredVariables;
- protected Set definedVariables;
- protected Set usedVariables;
-
- public > GraphNode(N1 node) {
- this(
- node.getId(),
- node.getData(),
- node.getAstNode(),
- node.getIncomingArcs(),
- node.getOutgoingArcs(),
- node.getDeclaredVariables(),
- node.getDefinedVariables(),
- node.getUsedVariables()
- );
- }
-
- public GraphNode(int id, String representation, @NotNull N astNode) {
+ GraphNode(int id, String instruction, @NotNull N astNode) {
this(
id,
- representation,
+ instruction,
astNode,
- Utils.emptyList(),
- Utils.emptyList(),
Utils.emptySet(),
Utils.emptySet(),
Utils.emptySet()
);
+
+ if (astNode instanceof Statement) {
+ extractVariables((Statement) astNode);
+ }
}
- public GraphNode(
+ GraphNode(
int id,
- String representation,
- @NonNull N astNode,
- Collection extends Arrow> incomingArcs,
- Collection extends Arrow> outgoingArcs,
- Set declaredVariables,
- Set definedVariables,
- Set usedVariables
+ String instruction,
+ @NotNull N astNode,
+ Collection declaredVariables,
+ Collection definedVariables,
+ Collection 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);
- }
+ this.declaredVariables = new HashSet<>(declaredVariables);
+ this.definedVariables = new HashSet<>(definedVariables);
+ this.usedVariables = new HashSet<>(usedVariables);
}
- private void extractVariables(@NonNull Statement statement) {
+ private void extractVariables(@NotNull 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, data: '%s', in: %s, out: %s}",
+ return String.format("GraphNode{id: %s, instruction: '%s', astNodeType: %s}",
getId(),
- getData(),
- getIncomingArcs().stream().map(arc -> arc.getFromNode().getId()).collect(Collectors.toList()),
- getOutgoingArcs().stream().map(arc -> arc.getToNode().getId()).collect(Collectors.toList()));
+ getInstruction(),
+ getAstNode().getClass().getSimpleName()
+ );
}
public N getAstNode() {
return astNode;
}
- public void setAstNode(N node) {
- this.astNode = node;
- }
-
- public Optional getFileLineNumber() {
- return astNode.getBegin()
- .map(begin -> begin.line);
- }
-
public void addDeclaredVariable(String variable) {
declaredVariables.add(variable);
}
@@ -135,19 +102,16 @@ 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
}
- public String toGraphvizRepresentation() {
- String text = getData().replace("\\", "\\\\")
- .replace("\"", "\\\"");
- return String.format("%s[label=\"%s: %s\"];", getId(), getId(), text);
+ @Override
+ public int hashCode() {
+ return Objects.hash(getId(), getInstruction(), getAstNode());
}
public Set getDeclaredVariables() {
@@ -162,47 +126,7 @@ public class GraphNode extends Vertex {
return usedVariables;
}
- public List> getIncomingArcs() {
- return super.getIncomingArrows().stream()
- .map(arrow -> (Arc) arrow)
- .collect(Collectors.toList());
- }
-
- 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 String getInstruction() {
+ return instruction;
}
}
diff --git a/src/main/java/tfm/nodes/JNode.java b/src/main/java/tfm/nodes/JNode.java
deleted file mode 100644
index 534f43315b09c02a8857e14cd7b30962f58c8b76..0000000000000000000000000000000000000000
--- 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 b241c5c580e514fdd996f43cff17cf960e16db85..95f0479710c03c4a68fcec061424d82b8c9e6f57 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;
@@ -17,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<>();
@@ -30,8 +27,8 @@ public class MethodCallNode extends GraphNode {
this.outParameters = new ArrayList<>();
}
- public MethodCallNode(int id, String representation, @NonNull ExpressionStmt node, Collection extends Arrow> incomingArcs, Collection extends Arrow> 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/NodeFactory.java b/src/main/java/tfm/nodes/NodeFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..7d4f96e5d1bbcb7c813bdf4e992521cc12584592
--- /dev/null
+++ b/src/main/java/tfm/nodes/NodeFactory.java
@@ -0,0 +1,70 @@
+package tfm.nodes;
+
+import com.github.javaparser.ast.Node;
+
+import java.util.Collection;
+import java.util.Objects;
+
+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
+ ) {
+ 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,
+ 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
+ ) {
+ Objects.requireNonNull(instruction, "Instruction cannot be null!");
+ Objects.requireNonNull(node, "AST Node cannot be null");
+
+ return new GraphNode<>(
+ id,
+ instruction,
+ node
+ );
+ }
+}
diff --git a/src/main/java/tfm/nodes/PDGNode.java b/src/main/java/tfm/nodes/PDGNode.java
deleted file mode 100644
index fe8c5be37a7a278ce00478172a2e970106260d98..0000000000000000000000000000000000000000
--- 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 extends Arrow> incomingArcs, Collection extends Arrow> 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 79a4120c68af66b1b3a17eeea681e0f08616a654..0000000000000000000000000000000000000000
--- 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 extends Arrow> incomingArcs, Collection extends Arrow> 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/readme.md b/src/main/java/tfm/readme.md
deleted file mode 100644
index 5ef10f60754416053c5d780b1ec52590789b430d..0000000000000000000000000000000000000000
--- 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 pdgGraph = Graphs.PDG.fromASTNode(astRoot);
-
- return pdgGraph.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
diff --git a/src/main/java/tfm/scopes/IfElseScope.java b/src/main/java/tfm/scopes/IfElseScope.java
deleted file mode 100644
index 765b7f08f91a0cc842e5dca41b5b84b544dd22b0..0000000000000000000000000000000000000000
--- 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 9d56e9088391497c39083c2b0f6a024d59be05cb..0000000000000000000000000000000000000000
--- 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 a5a47807223d97f294af72b7ee6b1cd2fdada51f..0000000000000000000000000000000000000000
--- 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