From 8b45be607aad3e4540ae0f55b4620d6e1ddb7e7e Mon Sep 17 00:00:00 2001 From: jacosro Date: Sat, 6 Jun 2020 21:35:32 +0200 Subject: [PATCH 1/2] Added Naive summary arcs builder --- src/main/java/tfm/arcs/Arc.java | 36 ++++++ src/main/java/tfm/arcs/sdg/SummaryArc.java | 16 +++ src/main/java/tfm/graphs/sdg/SDG.java | 5 + src/main/java/tfm/graphs/sdg/SDGBuilder.java | 13 ++- .../sdg/sumarcs/NaiveSummaryArcsBuilder.java | 106 ++++++++++++++++++ .../sdg/sumarcs/SummaryArcsBuilder.java | 14 +++ src/test/res/programs/sdg/Example1.java | 18 +-- 7 files changed, 189 insertions(+), 19 deletions(-) create mode 100644 src/main/java/tfm/arcs/sdg/SummaryArc.java create mode 100644 src/main/java/tfm/graphs/sdg/sumarcs/NaiveSummaryArcsBuilder.java create mode 100644 src/main/java/tfm/graphs/sdg/sumarcs/SummaryArcsBuilder.java diff --git a/src/main/java/tfm/arcs/Arc.java b/src/main/java/tfm/arcs/Arc.java index 5af9bde..950ae8f 100644 --- a/src/main/java/tfm/arcs/Arc.java +++ b/src/main/java/tfm/arcs/Arc.java @@ -6,6 +6,9 @@ import tfm.arcs.cfg.ControlFlowArc; import tfm.arcs.pdg.ControlDependencyArc; import tfm.arcs.pdg.DataDependencyArc; import tfm.arcs.sdg.CallArc; +import tfm.arcs.sdg.ParameterInOutArc; +import tfm.arcs.sdg.ReturnArc; +import tfm.arcs.sdg.SummaryArc; import tfm.nodes.GraphNode; import java.util.HashMap; @@ -73,6 +76,39 @@ public abstract class Arc extends DefaultEdge { throw new UnsupportedOperationException("Not a CallArc"); } + /** @see ParameterInOutArc */ + public final boolean isParameterInOutArc() { + return this instanceof ParameterInOutArc; + } + + public final ParameterInOutArc asParameterInOutArc() { + if (isParameterInOutArc()) + return (ParameterInOutArc) this; + throw new UnsupportedOperationException("Not a ParameterInOutArc"); + } + + /** @see ReturnArc */ + public final boolean isReturnArc() { + return this instanceof ReturnArc; + } + + public final ReturnArc asReturnArc() { + if (isReturnArc()) + return (ReturnArc) this; + throw new UnsupportedOperationException("Not a ReturnArc"); + } + + /** @see SummaryArc */ + public final boolean isSummaryArc() { + return this instanceof SummaryArc; + } + + public final SummaryArc asSummaryArcArc() { + if (isSummaryArc()) + return (SummaryArc) this; + throw new UnsupportedOperationException("Not a SummaryArc"); + } + @Override public String toString() { return String.format("%s{%d -> %d}", getClass().getName(), diff --git a/src/main/java/tfm/arcs/sdg/SummaryArc.java b/src/main/java/tfm/arcs/sdg/SummaryArc.java new file mode 100644 index 0000000..bde9724 --- /dev/null +++ b/src/main/java/tfm/arcs/sdg/SummaryArc.java @@ -0,0 +1,16 @@ +package tfm.arcs.sdg; + +import org.jgrapht.io.Attribute; +import org.jgrapht.io.DefaultAttribute; +import tfm.arcs.Arc; + +import java.util.Map; + +public class SummaryArc extends Arc { + @Override + public Map getDotAttributes() { + Map map = super.getDotAttributes(); + map.put("style", DefaultAttribute.createAttribute("bold")); + return map; + } +} diff --git a/src/main/java/tfm/graphs/sdg/SDG.java b/src/main/java/tfm/graphs/sdg/SDG.java index c17afc2..d25f3aa 100644 --- a/src/main/java/tfm/graphs/sdg/SDG.java +++ b/src/main/java/tfm/graphs/sdg/SDG.java @@ -14,6 +14,7 @@ import tfm.arcs.pdg.DataDependencyArc; import tfm.arcs.sdg.CallArc; import tfm.arcs.sdg.ParameterInOutArc; import tfm.arcs.sdg.ReturnArc; +import tfm.arcs.sdg.SummaryArc; import tfm.graphs.Buildable; import tfm.graphs.Graph; import tfm.graphs.cfg.CFG; @@ -90,6 +91,10 @@ public class SDG extends Graph implements Sliceable, Buildable from, GraphNode to) { + this.addEdge(from, to, new SummaryArc()); + } + public List> findDeclarationsOfVariable(String variable, GraphNode root) { return this.methodCFGMap.values().stream() .filter(cfg -> cfg.containsVertex(root)) diff --git a/src/main/java/tfm/graphs/sdg/SDGBuilder.java b/src/main/java/tfm/graphs/sdg/SDGBuilder.java index 48701ea..149976c 100644 --- a/src/main/java/tfm/graphs/sdg/SDGBuilder.java +++ b/src/main/java/tfm/graphs/sdg/SDGBuilder.java @@ -3,14 +3,21 @@ package tfm.graphs.sdg; 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.body.Parameter; -import com.github.javaparser.ast.expr.*; import com.github.javaparser.ast.stmt.ExpressionStmt; import com.github.javaparser.ast.visitor.VoidVisitorAdapter; import tfm.arcs.Arc; import tfm.graphs.pdg.PDG; +import tfm.graphs.sdg.sumarcs.NaiveSummaryArcsBuilder; +import tfm.graphs.sdg.sumarcs.SummaryArcsBuilder; import tfm.nodes.GraphNode; +import tfm.nodes.type.NodeType; import tfm.utils.Context; +import tfm.utils.Utils; + +import java.util.HashSet; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; class SDGBuilder extends VoidVisitorAdapter { @@ -77,6 +84,8 @@ class SDGBuilder extends VoidVisitorAdapter { // 3. Build summary arcs + SummaryArcsBuilder summaryArcsBuilder = new NaiveSummaryArcsBuilder(sdg); + summaryArcsBuilder.visit(); } @Override diff --git a/src/main/java/tfm/graphs/sdg/sumarcs/NaiveSummaryArcsBuilder.java b/src/main/java/tfm/graphs/sdg/sumarcs/NaiveSummaryArcsBuilder.java new file mode 100644 index 0000000..f87248a --- /dev/null +++ b/src/main/java/tfm/graphs/sdg/sumarcs/NaiveSummaryArcsBuilder.java @@ -0,0 +1,106 @@ +package tfm.graphs.sdg.sumarcs; + +import com.github.javaparser.ast.Node; +import com.github.javaparser.ast.body.MethodDeclaration; +import com.github.javaparser.ast.stmt.ExpressionStmt; +import tfm.arcs.Arc; +import tfm.graphs.Graph; +import tfm.graphs.sdg.SDG; +import tfm.nodes.GraphNode; +import tfm.nodes.type.NodeType; +import tfm.utils.Utils; + +import java.beans.Expression; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class NaiveSummaryArcsBuilder extends SummaryArcsBuilder { + + public NaiveSummaryArcsBuilder(SDG sdg) { + super(sdg); + } + + @Override + public void visit() { + for (MethodDeclaration methodDeclaration : sdg.getMethodDeclarations()) { + Optional> optionalMethodDeclarationNode = sdg.findNodeByASTNode(methodDeclaration); + assert optionalMethodDeclarationNode.isPresent(); + + GraphNode methodDeclarationNode = optionalMethodDeclarationNode.get(); + + Set> formalOutNodes = sdg.outgoingEdgesOf(methodDeclarationNode).stream() + .filter(arc -> sdg.getEdgeTarget(arc).getNodeType() == NodeType.FORMAL_OUT) + .map(arc -> (GraphNode) sdg.getEdgeTarget(arc)) + .collect(Collectors.toSet()); + + for (GraphNode formalOutNode : formalOutNodes) { + Set> reachableFormalInNodes = this.findReachableFormalInNodes(formalOutNode); + + Set> actualInNodes = reachableFormalInNodes.stream().flatMap(this::getActualInsStream).collect(Collectors.toSet()); + Set> actualOutNodes = this.getActualOuts(formalOutNode); + + for (GraphNode actualOutNode : actualOutNodes) { + for (GraphNode actualInNode : actualInNodes) { + if (this.match(actualInNode, actualOutNode)) { + sdg.addSummaryArc(actualInNode, actualOutNode); + } + } + } + } + } + } + + private Set> findReachableFormalInNodes(GraphNode formalOutNode) { + return this.doFindReachableFormalInNodes(formalOutNode, Utils.emptySet()); + } + + private Set> doFindReachableFormalInNodes(GraphNode root, Set visited) { + visited.add(root.getId()); + + Set> res = Utils.emptySet(); + + if (root.getNodeType() == NodeType.FORMAL_IN) { + res.add((GraphNode) root); + } else { + for (Arc arc : sdg.incomingEdgesOf(root)) { + if (arc.isControlDependencyArc() || arc.isDataDependencyArc()) { + res.addAll(this.doFindReachableFormalInNodes(sdg.getEdgeSource(arc), visited)); + } + } + } + + return res; + } + + private Stream> getActualInsStream(GraphNode formalIn) { + return sdg.incomingEdgesOf(formalIn).stream() + .filter(Arc::isParameterInOutArc) + .filter(arc -> sdg.getEdgeSource(arc).getNodeType() == NodeType.ACTUAL_IN) + .map(arc -> (GraphNode) sdg.getEdgeSource(arc)); + } + + private Set> getActualOuts(GraphNode formalOut) { + return sdg.outgoingEdgesOf(formalOut).stream() + .filter(Arc::isParameterInOutArc) + .filter(arc -> sdg.getEdgeTarget(arc).getNodeType() == NodeType.ACTUAL_OUT) + .map(arc -> (GraphNode) sdg.getEdgeTarget(arc)) + .collect(Collectors.toSet()); + } + + private boolean match(GraphNode actualIn, GraphNode actualOut) { + Optional> optionalInCallNode = this.getCallNode(actualIn); + Optional> optionalOutCallNode = this.getCallNode(actualOut); + + return optionalInCallNode.isPresent() && optionalOutCallNode.isPresent() + && optionalInCallNode.get() == optionalOutCallNode.get(); + } + + private Optional> getCallNode(GraphNode actualInOrOut) { + return sdg.incomingEdgesOf(actualInOrOut).stream() + .filter(arc -> sdg.getEdgeSource(arc).getNodeType() == NodeType.METHOD_CALL) + .map(arc -> (GraphNode) sdg.getEdgeSource(arc)) + .findFirst(); + } +} diff --git a/src/main/java/tfm/graphs/sdg/sumarcs/SummaryArcsBuilder.java b/src/main/java/tfm/graphs/sdg/sumarcs/SummaryArcsBuilder.java new file mode 100644 index 0000000..471a10a --- /dev/null +++ b/src/main/java/tfm/graphs/sdg/sumarcs/SummaryArcsBuilder.java @@ -0,0 +1,14 @@ +package tfm.graphs.sdg.sumarcs; + +import tfm.graphs.sdg.SDG; + +public abstract class SummaryArcsBuilder { + + protected SDG sdg; + + protected SummaryArcsBuilder(SDG sdg) { + this.sdg = sdg; + } + + public abstract void visit(); +} diff --git a/src/test/res/programs/sdg/Example1.java b/src/test/res/programs/sdg/Example1.java index 44fe6ee..63a06cc 100644 --- a/src/test/res/programs/sdg/Example1.java +++ b/src/test/res/programs/sdg/Example1.java @@ -4,32 +4,16 @@ import tfm.utils.Logger; public class Example1 { - /* - public Example1() { - - } - - */ - - int num; - public static void main(String[] args) { int n1 = 1; int n2 = 2; -// Example1 example1 = new Example1(); -// Example1 example2 = new Example1(); - - int f = sum(sum(n1, n2), n2); + int f = sum(n1, n2); Logger.log(f); Logger.log(z); } - public int getNum() { - return num; - } - private static int sum(int x, int y) { int res = x + y; return res; -- GitLab From e7d7df7a2eda3c1db4c108a3eda7799ea479ab01 Mon Sep 17 00:00:00 2001 From: jacosro Date: Sun, 7 Jun 2020 15:52:59 +0200 Subject: [PATCH 2/2] Fixed findReachableFormalInNodes: check if node is already visited --- .../sdg/sumarcs/NaiveSummaryArcsBuilder.java | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/main/java/tfm/graphs/sdg/sumarcs/NaiveSummaryArcsBuilder.java b/src/main/java/tfm/graphs/sdg/sumarcs/NaiveSummaryArcsBuilder.java index f87248a..8f11678 100644 --- a/src/main/java/tfm/graphs/sdg/sumarcs/NaiveSummaryArcsBuilder.java +++ b/src/main/java/tfm/graphs/sdg/sumarcs/NaiveSummaryArcsBuilder.java @@ -1,16 +1,13 @@ package tfm.graphs.sdg.sumarcs; -import com.github.javaparser.ast.Node; import com.github.javaparser.ast.body.MethodDeclaration; import com.github.javaparser.ast.stmt.ExpressionStmt; import tfm.arcs.Arc; -import tfm.graphs.Graph; import tfm.graphs.sdg.SDG; import tfm.nodes.GraphNode; import tfm.nodes.type.NodeType; import tfm.utils.Utils; -import java.beans.Expression; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; @@ -43,7 +40,7 @@ public class NaiveSummaryArcsBuilder extends SummaryArcsBuilder { for (GraphNode actualOutNode : actualOutNodes) { for (GraphNode actualInNode : actualInNodes) { - if (this.match(actualInNode, actualOutNode)) { + if (this.belongToSameMethodCall(actualInNode, actualOutNode)) { sdg.addSummaryArc(actualInNode, actualOutNode); } } @@ -65,8 +62,14 @@ public class NaiveSummaryArcsBuilder extends SummaryArcsBuilder { res.add((GraphNode) root); } else { for (Arc arc : sdg.incomingEdgesOf(root)) { + GraphNode nextNode = sdg.getEdgeSource(arc); + + if (visited.contains(nextNode.getId())) { + continue; + } + if (arc.isControlDependencyArc() || arc.isDataDependencyArc()) { - res.addAll(this.doFindReachableFormalInNodes(sdg.getEdgeSource(arc), visited)); + res.addAll(this.doFindReachableFormalInNodes(nextNode, visited)); } } } @@ -89,7 +92,7 @@ public class NaiveSummaryArcsBuilder extends SummaryArcsBuilder { .collect(Collectors.toSet()); } - private boolean match(GraphNode actualIn, GraphNode actualOut) { + private boolean belongToSameMethodCall(GraphNode actualIn, GraphNode actualOut) { Optional> optionalInCallNode = this.getCallNode(actualIn); Optional> optionalOutCallNode = this.getCallNode(actualOut); -- GitLab