Skip to content

Commit d71ef17

Browse files
committed
Merge branch 'carlos' into 'develop'
Add polymorphic calls See merge request program-slicing/SDG!61
2 parents a913382 + 5dc18b6 commit d71ef17

File tree

10 files changed

+143
-49
lines changed

10 files changed

+143
-49
lines changed

sdg-core/src/main/java/es/upv/mist/slicing/graphs/CallGraph.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ public void visit(ConstructorDeclaration n, Void arg) {
167167
// =============== Method calls ===============
168168
@Override
169169
public void visit(MethodCallExpr n, Void arg) {
170-
n.resolve().toAst().ifPresent(decl -> createNormalEdge(decl, n));
170+
n.resolve().toAst().ifPresent(decl -> createPolyEdges(decl, n));
171171
super.visit(n, arg);
172172
}
173173

sdg-core/src/main/java/es/upv/mist/slicing/graphs/ExpressionObjectTreeFinder.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package es.upv.mist.slicing.graphs;
22

3-
import com.github.javaparser.ast.Node;
43
import com.github.javaparser.ast.body.VariableDeclarator;
54
import com.github.javaparser.ast.expr.*;
65
import com.github.javaparser.ast.visitor.VoidVisitorAdapter;
@@ -203,7 +202,7 @@ protected void visitCall(Resolvable<? extends ResolvedMethodLikeDeclaration> cal
203202
for (VariableAction variableAction : graphNode.getVariableActions()) {
204203
if (variableAction instanceof VariableAction.CallMarker) {
205204
VariableAction.CallMarker marker = (VariableAction.CallMarker) variableAction;
206-
if (ASTUtils.equalsWithRange((Node) marker.getCall(), (Node) call) && !marker.isEnter()) {
205+
if (ASTUtils.equalsWithRange(marker.getCall(), call) && !marker.isEnter()) {
207206
assert lastUseOut != null;
208207
list.add(new Pair<>(lastUseOut, arg));
209208
return;

sdg-core/src/main/java/es/upv/mist/slicing/graphs/sdg/InterproceduralDefinitionFinder.java

Lines changed: 40 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -44,21 +44,28 @@ protected void handleActualAction(CallGraph.Edge<?> edge, Definition def) {
4444
Optional<Expression> arg = extractArgument(def, edge, false);
4545
if (arg.isEmpty())
4646
return;
47-
ActualIONode actualOut = ActualIONode.createActualOut(edge.getCall(), def.getName(), arg.get());
47+
ActualIONode actualOut = locateActualOutNode(edge, def.getName())
48+
.orElseGet(() -> ActualIONode.createActualOut(edge.getCall(), def.getName(), arg.get()));
4849
extractOutputVariablesAsMovables(arg.get(), movables, graphNode, actualOut, def);
4950
} else if (def.isField()) {
5051
if (def.isStatic()) {
5152
// Known limitation: static fields
5253
} else {
5354
assert !(edge.getCall() instanceof ObjectCreationExpr);
54-
ActualIONode actualOut = ActualIONode.createActualOut(edge.getCall(), def.getName(), null);
55+
ActualIONode actualOut = locateActualOutNode(edge, def.getName())
56+
.orElseGet(() -> ActualIONode.createActualOut(edge.getCall(), def.getName(), null));
5557
Optional<Expression> scope = ASTUtils.getResolvableScope(edge.getCall());
5658
if (scope.isPresent()) {
5759
extractOutputVariablesAsMovables(scope.get(), movables, graphNode, actualOut, def);
5860
} else {
5961
assert def.hasObjectTree();
60-
var movableDef = new Definition(DeclarationType.FIELD, "this", graphNode, (ObjectTree) def.getObjectTree().clone());
61-
movables.add(new Movable(movableDef, actualOut));
62+
Optional<VariableAction> optVA = locateDefinition(graphNode, "this");
63+
if (optVA.isPresent())
64+
optVA.get().getObjectTree().addAll(def.getObjectTree());
65+
else {
66+
var movableDef = new Definition(DeclarationType.FIELD, "this", graphNode, (ObjectTree) def.getObjectTree().clone());
67+
movables.add(new Movable(movableDef, actualOut));
68+
}
6269
}
6370
}
6471
} else {
@@ -75,14 +82,38 @@ protected void extractOutputVariablesAsMovables(Expression e, List<VariableActio
7582
e.accept(new OutNodeVariableVisitor(), defExpressions);
7683
for (Expression expression : defExpressions) {
7784
assert def.hasObjectTree();
78-
DeclarationType type = DeclarationType.valueOf(expression);
79-
Definition inner = new Definition(type, expression.toString(), graphNode, (ObjectTree) def.getObjectTree().clone());
80-
if (defExpressions.size() > 1)
81-
inner.setOptional(true);
82-
movables.add(new Movable(inner, actualOut));
85+
Optional<VariableAction> optVa = locateDefinition(graphNode, expression.toString());
86+
if (optVa.isPresent()) {
87+
optVa.get().getObjectTree().addAll(def.getObjectTree());
88+
} else {
89+
DeclarationType type = DeclarationType.valueOf(expression);
90+
Definition inner = new Definition(type, expression.toString(), graphNode, (ObjectTree) def.getObjectTree().clone());
91+
if (defExpressions.size() > 1)
92+
inner.setOptional(true);
93+
movables.add(new Movable(inner, actualOut));
94+
}
8395
}
8496
}
8597

98+
/** Find the actual out node in the given edge call that corresponds to the given variable name. */
99+
protected Optional<ActualIONode> locateActualOutNode(CallGraph.Edge<?> edge, String name) {
100+
return edge.getGraphNode().getSyntheticNodesInMovables().stream()
101+
.filter(ActualIONode.class::isInstance)
102+
.map(ActualIONode.class::cast)
103+
.filter(ActualIONode::isOutput)
104+
.filter(actual -> actual.getVariableName().equals(name))
105+
.filter(actual -> ASTUtils.equalsWithRange(actual.getAstNode(), edge.getCall()))
106+
.findFirst();
107+
}
108+
109+
/** Try to locate the definition for the given variable name in the given node. */
110+
protected Optional<VariableAction> locateDefinition(GraphNode<?> graphNode, String name) {
111+
return graphNode.getVariableActions().stream()
112+
.filter(va -> va.getName().equals(name))
113+
.filter(VariableAction::isDefinition)
114+
.findAny();
115+
}
116+
86117
@Override
87118
protected Stream<Definition> mapAndFilterActionStream(Stream<VariableAction> stream, CFG cfg) {
88119
return stream.filter(VariableAction::isDefinition)

sdg-core/src/main/java/es/upv/mist/slicing/graphs/sdg/InterproceduralUsageFinder.java

Lines changed: 69 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,16 @@
11
package es.upv.mist.slicing.graphs.sdg;
22

3-
import com.github.javaparser.ast.Node;
43
import com.github.javaparser.ast.body.CallableDeclaration;
54
import com.github.javaparser.ast.expr.Expression;
65
import com.github.javaparser.ast.expr.ObjectCreationExpr;
76
import com.github.javaparser.ast.expr.ThisExpr;
7+
import com.github.javaparser.resolution.Resolvable;
8+
import com.github.javaparser.resolution.declarations.ResolvedMethodLikeDeclaration;
89
import es.upv.mist.slicing.graphs.CallGraph;
910
import es.upv.mist.slicing.graphs.ExpressionObjectTreeFinder;
1011
import es.upv.mist.slicing.graphs.cfg.CFG;
1112
import es.upv.mist.slicing.nodes.GraphNode;
12-
import es.upv.mist.slicing.nodes.ObjectTree;
1313
import es.upv.mist.slicing.nodes.VariableAction;
14-
import es.upv.mist.slicing.nodes.VariableAction.Definition;
1514
import es.upv.mist.slicing.nodes.VariableAction.Movable;
1615
import es.upv.mist.slicing.nodes.VariableAction.Usage;
1716
import es.upv.mist.slicing.nodes.io.ActualIONode;
@@ -20,7 +19,9 @@
2019

2120
import java.util.Map;
2221
import java.util.Objects;
22+
import java.util.Set;
2323
import java.util.function.Predicate;
24+
import java.util.stream.Collectors;
2425
import java.util.stream.Stream;
2526

2627
/** An interprocedural usage finder, which adds the associated actions to formal and actual nodes in the CFGs. */
@@ -29,6 +30,32 @@ public InterproceduralUsageFinder(CallGraph callGraph, Map<CallableDeclaration<?
2930
super(callGraph, cfgMap);
3031
}
3132

33+
@Override
34+
public void save() {
35+
super.save();
36+
markTransferenceToRoot();
37+
}
38+
39+
/** For every variable action -scope-in- or -arg-in- in the graph,
40+
* runs {@link ExpressionObjectTreeFinder#locateAndMarkTransferenceToRoot(Expression, VariableAction)}. */
41+
protected void markTransferenceToRoot() {
42+
for (CallGraph.Edge<?> edge : graph.edgeSet()) {
43+
for (ActualIONode actualIn : locateActualInNode(edge)) {
44+
for (VariableAction va : edge.getGraphNode().getVariableActions()) {
45+
if (va instanceof Movable && ((Movable) va).getRealNode().equals(actualIn)) {
46+
ExpressionObjectTreeFinder finder = new ExpressionObjectTreeFinder(edge.getGraphNode());
47+
if (va.getName().equals("-scope-in-")) {
48+
Expression scope = Objects.requireNonNullElseGet(actualIn.getArgument(), ThisExpr::new);
49+
finder.locateAndMarkTransferenceToRoot(scope, va);
50+
} else if (va.getName().equals("-arg-in-")) {
51+
finder.locateAndMarkTransferenceToRoot(actualIn.getArgument(), va);
52+
}
53+
}
54+
}
55+
}
56+
}
57+
}
58+
3259
@Override
3360
protected void handleFormalAction(CallGraph.Vertex vertex, Usage use) {
3461
CFG cfg = cfgMap.get(vertex.getDeclaration());
@@ -43,42 +70,62 @@ protected void handleActualAction(CallGraph.Edge<?> edge, Usage use) {
4370
if (use.isParameter()) {
4471
if (!use.isPrimitive()) {
4572
assert use.hasObjectTree();
46-
ActualIONode actualIn = locateActualInNode(edge, use.getName());
47-
Definition def = new Definition(VariableAction.DeclarationType.SYNTHETIC, "-arg-in-", graphNode, (ObjectTree) use.getObjectTree().clone());
48-
Movable movDef = new Movable(def, actualIn);
49-
graphNode.addVariableActionAfterLastMatchingRealNode(movDef, actualIn);
50-
ExpressionObjectTreeFinder finder = new ExpressionObjectTreeFinder(graphNode);
51-
finder.locateAndMarkTransferenceToRoot(actualIn.getArgument(), def);
73+
int index = ASTUtils.getMatchingParameterIndex(graph.getEdgeTarget(edge).getDeclaration(), use.getName());
74+
VariableAction argIn = locateArgIn(graphNode, edge.getCall(), index);
75+
argIn.getObjectTree().addAll(use.getObjectTree());
5276
}
5377
} else if (use.isField()) {
5478
if (use.isStatic()) {
5579
// Known limitation: static fields
5680
} else {
5781
// An object creation expression input an existing object via actual-in because it creates it.
5882
assert !(edge.getCall() instanceof ObjectCreationExpr);
59-
ActualIONode actualIn = locateActualInNode(edge, use.getName());
60-
Definition def = new Definition(VariableAction.DeclarationType.SYNTHETIC, "-scope-in-", graphNode, (ObjectTree) use.getObjectTree().clone());
61-
Movable movDef = new Movable(def, actualIn);
62-
Expression scope = Objects.requireNonNullElseGet(actualIn.getArgument(), ThisExpr::new);
63-
graphNode.addVariableActionAfterLastMatchingRealNode(movDef, actualIn);
64-
ExpressionObjectTreeFinder finder = new ExpressionObjectTreeFinder(graphNode);
65-
finder.locateAndMarkTransferenceToRoot(scope, def);
83+
VariableAction scopeIn = locateScopeIn(graphNode, edge.getCall());
84+
scopeIn.getObjectTree().addAll(use.getObjectTree());
6685
}
6786
} else {
6887
throw new IllegalStateException("Definition must be either from a parameter or a field!");
6988
}
7089
}
7190

72-
/** Locates the actual-in node associated with the given variable name and call edge. */
73-
protected ActualIONode locateActualInNode(CallGraph.Edge<?> edge, String name) {
91+
/** Find all actual in nodes in the given call. */
92+
protected Set<ActualIONode> locateActualInNode(CallGraph.Edge<?> edge) {
7493
return edge.getGraphNode().getSyntheticNodesInMovables().stream()
7594
.filter(ActualIONode.class::isInstance)
7695
.map(ActualIONode.class::cast)
7796
.filter(ActualIONode::isInput)
78-
.filter(actual -> actual.getVariableName().equals(name))
79-
.filter(actual -> ASTUtils.equalsWithRange(actual.getAstNode(), (Node) edge.getCall()))
80-
.findFirst()
81-
.orElseThrow(() -> new IllegalStateException("can't locate actual-in node"));
97+
.filter(actual -> ASTUtils.equalsWithRange(actual.getAstNode(), edge.getCall()))
98+
.collect(Collectors.toSet());
99+
}
100+
101+
/** Find the -arg-in- variable action that corresponds to the given node, call and index. */
102+
protected VariableAction locateArgIn(GraphNode<?> graphNode, Resolvable<? extends ResolvedMethodLikeDeclaration> call, int index) {
103+
return locateActionIn(graphNode, call, index, "-arg-in-");
104+
}
105+
106+
/** Find the -scope-in- variable action that corresponds to the given node and call. */
107+
protected VariableAction locateScopeIn(GraphNode<?> graphNode, Resolvable<? extends ResolvedMethodLikeDeclaration> call) {
108+
return locateActionIn(graphNode, call, 0, "-scope-in-");
109+
}
110+
111+
/** Find the nth variable action from the given node and call that matches the given name. 0 represents the first occurrence. */
112+
protected VariableAction locateActionIn(GraphNode<?> graphNode, Resolvable<? extends ResolvedMethodLikeDeclaration> call, int index, String actionName) {
113+
boolean inCall = false;
114+
for (VariableAction va : graphNode.getVariableActions()) {
115+
if (va instanceof VariableAction.CallMarker && ASTUtils.equalsWithRange(((VariableAction.CallMarker) va).getCall(), call)) {
116+
if (((VariableAction.CallMarker) va).isEnter())
117+
inCall = true;
118+
else
119+
break; // The call has ended, can't find the action now
120+
}
121+
if (inCall && va.isDefinition() && va.getName().equals(actionName)) {
122+
if (index == 0)
123+
return va;
124+
else
125+
index--;
126+
}
127+
}
128+
throw new IllegalStateException("Could not locate " + actionName + " for call " + call + " in node " + graphNode);
82129
}
83130

84131
@Override

sdg-core/src/main/java/es/upv/mist/slicing/nodes/ObjectTree.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,6 @@
1111
import java.util.stream.Collectors;
1212
import java.util.stream.Stream;
1313

14-
import static es.upv.mist.slicing.graphs.cfg.CFGBuilder.VARIABLE_NAME_OUTPUT;
15-
import static es.upv.mist.slicing.graphs.exceptionsensitive.ESCFG.ACTIVE_EXCEPTION_VARIABLE;
16-
1714
/**
1815
* A tree data structure that mimics the tree found in an object's fields.
1916
* Each tree contains a MemberNode that represents its, including a name.
@@ -29,7 +26,7 @@ public class ObjectTree implements Cloneable {
2926
public static final String ROOT_NAME = "-root-";
3027

3128
/** Regex pattern to split the root from the fields of a field access expression. */
32-
private static final Pattern FIELD_SPLIT = Pattern.compile("^(?<root>(([_0-9A-Za-z]+\\.)*this)|([_0-9A-Za-z]+)|(" + ROOT_NAME + ")|(" + VARIABLE_NAME_OUTPUT + ")|(" + ACTIVE_EXCEPTION_VARIABLE + "))(\\.(?<fields>.+))?$");
29+
private static final Pattern FIELD_SPLIT = Pattern.compile("^(?<root>(([_0-9A-Za-z]+\\.)*this)|(?<dash>(-?))([_0-9A-Za-z]+\\k<dash>)+)(\\.(?<fields>.+))?$");
3330

3431
/** Direct children of this tree node, mapped by field name. */
3532
private final Map<String, ObjectTree> childrenMap = new HashMap<>();

sdg-core/src/main/java/es/upv/mist/slicing/nodes/VariableVisitor.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -475,6 +475,10 @@ protected boolean visitCall(Resolvable<? extends ResolvedMethodLikeDeclaration>
475475
acceptAction(FIELD, "this", USE);
476476
graphNode.getLastVariableAction().setStaticType(ASTUtils.resolvedTypeDeclarationToResolvedType(((MethodCallExpr) call).findAncestor(ClassOrInterfaceDeclaration.class).orElseThrow().resolve()));
477477
});
478+
// Generate -scope-in- action, so that InterproceduralUsageFinder does not need to do so.
479+
VariableAction.Definition def = new VariableAction.Definition(VariableAction.DeclarationType.SYNTHETIC, "-scope-in-", graphNode);
480+
VariableAction.Movable movDef = new VariableAction.Movable(def, scopeIn);
481+
graphNode.addVariableAction(movDef);
478482
realNodeStack.pop();
479483
}
480484
// Args
@@ -485,6 +489,10 @@ protected boolean visitCall(Resolvable<? extends ResolvedMethodLikeDeclaration>
485489
graphNode.addSyntheticNode(actualIn);
486490
realNodeStack.push(actualIn);
487491
argument.accept(this, action);
492+
// Generate -arg-in- action, so that InterproceduralUsageFinder does not need to do so.
493+
VariableAction.Definition def = new VariableAction.Definition(VariableAction.DeclarationType.SYNTHETIC, "-arg-in-", graphNode);
494+
VariableAction.Movable movDef = new VariableAction.Movable(def, actualIn);
495+
graphNode.addVariableAction(movDef);
488496
realNodeStack.pop();
489497
}
490498
// Return

sdg-core/src/main/java/es/upv/mist/slicing/nodes/io/ActualIONode.java

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
11
package es.upv.mist.slicing.nodes.io;
22

33
import com.github.javaparser.ast.Node;
4-
import com.github.javaparser.ast.body.BodyDeclaration;
54
import com.github.javaparser.ast.expr.Expression;
65
import com.github.javaparser.resolution.Resolvable;
76
import com.github.javaparser.resolution.declarations.ResolvedMethodLikeDeclaration;
8-
import es.upv.mist.slicing.utils.ASTUtils;
97

108
import java.util.Objects;
119

@@ -28,15 +26,7 @@ public boolean matchesFormalIO(FormalIONode o) {
2826
// 2. Our variables must match (type + name)
2927
&& Objects.equals(variableName, o.variableName)
3028
// 3. in matches in, out matches out
31-
&& isInput() == o.isInput()
32-
// 4. The method call must resolve to the method declaration of the argument.
33-
&& Objects.equals(o.getAstNode(), resolvedASTNode());
34-
}
35-
36-
@SuppressWarnings("unchecked")
37-
protected BodyDeclaration<?> resolvedASTNode() {
38-
return ASTUtils.getResolvedAST(((Resolvable<? extends ResolvedMethodLikeDeclaration>) astNode).resolve())
39-
.orElse(null);
29+
&& isInput() == o.isInput();
4030
}
4131

4232
@Override

sdg-core/src/main/java/es/upv/mist/slicing/utils/ASTUtils.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,26 @@ public static boolean equalsInDeclaration(Node n1, Node n2) {
4343
return n1.equals(n2) && equalsWithRange(d1, d2);
4444
}
4545

46+
/** @see #equalsWithRange(Node, Node) */
47+
public static boolean equalsWithRange(Resolvable<? extends ResolvedMethodLikeDeclaration> n1, Resolvable<? extends ResolvedMethodLikeDeclaration> n2) {
48+
return equalsWithRange((Node) n1, (Node) n2);
49+
}
50+
51+
/** @see #equalsWithRange(Node, Node) */
52+
public static boolean equalsWithRange(Node n1, Resolvable<? extends ResolvedMethodLikeDeclaration> n2) {
53+
return equalsWithRange(n1, (Node) n2);
54+
}
55+
56+
/** Compares two JavaParser nodes and their ranges (position in the file). If you need to compare between nodes
57+
* from different files, you may want to use {@link #equalsWithRangeInCU(Node, Node)} */
4658
public static boolean equalsWithRange(Node n1, Node n2) {
4759
if (n1 == null || n2 == null)
4860
return n1 == n2;
4961
return Objects.equals(n1.getRange(), n2.getRange()) && Objects.equals(n1, n2);
5062
}
5163

64+
/** Compares two JavaParser nodes, their ranges (position in the file) and compilation units (file they're in).
65+
* If the nodes belong to the same CU or have no CU, you can use {@link #equalsWithRange(Node, Node)}*/
5266
public static boolean equalsWithRangeInCU(Node n1, Node n2) {
5367
if (n1 == null || n2 == null)
5468
return n1 == n2;

sdg-core/src/test/res/regression/dinsa-tests/Josep2.java.sdg.sliced

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,8 @@ class GrandesNumeros extends Numeros {
3333
GrandesNumeros(double x) {
3434
haceFalta = 0;
3535
}
36+
37+
int random() {
38+
return haceFalta;
39+
}
3640
}

sdg-core/src/test/res/regression/review-07-2020/P5.java.sdg.sliced

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,8 @@ class GrandesNumeros extends Numeros {
3333
GrandesNumeros(double x) {
3434
haceFalta = 0;
3535
}
36+
37+
int random() {
38+
return haceFalta;
39+
}
3640
}

0 commit comments

Comments
 (0)