From 5617f6ff42ecf2f326c268dcc4c8631f134c6360 Mon Sep 17 00:00:00 2001 From: Carlos Galindo Date: Sat, 27 Feb 2021 08:57:43 +0100 Subject: [PATCH] Generate summary arcs between return nodes and actual-in. --- .../graphs/sdg/SummaryArcAnalyzer.java | 83 ++++++++++++++----- .../exceptionsensitive/ExceptionExitNode.java | 6 ++ .../nodes/exceptionsensitive/ExitNode.java | 4 +- .../exceptionsensitive/NormalExitNode.java | 5 ++ .../mist/slicing/nodes/io/MethodExitNode.java | 2 +- .../review-07-2020/P6.java.sdg.sliced | 1 + 6 files changed, 78 insertions(+), 23 deletions(-) diff --git a/sdg-core/src/main/java/es/upv/mist/slicing/graphs/sdg/SummaryArcAnalyzer.java b/sdg-core/src/main/java/es/upv/mist/slicing/graphs/sdg/SummaryArcAnalyzer.java index 3441cb7..c1ab83b 100644 --- a/sdg-core/src/main/java/es/upv/mist/slicing/graphs/sdg/SummaryArcAnalyzer.java +++ b/sdg-core/src/main/java/es/upv/mist/slicing/graphs/sdg/SummaryArcAnalyzer.java @@ -4,6 +4,8 @@ import com.github.javaparser.ast.body.CallableDeclaration; import es.upv.mist.slicing.graphs.BackwardDataFlowAnalysis; import es.upv.mist.slicing.graphs.CallGraph; import es.upv.mist.slicing.nodes.SyntheticNode; +import es.upv.mist.slicing.nodes.exceptionsensitive.ExitNode; +import es.upv.mist.slicing.nodes.exceptionsensitive.ReturnNode; import es.upv.mist.slicing.nodes.io.ActualIONode; import es.upv.mist.slicing.nodes.io.CallNode; import es.upv.mist.slicing.nodes.io.FormalIONode; @@ -11,6 +13,7 @@ import es.upv.mist.slicing.nodes.io.OutputNode; import java.util.*; import java.util.stream.Collectors; +import java.util.stream.Stream; public class SummaryArcAnalyzer extends BackwardDataFlowAnalysis, Map>, Set>> { protected final SDG sdg; @@ -28,8 +31,10 @@ public class SummaryArcAnalyzer extends BackwardDataFlowAnalysis>, Set> initialValue(CallGraph.Vertex vertex) { - var value = vertexDataMap.get(vertex); - if (value == null) { + Map>, Set> value; + if (vertexDataMap.containsKey(vertex)) { + value = vertexDataMap.get(vertex); + } else { value = new HashMap<>(); for (var formalOut : getFormalOutNodes(vertex.getDeclaration())) value.put(formalOut, new HashSet<>()); @@ -38,20 +43,31 @@ public class SummaryArcAnalyzer extends BackwardDataFlowAnalysis>> getFormalOutNodes(CallableDeclaration declaration) { - Set>> set = sdg.vertexSet().stream() - .filter(FormalIONode.class::isInstance) - .map(FormalIONode.class::cast) - .filter(FormalIONode::isOutput) - .collect(Collectors.toSet()); - sdg.vertexSet().stream() - .filter(OutputNode.class::isInstance) - .map(OutputNode.class::cast) - .filter(on -> on.getAstNode().equals(declaration)) + Set>> set = new HashSet<>(); + Stream.concat( + Stream.concat( + sdg.vertexSet().stream() // formal-out nodes + .filter(FormalIONode.class::isInstance) + .map(FormalIONode.class::cast) + .filter(FormalIONode::isOutput), + sdg.vertexSet().stream() // output nodes (the value returned) + .filter(OutputNode.class::isInstance) + .map(OutputNode.class::cast)), + sdg.vertexSet().stream() // normal/exception exit nodes (for exception handling) + .filter(ExitNode.class::isInstance) + .map(ExitNode.class::cast)) + // Only nodes that match the current declaration + .filter(node -> node.getAstNode() == declaration) .forEach(set::add); return set; } + /** Given an output or formal-out node, locate the formal-in nodes it depends on. + * This search should be performed intra-procedurally, the parent class will take + * care of the rest of cases by adding summary arcs computed for other declarations. */ protected Set computeFormalIn(SyntheticNode> formalOut) { return sdg.createSlicingAlgorithm().traverseProcedure(formalOut).getGraphNodes().stream() .filter(FormalIONode.class::isInstance) @@ -60,15 +76,17 @@ public class SummaryArcAnalyzer extends BackwardDataFlowAnalysis edge : graph.incomingEdgesOf(vertex)) { for (var entry : result.entrySet()) { - var actualOutOpt = getActualOut(edge, entry.getKey()); + var actualOutOpt = findOutputNode(edge, entry.getKey()); if (actualOutOpt.isEmpty()) continue; for (var formalIn : entry.getValue()) { - var actualInOpt = getActualIn(edge, formalIn); + var actualInOpt = findActualIn(edge, formalIn); if (actualInOpt.isEmpty()) continue; if (!sdg.containsEdge(actualInOpt.get(), actualOutOpt.get())) @@ -78,7 +96,10 @@ public class SummaryArcAnalyzer extends BackwardDataFlowAnalysis getActualIn(CallGraph.Edge edge, FormalIONode formalIn) { + /** Find the actual-in that represents the given formal-in in the given call. + * There may not be one. In that case, the dependency between formal-in/out should + * not result in a summary arc. */ + protected Optional findActualIn(CallGraph.Edge edge, FormalIONode formalIn) { return sdg.vertexSet().stream() .filter(ActualIONode.class::isInstance) .map(ActualIONode.class::cast) @@ -87,28 +108,48 @@ public class SummaryArcAnalyzer extends BackwardDataFlowAnalysis> getActualOut(CallGraph.Edge edge, SyntheticNode> formalOut) { + /** Find the actual-out, return or exception/normal return node that represents the given + * formal-out, output or exception/normal exit node in the given call. There may not be one. + * In that case, the dependency between formal-in/out should not result in a summary arc. */ + protected Optional> findOutputNode(CallGraph.Edge edge, SyntheticNode> formalOut) { if (formalOut instanceof FormalIONode) - return Optional.ofNullable(getActualOut(edge, (FormalIONode) formalOut)); + return findActualOut(edge, (FormalIONode) formalOut); if (formalOut instanceof OutputNode) - return Optional.ofNullable(getActualOut(edge)); + return Optional.of(findReturnNode(edge)); + if (formalOut instanceof ExitNode) + return getReturnNode(edge, (ExitNode) formalOut); throw new IllegalArgumentException("invalid type"); } - protected ActualIONode getActualOut(CallGraph.Edge edge, FormalIONode formalOut) { + /** Find the actual-out node that corresponds to the given formal-out in the given call. + * To locate any actual-out, you should use {@link #findOutputNode(CallGraph.Edge, SyntheticNode)}. */ + protected Optional findActualOut(CallGraph.Edge edge, FormalIONode formalOut) { return sdg.vertexSet().stream() .filter(ActualIONode.class::isInstance) .map(ActualIONode.class::cast) .filter(n -> n.getAstNode() == edge.getCall()) .filter(n -> n.matchesFormalIO(formalOut)) - .findAny().orElse(null); + .findAny(); } - protected CallNode.Return getActualOut(CallGraph.Edge edge) { + /** Find the return node of the given call. There is only one per method. + * To locate any actual-out, you should use {@link #findOutputNode(CallGraph.Edge, SyntheticNode)}. */ + protected CallNode.Return findReturnNode(CallGraph.Edge edge) { return sdg.vertexSet().stream() .filter(CallNode.Return.class::isInstance) .map(CallNode.Return.class::cast) .filter(n -> n.getAstNode() == edge.getCall()) - .findAny().orElse(null); + .findAny().orElseThrow(); + } + + /** Find the exception/normal return node that corresponds to the given exception/normal exit in the given call. + * To locate any actual-out, you should use {@link #findOutputNode(CallGraph.Edge, SyntheticNode)}. */ + protected Optional getReturnNode(CallGraph.Edge edge, ExitNode exitNode) { + return sdg.vertexSet().stream() + .filter(ReturnNode.class::isInstance) + .map(ReturnNode.class::cast) + .filter(n -> n.getAstNode() == edge.getCall()) + .filter(exitNode::matchesReturnNode) + .findAny(); } } diff --git a/sdg-core/src/main/java/es/upv/mist/slicing/nodes/exceptionsensitive/ExceptionExitNode.java b/sdg-core/src/main/java/es/upv/mist/slicing/nodes/exceptionsensitive/ExceptionExitNode.java index ae22920..e49ab1a 100644 --- a/sdg-core/src/main/java/es/upv/mist/slicing/nodes/exceptionsensitive/ExceptionExitNode.java +++ b/sdg-core/src/main/java/es/upv/mist/slicing/nodes/exceptionsensitive/ExceptionExitNode.java @@ -28,4 +28,10 @@ public class ExceptionExitNode extends ExitNode { public int hashCode() { return Objects.hash(super.hashCode(), exceptionType); } + + @Override + public boolean matchesReturnNode(ReturnNode node) { + // TODO: this is a temporary solution. When 1 exception return node per type is implemented, they must be compared + return node instanceof ExceptionReturnNode; + } } diff --git a/sdg-core/src/main/java/es/upv/mist/slicing/nodes/exceptionsensitive/ExitNode.java b/sdg-core/src/main/java/es/upv/mist/slicing/nodes/exceptionsensitive/ExitNode.java index b00ed6e..26259a0 100644 --- a/sdg-core/src/main/java/es/upv/mist/slicing/nodes/exceptionsensitive/ExitNode.java +++ b/sdg-core/src/main/java/es/upv/mist/slicing/nodes/exceptionsensitive/ExitNode.java @@ -6,8 +6,10 @@ import es.upv.mist.slicing.nodes.SyntheticNode; import java.util.LinkedList; /** A node that summarizes the normal or exceptional exits of a declaration. */ -public abstract class ExitNode extends SyntheticNode { +public abstract class ExitNode extends SyntheticNode> { protected ExitNode(String label, CallableDeclaration astNode) { super(label, astNode, new LinkedList<>()); } + + public abstract boolean matchesReturnNode(ReturnNode node); } diff --git a/sdg-core/src/main/java/es/upv/mist/slicing/nodes/exceptionsensitive/NormalExitNode.java b/sdg-core/src/main/java/es/upv/mist/slicing/nodes/exceptionsensitive/NormalExitNode.java index 179b819..1f4a6cc 100644 --- a/sdg-core/src/main/java/es/upv/mist/slicing/nodes/exceptionsensitive/NormalExitNode.java +++ b/sdg-core/src/main/java/es/upv/mist/slicing/nodes/exceptionsensitive/NormalExitNode.java @@ -7,4 +7,9 @@ public class NormalExitNode extends ExitNode { public NormalExitNode(CallableDeclaration astNode) { super("normal exit", astNode); } + + @Override + public boolean matchesReturnNode(ReturnNode node) { + return node instanceof NormalReturnNode; + } } diff --git a/sdg-core/src/main/java/es/upv/mist/slicing/nodes/io/MethodExitNode.java b/sdg-core/src/main/java/es/upv/mist/slicing/nodes/io/MethodExitNode.java index 63b5d0d..43f4d01 100644 --- a/sdg-core/src/main/java/es/upv/mist/slicing/nodes/io/MethodExitNode.java +++ b/sdg-core/src/main/java/es/upv/mist/slicing/nodes/io/MethodExitNode.java @@ -6,7 +6,7 @@ import es.upv.mist.slicing.nodes.SyntheticNode; import java.util.LinkedList; /** A node representing the returned value from a declaration. */ -public class MethodExitNode extends SyntheticNode { +public class MethodExitNode extends SyntheticNode> { public MethodExitNode(CallableDeclaration astNode) { super("Exit", astNode, new LinkedList<>()); } diff --git a/sdg-core/src/test/res/regression/review-07-2020/P6.java.sdg.sliced b/sdg-core/src/test/res/regression/review-07-2020/P6.java.sdg.sliced index b2595e2..4f00887 100644 --- a/sdg-core/src/test/res/regression/review-07-2020/P6.java.sdg.sliced +++ b/sdg-core/src/test/res/regression/review-07-2020/P6.java.sdg.sliced @@ -1,6 +1,7 @@ public class Bucles { public static void main(String[] args) { + int x = 2; try { for (int i = 0; i <= 12; i++) { metodoGeneradorExcepciones(x); -- GitLab