Commit ab67fdac authored by jacosro's avatar jacosro
Browse files

WIP: out nodes

parent 1f9911ff
Loading
Loading
Loading
Loading
+19 −1
Original line number Diff line number Diff line
@@ -31,4 +31,22 @@ So, for the list of expressions that are not literal:
- `ObjectCreationExpr`: NO
- `SuperExpr`: NO
- `ThisExpr`: NO
- `UnaryExpr (a++)`: we'll have to check if `a` is a variable
 No newline at end of file
- `UnaryExpr (a++)`: we'll have to check the operator (only `++`, `--` return the variable), and if `a` is a variable

## 11/5/20

### Implemented

- Added a CALL node between the node which contains the statement with the `MethodCallExpr` and the `MethodDeclaration`. This node is linked with `in` and `out` nodes. This is because if a statement has more than 1 `MethodCallExpr`, it may have repeated `in` and `out` nodes with the same variables
- Changed `out` node expression from `VariableDeclarationExpr` to `AssignExpr`, where the name of the variable is the argument expression

### WIP

- `OutNodeVariableVisitor`, a visitor that returns the expressions that should be candidate for being `out` nodes. This visitor overrides all `*Expr` methods who may contain a `NameExpr`
    - `ConditionalExpr`: Here, we have `ThenExpr` and `ElseExpr`. As we are performing a static analysis, both should be considered for `out` node in case they represented a variable (This is why `OutNodeVariableVisitor` uses a `List`, and doesn't just return a `String` representing the variable)

### Issues

- `Out` node is generated for `MethodCallExpr` as an argument

- When a `MethodCallExpr` is an argument of another, we have to link its output to the `in` node of the containing one
 No newline at end of file
+35 −36
Original line number Diff line number Diff line
package tfm.graphs.sdg;

import com.github.javaparser.ParserConfiguration;
import com.github.javaparser.ast.ArrayCreationLevel;
import com.github.javaparser.ast.Node;
import com.github.javaparser.ast.NodeList;
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
import com.github.javaparser.ast.body.MethodDeclaration;
import com.github.javaparser.ast.body.Parameter;
import com.github.javaparser.ast.body.VariableDeclarator;
import com.github.javaparser.ast.expr.*;
import com.github.javaparser.ast.stmt.*;
import com.github.javaparser.ast.type.Type;
import com.github.javaparser.ast.visitor.VoidVisitorAdapter;
import com.github.javaparser.resolution.UnsolvedSymbolException;
import com.github.javaparser.resolution.declarations.ResolvedMethodDeclaration;
import com.github.javaparser.resolution.declarations.ResolvedReferenceTypeDeclaration;
import com.github.javaparser.symbolsolver.JavaSymbolSolver;
import com.github.javaparser.symbolsolver.SourceFileInfoExtractor;
import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFacade;
import com.github.javaparser.symbolsolver.model.resolution.SymbolReference;
import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
import com.github.javaparser.symbolsolver.resolution.SymbolSolver;
import com.github.javaparser.symbolsolver.resolution.typesolvers.CombinedTypeSolver;
import com.github.javaparser.symbolsolver.resolution.typesolvers.JavaParserTypeSolver;
import com.github.javaparser.symbolsolver.resolution.typesolvers.ReflectionTypeSolver;
import tfm.arcs.Arc;
import tfm.arcs.pdg.DataDependencyArc;
import tfm.graphs.cfg.CFG;
@@ -34,16 +19,13 @@ import tfm.utils.Context;
import tfm.utils.Logger;
import tfm.utils.MethodDeclarationSolver;

import java.nio.file.Path;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.*;
import java.util.stream.Collectors;

class MethodCallReplacerVisitor extends VoidVisitorAdapter<Context> {

    private SDG sdg;
    private GraphNode<?> methodCallNode;
    private GraphNode<?> originalMethodCallNode;

    public MethodCallReplacerVisitor(SDG sdg) {
        this.sdg = sdg;
@@ -52,7 +34,7 @@ class MethodCallReplacerVisitor extends VoidVisitorAdapter<Context> {
    private void searchAndSetMethodCallNode(Node node) {
        Optional<GraphNode<Node>> optionalNode = sdg.findNodeByASTNode(node);
        assert optionalNode.isPresent();
        methodCallNode = optionalNode.get();
        originalMethodCallNode = optionalNode.get();

    }

@@ -108,10 +90,10 @@ class MethodCallReplacerVisitor extends VoidVisitorAdapter<Context> {
    public void visit(MethodCallExpr methodCallExpr, Context context) {
        NodeList<Expression> arguments = methodCallExpr.getArguments();

//        // Parse first method call expressions as arguments
//        arguments.stream()
//                .filter(Expression::isMethodCallExpr)
//                .forEach(expression -> expression.accept(this, context));
        // Parse first method call expressions as arguments
        arguments.stream()
                .filter(Expression::isMethodCallExpr)
                .forEach(expression -> expression.accept(this, context));

        Logger.log("MethodCallReplacerVisitor", context);

@@ -132,6 +114,9 @@ class MethodCallReplacerVisitor extends VoidVisitorAdapter<Context> {
        assert optionalCFG.isPresent();
        CFG methodCFG = optionalCFG.get();

        GraphNode<MethodCallExpr> methodCallNode = sdg.addNode("CALL " + methodCallExpr.toString(), methodCallExpr, TypeNodeFactory.fromType(NodeType.METHOD_CALL));

        sdg.addControlDependencyArc(originalMethodCallNode, methodCallNode);
        sdg.addCallArc(methodCallNode, methodDeclarationNode);

        NodeList<Parameter> parameters = methodDeclarationNode.getAstNode().getParameters();
@@ -169,7 +154,7 @@ class MethodCallReplacerVisitor extends VoidVisitorAdapter<Context> {

            // Handle data dependency: Remove arc from method call node and add it to IN node

            List<DataDependencyArc> inDataDependencies = sdg.incomingEdgesOf(methodCallNode).stream()
            List<DataDependencyArc> inDataDependencies = sdg.incomingEdgesOf(originalMethodCallNode).stream()
                .filter(arc -> arc.isDataDependencyArc() && Objects.equals(arc.getLabel(), argument.toString()))
                .map(Arc::asDataDependencyArc)
                .collect(Collectors.toList());
@@ -196,23 +181,37 @@ class MethodCallReplacerVisitor extends VoidVisitorAdapter<Context> {

            // Out expression

            if (!argument.isNameExpr() && !sdg.findDeclarationsOfVariable(argument.toString(), methodCallNode).isEmpty()) {
            OutNodeVariableVisitor shouldHaveOutNodeVisitor = new OutNodeVariableVisitor();
            Set<String> variablesForOutNode = new HashSet<>();
            argument.accept(shouldHaveOutNodeVisitor, variablesForOutNode);

            // Here, variablesForOutNode may have 1 variable or more depending on the expression

            if (variablesForOutNode.isEmpty()) {
                /*
                    If the argument is not a variable (is a name expression and it is declared in the scope),
                    If the argument is not a variable or it is not declared in the scope,
                    then there is no OUT node
                 */
                Logger.log("MethodCallReplacerVisitor", String.format("Expression '%s' should not have out node", argument.toString()));
                continue;
            } else if (variablesForOutNode.size() == 1) {
                String variable = variablesForOutNode.iterator().next();

                if (sdg.findDeclarationsOfVariable(variable, originalMethodCallNode).isEmpty()) {
                    Logger.log("MethodCallReplacerVisitor", String.format("Expression '%s' should not have out node", argument.toString()));
                    continue;
                }
            } else {
                continue;
            }

            VariableDeclarationExpr outVariableDeclarationExpr = new VariableDeclarationExpr(
                    new VariableDeclarator(
                            parameter.getType(),
                            parameter.getNameAsString(),
                            new NameExpr(parameter.getNameAsString() + "_out")
                    )
            AssignExpr outVariableAssignExpr = new AssignExpr(
                argument,
                new NameExpr(parameter.getNameAsString() + "_out"),
                AssignExpr.Operator.ASSIGN
            );

            ExpressionStmt outExprStmt = new ExpressionStmt(outVariableDeclarationExpr);
            ExpressionStmt outExprStmt = new ExpressionStmt(outVariableAssignExpr);

            GraphNode<ExpressionStmt> argumentOutNode = sdg.addNode(outExprStmt.toString(), outExprStmt, TypeNodeFactory.fromType(NodeType.VARIABLE_OUT));

@@ -227,7 +226,7 @@ class MethodCallReplacerVisitor extends VoidVisitorAdapter<Context> {

            // Handle data dependency: remove arc from method call node and add it to OUT node

            List<DataDependencyArc> outDataDependencies = sdg.outgoingEdgesOf(methodCallNode).stream()
            List<DataDependencyArc> outDataDependencies = sdg.outgoingEdgesOf(originalMethodCallNode).stream()
                    .filter(arc -> arc.isDataDependencyArc() && Objects.equals(arc.getLabel(), argument.toString()))
                    .map(Arc::asDataDependencyArc)
                    .collect(Collectors.toList());
+62 −0
Original line number Diff line number Diff line
package tfm.graphs.sdg;

import com.github.javaparser.ast.expr.*;
import com.github.javaparser.ast.stmt.ExpressionStmt;
import com.github.javaparser.ast.visitor.VoidVisitorAdapter;
import tfm.utils.Logger;

import java.util.Set;

public class OutNodeVariableVisitor extends VoidVisitorAdapter<Set<String>> {

    @Override
    public void visit(ArrayAccessExpr n, Set<String> variables) {
        n.getName().accept(this, variables);
    }

    @Override
    public void visit(CastExpr n, Set<String> variables) {
        n.getExpression().accept(this, variables);
    }

    @Override
    public void visit(ConditionalExpr n, Set<String> variables) {
        n.getThenExpr().accept(this, variables);
        n.getElseExpr().accept(this, variables);
    }

    @Override
    public void visit(EnclosedExpr n, Set<String> variables) {
        n.getInner().accept(this, variables);
    }

    @Override
    public void visit(ExpressionStmt n, Set<String> variables) {
        n.getExpression().accept(this, variables);
    }

    @Override
    public void visit(FieldAccessExpr n, Set<String> variables) {
        Logger.log("ShouldHaveOutNodeVisitor", "Exploring " + n);
        n.getScope().accept(this, variables);
    }

    @Override
    public void visit(NameExpr n, Set<String> variables) {
        Logger.log("ShouldHaveOutNodeVisitor", n + " is a variable!!");
        variables.add(n.getNameAsString());
    }

    @Override
    public void visit(UnaryExpr n, Set<String> variables) {
        switch (n.getOperator()) {
            case PLUS:
            case MINUS:
            case BITWISE_COMPLEMENT:
            case LOGICAL_COMPLEMENT:
                ;
        }

        n.getExpression().accept(this, variables);
    }
}
+1 −0
Original line number Diff line number Diff line
@@ -3,6 +3,7 @@ package tfm.nodes.type;
public enum NodeType {
    STATEMENT,
    METHOD,
    METHOD_CALL,
    VARIABLE_IN,
    VARIABLE_OUT
}
+44 −0
Original line number Diff line number Diff line
package tfm.programs.sdg;

class InnerObject {
    int x;

    public InnerObject() {

    }

    public InnerObject(int x) {
        this.x = x;
    }
}

class CustomObject {
    InnerObject inner;

    public CustomObject() {

    }

    public CustomObject(InnerObject inner) {
       this.inner = inner;
    }
}


public class Example2 {


    public static void main(String[] args) {
        CustomObject customObject = new CustomObject(new InnerObject(1));
        modifyCustomObject(customObject);
        modifyInnerObject(customObject.inner);
    }

    public static void modifyCustomObject(CustomObject customObject) {
        customObject.inner = new InnerObject(2);
    }

    public static void modifyInnerObject(InnerObject innerObject) {
        innerObject.x = 5;
    }
}
 No newline at end of file