Unverified Commit c48ab8ea authored by Javier Costa's avatar Javier Costa Committed by GitHub
Browse files

Merge pull request #33 from jacosro/7-build-summary-arcs

WIP: Added Naive summary arcs builder
parents 8c87900a e7d7df7a
Loading
Loading
Loading
Loading
+36 −0
Original line number Diff line number Diff line
@@ -6,6 +6,9 @@ import tfm.arcs.cfg.ControlFlowArc;
import tfm.arcs.pdg.ControlDependencyArc;
import tfm.arcs.pdg.DataDependencyArc;
import tfm.arcs.sdg.CallArc;
import tfm.arcs.sdg.ParameterInOutArc;
import tfm.arcs.sdg.ReturnArc;
import tfm.arcs.sdg.SummaryArc;
import tfm.nodes.GraphNode;

import java.util.HashMap;
@@ -73,6 +76,39 @@ public abstract class Arc extends DefaultEdge {
        throw new UnsupportedOperationException("Not a CallArc");
    }

    /** @see ParameterInOutArc */
    public final boolean isParameterInOutArc() {
        return this instanceof ParameterInOutArc;
    }

    public final ParameterInOutArc asParameterInOutArc() {
        if (isParameterInOutArc())
            return (ParameterInOutArc) this;
        throw new UnsupportedOperationException("Not a ParameterInOutArc");
    }

    /** @see ReturnArc */
    public final boolean isReturnArc() {
        return this instanceof ReturnArc;
    }

    public final ReturnArc asReturnArc() {
        if (isReturnArc())
            return (ReturnArc) this;
        throw new UnsupportedOperationException("Not a ReturnArc");
    }

    /** @see SummaryArc */
    public final boolean isSummaryArc() {
        return this instanceof SummaryArc;
    }

    public final SummaryArc asSummaryArcArc() {
        if (isSummaryArc())
            return (SummaryArc) this;
        throw new UnsupportedOperationException("Not a SummaryArc");
    }

    @Override
    public String toString() {
        return String.format("%s{%d -> %d}", getClass().getName(),
+16 −0
Original line number Diff line number Diff line
package tfm.arcs.sdg;

import org.jgrapht.io.Attribute;
import org.jgrapht.io.DefaultAttribute;
import tfm.arcs.Arc;

import java.util.Map;

public class SummaryArc extends Arc {
    @Override
    public Map<String, Attribute> getDotAttributes() {
        Map<String, Attribute> map = super.getDotAttributes();
        map.put("style", DefaultAttribute.createAttribute("bold"));
        return map;
    }
}
+5 −0
Original line number Diff line number Diff line
@@ -14,6 +14,7 @@ import tfm.arcs.pdg.DataDependencyArc;
import tfm.arcs.sdg.CallArc;
import tfm.arcs.sdg.ParameterInOutArc;
import tfm.arcs.sdg.ReturnArc;
import tfm.arcs.sdg.SummaryArc;
import tfm.graphs.Buildable;
import tfm.graphs.Graph;
import tfm.graphs.cfg.CFG;
@@ -90,6 +91,10 @@ public class SDG extends Graph implements Sliceable, Buildable<NodeList<Compilat
        this.addEdge(from, to, new ReturnArc());
    }

    public void addSummaryArc(GraphNode<ExpressionStmt> from, GraphNode<ExpressionStmt> to) {
        this.addEdge(from, to, new SummaryArc());
    }

    public List<GraphNode<?>> findDeclarationsOfVariable(String variable, GraphNode<?> root) {
        return this.methodCFGMap.values().stream()
                .filter(cfg -> cfg.containsVertex(root))
+11 −2
Original line number Diff line number Diff line
@@ -3,14 +3,21 @@ package tfm.graphs.sdg;
import com.github.javaparser.ast.CompilationUnit;
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.expr.*;
import com.github.javaparser.ast.stmt.ExpressionStmt;
import com.github.javaparser.ast.visitor.VoidVisitorAdapter;
import tfm.arcs.Arc;
import tfm.graphs.pdg.PDG;
import tfm.graphs.sdg.sumarcs.NaiveSummaryArcsBuilder;
import tfm.graphs.sdg.sumarcs.SummaryArcsBuilder;
import tfm.nodes.GraphNode;
import tfm.nodes.type.NodeType;
import tfm.utils.Context;
import tfm.utils.Utils;

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

class SDGBuilder extends VoidVisitorAdapter<Context> {

@@ -77,6 +84,8 @@ class SDGBuilder extends VoidVisitorAdapter<Context> {


        // 3. Build summary arcs
        SummaryArcsBuilder summaryArcsBuilder = new NaiveSummaryArcsBuilder(sdg);
        summaryArcsBuilder.visit();
    }

    @Override
+109 −0
Original line number Diff line number Diff line
package tfm.graphs.sdg.sumarcs;

import com.github.javaparser.ast.body.MethodDeclaration;
import com.github.javaparser.ast.stmt.ExpressionStmt;
import tfm.arcs.Arc;
import tfm.graphs.sdg.SDG;
import tfm.nodes.GraphNode;
import tfm.nodes.type.NodeType;
import tfm.utils.Utils;

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

public class NaiveSummaryArcsBuilder extends SummaryArcsBuilder {

    public NaiveSummaryArcsBuilder(SDG sdg) {
        super(sdg);
    }

    @Override
    public void visit() {
        for (MethodDeclaration methodDeclaration : sdg.getMethodDeclarations()) {
            Optional<GraphNode<MethodDeclaration>> optionalMethodDeclarationNode = sdg.findNodeByASTNode(methodDeclaration);
            assert optionalMethodDeclarationNode.isPresent();

            GraphNode<MethodDeclaration> methodDeclarationNode = optionalMethodDeclarationNode.get();

            Set<GraphNode<ExpressionStmt>> formalOutNodes = sdg.outgoingEdgesOf(methodDeclarationNode).stream()
                    .filter(arc -> sdg.getEdgeTarget(arc).getNodeType() == NodeType.FORMAL_OUT)
                    .map(arc -> (GraphNode<ExpressionStmt>) sdg.getEdgeTarget(arc))
                    .collect(Collectors.toSet());

            for (GraphNode<ExpressionStmt> formalOutNode : formalOutNodes) {
                Set<GraphNode<ExpressionStmt>> reachableFormalInNodes = this.findReachableFormalInNodes(formalOutNode);

                Set<GraphNode<ExpressionStmt>> actualInNodes = reachableFormalInNodes.stream().flatMap(this::getActualInsStream).collect(Collectors.toSet());
                Set<GraphNode<ExpressionStmt>> actualOutNodes = this.getActualOuts(formalOutNode);

                for (GraphNode<ExpressionStmt> actualOutNode : actualOutNodes) {
                    for (GraphNode<ExpressionStmt> actualInNode : actualInNodes) {
                        if (this.belongToSameMethodCall(actualInNode, actualOutNode)) {
                            sdg.addSummaryArc(actualInNode, actualOutNode);
                        }
                    }
                }
            }
        }
    }

    private Set<GraphNode<ExpressionStmt>> findReachableFormalInNodes(GraphNode<ExpressionStmt> formalOutNode) {
        return this.doFindReachableFormalInNodes(formalOutNode, Utils.emptySet());
    }

    private Set<GraphNode<ExpressionStmt>> doFindReachableFormalInNodes(GraphNode<?> root, Set<Long> visited) {
        visited.add(root.getId());

        Set<GraphNode<ExpressionStmt>> res = Utils.emptySet();

        if (root.getNodeType() == NodeType.FORMAL_IN) {
            res.add((GraphNode<ExpressionStmt>) root);
        } else {
            for (Arc arc : sdg.incomingEdgesOf(root)) {
                GraphNode<?> nextNode = sdg.getEdgeSource(arc);

                if (visited.contains(nextNode.getId())) {
                    continue;
                }

                if (arc.isControlDependencyArc() || arc.isDataDependencyArc()) {
                    res.addAll(this.doFindReachableFormalInNodes(nextNode, visited));
                }
            }
        }

        return res;
    }

    private Stream<GraphNode<ExpressionStmt>> getActualInsStream(GraphNode<ExpressionStmt> formalIn) {
        return sdg.incomingEdgesOf(formalIn).stream()
                .filter(Arc::isParameterInOutArc)
                .filter(arc -> sdg.getEdgeSource(arc).getNodeType() == NodeType.ACTUAL_IN)
                .map(arc -> (GraphNode<ExpressionStmt>) sdg.getEdgeSource(arc));
    }

    private Set<GraphNode<ExpressionStmt>> getActualOuts(GraphNode<ExpressionStmt> formalOut) {
        return sdg.outgoingEdgesOf(formalOut).stream()
                .filter(Arc::isParameterInOutArc)
                .filter(arc -> sdg.getEdgeTarget(arc).getNodeType() == NodeType.ACTUAL_OUT)
                .map(arc -> (GraphNode<ExpressionStmt>) sdg.getEdgeTarget(arc))
                .collect(Collectors.toSet());
    }

    private boolean belongToSameMethodCall(GraphNode<ExpressionStmt> actualIn, GraphNode<ExpressionStmt> actualOut) {
        Optional<GraphNode<ExpressionStmt>> optionalInCallNode = this.getCallNode(actualIn);
        Optional<GraphNode<ExpressionStmt>> optionalOutCallNode = this.getCallNode(actualOut);

        return optionalInCallNode.isPresent() && optionalOutCallNode.isPresent()
                && optionalInCallNode.get() == optionalOutCallNode.get();
    }

    private Optional<GraphNode<ExpressionStmt>> getCallNode(GraphNode<ExpressionStmt> actualInOrOut) {
        return sdg.incomingEdgesOf(actualInOrOut).stream()
                .filter(arc -> sdg.getEdgeSource(arc).getNodeType() == NodeType.METHOD_CALL)
                .map(arc -> (GraphNode<ExpressionStmt>) sdg.getEdgeSource(arc))
                .findFirst();
    }
}
Loading