Commit f88f878d authored by Javier Costa's avatar Javier Costa
Browse files

Slicing and validation

parent 34e1b707
Loading
Loading
Loading
Loading
+15 −13
Original line number Diff line number Diff line
@@ -6,11 +6,13 @@ import edg.graphlib.Arrow;
import tfm.arcs.Arc;
import tfm.arcs.pdg.ControlDependencyArc;
import tfm.arcs.pdg.DataDependencyArc;
import tfm.nodes.CFGNode;
import tfm.nodes.Node;
import tfm.nodes.PDGNode;
import tfm.slicing.SlicingCriterion;
import tfm.utils.Logger;
import tfm.utils.NodeNotFoundException;
import tfm.utils.Utils;
import tfm.visitors.PDGCFGVisitor;

import java.util.Comparator;
@@ -152,9 +154,21 @@ public class PDGGraph extends Graph<PDGNode> {

        PDGNode node = optionalPDGNode.get();

        // Find CFGNode and find last definition of variable
        CFGNode cfgNode = this.cfgGraph.findNodeByASTNode(node.getAstNode())
                .orElseThrow(() -> new NodeNotFoundException("CFGNode not found"));

        Set<CFGNode> definitionNodes = Utils.findLastDefinitionsFrom(cfgNode, slicingCriterion.getVariable());

        Logger.format("Slicing node: %s", node);

        Set<Integer> sliceNodes = getSliceNodes(new HashSet<>(), node);
        Set<Integer> sliceNodes = definitionNodes.stream()
                .flatMap(definitionNode -> getSliceNodes(new HashSet<>(), this.findNodeByASTNode(definitionNode.getAstNode()).get()).stream())
                .collect(Collectors.toSet());

        sliceNodes.add(node.getId());

//        Set<Integer> sliceNodes = getSliceNodes(new HashSet<>(), node);

        PDGGraph sliceGraph = new PDGGraph();

@@ -193,30 +207,18 @@ public class PDGGraph extends Graph<PDGNode> {
    private Set<Integer> getSliceNodes(Set<Integer> visited, PDGNode root) {
        visited.add(root.getId());

//        Set<String> searchVariables = new HashSet<>(variables);

        for (Arrow arrow : root.getIncomingArrows()) {
            Arc arc = (Arc) arrow;

//            if (arc.isDataDependencyArrow()
//                    && Collections.disjoint(((DataDependencyArc) arc).getData().getVariables(), searchVariables)) {
//                continue;
//            }

            PDGNode from = (PDGNode) arc.getFromNode();

//            Logger.log("Arrow from node: " + from);

            if (visited.contains(from.getId())) {
//                Logger.log("It's already visited. Continuing...");
                continue;
            }

            getSliceNodes(visited, from);
        }

//        Logger.format("Done with node %s", root.getId());

        return visited;
    }

+2 −44
Original line number Diff line number Diff line
@@ -15,7 +15,7 @@ import java.io.IOException;
public class Slice {

    public static final String PROGRAM_FOLDER = Utils.PROGRAMS_FOLDER + "pdg/";
    public static final String PROGRAM_NAME = "Example3";
    public static final String PROGRAM_NAME = "Example2";

    public static void main(String[] args) throws IOException {
        CompilationUnit compilationUnit = JavaParser.parse(new File(PROGRAM_FOLDER + PROGRAM_NAME + ".java"));
@@ -28,48 +28,7 @@ public class Slice {
        Logger.log("= Starting slice =");
        Logger.log("==================");

        PDGGraph sliced = pdgGraph.slice(new LineNumberCriterion(21, "sum"));

//        for (PDGNode node : slice) {
//            sliced.addNode(new PDGNode(node.getId(), node.getData(), node.getAstNode()));
//        }
//
//        for (Arc arc : pdgGraph.getArcs()) {
//
//            Optional<PDGNode> fromOptional = sliced.findNodeById(arc.getFromNode().getId());
//            Optional<PDGNode> toOptional = sliced.findNodeById(arc.getToNode().getId());
//
//            if (fromOptional.isPresent() && toOptional.isPresent()) {
//                PDGNode from = fromOptional.get();
//                PDGNode to = toOptional.get();
//
//                if (arc.isControlDependencyArrow()) {
//                    sliced.addControlDependencyArc(from, to);
//                } else {
//                    DataDependencyArc dataDependencyArc = (DataDependencyArc) arc;
//                    sliced.addDataDependencyArc(from, to, dataDependencyArc.getData().getVariables().get(0));
//                }
//            }

//            Logger.log(arc);
//            Logger.log("Must add? " + (sliceIds.contains(arc.getFromNode().getId()) && sliceIds.contains(arc.getToNode().getId())));
//
//            if (sliceIds.contains(arc.getFromNode().getId()) && sliceIds.contains(arc.getToNode().getId())) {
//                Logger.format("Added? %s", sliced.addEdge(arc));
//            }
//        }

//        Set<Arc> arcs = pdgGraph.getArcs().stream()
//                .filter(arc -> sliced.getNodes().contains(arc.getFrom()) || sliced.getNodes().contains(arc.getTo()))
//                .collect(Collectors.toSet());
////                .forEach(sliced::addEdge);
//
//        arcs.forEach(sliced::addEdge);

//        Logger.log("==== Arcs ====");
//        sliced.getArcs().forEach(Logger::log);

//        Logger.log(sliced.getArcs().stream().map(Arc::toString).collect(Collectors.joining(System.lineSeparator())));
        PDGGraph sliced = pdgGraph.slice(new LineNumberCriterion(18, "x"));

        PDGLog pdgLog = new PDGLog(sliced);
        pdgLog.log();
@@ -77,6 +36,5 @@ public class Slice {
        pdgLog.openVisualRepresentation();

        PDGValidator.printPDGProgram("Slice" + PROGRAM_NAME, sliced);
        PDGValidator.printPDGProgram("Generated" + PROGRAM_NAME, pdgGraph);
    }
}
+4 −0
Original line number Diff line number Diff line
@@ -7,4 +7,8 @@ public class NodeNotFoundException extends RuntimeException {
    public NodeNotFoundException(SlicingCriterion slicingCriterion) {
        super("Node not found for slicing criterion: " + slicingCriterion);
    }

    public NodeNotFoundException(String message) {
        super(message);
    }
}
+46 −4
Original line number Diff line number Diff line
@@ -4,11 +4,12 @@ import com.github.javaparser.ast.NodeList;
import com.github.javaparser.ast.stmt.BlockStmt;
import com.github.javaparser.ast.stmt.EmptyStmt;
import com.github.javaparser.ast.stmt.Statement;
import edg.graphlib.Arrow;
import tfm.arcs.cfg.ControlFlowArc;
import tfm.graphs.CFGGraph;
import tfm.nodes.CFGNode;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.*;
import java.util.function.Predicate;

public class Utils {
@@ -48,4 +49,45 @@ public class Utils {
    public static <E> Set<E> emptySet() {
        return new HashSet<>(0);
    }

    public static Set<CFGNode> findLastDefinitionsFrom(CFGNode startNode, String variable) {
//        Logger.log("=======================================================");
//        Logger.log("Starting from " + startNode);
//        Logger.log("Looking for variable " + variable);
//        Logger.log(cfgGraph.toString());
        return findLastDefinitionsFrom(new HashSet<>(), startNode, startNode, variable);
    }

    private static Set<CFGNode> findLastDefinitionsFrom(Set<Integer> visited, CFGNode startNode, CFGNode currentNode, String variable) {
        visited.add(currentNode.getId());

//        Logger.log("On " + currentNode);

        Set<CFGNode> res = new HashSet<>();

        for (Arrow arrow : currentNode.getIncomingArrows()) {
            ControlFlowArc controlFlowArc = (ControlFlowArc) arrow;

            CFGNode from = (CFGNode) controlFlowArc.getFromNode();

//            Logger.log("Arrow from node: " + from);

            if (!Objects.equals(startNode, from) && visited.contains(from.getId())) {
//                Logger.log("It's already visited. Continuing...");
                continue;
            }

            if (from.getDefinedVariables().contains(variable)) {
//                Logger.log("Contains defined variable: " + variable);
                res.add(from);
            } else {
//                Logger.log("Doesn't contain the variable, searching inside it");
                res.addAll(findLastDefinitionsFrom(visited, startNode, from, variable));
            }
        }

//        Logger.format("Done with node %s", currentNode.getId());

        return res;
    }
}
+68 −25
Original line number Diff line number Diff line
@@ -10,70 +10,113 @@ import com.github.javaparser.ast.body.Parameter;
import com.github.javaparser.ast.stmt.BlockStmt;
import com.github.javaparser.ast.type.ArrayType;
import com.github.javaparser.ast.type.VoidType;
import com.github.javaparser.ast.visitor.VoidVisitorAdapter;
import tfm.graphs.PDGGraph;
import tfm.nodes.Node;
import tfm.utils.Logger;
import tfm.utils.Utils;
import tfm.visitors.PDGCFGVisitor;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Objects;
import java.util.Optional;

public class PDGValidator {

    private static final String PROGRAM_FOLDER = Utils.PROGRAMS_FOLDER + "pdg";
    private static final String PROGRAM_NAME = "Example2";
    private static final String METHOD_NAME = "main";

    public static void main(String[] args) throws FileNotFoundException {
        JavaParser.getStaticConfiguration().setAttributeComments(false);

        CompilationUnit originalProgram = JavaParser.parse(new File(String.format("%s/%s.java", PROGRAM_FOLDER, PROGRAM_NAME)));

        if (METHOD_NAME.isEmpty()) {
            originalProgram.accept(new VoidVisitorAdapter<Void>() {
                @Override
                public void visit(MethodDeclaration n, Void arg) {
                    Logger.format("On method: %s. Generating and comparing...", n.getNameAsString());
                    boolean check = generateAndCheck(n);

                    Logger.format("Result: %s", check ? "equal" : "not equal");
                }
            }, null);
        } else {
            Optional<MethodDeclaration> optionalTarget = originalProgram.findFirst(MethodDeclaration.class,
                    methodDeclaration -> Objects.equals(methodDeclaration.getNameAsString(), METHOD_NAME));

            if (!optionalTarget.isPresent()) {
                throw new RuntimeException(String.format("Method '%s' not found", METHOD_NAME));
            }

            Logger.format("On method: %s. Generating and comparing...", METHOD_NAME);

            boolean check = generateAndCheck(optionalTarget.get());

            Logger.format("Result: %s", check ? "equal" : "not equal");
        }
    }

    public static boolean generateAndCheck(MethodDeclaration methodDeclaration) {
        PDGGraph graph = new PDGGraph();

        originalProgram.accept(new PDGCFGVisitor(graph), graph.getRootNode());

//        graph.depthFirstSearch(graph.getRootNode(), new NodeVisitor<PDGNode>() {
//            @Override
//            public void visit(PDGNode node) {
//                if (node.equals(graph.getRootNode()))
//                    return;
//
//                Logger.log(node);
//
//                methodBody.addStatement(node.get);
//            }
//        });

        printPDGProgram("Generated" + PROGRAM_NAME, graph);
        methodDeclaration.accept(new PDGCFGVisitor(graph), graph.getRootNode());

        return check(methodDeclaration, graph);
    }

    public static boolean check(MethodDeclaration methodDeclaration, PDGGraph graph) {
        MethodDeclaration generatedMethod = generateMethod(methodDeclaration, graph);

        return ProgramComparator.areEqual(methodDeclaration, generatedMethod);
    }

    public static MethodDeclaration generateMethod(MethodDeclaration info, PDGGraph graph) {
        MethodDeclaration methodDeclaration = new MethodDeclaration();

        methodDeclaration.setName(info.getNameAsString());
        methodDeclaration.setModifiers(info.getModifiers());
        methodDeclaration.setType(info.getType());
        methodDeclaration.setParameters(info.getParameters());

        BlockStmt methodBody = new BlockStmt();
        methodDeclaration.setBody(methodBody);

        graph.getNodesAtLevel(1).stream()
                .sorted(Comparator.comparingInt(Node::getId))
                .forEach(node -> methodBody.addStatement(node.getAstNode()));

        return methodDeclaration;
    }

    public static void printPDGProgram(String fileName, PDGGraph graph) throws FileNotFoundException {
        CompilationUnit generatedProgram = new CompilationUnit();
        ClassOrInterfaceDeclaration clazz = generatedProgram.addClass(fileName).setPublic(true);

        MethodDeclaration methodDeclaration = clazz.addMethod("main", Modifier.Keyword.PUBLIC, Modifier.Keyword.STATIC);
        methodDeclaration.setType(new VoidType());
        MethodDeclaration info = new MethodDeclaration();

        info.setModifiers(Modifier.Keyword.PUBLIC, Modifier.Keyword.STATIC);
        info.setType(new VoidType());
        info.setName("main");

        Parameter parameter = new Parameter(
                new ArrayType(JavaParser.parseClassOrInterfaceType("String")),
                "args"
        );
        info.setParameters(new NodeList<>(parameter));

        methodDeclaration.setParameters(new NodeList<>(Arrays.asList(parameter)));

        BlockStmt methodBody = new BlockStmt();
        methodDeclaration.setBody(methodBody);
        MethodDeclaration generated = generateMethod(info, graph);

        graph.getNodesAtLevel(1).stream()
                .sorted(Comparator.comparingInt(Node::getId))
                .forEach(node -> methodBody.addStatement(node.getAstNode()));
        clazz.addMember(generated);

        PrintWriter printWriter = new PrintWriter(new File(String.format("out/%s.java", fileName)));

        printWriter.print(clazz.toString());

        printWriter.close();
    }
}
Loading