Commit 719be1a4 authored by Carlos Galindo's avatar Carlos Galindo
Browse files

VariableAction now store static and dynamic typing.

Dynamic types are computed from the descendants of the static type, without further analysis.
parent 3fc34fe7
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -55,6 +55,10 @@ public class ClassGraph extends DirectedPseudograph<ClassGraph.Vertex, ClassGrap
        return vertexDeclarationMap.get(mapKey(declaration, ASTUtils.getClassNode(declaration)));
    }

    public boolean containsType(ResolvedReferenceType type) {
        return vertexDeclarationMap.containsKey(mapKey(type));
    }

    public Set<MethodDeclaration> overriddenSetOf(MethodDeclaration method) {
        return subclassesStreamOf(classVertexOf(findMethodVertex(method)))
                .flatMap(vertex -> outgoingEdgesOf(vertex).stream()
+42 −9
Original line number Diff line number Diff line
package es.upv.mist.slicing.nodes;

import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
import com.github.javaparser.ast.expr.*;
import com.github.javaparser.resolution.Resolvable;
import com.github.javaparser.resolution.UnsolvedSymbolException;
import com.github.javaparser.resolution.declarations.ResolvedMethodLikeDeclaration;
import com.github.javaparser.resolution.declarations.ResolvedValueDeclaration;
import com.github.javaparser.resolution.types.ResolvedType;
import com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserSymbolDeclaration;
import es.upv.mist.slicing.arcs.Arc;
import es.upv.mist.slicing.arcs.pdg.DataDependencyArc;
import es.upv.mist.slicing.graphs.ClassGraph;
import es.upv.mist.slicing.graphs.Graph;
import es.upv.mist.slicing.graphs.jsysdg.JSysDG;
import es.upv.mist.slicing.graphs.jsysdg.JSysPDG;
import es.upv.mist.slicing.graphs.pdg.PDG;
import es.upv.mist.slicing.utils.ASTUtils;

import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.*;
import java.util.stream.Collectors;

import static es.upv.mist.slicing.nodes.VariableAction.DeclarationType.*;
@@ -65,7 +66,9 @@ public abstract class VariableAction {

    protected final String name;
    protected final DeclarationType declarationType;
    protected final Set<ResolvedType> dynamicTypes = new HashSet<>();

    protected ResolvedType staticType;
    protected GraphNode<?> graphNode;
    protected ObjectTree objectTree;
    protected boolean optional = false;
@@ -156,6 +159,22 @@ public abstract class VariableAction {
        return isRootAction() && !hasObjectTree();
    }

    public void setStaticType(ResolvedType staticType) {
        this.staticType = staticType;
        dynamicTypes.clear();
        dynamicTypes.add(staticType);
        if (staticType.isReferenceType() && ClassGraph.getInstance().containsType(staticType.asReferenceType())) {
            ClassGraph.getInstance().subclassesOf(staticType.asReferenceType()).stream()
                    .map(ClassOrInterfaceDeclaration::resolve)
                    .map(ASTUtils::resolvedTypeDeclarationToResolvedType)
                    .forEach(dynamicTypes::add);
        }
    }

    public ResolvedType getStaticType() {
        return staticType;
    }

    // ======================================================
    // =================== OBJECT TREE ======================
    // ======================================================
@@ -199,13 +218,17 @@ public abstract class VariableAction {
            Movable movable = (Movable) this;
            return new Movable(movable.inner.getRootAction(), movable.getRealNode());
        }
        VariableAction action;
        if (this instanceof Usage)
            return new Usage(declarationType, ObjectTree.removeFields(name), graphNode);
        if (this instanceof Definition)
            return new Definition(declarationType, ObjectTree.removeFields(name), graphNode, asDefinition().expression);
        if (this instanceof Declaration)
            action = new Usage(declarationType, ObjectTree.removeFields(name), graphNode);
        else if (this instanceof Definition)
            action = new Definition(declarationType, ObjectTree.removeFields(name), graphNode, asDefinition().expression);
        else if (this instanceof Declaration)
            throw new UnsupportedOperationException("Can't create a root node for a declaration!");
        else
            throw new IllegalStateException("Invalid action type");
        action.setStaticType(staticType);
        return action;
    }

    public boolean isRootAction() {
@@ -465,6 +488,16 @@ public abstract class VariableAction {
            return inner.objectTree != null;
        }

        @Override
        public void setStaticType(ResolvedType staticType) {
            inner.setStaticType(staticType);
        }

        @Override
        public ResolvedType getStaticType() {
            return inner.getStaticType();
        }

        /** The final location of this action. This node may not yet be present
         *  in the graph, if {@link #move(Graph)} has not been invoked. */
        public SyntheticNode<?> getRealNode() {
+36 −10
Original line number Diff line number Diff line
package es.upv.mist.slicing.nodes;

import com.github.javaparser.ast.Node;
import com.github.javaparser.ast.body.CallableDeclaration;
import com.github.javaparser.ast.body.FieldDeclaration;
import com.github.javaparser.ast.body.Parameter;
import com.github.javaparser.ast.body.VariableDeclarator;
import com.github.javaparser.ast.body.*;
import com.github.javaparser.ast.expr.*;
import com.github.javaparser.ast.nodeTypes.NodeWithArguments;
import com.github.javaparser.ast.stmt.*;
@@ -110,14 +107,16 @@ public class VariableVisitor extends GraphNodeContentVisitor<VariableVisitor.Act
        }
        // Only accept the field access as action if it is a sequence of names (a.b.c.d, this.a.b.c)
        // Otherwise, we traverse the scope to handle other structures (calls, arrays, etc).
        if (scope.isNameExpr() || scope.isThisExpr())
        if (scope.isNameExpr() || scope.isThisExpr()) {
            acceptAction(n, action); // a.b.c.d
        else
            vaSetStaticType(scope);
        } else
            n.getScope().accept(this, action); // this.call().c.d
    }

    protected void acceptAction(Expression n, Action action) {
        acceptAction(DeclarationType.valueOf(n), getRealName(n), action, false);
        vaSetStaticType(n);
    }

    protected void acceptAction(DeclarationType declarationType, String realName, Action action) {
@@ -126,6 +125,7 @@ public class VariableVisitor extends GraphNodeContentVisitor<VariableVisitor.Act

    protected void acceptAction(Expression n, String realName, Action action) {
        acceptAction(DeclarationType.valueOf(n), realName, action, false);
        vaSetStaticType(n);
    }

    protected void acceptActionNullDefinition(DeclarationType declarationType, String realName) {
@@ -179,6 +179,7 @@ public class VariableVisitor extends GraphNodeContentVisitor<VariableVisitor.Act
        if (n.getExpression().isPresent()) {
            definitionStack.push(n.getExpression().get());
            acceptAction(SYNTHETIC, VARIABLE_NAME_OUTPUT, DEFINITION);
            vaSetStaticType(n.getExpression().get());
            definitionStack.pop();
            graphNode.getLastVariableAction().asDefinition()
                    .setTotallyDefinedMember(ROOT_NAME);
@@ -190,6 +191,7 @@ public class VariableVisitor extends GraphNodeContentVisitor<VariableVisitor.Act
        super.visit(n, arg);
        definitionStack.push(n.getExpression());
        acceptAction(SYNTHETIC, ACTIVE_EXCEPTION_VARIABLE, DEFINITION);
        vaSetStaticType(n.getExpression());
        definitionStack.pop();
        var fields = ClassGraph.getInstance().generateObjectTreeFor(n.getExpression().calculateResolvedType().asReferenceType());
        graphNode.getLastVariableAction().getObjectTree().addAll(fields);
@@ -201,8 +203,10 @@ public class VariableVisitor extends GraphNodeContentVisitor<VariableVisitor.Act
        n.getIterable().accept(this, USE);
        for (VariableDeclarator variable : n.getVariable().getVariables()) {
            acceptAction(LOCAL_VARIABLE, variable.getNameAsString(), DECLARATION);
            graphNode.getLastVariableAction().setStaticType(variable.getType().resolve());
            // ForEach initializes to each value of the iterable, but that expression is not available.
            acceptActionNullDefinition(LOCAL_VARIABLE, variable.getNameAsString());
            graphNode.getLastVariableAction().setStaticType(variable.getType().resolve());
        }
    }

@@ -284,8 +288,10 @@ public class VariableVisitor extends GraphNodeContentVisitor<VariableVisitor.Act
                definitionStack.push(n.getValue());
                if (root.equals(scope.toString()))
                    acceptAction(scope, root, DEFINITION);
                else
                else {
                    acceptAction(FIELD, root, DEFINITION);
                    graphNode.getLastVariableAction().setStaticType(ASTUtils.resolvedTypeDeclarationToResolvedType(fieldAccessExpr.findAncestor(ClassOrInterfaceDeclaration.class).orElseThrow().resolve()));
                }
                definitionStack.pop();
                VariableAction.Definition def = getLastDefinition();
                def.setTotallyDefinedMember(realName);
@@ -334,10 +340,12 @@ public class VariableVisitor extends GraphNodeContentVisitor<VariableVisitor.Act
    public void visit(VariableDeclarationExpr n, Action action) {
        for (VariableDeclarator v : n.getVariables()) {
            acceptAction(LOCAL_VARIABLE, v.getNameAsString(), DECLARATION);
            graphNode.getLastVariableAction().setStaticType(v.getType().resolve());
            v.getInitializer().ifPresent(init -> {
                init.accept(this, action);
                definitionStack.push(init);
                acceptAction(LOCAL_VARIABLE, v.getNameAsString(), DEFINITION);
                graphNode.getLastVariableAction().setStaticType(v.getType().resolve());
                definitionStack.pop();
                if (v.getType().isClassOrInterfaceType())
                    getLastDefinition().setTotallyDefinedMember(v.getNameAsString());
@@ -351,10 +359,12 @@ public class VariableVisitor extends GraphNodeContentVisitor<VariableVisitor.Act
        for (VariableDeclarator v : n.getVariables()) {
            String realName = getRealNameForFieldDeclaration(v);
            acceptAction(FIELD, realName, DECLARATION);
            graphNode.getLastVariableAction().setStaticType(v.getType().resolve());
            Expression init = v.getInitializer().orElseGet(() -> ASTUtils.initializerForField(n));
            init.accept(this, action);
            definitionStack.push(init);
            acceptAction(FIELD, realName, DEFINITION);
            graphNode.getLastVariableAction().setStaticType(v.getType().resolve());
            definitionStack.pop();
            if (v.getType().isClassOrInterfaceType())
                getLastDefinition().setTotallyDefinedMember(realName);
@@ -382,7 +392,9 @@ public class VariableVisitor extends GraphNodeContentVisitor<VariableVisitor.Act
    @Override
    public void visit(Parameter n, Action arg) {
        acceptAction(PARAMETER, n.getNameAsString(), DECLARATION);
        graphNode.getLastVariableAction().setStaticType(n.getType().resolve());
        acceptActionNullDefinition(PARAMETER, n.getNameAsString());
        graphNode.getLastVariableAction().setStaticType(n.getType().resolve());
    }

    // =======================================================================
@@ -401,10 +413,12 @@ public class VariableVisitor extends GraphNodeContentVisitor<VariableVisitor.Act
    public void visit(ExplicitConstructorInvocationStmt n, Action arg) {
        if (visitCall(n, arg)) {
            acceptAction(FIELD, "this", DECLARATION);
            graphNode.getLastVariableAction().setStaticType(ASTUtils.resolvedTypeDeclarationToResolvedType(ASTUtils.getClassNode(n).resolve()));
            super.visit(n, arg);
        }
        // Regardless of whether it resolves or not, 'this' is defined
        acceptActionNullDefinition(FIELD, "this");
        graphNode.getLastVariableAction().setStaticType(ASTUtils.resolvedTypeDeclarationToResolvedType(ASTUtils.getClassNode(n).resolve()));
        // setup a connection between USE(-output-) and DEF(this)
        List<VariableAction> vaList = graphNode.getVariableActions();
        if (vaList.size() >= 5) { // call-super, DEC(this), USE(-output-), ret-super, DEF(this)
@@ -433,15 +447,20 @@ public class VariableVisitor extends GraphNodeContentVisitor<VariableVisitor.Act
        // Start
        graphNode.addCallMarker(call, true);
        // Scope
        if (call instanceof ExplicitConstructorInvocationStmt)
        if (call instanceof ExplicitConstructorInvocationStmt) {
            acceptAction(FIELD, "this", DECLARATION);
            graphNode.getLastVariableAction().setStaticType(ASTUtils.resolvedTypeDeclarationToResolvedType(((ExplicitConstructorInvocationStmt) call).findAncestor(ClassOrInterfaceDeclaration.class).orElseThrow().resolve()));
        }
        if (call instanceof MethodCallExpr && !((JavaParserMethodDeclaration) call.resolve()).isStatic()) {
            ActualIONode scopeIn = ActualIONode.createActualIn(call, "this", ((MethodCallExpr) call).getScope().orElse(null));
            graphNode.addSyntheticNode(scopeIn);
            realNodeStack.push(scopeIn);
            ASTUtils.getResolvableScope(call).ifPresentOrElse(
                    scope -> scope.accept(this, action),
                    () -> acceptAction(FIELD, "this", USE));
                    () -> {
                        acceptAction(FIELD, "this", USE);
                        graphNode.getLastVariableAction().setStaticType(ASTUtils.resolvedTypeDeclarationToResolvedType(((MethodCallExpr) call).findAncestor(ClassOrInterfaceDeclaration.class).orElseThrow().resolve()));
                    });
            realNodeStack.pop();
        }
        // Args
@@ -470,12 +489,15 @@ public class VariableVisitor extends GraphNodeContentVisitor<VariableVisitor.Act
                fields.map(tree -> (ObjectTree) tree.clone()).orElse(null));
        def.setTotallyDefinedMember(ROOT_NAME);
        var defMov = new VariableAction.Movable(def, CallNode.Return.create(call));
        defMov.setStaticType(ASTUtils.getCallResolveType(call));
        graphNode.addVariableAction(defMov);
        // The container of the call uses -output-, unless the call is wrapped in an ExpressionStmt
        Optional<Node> parentNode = ((Node) call).getParentNode();
        if (parentNode.isEmpty() || !(parentNode.get() instanceof ExpressionStmt))
        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.getCallResolveType(call));
        }
    }

    protected Optional<ObjectTree> getFieldsForReturn(Resolvable<? extends ResolvedMethodLikeDeclaration> call) {
@@ -575,4 +597,8 @@ public class VariableVisitor extends GraphNodeContentVisitor<VariableVisitor.Act
    protected VariableAction.Definition getLastDefinition() {
        return graphNode.getLastVariableAction().asDefinition();
    }

    protected void vaSetStaticType(Expression e) {
        graphNode.getLastVariableAction().setStaticType(e.calculateResolvedType());
    }
}
+10 −0
Original line number Diff line number Diff line
@@ -99,6 +99,16 @@ public class ASTUtils {
        throw new IllegalStateException("The method must have a body!");
    }

    public static ResolvedType getCallResolveType(Resolvable<? extends ResolvedMethodLikeDeclaration> call) {
        if (call instanceof MethodCallExpr)
            return ((MethodCallExpr) call).calculateResolvedType();
        if (call instanceof ObjectCreationExpr)
            return ((ObjectCreationExpr) call).calculateResolvedType();
        if (call instanceof ExplicitConstructorInvocationStmt)
            return resolvedTypeDeclarationToResolvedType(((ExplicitConstructorInvocationStmt) call).resolve().declaringType());
        throw new IllegalArgumentException("Call wasn't of a compatible type!");
    }

    public static Optional<Expression> getResolvableScope(Resolvable<? extends ResolvedMethodLikeDeclaration> call) {
        if (call instanceof MethodCallExpr)
            return ((MethodCallExpr) call).getScope();
+1 −0
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@ public class Classic {
        int sum = 0;
        int product = 1;
        int w = 7;
        int N = 10;
        for (int i = 1; i < N; i++) {
            sum = sum + i + w;
            product *= i;
Loading