Loading src/main/java/tfm/arcs/Arc.java +36 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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(), Loading src/main/java/tfm/arcs/sdg/SummaryArc.java 0 → 100644 +16 −0 Original line number Diff line number Diff line 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<String, Attribute> getDotAttributes() { Map<String, Attribute> map = super.getDotAttributes(); map.put("style", DefaultAttribute.createAttribute("bold")); return map; } } src/main/java/tfm/graphs/sdg/SDG.java +5 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -90,6 +91,10 @@ public class SDG extends Graph implements Sliceable, Buildable<NodeList<Compilat this.addEdge(from, to, new ReturnArc()); } public void addSummaryArc(GraphNode<ExpressionStmt> from, GraphNode<ExpressionStmt> to) { this.addEdge(from, to, new SummaryArc()); } public List<GraphNode<?>> findDeclarationsOfVariable(String variable, GraphNode<?> root) { return this.methodCFGMap.values().stream() .filter(cfg -> cfg.containsVertex(root)) Loading src/main/java/tfm/graphs/sdg/SDGBuilder.java +11 −2 Original line number Diff line number Diff line Loading @@ -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<Context> { Loading Loading @@ -77,6 +84,8 @@ class SDGBuilder extends VoidVisitorAdapter<Context> { // 3. Build summary arcs SummaryArcsBuilder summaryArcsBuilder = new NaiveSummaryArcsBuilder(sdg); summaryArcsBuilder.visit(); } @Override Loading src/main/java/tfm/graphs/sdg/sumarcs/NaiveSummaryArcsBuilder.java 0 → 100644 +109 −0 Original line number Diff line number Diff line 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<GraphNode<MethodDeclaration>> optionalMethodDeclarationNode = sdg.findNodeByASTNode(methodDeclaration); assert optionalMethodDeclarationNode.isPresent(); GraphNode<MethodDeclaration> methodDeclarationNode = optionalMethodDeclarationNode.get(); Set<GraphNode<ExpressionStmt>> formalOutNodes = sdg.outgoingEdgesOf(methodDeclarationNode).stream() .filter(arc -> sdg.getEdgeTarget(arc).getNodeType() == NodeType.FORMAL_OUT) .map(arc -> (GraphNode<ExpressionStmt>) sdg.getEdgeTarget(arc)) .collect(Collectors.toSet()); for (GraphNode<ExpressionStmt> formalOutNode : formalOutNodes) { Set<GraphNode<ExpressionStmt>> reachableFormalInNodes = this.findReachableFormalInNodes(formalOutNode); Set<GraphNode<ExpressionStmt>> actualInNodes = reachableFormalInNodes.stream().flatMap(this::getActualInsStream).collect(Collectors.toSet()); Set<GraphNode<ExpressionStmt>> actualOutNodes = this.getActualOuts(formalOutNode); for (GraphNode<ExpressionStmt> actualOutNode : actualOutNodes) { for (GraphNode<ExpressionStmt> actualInNode : actualInNodes) { if (this.belongToSameMethodCall(actualInNode, actualOutNode)) { sdg.addSummaryArc(actualInNode, actualOutNode); } } } } } } private Set<GraphNode<ExpressionStmt>> findReachableFormalInNodes(GraphNode<ExpressionStmt> formalOutNode) { return this.doFindReachableFormalInNodes(formalOutNode, Utils.emptySet()); } private Set<GraphNode<ExpressionStmt>> doFindReachableFormalInNodes(GraphNode<?> root, Set<Long> visited) { visited.add(root.getId()); Set<GraphNode<ExpressionStmt>> res = Utils.emptySet(); if (root.getNodeType() == NodeType.FORMAL_IN) { res.add((GraphNode<ExpressionStmt>) 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<GraphNode<ExpressionStmt>> getActualInsStream(GraphNode<ExpressionStmt> formalIn) { return sdg.incomingEdgesOf(formalIn).stream() .filter(Arc::isParameterInOutArc) .filter(arc -> sdg.getEdgeSource(arc).getNodeType() == NodeType.ACTUAL_IN) .map(arc -> (GraphNode<ExpressionStmt>) sdg.getEdgeSource(arc)); } private Set<GraphNode<ExpressionStmt>> getActualOuts(GraphNode<ExpressionStmt> formalOut) { return sdg.outgoingEdgesOf(formalOut).stream() .filter(Arc::isParameterInOutArc) .filter(arc -> sdg.getEdgeTarget(arc).getNodeType() == NodeType.ACTUAL_OUT) .map(arc -> (GraphNode<ExpressionStmt>) sdg.getEdgeTarget(arc)) .collect(Collectors.toSet()); } private boolean belongToSameMethodCall(GraphNode<ExpressionStmt> actualIn, GraphNode<ExpressionStmt> actualOut) { Optional<GraphNode<ExpressionStmt>> optionalInCallNode = this.getCallNode(actualIn); Optional<GraphNode<ExpressionStmt>> optionalOutCallNode = this.getCallNode(actualOut); return optionalInCallNode.isPresent() && optionalOutCallNode.isPresent() && optionalInCallNode.get() == optionalOutCallNode.get(); } private Optional<GraphNode<ExpressionStmt>> getCallNode(GraphNode<ExpressionStmt> actualInOrOut) { return sdg.incomingEdgesOf(actualInOrOut).stream() .filter(arc -> sdg.getEdgeSource(arc).getNodeType() == NodeType.METHOD_CALL) .map(arc -> (GraphNode<ExpressionStmt>) sdg.getEdgeSource(arc)) .findFirst(); } } Loading
src/main/java/tfm/arcs/Arc.java +36 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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(), Loading
src/main/java/tfm/arcs/sdg/SummaryArc.java 0 → 100644 +16 −0 Original line number Diff line number Diff line 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<String, Attribute> getDotAttributes() { Map<String, Attribute> map = super.getDotAttributes(); map.put("style", DefaultAttribute.createAttribute("bold")); return map; } }
src/main/java/tfm/graphs/sdg/SDG.java +5 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -90,6 +91,10 @@ public class SDG extends Graph implements Sliceable, Buildable<NodeList<Compilat this.addEdge(from, to, new ReturnArc()); } public void addSummaryArc(GraphNode<ExpressionStmt> from, GraphNode<ExpressionStmt> to) { this.addEdge(from, to, new SummaryArc()); } public List<GraphNode<?>> findDeclarationsOfVariable(String variable, GraphNode<?> root) { return this.methodCFGMap.values().stream() .filter(cfg -> cfg.containsVertex(root)) Loading
src/main/java/tfm/graphs/sdg/SDGBuilder.java +11 −2 Original line number Diff line number Diff line Loading @@ -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<Context> { Loading Loading @@ -77,6 +84,8 @@ class SDGBuilder extends VoidVisitorAdapter<Context> { // 3. Build summary arcs SummaryArcsBuilder summaryArcsBuilder = new NaiveSummaryArcsBuilder(sdg); summaryArcsBuilder.visit(); } @Override Loading
src/main/java/tfm/graphs/sdg/sumarcs/NaiveSummaryArcsBuilder.java 0 → 100644 +109 −0 Original line number Diff line number Diff line 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<GraphNode<MethodDeclaration>> optionalMethodDeclarationNode = sdg.findNodeByASTNode(methodDeclaration); assert optionalMethodDeclarationNode.isPresent(); GraphNode<MethodDeclaration> methodDeclarationNode = optionalMethodDeclarationNode.get(); Set<GraphNode<ExpressionStmt>> formalOutNodes = sdg.outgoingEdgesOf(methodDeclarationNode).stream() .filter(arc -> sdg.getEdgeTarget(arc).getNodeType() == NodeType.FORMAL_OUT) .map(arc -> (GraphNode<ExpressionStmt>) sdg.getEdgeTarget(arc)) .collect(Collectors.toSet()); for (GraphNode<ExpressionStmt> formalOutNode : formalOutNodes) { Set<GraphNode<ExpressionStmt>> reachableFormalInNodes = this.findReachableFormalInNodes(formalOutNode); Set<GraphNode<ExpressionStmt>> actualInNodes = reachableFormalInNodes.stream().flatMap(this::getActualInsStream).collect(Collectors.toSet()); Set<GraphNode<ExpressionStmt>> actualOutNodes = this.getActualOuts(formalOutNode); for (GraphNode<ExpressionStmt> actualOutNode : actualOutNodes) { for (GraphNode<ExpressionStmt> actualInNode : actualInNodes) { if (this.belongToSameMethodCall(actualInNode, actualOutNode)) { sdg.addSummaryArc(actualInNode, actualOutNode); } } } } } } private Set<GraphNode<ExpressionStmt>> findReachableFormalInNodes(GraphNode<ExpressionStmt> formalOutNode) { return this.doFindReachableFormalInNodes(formalOutNode, Utils.emptySet()); } private Set<GraphNode<ExpressionStmt>> doFindReachableFormalInNodes(GraphNode<?> root, Set<Long> visited) { visited.add(root.getId()); Set<GraphNode<ExpressionStmt>> res = Utils.emptySet(); if (root.getNodeType() == NodeType.FORMAL_IN) { res.add((GraphNode<ExpressionStmt>) 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<GraphNode<ExpressionStmt>> getActualInsStream(GraphNode<ExpressionStmt> formalIn) { return sdg.incomingEdgesOf(formalIn).stream() .filter(Arc::isParameterInOutArc) .filter(arc -> sdg.getEdgeSource(arc).getNodeType() == NodeType.ACTUAL_IN) .map(arc -> (GraphNode<ExpressionStmt>) sdg.getEdgeSource(arc)); } private Set<GraphNode<ExpressionStmt>> getActualOuts(GraphNode<ExpressionStmt> formalOut) { return sdg.outgoingEdgesOf(formalOut).stream() .filter(Arc::isParameterInOutArc) .filter(arc -> sdg.getEdgeTarget(arc).getNodeType() == NodeType.ACTUAL_OUT) .map(arc -> (GraphNode<ExpressionStmt>) sdg.getEdgeTarget(arc)) .collect(Collectors.toSet()); } private boolean belongToSameMethodCall(GraphNode<ExpressionStmt> actualIn, GraphNode<ExpressionStmt> actualOut) { Optional<GraphNode<ExpressionStmt>> optionalInCallNode = this.getCallNode(actualIn); Optional<GraphNode<ExpressionStmt>> optionalOutCallNode = this.getCallNode(actualOut); return optionalInCallNode.isPresent() && optionalOutCallNode.isPresent() && optionalInCallNode.get() == optionalOutCallNode.get(); } private Optional<GraphNode<ExpressionStmt>> getCallNode(GraphNode<ExpressionStmt> actualInOrOut) { return sdg.incomingEdgesOf(actualInOrOut).stream() .filter(arc -> sdg.getEdgeSource(arc).getNodeType() == NodeType.METHOD_CALL) .map(arc -> (GraphNode<ExpressionStmt>) sdg.getEdgeSource(arc)) .findFirst(); } }