Loading sdg-core/src/main/java/es/upv/mist/slicing/graphs/BackwardDataFlowAnalysis.java +6 −1 Original line number Diff line number Diff line Loading @@ -37,7 +37,7 @@ public abstract class BackwardDataFlowAnalysis<V, E, D> { Set<V> mayAffectVertex = graph.outgoingEdgesOf(vertex).stream() .map(graph::getEdgeTarget).collect(Collectors.toCollection(ASTUtils::newIdentityHashSet)); D newValue = compute(vertex, mayAffectVertex); if (!Objects.equals(vertexDataMap.get(vertex), newValue)) { if (!dataMatch(vertexDataMap.get(vertex), newValue)) { vertexDataMap.put(vertex, newValue); graph.incomingEdgesOf(vertex).stream().map(graph::getEdgeSource).forEach(newWorkList::add); } Loading @@ -47,6 +47,11 @@ public abstract class BackwardDataFlowAnalysis<V, E, D> { built = true; } /** Checks whether the computed value has changed or not. */ protected boolean dataMatch(D oldData, D newData) { return Objects.equals(oldData, newData); } /** Compute a new value for a given vertex, given a set of nodes that might affect its value. */ protected abstract D compute(V vertex, Set<V> predecessors); Loading sdg-core/src/main/java/es/upv/mist/slicing/graphs/sdg/InterproceduralActionFinder.java +44 −20 Original line number Diff line number Diff line Loading @@ -39,7 +39,7 @@ public abstract class InterproceduralActionFinder<A extends VariableAction> exte /** Entry-point to the class. Performs the analysis and then saves the results to the CFG nodes. */ public void save() { if (!built) analyze(); graph.vertexSet().forEach(this::saveDeclaration); graph.vertexSet().forEach(this::saveDeclarationFormalNodes); } /** Obtains the StoredAction object with information on which actions have been stored. */ Loading @@ -47,21 +47,31 @@ public abstract class InterproceduralActionFinder<A extends VariableAction> exte return actionStoredMap.get(vertex).get(action); } /** Save the current set of actions associated to the given declaration. It will avoid saving * duplicates by default, so this method may be called multiple times safely. */ protected void saveDeclaration(CallGraph.Vertex vertex) { /** Save the current set of actions associated with the given declaration. This method will * only generate actual-in and actual-out nodes. It is idempotent, and won't generate duplicates. */ protected void saveDeclarationActualNodes(CallGraph.Vertex vertex) { var actions = vertexDataMap.get(vertex); // Update stored action map actionStoredMap.computeIfAbsent(vertex, v -> new HashMap<>()); for (A a : actions) actionStoredMap.get(vertex).computeIfAbsent(a, __ -> new StoredAction()); // FORMAL: per declaration (1) for (A a : actions) getStored(vertex, a).storeFormal(() -> sandBoxedHandler(vertex, a, this::handleFormalAction)); // ACTUAL: per call (n) for (CallGraph.Edge<?> edge : graph.incomingEdgesOf(vertex)) actions.stream().sorted(new ParameterFieldSorter(edge)).forEach(a -> getStored(vertex, a).storeActual(edge, e -> sandBoxedHandler(e, a, this::handleActualAction))); getStored(vertex, a).storeActual(edge, a, e -> sandBoxedHandler(e, a, this::handleActualAction))); } /** Save the current set of actions associated with the given declaration. This method will * only generate formal-in and formal-out nodes. It is idempotent, and won't generate duplicates. */ protected void saveDeclarationFormalNodes(CallGraph.Vertex vertex) { var actions = vertexDataMap.get(vertex); // Update stored action map actionStoredMap.computeIfAbsent(vertex, __ -> new HashMap<>()); for (A a : actions) actionStoredMap.get(vertex).computeIfAbsent(a, __ -> new StoredAction()); // 1 formal per declaration and action for (A a : actions) getStored(vertex, a).storeFormal(a, () -> sandBoxedHandler(vertex, a, this::handleFormalAction)); } /** A sandbox to avoid resolution errors when a variable is included that is a class name Loading Loading @@ -100,10 +110,8 @@ public abstract class InterproceduralActionFinder<A extends VariableAction> exte @Override protected Set<A> compute(CallGraph.Vertex vertex, Set<CallGraph.Vertex> predecessors) { saveDeclaration(vertex); Set<A> newValue = new HashSet<>(vertexDataMap.get(vertex)); newValue.addAll(initialValue(vertex)); return newValue; saveDeclarationActualNodes(vertex); return initialValue(vertex); } @Override Loading Loading @@ -136,6 +144,21 @@ public abstract class InterproceduralActionFinder<A extends VariableAction> exte * filter unwanted items (only if the filter is specific to that type). */ protected abstract Stream<A> mapAndFilterActionStream(Stream<VariableAction> stream, CFG cfg); @Override protected boolean dataMatch(Set<A> oldData, Set<A> newData) { if (oldData == newData) return true; if (oldData.size() != newData.size()) return false; HashMap<String, A> map = new HashMap<>(); for (A a : oldData) map.put(a.getName(), a); for (A b : newData) if (!VariableAction.objectTreeMatches(map.get(b.getName()), b)) return false; return true; } // =========================================================== // ========================= SUBCLASSES ====================== // =========================================================== Loading Loading @@ -168,27 +191,28 @@ public abstract class InterproceduralActionFinder<A extends VariableAction> exte * have been saved to the graph or not. */ protected static class StoredAction { /** Whether the action has been saved as actual node for each call. */ private final Map<CallGraph.Edge<?>, Boolean> actualStoredMap = new HashMap<>(); private final Map<CallGraph.Edge<?>, VariableAction> actualStoredMap = new HashMap<>(); /** Whether the action has been saved as formal node. */ protected boolean formalStored = false; protected VariableAction formalStored = null; private StoredAction() {} /** If this action has not yet been saved as formal node, use the argument to do so, then mark it as stored. */ private void storeFormal(Runnable save) { if (!formalStored) { private void storeFormal(VariableAction action, Runnable save) { if (formalStored == null || !VariableAction.objectTreeMatches(action, formalStored)) { save.run(); formalStored = true; formalStored = action; } } /** If this action has not yet been saved as actual node for the given edge, * use the consumer to do so, then mark it as stored. */ private void storeActual(CallGraph.Edge<?> edge, Consumer<CallGraph.Edge<?>> save) { if (!actualStoredMap.getOrDefault(edge, false)) { private void storeActual(CallGraph.Edge<?> edge, VariableAction action, Consumer<CallGraph.Edge<?>> save) { VariableAction storedAction = actualStoredMap.get(edge); if (storedAction == null || !VariableAction.objectTreeMatches(storedAction, action)) { save.accept(edge); actualStoredMap.put(edge, true); actualStoredMap.put(edge, action); } } } Loading sdg-core/src/main/java/es/upv/mist/slicing/graphs/sdg/InterproceduralUsageFinder.java +14 −16 Original line number Diff line number Diff line Loading @@ -29,15 +29,14 @@ public class InterproceduralUsageFinder extends InterproceduralActionFinder<Usag } @Override public void save() { super.save(); markTransferenceToRoot(); protected void saveDeclarationActualNodes(CallGraph.Vertex vertex) { super.saveDeclarationActualNodes(vertex); graph.incomingEdgesOf(vertex).forEach(this::markTransferenceToRoot); } /** For every variable action -scope-in- or -arg-in- in the graph, * runs {@link ExpressionObjectTreeFinder#locateAndMarkTransferenceToRoot(Expression, VariableAction)}. */ protected void markTransferenceToRoot() { for (CallGraph.Edge<?> edge : graph.edgeSet()) { protected void markTransferenceToRoot(CallGraph.Edge<?> edge) { for (ActualIONode actualIn : locateActualInNode(edge)) { for (VariableAction va : edge.getGraphNode().getVariableActions()) { if (va instanceof Movable && ((Movable) va).getRealNode().equals(actualIn)) { Loading @@ -54,7 +53,6 @@ public class InterproceduralUsageFinder extends InterproceduralActionFinder<Usag } } } } @Override protected void handleFormalAction(CallGraph.Vertex vertex, Usage use) { Loading sdg-core/src/main/java/es/upv/mist/slicing/nodes/ObjectTree.java +1 −1 Original line number Diff line number Diff line Loading @@ -444,7 +444,7 @@ public class ObjectTree implements Cloneable { if (o == null || getClass() != o.getClass()) return false; ObjectTree tree = (ObjectTree) o; return Objects.equals(getMemberName(), tree.getMemberName()) && childrenMap.values().equals(tree.childrenMap.values()); childrenMap.equals(tree.childrenMap); } @Override Loading sdg-core/src/main/java/es/upv/mist/slicing/nodes/VariableAction.java +15 −1 Original line number Diff line number Diff line Loading @@ -239,6 +239,20 @@ public abstract class VariableAction { connection.applySDG(sdg); } public static boolean objectTreeMatches(VariableAction a, VariableAction b) { if (a == b) return true; if (a == null || b == null) return false; boolean aHasTree = a.hasObjectTree() && a.getObjectTree().hasChildren(); boolean bHasTree = b.hasObjectTree() && b.getObjectTree().hasChildren(); if (aHasTree != bHasTree) return false; if (!aHasTree) return true; return a.getObjectTree().equals(b.getObjectTree()); } // ====================================================== // =================== ROOT ACTIONS ===================== // ====================================================== Loading Loading
sdg-core/src/main/java/es/upv/mist/slicing/graphs/BackwardDataFlowAnalysis.java +6 −1 Original line number Diff line number Diff line Loading @@ -37,7 +37,7 @@ public abstract class BackwardDataFlowAnalysis<V, E, D> { Set<V> mayAffectVertex = graph.outgoingEdgesOf(vertex).stream() .map(graph::getEdgeTarget).collect(Collectors.toCollection(ASTUtils::newIdentityHashSet)); D newValue = compute(vertex, mayAffectVertex); if (!Objects.equals(vertexDataMap.get(vertex), newValue)) { if (!dataMatch(vertexDataMap.get(vertex), newValue)) { vertexDataMap.put(vertex, newValue); graph.incomingEdgesOf(vertex).stream().map(graph::getEdgeSource).forEach(newWorkList::add); } Loading @@ -47,6 +47,11 @@ public abstract class BackwardDataFlowAnalysis<V, E, D> { built = true; } /** Checks whether the computed value has changed or not. */ protected boolean dataMatch(D oldData, D newData) { return Objects.equals(oldData, newData); } /** Compute a new value for a given vertex, given a set of nodes that might affect its value. */ protected abstract D compute(V vertex, Set<V> predecessors); Loading
sdg-core/src/main/java/es/upv/mist/slicing/graphs/sdg/InterproceduralActionFinder.java +44 −20 Original line number Diff line number Diff line Loading @@ -39,7 +39,7 @@ public abstract class InterproceduralActionFinder<A extends VariableAction> exte /** Entry-point to the class. Performs the analysis and then saves the results to the CFG nodes. */ public void save() { if (!built) analyze(); graph.vertexSet().forEach(this::saveDeclaration); graph.vertexSet().forEach(this::saveDeclarationFormalNodes); } /** Obtains the StoredAction object with information on which actions have been stored. */ Loading @@ -47,21 +47,31 @@ public abstract class InterproceduralActionFinder<A extends VariableAction> exte return actionStoredMap.get(vertex).get(action); } /** Save the current set of actions associated to the given declaration. It will avoid saving * duplicates by default, so this method may be called multiple times safely. */ protected void saveDeclaration(CallGraph.Vertex vertex) { /** Save the current set of actions associated with the given declaration. This method will * only generate actual-in and actual-out nodes. It is idempotent, and won't generate duplicates. */ protected void saveDeclarationActualNodes(CallGraph.Vertex vertex) { var actions = vertexDataMap.get(vertex); // Update stored action map actionStoredMap.computeIfAbsent(vertex, v -> new HashMap<>()); for (A a : actions) actionStoredMap.get(vertex).computeIfAbsent(a, __ -> new StoredAction()); // FORMAL: per declaration (1) for (A a : actions) getStored(vertex, a).storeFormal(() -> sandBoxedHandler(vertex, a, this::handleFormalAction)); // ACTUAL: per call (n) for (CallGraph.Edge<?> edge : graph.incomingEdgesOf(vertex)) actions.stream().sorted(new ParameterFieldSorter(edge)).forEach(a -> getStored(vertex, a).storeActual(edge, e -> sandBoxedHandler(e, a, this::handleActualAction))); getStored(vertex, a).storeActual(edge, a, e -> sandBoxedHandler(e, a, this::handleActualAction))); } /** Save the current set of actions associated with the given declaration. This method will * only generate formal-in and formal-out nodes. It is idempotent, and won't generate duplicates. */ protected void saveDeclarationFormalNodes(CallGraph.Vertex vertex) { var actions = vertexDataMap.get(vertex); // Update stored action map actionStoredMap.computeIfAbsent(vertex, __ -> new HashMap<>()); for (A a : actions) actionStoredMap.get(vertex).computeIfAbsent(a, __ -> new StoredAction()); // 1 formal per declaration and action for (A a : actions) getStored(vertex, a).storeFormal(a, () -> sandBoxedHandler(vertex, a, this::handleFormalAction)); } /** A sandbox to avoid resolution errors when a variable is included that is a class name Loading Loading @@ -100,10 +110,8 @@ public abstract class InterproceduralActionFinder<A extends VariableAction> exte @Override protected Set<A> compute(CallGraph.Vertex vertex, Set<CallGraph.Vertex> predecessors) { saveDeclaration(vertex); Set<A> newValue = new HashSet<>(vertexDataMap.get(vertex)); newValue.addAll(initialValue(vertex)); return newValue; saveDeclarationActualNodes(vertex); return initialValue(vertex); } @Override Loading Loading @@ -136,6 +144,21 @@ public abstract class InterproceduralActionFinder<A extends VariableAction> exte * filter unwanted items (only if the filter is specific to that type). */ protected abstract Stream<A> mapAndFilterActionStream(Stream<VariableAction> stream, CFG cfg); @Override protected boolean dataMatch(Set<A> oldData, Set<A> newData) { if (oldData == newData) return true; if (oldData.size() != newData.size()) return false; HashMap<String, A> map = new HashMap<>(); for (A a : oldData) map.put(a.getName(), a); for (A b : newData) if (!VariableAction.objectTreeMatches(map.get(b.getName()), b)) return false; return true; } // =========================================================== // ========================= SUBCLASSES ====================== // =========================================================== Loading Loading @@ -168,27 +191,28 @@ public abstract class InterproceduralActionFinder<A extends VariableAction> exte * have been saved to the graph or not. */ protected static class StoredAction { /** Whether the action has been saved as actual node for each call. */ private final Map<CallGraph.Edge<?>, Boolean> actualStoredMap = new HashMap<>(); private final Map<CallGraph.Edge<?>, VariableAction> actualStoredMap = new HashMap<>(); /** Whether the action has been saved as formal node. */ protected boolean formalStored = false; protected VariableAction formalStored = null; private StoredAction() {} /** If this action has not yet been saved as formal node, use the argument to do so, then mark it as stored. */ private void storeFormal(Runnable save) { if (!formalStored) { private void storeFormal(VariableAction action, Runnable save) { if (formalStored == null || !VariableAction.objectTreeMatches(action, formalStored)) { save.run(); formalStored = true; formalStored = action; } } /** If this action has not yet been saved as actual node for the given edge, * use the consumer to do so, then mark it as stored. */ private void storeActual(CallGraph.Edge<?> edge, Consumer<CallGraph.Edge<?>> save) { if (!actualStoredMap.getOrDefault(edge, false)) { private void storeActual(CallGraph.Edge<?> edge, VariableAction action, Consumer<CallGraph.Edge<?>> save) { VariableAction storedAction = actualStoredMap.get(edge); if (storedAction == null || !VariableAction.objectTreeMatches(storedAction, action)) { save.accept(edge); actualStoredMap.put(edge, true); actualStoredMap.put(edge, action); } } } Loading
sdg-core/src/main/java/es/upv/mist/slicing/graphs/sdg/InterproceduralUsageFinder.java +14 −16 Original line number Diff line number Diff line Loading @@ -29,15 +29,14 @@ public class InterproceduralUsageFinder extends InterproceduralActionFinder<Usag } @Override public void save() { super.save(); markTransferenceToRoot(); protected void saveDeclarationActualNodes(CallGraph.Vertex vertex) { super.saveDeclarationActualNodes(vertex); graph.incomingEdgesOf(vertex).forEach(this::markTransferenceToRoot); } /** For every variable action -scope-in- or -arg-in- in the graph, * runs {@link ExpressionObjectTreeFinder#locateAndMarkTransferenceToRoot(Expression, VariableAction)}. */ protected void markTransferenceToRoot() { for (CallGraph.Edge<?> edge : graph.edgeSet()) { protected void markTransferenceToRoot(CallGraph.Edge<?> edge) { for (ActualIONode actualIn : locateActualInNode(edge)) { for (VariableAction va : edge.getGraphNode().getVariableActions()) { if (va instanceof Movable && ((Movable) va).getRealNode().equals(actualIn)) { Loading @@ -54,7 +53,6 @@ public class InterproceduralUsageFinder extends InterproceduralActionFinder<Usag } } } } @Override protected void handleFormalAction(CallGraph.Vertex vertex, Usage use) { Loading
sdg-core/src/main/java/es/upv/mist/slicing/nodes/ObjectTree.java +1 −1 Original line number Diff line number Diff line Loading @@ -444,7 +444,7 @@ public class ObjectTree implements Cloneable { if (o == null || getClass() != o.getClass()) return false; ObjectTree tree = (ObjectTree) o; return Objects.equals(getMemberName(), tree.getMemberName()) && childrenMap.values().equals(tree.childrenMap.values()); childrenMap.equals(tree.childrenMap); } @Override Loading
sdg-core/src/main/java/es/upv/mist/slicing/nodes/VariableAction.java +15 −1 Original line number Diff line number Diff line Loading @@ -239,6 +239,20 @@ public abstract class VariableAction { connection.applySDG(sdg); } public static boolean objectTreeMatches(VariableAction a, VariableAction b) { if (a == b) return true; if (a == null || b == null) return false; boolean aHasTree = a.hasObjectTree() && a.getObjectTree().hasChildren(); boolean bHasTree = b.hasObjectTree() && b.getObjectTree().hasChildren(); if (aHasTree != bHasTree) return false; if (!aHasTree) return true; return a.getObjectTree().equals(b.getObjectTree()); } // ====================================================== // =================== ROOT ACTIONS ===================== // ====================================================== Loading