Commit d71ef175 authored by Carlos Galindo's avatar Carlos Galindo
Browse files

Merge branch 'carlos' into 'develop'

Add polymorphic calls

See merge request !61
parents a9133823 5dc18b6e
Loading
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -167,7 +167,7 @@ public class CallGraph extends DirectedPseudograph<CallGraph.Vertex, CallGraph.E
            // =============== Method calls ===============
            @Override
            public void visit(MethodCallExpr n, Void arg) {
                n.resolve().toAst().ifPresent(decl -> createNormalEdge(decl, n));
                n.resolve().toAst().ifPresent(decl -> createPolyEdges(decl, n));
                super.visit(n, arg);
            }

+1 −2
Original line number Diff line number Diff line
package es.upv.mist.slicing.graphs;

import com.github.javaparser.ast.Node;
import com.github.javaparser.ast.body.VariableDeclarator;
import com.github.javaparser.ast.expr.*;
import com.github.javaparser.ast.visitor.VoidVisitorAdapter;
@@ -203,7 +202,7 @@ public class ExpressionObjectTreeFinder {
                for (VariableAction variableAction : graphNode.getVariableActions()) {
                    if (variableAction instanceof VariableAction.CallMarker) {
                        VariableAction.CallMarker marker = (VariableAction.CallMarker) variableAction;
                        if (ASTUtils.equalsWithRange((Node) marker.getCall(), (Node) call) && !marker.isEnter()) {
                        if (ASTUtils.equalsWithRange(marker.getCall(), call) && !marker.isEnter()) {
                            assert lastUseOut != null;
                            list.add(new Pair<>(lastUseOut, arg));
                            return;
+40 −9
Original line number Diff line number Diff line
@@ -44,23 +44,30 @@ public class InterproceduralDefinitionFinder extends InterproceduralActionFinder
            Optional<Expression> arg = extractArgument(def, edge, false);
            if (arg.isEmpty())
                return;
            ActualIONode actualOut = ActualIONode.createActualOut(edge.getCall(), def.getName(), arg.get());
            ActualIONode actualOut = locateActualOutNode(edge, def.getName())
                    .orElseGet(() -> ActualIONode.createActualOut(edge.getCall(), def.getName(), arg.get()));
            extractOutputVariablesAsMovables(arg.get(), movables, graphNode, actualOut, def);
        } else if (def.isField()) {
            if (def.isStatic()) {
                // Known limitation: static fields
            } else {
                assert !(edge.getCall() instanceof ObjectCreationExpr);
                ActualIONode actualOut = ActualIONode.createActualOut(edge.getCall(), def.getName(), null);
                ActualIONode actualOut = locateActualOutNode(edge, def.getName())
                        .orElseGet(() -> ActualIONode.createActualOut(edge.getCall(), def.getName(), null));
                Optional<Expression> scope = ASTUtils.getResolvableScope(edge.getCall());
                if (scope.isPresent()) {
                    extractOutputVariablesAsMovables(scope.get(), movables, graphNode, actualOut, def);
                } else {
                    assert def.hasObjectTree();
                    Optional<VariableAction> optVA = locateDefinition(graphNode, "this");
                    if (optVA.isPresent())
                        optVA.get().getObjectTree().addAll(def.getObjectTree());
                    else {
                        var movableDef = new Definition(DeclarationType.FIELD, "this", graphNode, (ObjectTree) def.getObjectTree().clone());
                        movables.add(new Movable(movableDef, actualOut));
                    }
                }
            }
        } else {
            throw new IllegalStateException("Definition must be either from a parameter or a field!");
        }
@@ -75,6 +82,10 @@ public class InterproceduralDefinitionFinder extends InterproceduralActionFinder
        e.accept(new OutNodeVariableVisitor(), defExpressions);
        for (Expression expression : defExpressions) {
            assert def.hasObjectTree();
            Optional<VariableAction> optVa = locateDefinition(graphNode, expression.toString());
            if (optVa.isPresent()) {
                optVa.get().getObjectTree().addAll(def.getObjectTree());
            } else {
                DeclarationType type = DeclarationType.valueOf(expression);
                Definition inner = new Definition(type, expression.toString(), graphNode, (ObjectTree) def.getObjectTree().clone());
                if (defExpressions.size() > 1)
@@ -82,6 +93,26 @@ public class InterproceduralDefinitionFinder extends InterproceduralActionFinder
                movables.add(new Movable(inner, actualOut));
            }
        }
    }

    /** Find the actual out node in the given edge call that corresponds to the given variable name. */
    protected Optional<ActualIONode> locateActualOutNode(CallGraph.Edge<?> edge, String name) {
        return edge.getGraphNode().getSyntheticNodesInMovables().stream()
                .filter(ActualIONode.class::isInstance)
                .map(ActualIONode.class::cast)
                .filter(ActualIONode::isOutput)
                .filter(actual -> actual.getVariableName().equals(name))
                .filter(actual -> ASTUtils.equalsWithRange(actual.getAstNode(), edge.getCall()))
                .findFirst();
    }

    /** Try to locate the definition for the given variable name in the given node. */
    protected Optional<VariableAction> locateDefinition(GraphNode<?> graphNode, String name) {
        return graphNode.getVariableActions().stream()
                .filter(va -> va.getName().equals(name))
                .filter(VariableAction::isDefinition)
                .findAny();
    }

    @Override
    protected Stream<Definition> mapAndFilterActionStream(Stream<VariableAction> stream, CFG cfg) {
+69 −22
Original line number Diff line number Diff line
package es.upv.mist.slicing.graphs.sdg;

import com.github.javaparser.ast.Node;
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;
import es.upv.mist.slicing.graphs.ExpressionObjectTreeFinder;
import es.upv.mist.slicing.graphs.cfg.CFG;
import es.upv.mist.slicing.nodes.GraphNode;
import es.upv.mist.slicing.nodes.ObjectTree;
import es.upv.mist.slicing.nodes.VariableAction;
import es.upv.mist.slicing.nodes.VariableAction.Definition;
import es.upv.mist.slicing.nodes.VariableAction.Movable;
import es.upv.mist.slicing.nodes.VariableAction.Usage;
import es.upv.mist.slicing.nodes.io.ActualIONode;
@@ -20,7 +19,9 @@ 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;
import java.util.stream.Stream;

/** An interprocedural usage finder, which adds the associated actions to formal and actual nodes in the CFGs. */
@@ -29,6 +30,32 @@ public class InterproceduralUsageFinder extends InterproceduralActionFinder<Usag
        super(callGraph, cfgMap);
    }

    @Override
    public void save() {
        super.save();
        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()) {
            for (ActualIONode actualIn : locateActualInNode(edge)) {
                for (VariableAction va : edge.getGraphNode().getVariableActions()) {
                    if (va instanceof Movable && ((Movable) va).getRealNode().equals(actualIn)) {
                        ExpressionObjectTreeFinder finder = new ExpressionObjectTreeFinder(edge.getGraphNode());
                        if (va.getName().equals("-scope-in-")) {
                            Expression scope = Objects.requireNonNullElseGet(actualIn.getArgument(), ThisExpr::new);
                            finder.locateAndMarkTransferenceToRoot(scope, va);
                        } else if (va.getName().equals("-arg-in-")) {
                            finder.locateAndMarkTransferenceToRoot(actualIn.getArgument(), va);
                        }
                    }
                }
            }
        }
    }

    @Override
    protected void handleFormalAction(CallGraph.Vertex vertex, Usage use) {
        CFG cfg = cfgMap.get(vertex.getDeclaration());
@@ -43,12 +70,9 @@ public class InterproceduralUsageFinder extends InterproceduralActionFinder<Usag
        if (use.isParameter()) {
            if (!use.isPrimitive()) {
                assert use.hasObjectTree();
                ActualIONode actualIn = locateActualInNode(edge, use.getName());
                Definition def = new Definition(VariableAction.DeclarationType.SYNTHETIC, "-arg-in-", graphNode, (ObjectTree) use.getObjectTree().clone());
                Movable movDef = new Movable(def, actualIn);
                graphNode.addVariableActionAfterLastMatchingRealNode(movDef, actualIn);
                ExpressionObjectTreeFinder finder = new ExpressionObjectTreeFinder(graphNode);
                finder.locateAndMarkTransferenceToRoot(actualIn.getArgument(), def);
                int index = ASTUtils.getMatchingParameterIndex(graph.getEdgeTarget(edge).getDeclaration(), use.getName());
                VariableAction argIn = locateArgIn(graphNode, edge.getCall(), index);
                argIn.getObjectTree().addAll(use.getObjectTree());
            }
        } else if (use.isField()) {
            if (use.isStatic()) {
@@ -56,29 +80,52 @@ public class InterproceduralUsageFinder extends InterproceduralActionFinder<Usag
            } else {
                // An object creation expression input an existing object via actual-in because it creates it.
                assert !(edge.getCall() instanceof ObjectCreationExpr);
                ActualIONode actualIn = locateActualInNode(edge, use.getName());
                Definition def = new Definition(VariableAction.DeclarationType.SYNTHETIC, "-scope-in-", graphNode, (ObjectTree) use.getObjectTree().clone());
                Movable movDef = new Movable(def, actualIn);
                Expression scope = Objects.requireNonNullElseGet(actualIn.getArgument(), ThisExpr::new);
                graphNode.addVariableActionAfterLastMatchingRealNode(movDef, actualIn);
                ExpressionObjectTreeFinder finder = new ExpressionObjectTreeFinder(graphNode);
                finder.locateAndMarkTransferenceToRoot(scope, def);
                VariableAction scopeIn = locateScopeIn(graphNode, edge.getCall());
                scopeIn.getObjectTree().addAll(use.getObjectTree());
            }
        } else {
            throw new IllegalStateException("Definition must be either from a parameter or a field!");
        }
    }

    /** Locates the actual-in node associated with the given variable name and call edge. */
    protected ActualIONode locateActualInNode(CallGraph.Edge<?> edge, String name) {
    /** Find all actual in nodes in the given call. */
    protected Set<ActualIONode> locateActualInNode(CallGraph.Edge<?> edge) {
        return edge.getGraphNode().getSyntheticNodesInMovables().stream()
                .filter(ActualIONode.class::isInstance)
                .map(ActualIONode.class::cast)
                .filter(ActualIONode::isInput)
                .filter(actual -> actual.getVariableName().equals(name))
                .filter(actual -> ASTUtils.equalsWithRange(actual.getAstNode(), (Node) edge.getCall()))
                .findFirst()
                .orElseThrow(() -> new IllegalStateException("can't locate actual-in node"));
                .filter(actual -> ASTUtils.equalsWithRange(actual.getAstNode(), edge.getCall()))
                .collect(Collectors.toSet());
    }

    /** Find the -arg-in- variable action that corresponds to the given node, call and index. */
    protected VariableAction locateArgIn(GraphNode<?> graphNode, Resolvable<? extends ResolvedMethodLikeDeclaration> call, int index) {
        return locateActionIn(graphNode, call, index, "-arg-in-");
    }

    /** Find the -scope-in- variable action that corresponds to the given node and call. */
    protected VariableAction locateScopeIn(GraphNode<?> graphNode, Resolvable<? extends ResolvedMethodLikeDeclaration> call) {
        return locateActionIn(graphNode, call, 0, "-scope-in-");
    }

    /** Find the nth variable action from the given node and call that matches the given name. 0 represents the first occurrence. */
    protected VariableAction locateActionIn(GraphNode<?> graphNode, Resolvable<? extends ResolvedMethodLikeDeclaration> call, int index, String actionName) {
        boolean inCall = false;
        for (VariableAction va : graphNode.getVariableActions()) {
            if (va instanceof VariableAction.CallMarker && ASTUtils.equalsWithRange(((VariableAction.CallMarker) va).getCall(), call)) {
                if (((VariableAction.CallMarker) va).isEnter())
                    inCall = true;
                else
                    break; // The call has ended, can't find the action now
            }
            if (inCall && va.isDefinition() && va.getName().equals(actionName)) {
                if (index == 0)
                    return va;
                else
                    index--;
            }
        }
        throw new IllegalStateException("Could not locate " + actionName + " for call " + call + " in node " + graphNode);
    }

    @Override
+1 −4
Original line number Diff line number Diff line
@@ -11,9 +11,6 @@ import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static es.upv.mist.slicing.graphs.cfg.CFGBuilder.VARIABLE_NAME_OUTPUT;
import static es.upv.mist.slicing.graphs.exceptionsensitive.ESCFG.ACTIVE_EXCEPTION_VARIABLE;

/**
 * A tree data structure that mimics the tree found in an object's fields.
 * Each tree contains a MemberNode that represents its, including a name.
@@ -29,7 +26,7 @@ public class ObjectTree implements Cloneable {
    public static final String ROOT_NAME = "-root-";

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

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