From 3efd5231b92de82a5e5b8c1a51c93a2754f3210a Mon Sep 17 00:00:00 2001 From: Carlos Galindo Date: Thu, 28 Jan 2021 16:52:17 +0100 Subject: [PATCH 1/3] Interprocedural DynamicTypeResolver * Closes #45 * Alters VariableAction to take Expression as argument (either NameExpr or FieldAccessExpr). * Expands the CallGraph API * Fixes bug where movable definitions were created incorrectly. * Now accepting FieldAccessExpr completely. --- .../es/upv/mist/slicing/graphs/CallGraph.java | 38 ++++ .../graphs/oo/DynamicTypeResolver.java | 166 ++++++++++++++---- .../sdg/InterproceduralActionFinder.java | 8 +- .../sdg/InterproceduralDefinitionFinder.java | 4 +- .../sdg/InterproceduralUsageFinder.java | 4 +- .../es/upv/mist/slicing/nodes/GraphNode.java | 7 +- .../mist/slicing/nodes/VariableAction.java | 41 +++-- .../mist/slicing/nodes/VariableVisitor.java | 36 ++-- 8 files changed, 229 insertions(+), 75 deletions(-) diff --git a/sdg-core/src/main/java/es/upv/mist/slicing/graphs/CallGraph.java b/sdg-core/src/main/java/es/upv/mist/slicing/graphs/CallGraph.java index 6b1b527..d6a2e6b 100644 --- a/sdg-core/src/main/java/es/upv/mist/slicing/graphs/CallGraph.java +++ b/sdg-core/src/main/java/es/upv/mist/slicing/graphs/CallGraph.java @@ -1,6 +1,7 @@ package es.upv.mist.slicing.graphs; import com.github.javaparser.ast.CompilationUnit; +import com.github.javaparser.ast.Node; import com.github.javaparser.ast.NodeList; import com.github.javaparser.ast.body.*; import com.github.javaparser.ast.expr.Expression; @@ -59,6 +60,43 @@ public class CallGraph extends DirectedPseudograph (CallableDeclaration) decl); } + /** Locates the calls to a given declaration. The result is any node that represents a call. */ + public Stream callsTo(CallableDeclaration callee) { + return incomingEdgesOf(findVertexByDeclaration(callee)).stream() + .map(Edge::getCall) + .map(Node.class::cast); + } + + /** Locates the calls contained in a given method or constructor. + * See {@link #callsTo(CallableDeclaration)} for the return value. */ + public Stream callsFrom(CallableDeclaration caller) { + return outgoingEdgesOf(findVertexByDeclaration(caller)).stream() + .map(Edge::getCall) + .map(Node.class::cast); + } + + /** Locates the methods that may call the given declaration. */ + public Stream> callersOf(CallableDeclaration callee) { + return incomingEdgesOf(findVertexByDeclaration(callee)).stream() + .map(this::getEdgeSource) + .map(Vertex::getDeclaration); + } + + /** Locates the methods that may be called when executing the given declaration. */ + public Stream> calleesOf(CallableDeclaration caller) { + return outgoingEdgesOf(findVertexByDeclaration(caller)).stream() + .map(this::getEdgeTarget) + .map(Vertex::getDeclaration); + } + + /** Locate the vertex that represents in this graph the given declaration. */ + protected Vertex findVertexByDeclaration(CallableDeclaration declaration) { + return vertexSet().stream() + .filter(v -> v.declaration == declaration || + ASTUtils.equalsWithRange(v.declaration, declaration)) + .findFirst().orElseThrow(); + } + @Override public void build(NodeList arg) { if (isBuilt()) diff --git a/sdg-core/src/main/java/es/upv/mist/slicing/graphs/oo/DynamicTypeResolver.java b/sdg-core/src/main/java/es/upv/mist/slicing/graphs/oo/DynamicTypeResolver.java index abb527d..7b621d6 100644 --- a/sdg-core/src/main/java/es/upv/mist/slicing/graphs/oo/DynamicTypeResolver.java +++ b/sdg-core/src/main/java/es/upv/mist/slicing/graphs/oo/DynamicTypeResolver.java @@ -1,69 +1,159 @@ package es.upv.mist.slicing.graphs.oo; +import com.github.javaparser.ast.Node; +import com.github.javaparser.ast.body.CallableDeclaration; import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration; +import com.github.javaparser.ast.expr.CastExpr; import com.github.javaparser.ast.expr.Expression; +import com.github.javaparser.ast.expr.MethodCallExpr; +import com.github.javaparser.ast.stmt.ReturnStmt; +import com.github.javaparser.resolution.declarations.ResolvedClassDeclaration; import com.github.javaparser.resolution.types.ResolvedType; +import es.upv.mist.slicing.graphs.CallGraph; import es.upv.mist.slicing.graphs.ClassGraph; import es.upv.mist.slicing.graphs.cfg.CFG; +import es.upv.mist.slicing.nodes.GraphNode; import es.upv.mist.slicing.nodes.VariableAction; +import es.upv.mist.slicing.nodes.io.ActualIONode; +import es.upv.mist.slicing.nodes.io.FormalIONode; import es.upv.mist.slicing.utils.ASTUtils; -import java.util.HashSet; -import java.util.Objects; +import java.util.List; +import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; +import java.util.stream.Stream; /** A dynamic type solver that complements Javaparser's {@code resolve()} method. */ public class DynamicTypeResolver { protected final CFG cfg; + protected final Map, CFG> cfgMap; protected final ClassGraph classGraph; + protected final CallGraph callGraph; - public DynamicTypeResolver(CFG cfg, ClassGraph classGraph) { + public DynamicTypeResolver(CFG cfg, Map, CFG> cfgMap, ClassGraph classGraph, CallGraph callGraph) { this.cfg = cfg; + this.cfgMap = cfgMap; this.classGraph = classGraph; + this.callGraph = callGraph; } - /** Obtains the set of dynamic types that the variable passed as argument - * may take. The current implementation is intra-procedural! */ - public Set resolve(VariableAction action) { - return resolveIntraProcedural(action); + /** Obtains the possible dynamic types of the given expression, which is contained within a GraphNode. + * Only expressions of a reference type are allowed (e.g. objects, arrays, but not primitives). */ + public Set resolve(Expression expression, GraphNode container) { + assert expression.calculateResolvedType().isReference(): "The expression must be of reference type (no primitives)."; + return resolveStreamed(expression, container).collect(Collectors.toSet()); } - /** Obtains a list of possible dynamic types for the given action, by - * searching for definitions intraprocedurally. */ - public Set resolveIntraProcedural(VariableAction action) { - return cfg.findLastDefinitionsFrom(action).stream() - .map(VariableAction::asDefinition) - .filter(Objects::nonNull) - .map(def -> { - Expression expr = unwrapExpr(def.getExpression()); - if (expr.isObjectCreationExpr() || expr.isArrayCreationExpr() - || expr.isArrayInitializerExpr()) - return Set.of(expr.calculateResolvedType()); - else - return findAllSubtypes(def.getExpression().calculateResolvedType()); - }) - .reduce(new HashSet<>(), (a, b) -> { a.addAll(b); return a; }); + /** Directs each kind of expression to the appropriate resolve method. */ + protected Stream resolveStreamed(Expression expression, GraphNode container) { + if (expression.isMethodCallExpr()) + return resolveMethodCallExpr(expression.asMethodCallExpr()); + if (expression.isNameExpr() || expression.isFieldAccessExpr()) // May be field, local variable or parameter + return resolveVariable(expression, container); + if (expression.isArrayAccessExpr()) + return anyTypeOf(expression); + if (expression.isCastExpr()) + return resolveCast(expression.asCastExpr(), container); + if (expression.isEnclosedExpr()) + return resolveStreamed(expression.asEnclosedExpr().getInner(), container); + if (expression.isObjectCreationExpr() || + expression.isArrayCreationExpr()) + return Stream.of(expression.calculateResolvedType()); + throw new IllegalArgumentException("The given expression is not an object-compatible one."); } - /** Unwraps an enclosed expression, and other constructs that are type-transparent. */ - protected Expression unwrapExpr(Expression expr) { - if (expr.isCastExpr()) - if (ASTUtils.isDownCast(expr.asCastExpr())) - return expr; - else - return unwrapExpr(expr.asCastExpr().getExpression()); - if (expr.isEnclosedExpr()) - return unwrapExpr(expr.asEnclosedExpr().getInner()); - return expr; + /** Checks the possible values of all ReturnStmt of this call's target methods. */ + protected Stream resolveMethodCallExpr(MethodCallExpr methodCallExpr) { + assert !methodCallExpr.calculateResolvedType().isVoid(); + return callGraph.getCallTargets(methodCallExpr) + .map(cfgMap::get) + .flatMap(cfg -> cfg.vertexSet().stream()) + .filter(node -> node.getAstNode() instanceof ReturnStmt) + .flatMap(node -> resolveStreamed(((ReturnStmt) node.getAstNode()).getExpression().orElseThrow(), node)); } - /** Extracts from the call graph all the subtypes of the given argument. - * The input is included as part of the output. */ - protected Set findAllSubtypes(ResolvedType t) { - return classGraph.subclassesOf(t.asReferenceType().getTypeDeclaration().orElseThrow().asClass()).stream() + /** Searches for the corresponding VariableAction object, then calls {@link #resolveVariableAction(VariableAction)}. */ + // TODO: make VariableVisitor register FieldAccessExpr as a possible action source. + protected Stream resolveVariable(Expression expression, GraphNode graphNode) { + return resolveVariableAction(graphNode.getVariableActions().stream() + .filter(action -> ASTUtils.equalsWithRange(action.getVariableExpression(), expression)) + .findFirst().orElseThrow()); + } + + /** + * Looks up the last definitions according to the CFG, then resolves the last assignment to it. + * If the last definition was not in this method (in the case of parameters or fields), it + * uses auxiliary methods to locate the last interprocedural definition. + * Otherwise, the last expression(s) assigned to it is found and recursively resolved. + */ + protected Stream resolveVariableAction(VariableAction va) { + return cfg.findLastDefinitionsFrom(va).stream() + .flatMap(def -> { + if (def.asDefinition().getExpression() == null) { + if (def instanceof VariableAction.Movable && ((VariableAction.Movable) def).getRealNode() instanceof FormalIONode) + return resolveFormalIn((FormalIONode) ((VariableAction.Movable) def).getRealNode()); + throw new IllegalArgumentException("Definition was not movable and hadn't an expression."); + } + return resolveStreamed(def.asDefinition().getExpression(), def.getGraphNode()); + }); + } + + /** Locate the declaration (method or constructor) where the given node is located. */ + protected CallableDeclaration findCallableDeclarationFromGraphNode(GraphNode node) { + return cfgMap.values().stream() + .filter(cfg -> cfg.containsVertex(node)) + .map(CFG::getDeclaration) + .findFirst().orElseThrow(); + } + + /** Looks up the expression assigned to all corresponding actual-in nodes and resolves it. */ + protected Stream resolveFormalIn(FormalIONode formalIn) { + assert formalIn.isInput(); + return callGraph.callsTo(findCallableDeclarationFromGraphNode(formalIn)) + .map(this::findNodeInMapByAST) + .map(GraphNode::getVariableActions) + .flatMap(List::stream) + .filter(VariableAction.Movable.class::isInstance) + .map(VariableAction.Movable.class::cast) + .flatMap(movable -> { + GraphNode realNode = movable.getRealNode(); + if (!(realNode instanceof ActualIONode)) + return Stream.empty(); + ActualIONode actualIn = (ActualIONode) realNode; + if (!actualIn.matchesFormalIO(formalIn)) + return Stream.empty(); + return resolveStreamed(actualIn.getArgument(), movable.getGraphNode()); + }); + } + + /** Locate the CFG graph node in which the argument is contained. + * Its time requirement is linear with the number of total nodes in */ + protected GraphNode findNodeInMapByAST(Node astNode) { + return cfgMap.values().stream() + .map(cfg -> cfg.findNodeByASTNode(astNode)) + .filter(Optional::isPresent) + .map(Optional::get) + .findFirst().orElseThrow(); + } + + /** Checks if the cast marks a more specific type and returns that one. + * Otherwise, it unwraps the cast expression and recursively resolves the type + * of the inner expression. */ + protected Stream resolveCast(CastExpr cast, GraphNode container) { + if (ASTUtils.isDownCast(cast)) + return Stream.of(cast.getType().resolve()); + return resolveStreamed(cast.getExpression(), container); + } + + /** Returns all possible types that the given expression can be, by obtaining its static type + * and locating all subtypes in the class graph. */ + protected Stream anyTypeOf(Expression expression) { + ResolvedClassDeclaration type = expression.calculateResolvedType().asReferenceType() + .getTypeDeclaration().orElseThrow().asClass(); + return classGraph.subclassesOf(type).stream() .map(ClassOrInterfaceDeclaration::resolve) - .map(ASTUtils::resolvedTypeDeclarationToResolvedType) - .collect(Collectors.toSet()); + .map(ASTUtils::resolvedTypeDeclarationToResolvedType); } } diff --git a/sdg-core/src/main/java/es/upv/mist/slicing/graphs/sdg/InterproceduralActionFinder.java b/sdg-core/src/main/java/es/upv/mist/slicing/graphs/sdg/InterproceduralActionFinder.java index ee4883d..30e3aae 100644 --- a/sdg-core/src/main/java/es/upv/mist/slicing/graphs/sdg/InterproceduralActionFinder.java +++ b/sdg-core/src/main/java/es/upv/mist/slicing/graphs/sdg/InterproceduralActionFinder.java @@ -74,7 +74,7 @@ public abstract class InterproceduralActionFinder exte /** Obtains the expression passed as argument for the given action at the given call. If {@code input} * is false, primitive parameters will be skipped, as their value cannot be redefined.*/ protected Expression extractArgument(VariableAction action, CallGraph.Edge edge, boolean input) { - ResolvedValueDeclaration resolved = action.getNameExpr().resolve(); + ResolvedValueDeclaration resolved = action.getResolvedValueDeclaration(); CallableDeclaration callTarget = graph.getEdgeTarget(edge).getDeclaration(); if (resolved.isParameter()) { ResolvedParameterDeclaration p = resolved.asParameter(); @@ -83,7 +83,7 @@ public abstract class InterproceduralActionFinder exte int paramIndex = ASTUtils.getMatchingParameterIndex(callTarget, p); return ASTUtils.getResolvableArgs(edge.getCall()).get(paramIndex); } else if (resolved.isField()) { - return action.getNameExpr(); + return action.getVariableExpression(); } else { throw new IllegalArgumentException("Variable should be either param or field!"); } @@ -116,8 +116,8 @@ public abstract class InterproceduralActionFinder exte ResolvedValueDeclaration r1 = null; ResolvedValueDeclaration r2 = null; try { - r1 = o1.getAction().getNameExpr().resolve(); - r2 = o2.getAction().getNameExpr().resolve(); + r1 = o1.getAction().getResolvedValueDeclaration(); + r2 = o2.getAction().getResolvedValueDeclaration(); if (r1.isParameter() && r2.isParameter()) return -Integer.compare(ASTUtils.getMatchingParameterIndex(graph.getEdgeTarget(edge).getDeclaration(), r1.asParameter()), ASTUtils.getMatchingParameterIndex(graph.getEdgeTarget(edge).getDeclaration(), r2.asParameter())); diff --git a/sdg-core/src/main/java/es/upv/mist/slicing/graphs/sdg/InterproceduralDefinitionFinder.java b/sdg-core/src/main/java/es/upv/mist/slicing/graphs/sdg/InterproceduralDefinitionFinder.java index 720d403..d665dd5 100644 --- a/sdg-core/src/main/java/es/upv/mist/slicing/graphs/sdg/InterproceduralDefinitionFinder.java +++ b/sdg-core/src/main/java/es/upv/mist/slicing/graphs/sdg/InterproceduralDefinitionFinder.java @@ -27,7 +27,7 @@ public class InterproceduralDefinitionFinder extends InterproceduralActionFinder @Override protected void handleFormalAction(CallableDeclaration declaration, VariableAction.Definition def) { CFG cfg = cfgMap.get(declaration); - ResolvedValueDeclaration resolved = def.getNameExpr().resolve(); + ResolvedValueDeclaration resolved = def.getResolvedValueDeclaration(); if (!resolved.isParameter() || !resolved.getType().isPrimitive()) { FormalIONode formalOut = FormalIONode.createFormalOut(declaration, resolved); cfg.getExitNode().addMovableVariable(new VariableAction.Movable(def.toUsage(cfg.getExitNode()), formalOut)); @@ -40,7 +40,7 @@ public class InterproceduralDefinitionFinder extends InterproceduralActionFinder protected void handleActualAction(CallGraph.Edge edge, VariableAction.Definition def) { Set movables = new HashSet<>(); GraphNode graphNode = edge.getGraphNode(); - ResolvedValueDeclaration resolved = def.getNameExpr().resolve(); + ResolvedValueDeclaration resolved = def.getResolvedValueDeclaration(); Expression arg = extractArgument(def, edge, false); if (arg == null) return; 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 4b64148..1e3ee0c 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 @@ -27,7 +27,7 @@ public class InterproceduralUsageFinder extends InterproceduralActionFinder declaration, VariableAction.Usage use) { CFG cfg = cfgMap.get(declaration); - ResolvedValueDeclaration resolved = use.getNameExpr().resolve(); + ResolvedValueDeclaration resolved = use.getResolvedValueDeclaration(); FormalIONode formalIn = FormalIONode.createFormalIn(declaration, resolved); cfg.getRootNode().addMovableVariable(new VariableAction.Movable(use.toDefinition(cfg.getRootNode()), formalIn)); } @@ -36,7 +36,7 @@ public class InterproceduralUsageFinder extends InterproceduralActionFinder edge, VariableAction.Usage use) { Set movables = new HashSet<>(); GraphNode graphNode = edge.getGraphNode(); - ResolvedValueDeclaration resolved = use.getNameExpr().resolve(); + ResolvedValueDeclaration resolved = use.getResolvedValueDeclaration(); Expression argument = extractArgument(use, edge, true); ActualIONode actualIn = ActualIONode.createActualIn(edge.getCall(), resolved, argument); argument.accept(new VariableVisitor( diff --git a/sdg-core/src/main/java/es/upv/mist/slicing/nodes/GraphNode.java b/sdg-core/src/main/java/es/upv/mist/slicing/nodes/GraphNode.java index f56a2bf..5314a9c 100644 --- a/sdg-core/src/main/java/es/upv/mist/slicing/nodes/GraphNode.java +++ b/sdg-core/src/main/java/es/upv/mist/slicing/nodes/GraphNode.java @@ -2,7 +2,6 @@ package es.upv.mist.slicing.nodes; import com.github.javaparser.ast.Node; import com.github.javaparser.ast.expr.Expression; -import com.github.javaparser.ast.expr.NameExpr; import com.github.javaparser.resolution.Resolvable; import com.github.javaparser.resolution.declarations.ResolvedMethodLikeDeclaration; import es.upv.mist.slicing.graphs.cfg.CFG; @@ -127,18 +126,18 @@ public class GraphNode implements Comparable> { } /** Create and append a declaration of a variable to the list of actions of this node. */ - public void addDeclaredVariable(NameExpr variable) { + public void addDeclaredVariable(Expression variable) { variableActions.add(new VariableAction.Declaration(variable, this)); } /** Create and append a definition of a variable to the list of actions of this node. */ - public void addDefinedVariable(NameExpr variable, Expression expression) { + public void addDefinedVariable(Expression variable, Expression expression) { VariableAction.Definition def = new VariableAction.Definition(variable, this, expression); variableActions.add(def); } /** Create and append a usage of a variable to the list of actions of this node. */ - public void addUsedVariable(NameExpr variable) { + public void addUsedVariable(Expression variable) { VariableAction.Usage use = new VariableAction.Usage(variable, this); variableActions.add(use); } diff --git a/sdg-core/src/main/java/es/upv/mist/slicing/nodes/VariableAction.java b/sdg-core/src/main/java/es/upv/mist/slicing/nodes/VariableAction.java index 0b6bf84..385076e 100644 --- a/sdg-core/src/main/java/es/upv/mist/slicing/nodes/VariableAction.java +++ b/sdg-core/src/main/java/es/upv/mist/slicing/nodes/VariableAction.java @@ -4,6 +4,7 @@ import com.github.javaparser.ast.expr.Expression; import com.github.javaparser.ast.expr.NameExpr; import com.github.javaparser.resolution.Resolvable; import com.github.javaparser.resolution.declarations.ResolvedMethodLikeDeclaration; +import com.github.javaparser.resolution.declarations.ResolvedValueDeclaration; import es.upv.mist.slicing.arcs.Arc; import es.upv.mist.slicing.arcs.pdg.DataDependencyArc; import es.upv.mist.slicing.graphs.Graph; @@ -18,12 +19,14 @@ import java.util.stream.Collectors; public abstract class VariableAction { protected static final String VARIABLE_PATTERN = "^([a-zA-Z][a-zA-Z0-9_]*|[_a-zA-Z][a-zA-Z0-9_]+)$"; - protected final NameExpr variable; + protected final Expression variable; protected final GraphNode graphNode; protected boolean optional = false; + protected ResolvedValueDeclaration resolvedVariableCache; - public VariableAction(NameExpr variable, GraphNode graphNode) { + public VariableAction(Expression variable, GraphNode graphNode) { + assert variable.isNameExpr() || variable.isFieldAccessExpr(); this.variable = variable; this.graphNode = graphNode; } @@ -31,17 +34,27 @@ public abstract class VariableAction { /** Whether this action is performed upon an invented variable, * introduced by this library (e.g. the active exception or the returned value). */ public boolean isSynthetic() { - return !variable.getNameAsString().matches(VARIABLE_PATTERN); + return !getVariable().matches(VARIABLE_PATTERN); } public String getVariable() { - return variable.getNameAsString(); + return variable.toString(); } - public NameExpr getNameExpr() { + public Expression getVariableExpression() { return variable; } + public ResolvedValueDeclaration getResolvedValueDeclaration() { + if (resolvedVariableCache == null) { + if (variable.isFieldAccessExpr()) + resolvedVariableCache = variable.asFieldAccessExpr().resolve(); + else if (variable.isNameExpr()) + resolvedVariableCache = variable.asNameExpr().resolve(); + } + return resolvedVariableCache; + } + // TODO: detected optional actions /** Whether this action is always performed when its parent node is executed or not. */ public boolean isOptional() { @@ -149,7 +162,7 @@ public abstract class VariableAction { /** A usage of a variable. */ public static class Usage extends VariableAction { - public Usage(NameExpr variable, GraphNode graphNode) { + public Usage(Expression variable, GraphNode graphNode) { super(variable, graphNode); } @@ -164,11 +177,11 @@ public abstract class VariableAction { /** The value to which the variable has been defined. */ protected final Expression expression; - public Definition(NameExpr variable, GraphNode graphNode) { + public Definition(Expression variable, GraphNode graphNode) { this(variable, graphNode, null); } - public Definition(NameExpr variable, GraphNode graphNode, Expression expression) { + public Definition(Expression variable, GraphNode graphNode, Expression expression) { super(variable, graphNode); this.expression = expression; } @@ -186,7 +199,7 @@ public abstract class VariableAction { /** A declaration of a variable. */ public static class Declaration extends VariableAction { - public Declaration(NameExpr variable, GraphNode graphNode) { + public Declaration(Expression variable, GraphNode graphNode) { super(variable, graphNode); } @@ -226,11 +239,15 @@ public abstract class VariableAction { * the action is deleted from its original node's list, a copy is created with the real * target and any {@link DataDependencyArc} is relocated to match this change. */ public VariableAction move(Graph graph) { - // Create unwrapped action + // Create unwrapped action (the graphNode field must be changed). VariableAction newAction; try { - newAction = inner.getClass().getConstructor(NameExpr.class, GraphNode.class) - .newInstance(variable, (GraphNode) realNode); + if (inner instanceof Definition && inner.asDefinition().getExpression() != null) + newAction = inner.getClass().getConstructor(Expression.class, GraphNode.class, Expression.class) + .newInstance(variable, realNode, inner.asDefinition().expression); + else + newAction = inner.getClass().getConstructor(Expression.class, GraphNode.class) + .newInstance(variable, realNode); } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { throw new UnsupportedOperationException("The VariableAction constructor has changed!", e); } 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 c5dc0ab..516c475 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 @@ -44,15 +44,15 @@ public class VariableVisitor extends GraphNodeContentVisitor, NameExpr> BLANK_CONSUMER = (a, b) -> {}; - protected static final TriConsumer, NameExpr, Expression> BLANK_TRICONSUMER = (a, b, c) -> {}; + protected static final BiConsumer, Expression> BLANK_BICONSUMER = (a, b) -> {}; + protected static final TriConsumer, Expression, Expression> BLANK_TRICONSUMER = (a, b, c) -> {}; /** The action to perform when a declaration is found. */ - protected final BiConsumer, NameExpr> declConsumer; + protected final BiConsumer, Expression> declConsumer; /** The action to perform when a definition is found. */ - protected final TriConsumer, NameExpr, Expression> defConsumer; + protected final TriConsumer, Expression, Expression> defConsumer; /** The action to perform when a usage is found. */ - protected final BiConsumer, NameExpr> useConsumer; + protected final BiConsumer, Expression> useConsumer; /** A stack with the last definition expression, to provide it when a variable definition is found. */ protected final Deque definitionStack = new LinkedList<>(); @@ -65,10 +65,10 @@ public class VariableVisitor extends GraphNodeContentVisitor, NameExpr> declConsumer, TriConsumer, NameExpr, Expression> defConsumer, BiConsumer, NameExpr> useConsumer) { - this.declConsumer = Objects.requireNonNullElse(declConsumer, BLANK_CONSUMER); + public VariableVisitor(BiConsumer, Expression> declConsumer, TriConsumer, Expression, Expression> defConsumer, BiConsumer, Expression> useConsumer) { + this.declConsumer = Objects.requireNonNullElse(declConsumer, BLANK_BICONSUMER); this.defConsumer = Objects.requireNonNullElse(defConsumer, BLANK_TRICONSUMER); - this.useConsumer = Objects.requireNonNullElse(useConsumer, BLANK_CONSUMER); + this.useConsumer = Objects.requireNonNullElse(useConsumer, BLANK_BICONSUMER); } public void visitAsDefinition(Node node, Expression value) { @@ -88,11 +88,25 @@ public class VariableVisitor extends GraphNodeContentVisitor Date: Thu, 28 Jan 2021 22:29:46 +0100 Subject: [PATCH 2/3] fix! consider ThisExpr --- .../mist/slicing/graphs/oo/DynamicTypeResolver.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sdg-core/src/main/java/es/upv/mist/slicing/graphs/oo/DynamicTypeResolver.java b/sdg-core/src/main/java/es/upv/mist/slicing/graphs/oo/DynamicTypeResolver.java index 7b621d6..676ee63 100644 --- a/sdg-core/src/main/java/es/upv/mist/slicing/graphs/oo/DynamicTypeResolver.java +++ b/sdg-core/src/main/java/es/upv/mist/slicing/graphs/oo/DynamicTypeResolver.java @@ -25,15 +25,13 @@ import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; -/** A dynamic type solver that complements Javaparser's {@code resolve()} method. */ +/** A dynamic type solver that complements JavaParser's {@code resolve()} method. */ public class DynamicTypeResolver { - protected final CFG cfg; protected final Map, CFG> cfgMap; protected final ClassGraph classGraph; protected final CallGraph callGraph; - public DynamicTypeResolver(CFG cfg, Map, CFG> cfgMap, ClassGraph classGraph, CallGraph callGraph) { - this.cfg = cfg; + public DynamicTypeResolver(Map, CFG> cfgMap, ClassGraph classGraph, CallGraph callGraph) { this.cfgMap = cfgMap; this.classGraph = classGraph; this.callGraph = callGraph; @@ -52,7 +50,8 @@ public class DynamicTypeResolver { return resolveMethodCallExpr(expression.asMethodCallExpr()); if (expression.isNameExpr() || expression.isFieldAccessExpr()) // May be field, local variable or parameter return resolveVariable(expression, container); - if (expression.isArrayAccessExpr()) + if (expression.isArrayAccessExpr() || + expression.isThisExpr()) return anyTypeOf(expression); if (expression.isCastExpr()) return resolveCast(expression.asCastExpr(), container); @@ -89,6 +88,7 @@ public class DynamicTypeResolver { * Otherwise, the last expression(s) assigned to it is found and recursively resolved. */ protected Stream resolveVariableAction(VariableAction va) { + CFG cfg = cfgMap.get(findCallableDeclarationFromGraphNode(va.getGraphNode())); return cfg.findLastDefinitionsFrom(va).stream() .flatMap(def -> { if (def.asDefinition().getExpression() == null) { -- GitLab From 01af2259f76c0d221cac58c3b6d6c558d408b1c8 Mon Sep 17 00:00:00 2001 From: Carlos Galindo Date: Mon, 1 Feb 2021 17:00:39 +0100 Subject: [PATCH 3/3] fix! handling of FieldAccessExpr as VariableAction --- .../graphs/oo/DynamicTypeResolver.java | 8 ++++--- .../mist/slicing/nodes/VariableVisitor.java | 22 +++++++++++++++---- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/sdg-core/src/main/java/es/upv/mist/slicing/graphs/oo/DynamicTypeResolver.java b/sdg-core/src/main/java/es/upv/mist/slicing/graphs/oo/DynamicTypeResolver.java index 676ee63..4692086 100644 --- a/sdg-core/src/main/java/es/upv/mist/slicing/graphs/oo/DynamicTypeResolver.java +++ b/sdg-core/src/main/java/es/upv/mist/slicing/graphs/oo/DynamicTypeResolver.java @@ -74,11 +74,13 @@ public class DynamicTypeResolver { } /** Searches for the corresponding VariableAction object, then calls {@link #resolveVariableAction(VariableAction)}. */ - // TODO: make VariableVisitor register FieldAccessExpr as a possible action source. protected Stream resolveVariable(Expression expression, GraphNode graphNode) { - return resolveVariableAction(graphNode.getVariableActions().stream() + Optional va = graphNode.getVariableActions().stream() .filter(action -> ASTUtils.equalsWithRange(action.getVariableExpression(), expression)) - .findFirst().orElseThrow()); + .findFirst(); + if (va.isEmpty()) + return anyTypeOf(expression); + return resolveVariableAction(va.get()); } /** 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 516c475..dd407e5 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 @@ -93,11 +93,24 @@ public class VariableVisitor extends GraphNodeContentVisitor