Skip to content
CFGVisitor.java 6.85 KiB
Newer Older
Javier Costa's avatar
Javier Costa committed
package tfm.visitors;
Javier Costa's avatar
Javier Costa committed

Javier Costa's avatar
Javier Costa committed
import com.github.javaparser.ast.Node;
Javier Costa's avatar
Javier Costa committed
import com.github.javaparser.ast.NodeList;
import com.github.javaparser.ast.body.MethodDeclaration;
Javier Costa's avatar
Javier Costa committed
import com.github.javaparser.ast.body.VariableDeclarator;
import com.github.javaparser.ast.expr.*;
Javier Costa's avatar
Javier Costa committed
import com.github.javaparser.ast.stmt.*;
Javier Costa's avatar
Javier Costa committed
import com.github.javaparser.ast.visitor.GenericVisitor;
import com.github.javaparser.ast.visitor.VoidVisitor;
Javier Costa's avatar
Javier Costa committed
import com.github.javaparser.ast.visitor.VoidVisitorAdapter;
Javier Costa's avatar
Javier Costa committed
import sun.rmi.runtime.Log;
Javier Costa's avatar
Javier Costa committed
import tfm.graphs.CFGGraph;
Javier Costa's avatar
Javier Costa committed
import tfm.nodes.CFGNode;
Javier Costa's avatar
Javier Costa committed
import tfm.utils.Utils;
Javier Costa's avatar
Javier Costa committed

import java.util.*;
Javier Costa's avatar
Javier Costa committed
import java.util.stream.Collectors;
Javier Costa's avatar
Javier Costa committed

public class CFGVisitor extends VoidVisitorAdapter<Void> {

    private CFGGraph graph;

Javier Costa's avatar
Javier Costa committed
    private Queue<CFGNode> lastParentNodes;
Javier Costa's avatar
Javier Costa committed

    public CFGVisitor(CFGGraph graph) {
        this.graph = graph;
        this.lastParentNodes = Collections.asLifoQueue(
                new ArrayDeque<>(
Javier Costa's avatar
Javier Costa committed
                        Collections.singletonList(graph.getRootNode())
Javier Costa's avatar
Javier Costa committed
                )
        );
    }

    @Override
    public void visit(ExpressionStmt expressionStmt, Void arg) {
Javier Costa's avatar
Javier Costa committed
        String expression = expressionStmt.toString().replace("\"", "\\\"");
Javier Costa's avatar
Javier Costa committed

Javier Costa's avatar
Javier Costa committed
        CFGNode nextNode = addNodeAndArcs(expression, expressionStmt);
Javier Costa's avatar
Javier Costa committed

Javier Costa's avatar
Javier Costa committed
        lastParentNodes.add(nextNode);
Javier Costa's avatar
Javier Costa committed
    }

//    @Override
//    public void visit(VariableDeclarationExpr variableDeclarationExpr, Void arg) {
Javier Costa's avatar
Javier Costa committed
//        CFGNode<String> nextNode = addNodeAndArcs(variableDeclarationExpr.toString());
Javier Costa's avatar
Javier Costa committed
//
//        lastParentNodes.add(nextNode);
//
//        Logger.log(variableDeclarationExpr);
Javier Costa's avatar
Javier Costa committed
//
//        super.visit(variableDeclarationExpr, arg);
//    }

    @Override
    public void visit(IfStmt ifStmt, Void arg) {
Javier Costa's avatar
Javier Costa committed
        CFGNode ifCondition = addNodeAndArcs(
Javier Costa's avatar
Javier Costa committed
                String.format("if (%s)", ifStmt.getCondition().toString()),
Javier Costa's avatar
Javier Costa committed
                ifStmt
Javier Costa's avatar
Javier Costa committed
        );

        lastParentNodes.add(ifCondition);

        // Visit "then"
Javier Costa's avatar
Javier Costa committed
        ifStmt.getThenStmt().accept(this, arg);
Javier Costa's avatar
Javier Costa committed

Javier Costa's avatar
Javier Costa committed
        Queue<CFGNode> lastThenNodes = new ArrayDeque<>(lastParentNodes);
Javier Costa's avatar
Javier Costa committed

        if (ifStmt.hasElseBranch()) {
            lastParentNodes.clear();
            lastParentNodes.add(ifCondition); // Set if nodes as root

Javier Costa's avatar
Javier Costa committed
            ifStmt.getElseStmt().get().accept(this, arg);
Javier Costa's avatar
Javier Costa committed

            lastParentNodes.addAll(lastThenNodes);
        } else {
            lastParentNodes.add(ifCondition);
        }
    }

    @Override
    public void visit(WhileStmt whileStmt, Void arg) {
Javier Costa's avatar
Javier Costa committed
        CFGNode whileCondition = addNodeAndArcs(
Javier Costa's avatar
Javier Costa committed
                String.format("while (%s)", whileStmt.getCondition().toString()),
Javier Costa's avatar
Javier Costa committed
                whileStmt
Javier Costa's avatar
Javier Costa committed
        );

        lastParentNodes.add(whileCondition);

Javier Costa's avatar
Javier Costa committed
        whileStmt.getBody().accept(this, arg);
Javier Costa's avatar
Javier Costa committed

        while (!lastParentNodes.isEmpty()) {
            graph.addControlFlowEdge(lastParentNodes.poll(), whileCondition);
        }

        lastParentNodes.add(whileCondition);
    }

Javier Costa's avatar
Javier Costa committed
    @Override
    public void visit(DoStmt doStmt, Void arg) {
        BlockStmt body = Utils.blockWrapper(doStmt.getBody());

        body.accept(this, arg);

        CFGNode doWhileNode = addNodeAndArcs(
                String.format("while (%s)", doStmt.getCondition()),
                doStmt
        );

        if (!body.isEmpty()) {
            Statement firstBodyStatement = body.getStatement(0);

            graph.findNodeByStatement(firstBodyStatement)
                    .ifPresent(node -> graph.addControlFlowEdge(doWhileNode, node));
        }

        lastParentNodes.add(doWhileNode);
    }

Javier Costa's avatar
Javier Costa committed
    @Override
    public void visit(ForStmt forStmt, Void arg) {
Javier Costa's avatar
Javier Costa committed
//        String inizialization = forStmt.getInitialization().stream()
//                .map(Node::toString)
//                .collect(Collectors.joining(","));
//
//        String update = forStmt.getUpdate().stream()
//                .map(Node::toString)
//                .collect(Collectors.joining(","));
Javier Costa's avatar
Javier Costa committed

        Expression comparison = forStmt.getCompare().orElse(new BooleanLiteralExpr(true));

Javier Costa's avatar
Javier Costa committed
        forStmt.getInitialization().forEach(expression -> new ExpressionStmt(expression).accept(this, null));

Javier Costa's avatar
Javier Costa committed
        CFGNode forNode = addNodeAndArcs(
Javier Costa's avatar
Javier Costa committed
                String.format("for (;%s;)", comparison),
Javier Costa's avatar
Javier Costa committed
                forStmt
        );

        lastParentNodes.add(forNode);

        BlockStmt body = Utils.blockWrapper(forStmt.getBody());
Javier Costa's avatar
Javier Costa committed

Javier Costa's avatar
Javier Costa committed
        forStmt.getUpdate().forEach(body::addStatement);
Javier Costa's avatar
Javier Costa committed

Javier Costa's avatar
Javier Costa committed
        body.accept(this, arg);

        while (!lastParentNodes.isEmpty()) {
            graph.addControlFlowEdge(lastParentNodes.poll(), forNode);
        }
Javier Costa's avatar
Javier Costa committed

Javier Costa's avatar
Javier Costa committed
        lastParentNodes.add(forNode);
Javier Costa's avatar
Javier Costa committed
    }

Javier Costa's avatar
Javier Costa committed
    @Override
    public void visit(ForEachStmt forEachStmt, Void arg) {
Javier Costa's avatar
Javier Costa committed
        CFGNode foreachNode = addNodeAndArcs(
                String.format("for (%s : %s)", forEachStmt.getVariable(), forEachStmt.getIterable()),
                forEachStmt
Javier Costa's avatar
Javier Costa committed
        );

Javier Costa's avatar
Javier Costa committed
        lastParentNodes.add(foreachNode);

        forEachStmt.getBody().accept(this, arg);

        while (!lastParentNodes.isEmpty()) {
            graph.addControlFlowEdge(lastParentNodes.poll(), foreachNode);
        }

        lastParentNodes.add(foreachNode);
    }

    @Override
    public void visit(SwitchStmt switchStmt, Void arg) {
        CFGNode switchNode = addNodeAndArcs(
                String.format("switch (%s)", switchStmt.getSelector()),
                switchStmt
        );

        lastParentNodes.add(switchNode);

        List<CFGNode> lastEntryParents = new ArrayList<>();

        switchStmt.getEntries().forEach(entry -> {
            Optional<BreakStmt> entryBreak = entry.findFirst(BreakStmt.class, breakStmt -> {
                Optional<Node> parent = breakStmt.getParentNode();

Javier Costa's avatar
Javier Costa committed
                return parent.isPresent() && parent.get()   .equals(entry);
Javier Costa's avatar
Javier Costa committed
            });

            new BlockStmt(entry.getStatements()).accept(this, arg);

            if (entryBreak.isPresent()) {
                while (!lastParentNodes.isEmpty()) {
                    lastEntryParents.add(lastParentNodes.poll());
                }
            }

            lastParentNodes.add(switchNode);
        });

        lastParentNodes.clear();
        lastParentNodes.addAll(lastEntryParents);
    }

    @Override
Javier Costa's avatar
Javier Costa committed
    public void visit(BreakStmt breakStmt, Void arg) {

    }

    @Override
    public void visit(ContinueStmt continueStmt, Void arg) {
Javier Costa's avatar
Javier Costa committed

Javier Costa's avatar
Javier Costa committed
    @Override
    public void visit(MethodDeclaration methodDeclaration, Void arg) {
        super.visit(methodDeclaration, arg);

Javier Costa's avatar
Javier Costa committed
        addNodeAndArcs("Stop", new EmptyStmt());
Javier Costa's avatar
Javier Costa committed
    }

Javier Costa's avatar
Javier Costa committed
    private CFGNode addNodeAndArcs(String nodeData, Statement statement) {
        CFGNode node = graph.addNode(nodeData, statement);
Javier Costa's avatar
Javier Costa committed

Javier Costa's avatar
Javier Costa committed
        CFGNode parent = lastParentNodes.poll(); // ALWAYS exists a parent
Javier Costa's avatar
Javier Costa committed
        graph.addControlFlowEdge(parent, node);

        while (!lastParentNodes.isEmpty()) {
            parent = lastParentNodes.poll();
            graph.addControlFlowEdge(parent, node);
        }

        return node;
    }
}