Skip to content
PDGTests.java 6.84 KiB
Newer Older
package tfm;

import com.github.javaparser.JavaParser;
import com.github.javaparser.ast.Modifier;
import com.github.javaparser.ast.Node;
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
import com.github.javaparser.ast.body.MethodDeclaration;
import com.github.javaparser.ast.stmt.ThrowStmt;
import com.github.javaparser.ast.stmt.TryStmt;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import tfm.exec.GraphLog;
import tfm.exec.PDGLog;
import tfm.graphs.CFG.ACFG;
import tfm.graphs.PDG;
import tfm.graphs.PDG.APDG;
import tfm.graphs.PDG.PPDG;
import tfm.nodes.GraphNode;
import tfm.slicing.GraphNodeCriterion;
import tfm.slicing.SlicingCriterion;
import tfm.utils.Logger;
import tfm.visitors.cfg.CFGBuilder;
import tfm.visitors.pdg.ControlDependencyBuilder;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;

public class PDGTests {
    static {
        JavaParser.getStaticConfiguration().setAttributeComments(false);
    }

    private boolean error = false;

    @ParameterizedTest(name = "[{index}] {0} ({1})")
    @MethodSource("tfm.FileFinder#findAllMethodDeclarations")
    public void ppdgTest(File file, String methodName, MethodDeclaration root) throws IOException {
        runPdg(file, methodName, root, PDGLog.PPDG);
    }

    @ParameterizedTest(name = "[{index}] {0} ({1})")
    @MethodSource("tfm.FileFinder#findAllMethodDeclarations")
    public void apdgTest(File file, String methodName, MethodDeclaration root) throws IOException {
        runPdg(file, methodName, root, PDGLog.APDG);
    }

    @ParameterizedTest(name = "[{index}] {0} ({1})")
    @MethodSource("tfm.FileFinder#findAllMethodDeclarations")
    public void pdgTest(File file, String methodName, MethodDeclaration root) throws IOException {
        runPdg(file, methodName, root, PDGLog.PDG);
    private void runPdg(File file, String methodName, Node root, int type) throws IOException {
        GraphLog<?> graphLog = new PDGLog(type);
        graphLog.visit(root);
        graphLog.log();
        try {
            graphLog.generateImages(file.getPath() + "-" + methodName);
        } catch (Exception e) {
            System.err.println("Could not generate PNG");
            System.err.println(e.getMessage());
        }
    }

    @ParameterizedTest(name = "[{index}] {0} ({1})")
    @MethodSource("tfm.FileFinder#findAllMethodDeclarations")
    public void pdgCompare(File file, String methodName, MethodDeclaration root) throws IOException {
        ControlDependencyBuilder ctrlDepBuilder;

        if (containsUnsupportedStatements(root)) {
            System.err.println("Contains unsupported instructions");
        }

        // Create PDG
        CFG cfg = new CFG();
        root.accept(new CFGBuilder(cfg), null);
        PDG pdg = new PDG(cfg);
        ctrlDepBuilder = new ControlDependencyBuilder(pdg, cfg);
        ctrlDepBuilder.analyze();

        // Create APDG
        ACFG acfg = new ACFG();
        root.accept(new CFGBuilder(acfg), null);
        APDG apdg = new APDG(acfg);
        ctrlDepBuilder = new ControlDependencyBuilder(apdg, acfg);
        ctrlDepBuilder.analyze();

        // Create PPDG
        PPDG ppdg = new PPDG(acfg);
        ctrlDepBuilder = new ControlDependencyBuilder(ppdg, acfg);
        ctrlDepBuilder.analyze();

        // Print graphs (commented to decrease the test's time)
        String filePathNoExt = file.getPath().substring(0, file.getPath().lastIndexOf('.'));
//        String name = filePathNoExt + "/" + methodName;
//        new PDGLog(pdg).generateImages(name);
//        new PDGLog(apdg).generateImages(name);
//        new PDGLog(ppdg).generateImages(name);

        List<MethodDeclaration> slicedMethods = compareGraphs(pdg, apdg, ppdg);

        // Write sliced methods to a java file.
        ClassOrInterfaceDeclaration clazz = new ClassOrInterfaceDeclaration();
        slicedMethods.forEach(clazz::addMember);
        clazz.setName(methodName);
        clazz.setModifier(Modifier.Keyword.PUBLIC, true);
        try (PrintWriter pw = new PrintWriter(new File("./out/" + filePathNoExt + "/" + methodName + ".java"))) {
            pw.println(clazz);
        } catch (Exception e) {
            Logger.log("Error! Could not write classes to file");
        }

        assert !error;
    }

    public static boolean containsUnsupportedStatements(Node node) {
        return node.findFirst(TryStmt.class).isPresent()
                || node.findFirst(ThrowStmt.class).isPresent();
    }


    /** Slices both graphs on every possible node and compares the result */
    public List<MethodDeclaration> compareGraphs(PDG... pdgs) {
        List<MethodDeclaration> slicedMethods = new LinkedList<>();
        assert pdgs.length > 0;
        for (GraphNode<?> node : pdgs[0].getNodes().stream()
                .sorted(Comparator.comparingInt(GraphNode::getId))
                .collect(Collectors.toList())) {
            if (node.getAstNode() instanceof MethodDeclaration)
                continue;
            SlicingCriterion sc = new GraphNodeCriterion(node, "x");
            Slice[] slices = Arrays.stream(pdgs).map(p -> p.slice(sc)).toArray(Slice[]::new);

            // Compare slices
            boolean ok = true;
            Slice referenceSlice = slices[0];
            for (Slice slice : slices) {
                ok = referenceSlice.equals(slice);
                error |= !ok;
                if (!ok) break;
            }

            // Display slice
            Logger.log("Slicing on " + node.getId());
                Logger.log("FAILED!");
            printSlices(pdgs[0], slices);

            // Save slices as MethodDeclaration
            int i = 0;
            for (Slice s : slices) {
                i++;
                try {
                    MethodDeclaration m = ((MethodDeclaration) s.getAst());
                    m.setName(m.getName() + "_slice" + node.getId() + "_pdg" + i);
                    slicedMethods.add(m);
                } catch (RuntimeException e) {
                    Logger.log("Error: " + e.getMessage());
                }
    public final void printSlices(PDG pdg, Slice... slices) {
        pdg.getNodes().stream()
                .sorted(Comparator.comparingInt(GraphNode::getId))
                .forEach(n -> Logger.format("%3d: %s %s",
                        n.getId(),
                        Arrays.stream(slices)
                                .map(s -> s.contains(n) ? "x" : " ")
                                .reduce((a, b) -> a + " " + b).orElse("--error--"),