diff --git a/sdg-core/src/main/java/es/upv/mist/slicing/graphs/ExpressionObjectTreeFinder.java b/sdg-core/src/main/java/es/upv/mist/slicing/graphs/ExpressionObjectTreeFinder.java index f5b063d437479bf79ca5450e89b57f983fc14c26..baefca7c6fc164007a6ca023096cf7169a427d51 100644 --- a/sdg-core/src/main/java/es/upv/mist/slicing/graphs/ExpressionObjectTreeFinder.java +++ b/sdg-core/src/main/java/es/upv/mist/slicing/graphs/ExpressionObjectTreeFinder.java @@ -14,6 +14,8 @@ import es.upv.mist.slicing.utils.ASTUtils; import java.util.LinkedList; import java.util.List; +import java.util.Optional; +import java.util.function.Predicate; import static es.upv.mist.slicing.graphs.cfg.CFGBuilder.VARIABLE_NAME_OUTPUT; @@ -124,6 +126,26 @@ public class ExpressionObjectTreeFinder { .forEach(pair -> markTransference(pair, targetAction, "")); } + public void locateAndMarkTransferenceToRoot(Resolvable call, VariableAction targetAction) { + boolean enteredCall = false; + for (VariableAction va : graphNode.getVariableActions()) { + if (va instanceof VariableAction.CallMarker && + ASTUtils.equalsWithRange(((VariableAction.CallMarker) va).getCall(), call)) { + if (((VariableAction.CallMarker) va).isEnter()) + enteredCall = true; + else + break; + } + if (enteredCall && va.isDefinition() && va.getName().equals("-scope-in-")) + break; + if (enteredCall && va.isUsage() && va.getName().equals("this")) { + markTransference(new Pair<>(va, ""), targetAction, ""); + return; + } + } + throw new IllegalStateException("Can't locate USE(this)--scope--for call " + call); + } + /** * Finds object trees that correspond to the output of the given expression. * @param expression An expression that outputs an object. @@ -155,27 +177,25 @@ public class ExpressionObjectTreeFinder { if (resolved.isType()) return; if (resolved.isField() && !resolved.asField().isStatic()) { - new FieldAccessExpr(new ThisExpr(), n.getNameAsString()).accept(this, arg); - return; + String newArg = n.getNameAsString() + (!arg.isEmpty() ? "." : "") + arg; + var optVa = locateVariableAction(n, va -> va.getName().matches("^.*this$")); + if (optVa.isEmpty()) + throw new IllegalStateException("Could not find USE action for var " + newArg); + list.add(new Pair<>(optVa.get(), newArg)); + } else { + var optVa = locateVariableAction(n, va -> va.getName().equals(n.getNameAsString())); + if (optVa.isEmpty()) + throw new IllegalStateException("Cannot find USE action for var " + n); + list.add(new Pair<>(optVa.get(), arg)); } - for (VariableAction action : graphNode.getVariableActions()) { - if (action.isUsage() && action.getName().equals(n.getNameAsString())) { - list.add(new Pair<>(action, arg)); - return; - } - } - throw new IllegalStateException("Cannot find USE action for var " + n); } @Override public void visit(ThisExpr n, String arg) { - for (VariableAction action : graphNode.getVariableActions()) { - if (action.isUsage() && action.getName().matches("^.*this$")) { - list.add(new Pair<>(action, arg)); - return; - } - } - throw new IllegalStateException("Could not find USE(this)"); + var vaOpt = locateVariableAction(n, va -> va.getName().matches("^.*this$")); + if (vaOpt.isEmpty()) + throw new IllegalStateException("Could not find USE(this)"); + list.add(new Pair<>(vaOpt.get(), arg)); } @Override @@ -247,6 +267,14 @@ public class ExpressionObjectTreeFinder { @Override public void visit(PatternExpr n, String arg) {} + + protected Optional locateVariableAction(Expression expression, Predicate predicate) { + return graphNode.getVariableActions().stream() + .filter(VariableAction::isUsage) + .filter(predicate) + .filter(va -> va.matches(expression)) + .findAny(); + } }, ""); return list; } diff --git a/sdg-core/src/main/java/es/upv/mist/slicing/graphs/sdg/InterproceduralUsageFinder.java b/sdg-core/src/main/java/es/upv/mist/slicing/graphs/sdg/InterproceduralUsageFinder.java index ad1e3846d2422b6a43e27372e4080df28b08b3a1..d3a49a18b71f9bd09df2b00f4e917fd21f620cb3 100644 --- a/sdg-core/src/main/java/es/upv/mist/slicing/graphs/sdg/InterproceduralUsageFinder.java +++ b/sdg-core/src/main/java/es/upv/mist/slicing/graphs/sdg/InterproceduralUsageFinder.java @@ -3,7 +3,6 @@ package es.upv.mist.slicing.graphs.sdg; import com.github.javaparser.ast.body.CallableDeclaration; import com.github.javaparser.ast.expr.Expression; import com.github.javaparser.ast.expr.ObjectCreationExpr; -import com.github.javaparser.ast.expr.ThisExpr; import com.github.javaparser.resolution.Resolvable; import com.github.javaparser.resolution.declarations.ResolvedMethodLikeDeclaration; import es.upv.mist.slicing.graphs.CallGraph; @@ -18,7 +17,6 @@ import es.upv.mist.slicing.nodes.io.FormalIONode; import es.upv.mist.slicing.utils.ASTUtils; import java.util.Map; -import java.util.Objects; import java.util.Set; import java.util.function.Predicate; import java.util.stream.Collectors; @@ -45,8 +43,10 @@ public class InterproceduralUsageFinder extends InterproceduralActionFinder dynamicTypes = new HashSet<>(); + protected final Set expressions = new NodeHashSet<>(); protected ResolvedType staticType; protected GraphNode graphNode; @@ -176,6 +178,21 @@ public abstract class VariableAction { return dynamicTypes; } + public void addExpression(Expression expression) { + expressions.add(expression); + } + + public void copyExpressions(VariableAction variableAction) { + if (variableAction instanceof Movable) + variableAction = ((Movable) variableAction).inner; + variableAction.expressions.forEach(this::addExpression); + } + + /** Whether this variable action represents the given expression. */ + public boolean matches(Expression expression) { + return expressions.contains(expression); + } + // ====================================================== // =================== OBJECT TREE ====================== // ====================================================== @@ -521,6 +538,16 @@ public abstract class VariableAction { inner.applySDGTreeConnection(sdg, targetAction); } + @Override + public void addExpression(Expression expression) { + inner.addExpression(expression); + } + + @Override + public boolean matches(Expression expression) { + return inner.matches(expression); + } + @Override public void setStaticType(ResolvedType staticType) { inner.setStaticType(staticType); diff --git a/sdg-core/src/main/java/es/upv/mist/slicing/nodes/VariableVisitor.java b/sdg-core/src/main/java/es/upv/mist/slicing/nodes/VariableVisitor.java index 370649b38e59a8dad0ee7c87d43b1dc78934234b..6228adb24a030507d0c75a8ae3a9d874097b1278 100644 --- a/sdg-core/src/main/java/es/upv/mist/slicing/nodes/VariableVisitor.java +++ b/sdg-core/src/main/java/es/upv/mist/slicing/nodes/VariableVisitor.java @@ -11,6 +11,7 @@ import com.github.javaparser.resolution.UnsolvedSymbolException; import com.github.javaparser.resolution.declarations.AssociableToAST; import com.github.javaparser.resolution.declarations.ResolvedMethodLikeDeclaration; import com.github.javaparser.resolution.declarations.ResolvedValueDeclaration; +import com.github.javaparser.resolution.types.ResolvedReferenceType; import com.github.javaparser.resolution.types.ResolvedType; import com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserMethodDeclaration; import es.upv.mist.slicing.graphs.ClassGraph; @@ -81,8 +82,9 @@ public class VariableVisitor extends GraphNodeContentVisitor l.accept(this, arg)); } @Override @@ -265,16 +275,16 @@ public class VariableVisitor extends GraphNodeContentVisitor { init.accept(this, action); definitionStack.push(init); - acceptAction(LOCAL_VARIABLE, v.getNameAsString(), DEFINITION); - graphNode.getLastVariableAction().setStaticType(v.getType().resolve()); + VariableAction vaDef = acceptAction(LOCAL_VARIABLE, v.getNameAsString(), DEFINITION); + vaDef.addExpression(n); + vaDef.setStaticType(v.getType().resolve()); definitionStack.pop(); if (v.getType().isClassOrInterfaceType()) - getLastDefinition().setTotallyDefinedMember(v.getNameAsString()); + vaDef.asDefinition().setTotallyDefinedMember(v.getNameAsString()); v.accept(this, action); }); } @@ -369,19 +384,19 @@ public class VariableVisitor extends GraphNodeContentVisitor ASTUtils.initializerForField(n)); init.accept(this, action); definitionStack.push(init); - acceptAction(FIELD, realName, DEFINITION); - graphNode.getLastVariableAction().setStaticType(staticType); + VariableAction vaDef = acceptAction(FIELD, realName, DEFINITION); + vaDef.setStaticType(staticType); definitionStack.pop(); if (v.getType().isClassOrInterfaceType()) - getLastDefinition().setTotallyDefinedMember(realName); + vaDef.asDefinition().setTotallyDefinedMember(realName); v.accept(this, action); } } @@ -405,10 +420,10 @@ public class VariableVisitor extends GraphNodeContentVisitor vaList = graphNode.getVariableActions(); - if (vaList.size() >= 5) { // call-super, DEC(this), USE(-output-), ret-super, DEF(this) + if (!visitCall) { // call-super, DEC(this), USE(-output-), ret-super, DEF(this) + assert vaList.size() >= 5; VariableAction useOutput = vaList.get(vaList.size() - 3); - VariableAction defThis = graphNode.getLastVariableAction(); assert useOutput.isUsage() && useOutput.getName().equals(VARIABLE_NAME_OUTPUT); - assert defThis.isDefinition() && defThis.getName().equals("this"); defThis.asDefinition().setTotallyDefinedMember("this"); ObjectTree.copyTargetTreeToSource(defThis.getObjectTree(), useOutput.getObjectTree(), "", ""); useOutput.setPDGTreeConnectionTo(defThis, "", ""); @@ -462,8 +477,8 @@ public class VariableVisitor extends GraphNodeContentVisitor scope.accept(this, action), () -> { - acceptAction(FIELD, "this", USE); - graphNode.getLastVariableAction().setStaticType(ASTUtils.resolvedTypeDeclarationToResolvedType(((MethodCallExpr) call).findAncestor(ClassOrInterfaceDeclaration.class).orElseThrow().resolve())); + VariableAction va = acceptAction(FIELD, "this", USE); + va.setStaticType(ASTUtils.resolvedTypeOfCurrentClass((MethodCallExpr) call)); }); // Generate -scope-in- action, so that InterproceduralUsageFinder does not need to do so. VariableAction.Definition def = new VariableAction.Definition(VariableAction.DeclarationType.SYNTHETIC, "-scope-in-", graphNode); @@ -516,9 +531,10 @@ public class VariableVisitor extends GraphNodeContentVisitor parentNode = ((Node) call).getParentNode(); if (parentNode.isEmpty() || !(parentNode.get() instanceof ExpressionStmt)) { - graphNode.addVariableAction(new VariableAction.Usage(SYNTHETIC, VARIABLE_NAME_OUTPUT, graphNode, - fields.map(tree -> (ObjectTree) tree.clone()).orElse(null))); - graphNode.getLastVariableAction().setStaticType(ASTUtils.getCallResolvedType(call)); + VariableAction use = new VariableAction.Usage(SYNTHETIC, VARIABLE_NAME_OUTPUT, graphNode, + fields.map(tree -> (ObjectTree) tree.clone()).orElse(null)); + graphNode.addVariableAction(use); + use.setStaticType(ASTUtils.getCallResolvedType(call)); } } @@ -542,7 +558,7 @@ public class VariableVisitor extends GraphNodeContentVisitor diff --git a/sdg-core/src/main/java/es/upv/mist/slicing/utils/ASTUtils.java b/sdg-core/src/main/java/es/upv/mist/slicing/utils/ASTUtils.java index b84f83848f1d78b69c530eb040aee4b2a3e79d80..94004bf1d201facef02195886a2eb7202aa7ccd5 100644 --- a/sdg-core/src/main/java/es/upv/mist/slicing/utils/ASTUtils.java +++ b/sdg-core/src/main/java/es/upv/mist/slicing/utils/ASTUtils.java @@ -250,4 +250,9 @@ public class ASTUtils { } return classInit; } + + public static ResolvedType resolvedTypeOfCurrentClass(Node n) { + return ASTUtils.resolvedTypeDeclarationToResolvedType( + n.findAncestor(ClassOrInterfaceDeclaration.class).orElseThrow().resolve()); + } }