Commit 31f15bcc authored by Carlos Galindo's avatar Carlos Galindo
Browse files

Extended Slice and SliceAstVisitor to handle multiple methods, classes and files

parent 9ae5825e
Loading
Loading
Loading
Loading
+36 −1
Original line number Diff line number Diff line
package tfm.slicing;

import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.Node;
import com.github.javaparser.ast.NodeList;
import com.github.javaparser.ast.body.MethodDeclaration;
import com.github.javaparser.ast.visitor.CloneVisitor;
import com.github.javaparser.ast.visitor.Visitable;
@@ -43,6 +45,39 @@ public class Slice {
        return Set.copyOf(map.values());
    }

    /**
     * Organize all nodes pertaining to this slice in one or more CompilationUnits.
     * CompilationUnits themselves need not be part of the slice to be included if any of their
     * components are present.
     */
    public NodeList<CompilationUnit> toAst() {
        Map<CompilationUnit, Set<Node>> cuMap = new HashMap<>();
        // Build key set
        nodes.stream().filter(n -> n instanceof CompilationUnit)
                .forEach(cu -> cuMap.put((CompilationUnit) cu, new HashSet<>()));
        // Add each node to the corresponding bucket of the map
        // Nodes may not belong to a compilation unit (fictional nodes), and they are skipped for the slice.
        for (Node node : nodes)
            node.findCompilationUnit()
                    .flatMap(n -> Optional.ofNullable(cuMap.get(n)))
                    .ifPresent(set -> set.add(node));
        // Traverse the AST of each compilation unit, creating a copy and
        // removing any element not present in the slice.
        NodeList<CompilationUnit> cus = new NodeList<>();
        SlicePruneVisitor sliceVisitor = new SlicePruneVisitor();
        CloneVisitor cloneVisitor = new CloneVisitor();
        for (Map.Entry<CompilationUnit, Set<Node>> entry : cuMap.entrySet()) {
            CompilationUnit clone = (CompilationUnit) entry.getKey().accept(cloneVisitor, null);
            assert entry.getKey().getStorage().isPresent();
            clone.setStorage(entry.getKey().getStorage().get().getPath());
            Visitable sliced = clone.accept(sliceVisitor, entry.getValue());
            assert sliced instanceof CompilationUnit;
            cus.add((CompilationUnit) sliced);
        }
        return cus;
    }

    @Deprecated
    public Node getAst() {
        List<GraphNode<?>> methods = map.values().stream().filter(e -> e.getAstNode() instanceof MethodDeclaration).collect(Collectors.toList());
        if (methods.size() == 1) {
@@ -63,7 +98,7 @@ public class Slice {
    private MethodDeclaration getMethodAst(Node node) {
        Visitable clone = node.accept(new CloneVisitor(), null);
        assert clone instanceof MethodDeclaration;
        clone.accept(new SliceAstVisitor(), this);
        clone.accept(new SlicePruneVisitor(), nodes);
        return ((MethodDeclaration) clone);
    }
}
+171 −0
Original line number Diff line number Diff line
package tfm.slicing;

import com.github.javaparser.ast.CompilationUnit;
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.ConstructorDeclaration;
import com.github.javaparser.ast.body.FieldDeclaration;
import com.github.javaparser.ast.body.MethodDeclaration;
import com.github.javaparser.ast.expr.BooleanLiteralExpr;
import com.github.javaparser.ast.nodeTypes.NodeWithBody;
import com.github.javaparser.ast.stmt.*;
import com.github.javaparser.ast.visitor.ModifierVisitor;
import com.github.javaparser.ast.visitor.Visitable;

import java.util.Set;
import java.util.stream.Collectors;

public class SliceAstVisitor extends ModifierVisitor<Slice> {
public class SlicePruneVisitor extends ModifierVisitor<Set<Node>> {
    // ========== Utility methods ==========

    protected void fillBody(Node n) {
        if (!(n instanceof NodeWithBody))
            return;
        NodeWithBody<?> nb = ((NodeWithBody<?>) n);
        if (nb.getBody() == null)
            nb.setBody(new EmptyStmt());
    }

    // ========== File visitors ==========

    @Override
    public Visitable visit(CompilationUnit n, Set<Node> arg) {
        boolean keep = arg.contains(n);
        Visitable v = super.visit(n, arg);
        return keep ? v : null;
    }

    @Override
    public Visitable visit(ClassOrInterfaceDeclaration n, Set<Node> arg) {
        boolean keep = arg.contains(n);
        Visitable v = super.visit(n, arg);
        return keep ? v : null;
    }

    // ========== Class body visitors ==========

    @Override
    public Visitable visit(MethodDeclaration n, Set<Node> arg) {
        boolean keep = arg.contains(n);
        Visitable v = super.visit(n, arg);
        return keep ? v : null;
    }

    @Override
    public Visitable visit(ConstructorDeclaration n, Set<Node> arg) {
        boolean keep = arg.contains(n);
        Visitable v = super.visit(n, arg);
        return keep ? v : null;
    }

    @Override
    public Visitable visit(BreakStmt n, Slice arg) {
    public Visitable visit(FieldDeclaration n, Set<Node> arg) {
        boolean keep = arg.contains(n);
        Visitable v = super.visit(n, arg);
        return keep ? v : null;
    }

// ========== Method body visitors ==========
    // 3 alternatives:
    //      a. Without relevant children and included if on the slice or not (e.g. ExpressionStmt)
    //      b. With relevant children and included if of the slice or not, children are discarded if not included (e.g. WhileStmt)
    //      c. With relevant children and included if any children is included OR if on the slice (e.g. SwitchEntryStmt, LabeledStmt)

    @Override
    public Visitable visit(BreakStmt n, Set<Node> arg) {
        return arg.contains(n) ? n : null;
    }

    @Override
    public Visitable visit(ContinueStmt n, Slice arg) {
    public Visitable visit(ContinueStmt n, Set<Node> arg) {
        return arg.contains(n) ? n : null;
    }

    @Override
    public Visitable visit(DoStmt n, Slice arg) {
    public Visitable visit(DoStmt n, Set<Node> arg) {
        boolean keep = arg.contains(n);
        super.visit(n, arg);
        fillBody(n);
@@ -30,7 +91,7 @@ public class SliceAstVisitor extends ModifierVisitor<Slice> {
    }

    @Override
    public Visitable visit(ForEachStmt n, Slice arg) {
    public Visitable visit(ForEachStmt n, Set<Node> arg) {
        boolean keep = arg.contains(n);
        super.visit(n, arg);
        fillBody(n);
@@ -38,7 +99,7 @@ public class SliceAstVisitor extends ModifierVisitor<Slice> {
    }

    @Override
    public Visitable visit(ForStmt n, Slice arg) {
    public Visitable visit(ForStmt n, Set<Node> arg) {
        boolean keep = arg.contains(n);
        super.visit(n, arg);
        n.setInitialization(new NodeList<>(n.getInitialization().stream()
@@ -55,7 +116,7 @@ public class SliceAstVisitor extends ModifierVisitor<Slice> {
    }

    @Override
    public Visitable visit(WhileStmt n, Slice arg) {
    public Visitable visit(WhileStmt n, Set<Node> arg) {
        boolean keep = arg.contains(n);
        super.visit(n, arg);
        fillBody(n);
@@ -63,7 +124,7 @@ public class SliceAstVisitor extends ModifierVisitor<Slice> {
    }

    @Override
    public Visitable visit(IfStmt n, Slice arg) {
    public Visitable visit(IfStmt n, Set<Node> arg) {
        boolean keep = arg.contains(n);
        super.visit(n, arg);
        if (n.getThenStmt() == null)
@@ -72,23 +133,23 @@ public class SliceAstVisitor extends ModifierVisitor<Slice> {
    }

    @Override
    public Visitable visit(LabeledStmt n, Slice arg) {
    public Visitable visit(LabeledStmt n, Set<Node> arg) {
        super.visit(n, arg);
        return n.getStatement() != null ? n : null;
    }

    @Override
    public Visitable visit(ReturnStmt n, Slice arg) {
    public Visitable visit(ReturnStmt n, Set<Node> arg) {
        return arg.contains(n) ? n : null;
    }

    @Override
    public Visitable visit(ThrowStmt n, Slice arg) {
    public Visitable visit(ThrowStmt n, Set<Node> arg) {
        return arg.contains(n) ? n : null;
    }

    @Override
    public Visitable visit(SwitchEntryStmt n, Slice arg) {
    public Visitable visit(SwitchEntryStmt n, Set<Node> arg) {
        boolean keep = arg.contains(n);
        super.visit(n, arg);
        if (!n.getStatements().isEmpty())
@@ -97,22 +158,14 @@ public class SliceAstVisitor extends ModifierVisitor<Slice> {
    }

    @Override
    public Visitable visit(SwitchStmt n, Slice arg) {
    public Visitable visit(SwitchStmt n, Set<Node> arg) {
        boolean keep = arg.contains(n);
        super.visit(n, arg);
        return keep ? n : null;
    }

    @Override
    public Visitable visit(ExpressionStmt n, Slice arg) {
    public Visitable visit(ExpressionStmt n, Set<Node> arg) {
        return arg.contains(n) ? n : null;
    }

    private void fillBody(Node n) {
        if (!(n instanceof NodeWithBody))
            return;
        NodeWithBody<?> nb = ((NodeWithBody<?>) n);
        if (nb.getBody() == null)
            nb.setBody(new EmptyStmt());
    }
}