diff --git a/src/main/java/tfm/arcs/Arc.java b/src/main/java/tfm/arcs/Arc.java index 5af9bde90e8b31acc3a6c0f285ef7bf3bbf4461b..950ae8f85c3852754f0a97b5cd420baf0f8e8939 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 0000000000000000000000000000000000000000..bde9724c0026bc919cfbe4c317618bf93db644af --- /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 c17afc2e0c816521c988e4c1064bbd6612f73239..d25f3aacf33c9b44809d5f185d9c8149c3642f7c 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 48701eacbd3781932475421d0d30f7a427e50f29..149976ce6e8c5c57d2c5d2f9327a6767bdf9ade2 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 0000000000000000000000000000000000000000..8f116782fdf126a5c961731e743936d5d5fa08c9 --- /dev/null +++ b/src/main/java/tfm/graphs/sdg/sumarcs/NaiveSummaryArcsBuilder.java @@ -0,0 +1,109 @@ +package tfm.graphs.sdg.sumarcs; + +import com.github.javaparser.ast.body.MethodDeclaration; +import com.github.javaparser.ast.stmt.ExpressionStmt; +import tfm.arcs.Arc; +import tfm.graphs.sdg.SDG; +import tfm.nodes.GraphNode; +import tfm.nodes.type.NodeType; +import tfm.utils.Utils; + +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.belongToSameMethodCall(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)) { + GraphNode nextNode = sdg.getEdgeSource(arc); + + if (visited.contains(nextNode.getId())) { + continue; + } + + if (arc.isControlDependencyArc() || arc.isDataDependencyArc()) { + res.addAll(this.doFindReachableFormalInNodes(nextNode, 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 belongToSameMethodCall(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 0000000000000000000000000000000000000000..471a10a3326c259ba926b2327a7408a9b9431c5e --- /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 44fe6ee60f257481a63cdcb2ed93520dd23f6aa7..63a06cc61097df0a5990826b38d1a326bec15e06 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;