Skip to content

Commit a913382

Browse files
committed
Merge branch 'carlos' into develop
# Conflicts: # sdg-core/src/main/java/es/upv/mist/slicing/nodes/VariableAction.java
2 parents b2b2401 + 0a230da commit a913382

18 files changed

+519
-174
lines changed

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

Lines changed: 92 additions & 64 deletions
Large diffs are not rendered by default.

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

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ protected VariableAction locateVAVariableDeclarator(String realName) {
8181
else if (foundDecl)
8282
return lastDef;
8383
} else if (a.isDefinition() && a.getName().equals(root)) {
84-
if (root.equals(realName) || a.hasTreeMember(realName))
84+
if (root.equals(realName) || a.hasPolyTreeMember(realName))
8585
lastDef = a;
8686
}
8787
}
@@ -196,14 +196,14 @@ public void visit(MethodCallExpr n, String arg) {
196196
visitCall(n, arg);
197197
}
198198

199-
protected void visitCall(Expression call, String arg) {
200-
if (ASTUtils.shouldVisitArgumentsForMethodCalls((Resolvable<? extends ResolvedMethodLikeDeclaration>) call))
199+
protected void visitCall(Resolvable<? extends ResolvedMethodLikeDeclaration> call, String arg) {
200+
if (ASTUtils.shouldVisitArgumentsForMethodCalls(call))
201201
return;
202202
VariableAction lastUseOut = null;
203203
for (VariableAction variableAction : graphNode.getVariableActions()) {
204204
if (variableAction instanceof VariableAction.CallMarker) {
205205
VariableAction.CallMarker marker = (VariableAction.CallMarker) variableAction;
206-
if (ASTUtils.equalsWithRange((Node) marker.getCall(), call) && !marker.isEnter()) {
206+
if (ASTUtils.equalsWithRange((Node) marker.getCall(), (Node) call) && !marker.isEnter()) {
207207
assert lastUseOut != null;
208208
list.add(new Pair<>(lastUseOut, arg));
209209
return;
@@ -252,7 +252,10 @@ protected void markTransference(Pair<VariableAction, String> sourcePair, Variabl
252252
VariableAction sourceAction = sourcePair.a;
253253
String sourceMember = sourcePair.b;
254254
if (targetAction.hasObjectTree()) {
255-
ObjectTree.copyTargetTreeToSource(sourceAction.getObjectTree(), targetAction.getObjectTree(), sourceMember, targetMember);
255+
boolean sourceTypesInClassGraph = sourceAction.getDynamicTypes().stream()
256+
.anyMatch(ClassGraph.getInstance()::containsType);
257+
if (sourceTypesInClassGraph && !sourceAction.hasObjectTree())
258+
ObjectTree.copyTargetTreeToSource(sourceAction.getObjectTree(), targetAction.getObjectTree(), sourceMember, targetMember);
256259
sourceAction.setPDGTreeConnectionTo(targetAction, sourceMember, targetMember);
257260
} else {
258261
sourceAction.setPDGValueConnection(sourceMember);

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ public List<VariableAction> findLastDefinitionOfObjectRoot(VariableAction usage)
7777
/** Given a field declaration, locate all definitions that affect the given member. */
7878
public List<VariableAction> findAllFutureObjectDefinitionsFor(VariableAction action) {
7979
List<VariableAction> list = new LinkedList<>();
80-
Predicate<VariableAction> filter = a -> a.isDefinition() && a.getName().equals("this") && a.hasTreeMember(action.getName());
80+
Predicate<VariableAction> filter = a -> a.isDefinition() && a.getName().equals("this") && a.hasPolyTreeMember(action.getName());
8181
findAllFutureVarActionsFor(new HashSet<>(), list, action.getGraphNode(), action, filter);
8282
return list;
8383
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,8 @@ protected void addFlowDependencyArc(VariableAction source, VariableAction target
5454
}
5555

5656
protected void addDeclarationFlowDependencyArc(VariableAction declaration, VariableAction definition) {
57-
MemberNode defMember = definition.getObjectTree().getNodeFor(declaration.getName());
58-
addEdge(graphNodeOf(declaration), defMember, new FlowDependencyArc());
57+
for (MemberNode target : definition.getObjectTree().getNodesForPoly(declaration.getName()))
58+
addEdge(graphNodeOf(declaration), target, new FlowDependencyArc());
5959
}
6060

6161
// definicion de miembro --flow--> uso de miembro

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

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,8 @@ protected Set<SyntheticNode<?>> getFormalOutNodes(CallableDeclaration<?> declara
3131
continue;
3232
assert node.getVariableActions().size() == 1;
3333
VariableAction action = node.getVariableActions().get(0);
34-
if (action.hasObjectTree()) {
35-
set.add(action.getObjectTree().getMemberNode());
36-
for (MemberNode memberNode : action.getObjectTree().nodeIterable())
37-
set.add(memberNode);
38-
}
34+
if (action.hasObjectTree())
35+
set.addAll(action.getObjectTree().leaves());
3936
}
4037
return set;
4138
}

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

Lines changed: 145 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,18 @@
11
package es.upv.mist.slicing.nodes;
22

3+
import com.github.javaparser.resolution.types.ResolvedType;
34
import es.upv.mist.slicing.nodes.oo.MemberNode;
5+
import es.upv.mist.slicing.nodes.oo.PolyMemberNode;
46
import es.upv.mist.slicing.utils.Utils;
57

68
import java.util.*;
79
import java.util.regex.Matcher;
810
import java.util.regex.Pattern;
11+
import java.util.stream.Collectors;
12+
import java.util.stream.Stream;
13+
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;
916

1017
/**
1118
* A tree data structure that mimics the tree found in an object's fields.
@@ -22,7 +29,7 @@ public class ObjectTree implements Cloneable {
2229
public static final String ROOT_NAME = "-root-";
2330

2431
/** Regex pattern to split the root from the fields of a field access expression. */
25-
private static final Pattern FIELD_SPLIT = Pattern.compile("^(?<root>(([_0-9A-Za-z]+\\.)*this)|([_0-9A-Za-z]+)|(-root-))(\\.(?<fields>.+))?$");
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>.+))?$");
2633

2734
/** Direct children of this tree node, mapped by field name. */
2835
private final Map<String, ObjectTree> childrenMap = new HashMap<>();
@@ -36,12 +43,22 @@ public ObjectTree() {
3643

3744
/** Create a root of a new object tree with the given name. */
3845
public ObjectTree(String memberName) {
39-
memberNode = new MemberNode(memberName, null);
46+
this(new MemberNode(memberName, null));
4047
}
4148

4249
/** Create a child tree node for the given field, whose node is linked to the given parent. */
4350
private ObjectTree(String memberName, ObjectTree parent) {
44-
this.memberNode = new MemberNode(memberName, parent.memberNode);
51+
this(new MemberNode(memberName, parent.memberNode));
52+
}
53+
54+
/** Create a child tree node for the given type, whose node is linked to the given parent. */
55+
private ObjectTree(ResolvedType resolvedType, ObjectTree parent) {
56+
this(new PolyMemberNode(resolvedType, parent.memberNode));
57+
}
58+
59+
/** Create a child tree with the given member node. */
60+
private ObjectTree(MemberNode memberNode) {
61+
this.memberNode = memberNode;
4562
}
4663

4764
/** The name of the variable or field represented by this tree. It doesn't include ancestors. */
@@ -58,6 +75,44 @@ public boolean hasChildren() {
5875
return !childrenMap.isEmpty();
5976
}
6077

78+
/** Whether the field passed as argument has children. */
79+
public boolean hasChildren(String memberWithRoot) {
80+
String member = removeRoot(memberWithRoot);
81+
if (member.isEmpty())
82+
return hasChildren();
83+
return hasChildrenInternal(member);
84+
}
85+
86+
protected boolean hasChildrenInternal(String members) {
87+
if (members.contains(".")) {
88+
int firstDot = members.indexOf('.');
89+
String first = members.substring(0, firstDot);
90+
String rest = members.substring(firstDot + 1);
91+
childrenMap.computeIfAbsent(first, f -> new ObjectTree(f, this));
92+
return childrenMap.get(first).hasChildrenInternal(rest);
93+
} else {
94+
return childrenMap.get(members).hasChildren();
95+
}
96+
}
97+
98+
/** Whether this object tree immediately contains polymorphic nodes. */
99+
public boolean hasPoly() {
100+
return childrenMap.values().stream().anyMatch(ot -> ot.getMemberNode() instanceof PolyMemberNode);
101+
}
102+
103+
/** A set of entry pairs, containing the field name and its corresponding tree. It is unmodifiable. */
104+
public Set<Map.Entry<String, ObjectTree>> entrySet() {
105+
return Collections.unmodifiableSet(childrenMap.entrySet());
106+
}
107+
108+
/** Insert a polymorphic node for the given type. The type node will be
109+
* generated immediately beneath this tree node. */
110+
public ObjectTree addType(ResolvedType rt) {
111+
assert !rt.describe().isBlank();
112+
assert !(memberNode instanceof PolyMemberNode);
113+
return childrenMap.computeIfAbsent(rt.describe(), n -> new ObjectTree(rt, this));
114+
}
115+
61116
/**
62117
* Insert a field with the given name. This method should only be called on a root object tree.
63118
* This method may be used to add multiple levels simultaneously, calling this method with
@@ -66,22 +121,30 @@ public boolean hasChildren() {
66121
* @param fieldName The field to be added, should include the root variable name. For example,
67122
* to add the field "x" to a variable "a", this argument should be "a.x".
68123
*/
69-
public void addField(String fieldName) {
124+
public ObjectTree addField(String fieldName) {
70125
String members = removeRoot(fieldName);
71-
addNonRootField(members);
126+
return addNonRootField(members);
127+
}
128+
129+
/** Insert a field in the current level of object tree. The field should be a variable name,
130+
* and not contain dots or be blank. */
131+
public ObjectTree addImmediateField(String fieldName) {
132+
if (fieldName.contains(".") || fieldName.isBlank())
133+
throw new IllegalArgumentException("field name must not include dots or be blank!");
134+
return childrenMap.computeIfAbsent(fieldName, f -> new ObjectTree(f, this));
72135
}
73136

74137
/** Similar to {@link #addField(String)}, but may be called at any level
75138
* and the argument must not contain the root variable. */
76-
private void addNonRootField(String members) {
139+
private ObjectTree addNonRootField(String members) {
77140
if (members.contains(".")) {
78141
int firstDot = members.indexOf('.');
79142
String first = members.substring(0, firstDot);
80143
String rest = members.substring(firstDot + 1);
81144
childrenMap.computeIfAbsent(first, f -> new ObjectTree(f, this));
82-
childrenMap.get(first).addNonRootField(rest);
145+
return childrenMap.get(first).addNonRootField(rest);
83146
} else {
84-
childrenMap.computeIfAbsent(members, f -> new ObjectTree(f, this));
147+
return childrenMap.computeIfAbsent(members, f -> new ObjectTree(f, this));
85148
}
86149
}
87150

@@ -96,25 +159,39 @@ public void addAll(ObjectTree tree) {
96159
}
97160

98161
/**
99-
* Copies a subtree from source into another subtree in target.
100-
*
162+
* Copies a subtree from source into another subtree in target. The tree may be
163+
* pasted multiple times, if there are polymorphic nodes that are not explicitly marked
164+
* in the prefix arguments.
101165
* @param source The source of the nodes.
102166
* @param target The tree where nodes will be added
103167
* @param sourcePrefix The prefix to be consumed before copying nodes. Without root.
104168
* @param targetPrefix The prefix to be consumed before copying nodes. Without root.
105169
*/
106170
public static void copyTargetTreeToSource(ObjectTree source, ObjectTree target, String sourcePrefix, String targetPrefix) {
107-
ObjectTree a = source.findObjectTreeOfMember(sourcePrefix);
108-
ObjectTree b = target.findObjectTreeOfMember(targetPrefix);
109-
a.addAll(b);
171+
Collection<ObjectTree> a = source.findObjectTreeOfPolyMember(sourcePrefix);
172+
Collection<ObjectTree> b = target.findObjectTreeOfPolyMember(targetPrefix);
173+
for (ObjectTree sourceTree : a)
174+
for (ObjectTree targetTree : b)
175+
sourceTree.addAll(targetTree);
110176
}
111177

112-
/**
113-
* Locate an object tree that represents a field of this object.
114-
* @param member The field, without a root prefix.
115-
*/
116-
ObjectTree findObjectTreeOfMember(String member) {
117-
ObjectTree result = this;
178+
/** Obtains the set of nodes in this object tree that have no children. */
179+
public Collection<MemberNode> leaves() {
180+
return streamLeaves().collect(Collectors.toSet());
181+
}
182+
183+
/** @see #leaves() */
184+
protected Stream<MemberNode> streamLeaves() {
185+
if (childrenMap.isEmpty())
186+
return Stream.of(memberNode);
187+
return childrenMap.values().stream()
188+
.flatMap(ObjectTree::streamLeaves);
189+
}
190+
191+
/** Similar to {@link #getNodesForPoly(String)}, but returns object trees
192+
* instead of member nodes. */
193+
Collection<ObjectTree> findObjectTreeOfPolyMember(String member) {
194+
Collection<ObjectTree> result = List.of(this);
118195
while (!member.isEmpty()) {
119196
int firstDot = member.indexOf('.');
120197
String first, rest;
@@ -125,7 +202,22 @@ ObjectTree findObjectTreeOfMember(String member) {
125202
first = member;
126203
rest = "";
127204
}
128-
result = result.childrenMap.get(first);
205+
result = result.stream().flatMap(res -> {
206+
ObjectTree ot = res.childrenMap.get(first);
207+
if (ot == null && res.childrenMap.size() > 0) {
208+
Collection<ObjectTree> collection = new LinkedList<>();
209+
for (ObjectTree child : childrenMap.values()) {
210+
if (!(child.getMemberNode() instanceof PolyMemberNode) || !child.childrenMap.containsKey(first))
211+
throw new IllegalArgumentException("Could not locate member in object tree");
212+
collection.add(child.childrenMap.get(first));
213+
}
214+
return collection.stream();
215+
} else if (ot == null) {
216+
throw new IllegalArgumentException("Could not locate member in object tree");
217+
} else {
218+
return Stream.of(ot);
219+
}
220+
}).collect(Collectors.toList());
129221
member = rest;
130222
}
131223
return result;
@@ -134,19 +226,34 @@ ObjectTree findObjectTreeOfMember(String member) {
134226
/** Whether this object tree contains the given member. The argument should contain the root variable name. */
135227
public boolean hasMember(String member) {
136228
String field = removeRoot(member);
137-
return hasNonRootMember(field);
229+
return hasNonRootMember(field, false);
230+
}
231+
232+
/** Whether this object tree contains the given member. The argument may omit typing
233+
* information (i.e., 'a.x' will find 'a.A.x', where A is a polymorphic node). */
234+
public boolean hasPolyMember(String member) {
235+
String field = removeRoot(member);
236+
return hasNonRootMember(field, true);
138237
}
139238

140239
/** Similar to hasMember, but valid at any level of the tree and the argument should not contain
141240
* the root variable's name.
142241
* @see #hasMember(String) */
143-
private boolean hasNonRootMember(String members) {
242+
private boolean hasNonRootMember(String members, boolean polymorphic) {
144243
if (members.contains(".")) {
145244
int firstDot = members.indexOf('.');
146245
String first = members.substring(0, firstDot);
147246
String rest = members.substring(firstDot + 1);
148-
return childrenMap.containsKey(first) && childrenMap.get(first).hasNonRootMember(rest);
247+
if (polymorphic && !childrenMap.containsKey(first) && !childrenMap.isEmpty())
248+
return childrenMap.values().stream()
249+
.filter(ot -> ot.getMemberNode() instanceof PolyMemberNode)
250+
.anyMatch(ot -> ot.hasNonRootMember(members, true));
251+
return childrenMap.containsKey(first) && childrenMap.get(first).hasNonRootMember(rest, polymorphic);
149252
} else {
253+
if (polymorphic && !childrenMap.containsKey(members) && !childrenMap.isEmpty())
254+
return childrenMap.values().stream()
255+
.filter(ot -> ot.getMemberNode() instanceof PolyMemberNode)
256+
.anyMatch(ot -> ot.hasNonRootMember(members, true));
150257
return childrenMap.containsKey(members);
151258
}
152259
}
@@ -174,6 +281,16 @@ MemberNode getNodeForNonRoot(String members) {
174281
}
175282
}
176283

284+
/** Similar to {@link #getNodeFor(String)}, but if the argument does not contain
285+
* types, it will obtain all member nodes that represent a given field (in multiple
286+
* types). For example, the argument 'a.x' may produce 'a.A.x' and 'a.B.x'; whereas
287+
* the argument 'a.A.x' will only produce one node. */
288+
public Collection<MemberNode> getNodesForPoly(String memberWithRoot) {
289+
return findObjectTreeOfPolyMember(removeRoot(memberWithRoot)).stream()
290+
.map(ObjectTree::getMemberNode)
291+
.collect(Collectors.toList());
292+
}
293+
177294
/** @return An iterable through the names (with full prefixes) of all members of this tree,
178295
* excluding the root. */
179296
public Iterable<String> nameIterable() {
@@ -192,14 +309,16 @@ public String next() {
192309
MemberNode node = element.memberNode;
193310
if (node == null)
194311
return ROOT_NAME;
312+
else if (node instanceof PolyMemberNode)
313+
return next();
195314
else
196315
builder.append(node.getLabel());
197-
while (node.getParent() instanceof MemberNode && node.getParent().getLabel().matches("^(USE|DEF|DEC)\\{")) {
316+
while (node.getParent() instanceof MemberNode) {
198317
node = (MemberNode) node.getParent();
199318
builder.insert(0, '.');
200319
builder.insert(0, node.getLabel());
201320
}
202-
return builder.insert(0, ROOT_NAME + ".").toString();
321+
return builder.toString();
203322
}
204323
};
205324
}
@@ -248,11 +367,6 @@ public ObjectTree next() {
248367
};
249368
}
250369

251-
/** @see #treeIterator() */
252-
Iterable<ObjectTree> treeIterable() {
253-
return this::treeIterator;
254-
}
255-
256370
@SuppressWarnings("MethodDoesntCallSuperMethod")
257371
@Override
258372
public Object clone() {
@@ -263,7 +377,7 @@ public Object clone() {
263377
}
264378

265379
private ObjectTree clone(ObjectTree parent) {
266-
ObjectTree clone = new ObjectTree(getMemberName(), parent);
380+
ObjectTree clone = new ObjectTree(getMemberNode().copyToParent(parent.getMemberNode()));
267381
for (Map.Entry<String, ObjectTree> entry : childrenMap.entrySet())
268382
clone.childrenMap.put(entry.getKey(), entry.getValue().clone(clone));
269383
return clone;

0 commit comments

Comments
 (0)