Commit 23586948 authored by Carlos Galindo's avatar Carlos Galindo
Browse files

SummaryArcs are now generated between every child node of actual-outs and actual-ins.

parent bbc7464e
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -8,12 +8,14 @@ import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
import com.github.javaparser.ast.body.ConstructorDeclaration;
import com.github.javaparser.ast.visitor.ModifierVisitor;
import com.github.javaparser.ast.visitor.Visitable;
import es.upv.mist.slicing.arcs.sdg.SummaryArc;
import es.upv.mist.slicing.graphs.ClassGraph;
import es.upv.mist.slicing.graphs.augmented.PSDG;
import es.upv.mist.slicing.graphs.cfg.CFG;
import es.upv.mist.slicing.graphs.exceptionsensitive.ESSDG;
import es.upv.mist.slicing.graphs.exceptionsensitive.ExceptionSensitiveCallConnector;
import es.upv.mist.slicing.graphs.pdg.PDG;
import es.upv.mist.slicing.nodes.SyntheticNode;
import es.upv.mist.slicing.slicing.JSysDGSlicingAlgorithm;
import es.upv.mist.slicing.slicing.SlicingAlgorithm;
import es.upv.mist.slicing.utils.NodeHashSet;
@@ -29,6 +31,10 @@ public class JSysDG extends ESSDG {
        return new JSysDG.Builder();
    }

    public void addSummaryArc(SyntheticNode<?> from, SyntheticNode<?> to) {
        addEdge(from, to, new SummaryArc());
    }

    /** Populates an ESSDG, using ESPDG and ESCFG as default graphs.
     * @see PSDG.Builder
     * @see ExceptionSensitiveCallConnector */
@@ -73,5 +79,10 @@ public class JSysDG extends ESSDG {
        protected void connectCalls() {
            new JSysCallConnector(JSysDG.this).connectAllCalls(callGraph);
        }

        @Override
        protected void createSummaryArcs() {
            new SummaryArcAnalyzer(JSysDG.this, callGraph).analyze();;
        }
    }
}
+133 −0
Original line number Diff line number Diff line
package es.upv.mist.slicing.graphs.jsysdg;

import com.github.javaparser.ast.body.CallableDeclaration;
import es.upv.mist.slicing.arcs.Arc;
import es.upv.mist.slicing.graphs.BackwardDataFlowAnalysis;
import es.upv.mist.slicing.graphs.CallGraph;
import es.upv.mist.slicing.nodes.GraphNode;
import es.upv.mist.slicing.nodes.SyntheticNode;
import es.upv.mist.slicing.nodes.VariableAction;
import es.upv.mist.slicing.nodes.exceptionsensitive.ExitNode;
import es.upv.mist.slicing.nodes.io.FormalIONode;
import es.upv.mist.slicing.nodes.io.OutputNode;
import es.upv.mist.slicing.nodes.oo.MemberNode;

import java.util.*;
import java.util.stream.Stream;

public class SummaryArcAnalyzer extends BackwardDataFlowAnalysis<CallGraph.Vertex, CallGraph.Edge<?>, Map<SyntheticNode<?>, Set<SyntheticNode<?>>>> {
    protected final JSysDG sdg;

    public SummaryArcAnalyzer(JSysDG sdg, CallGraph graph) {
        super(graph);
        this.sdg = sdg;
    }

    @Override
    protected Map<SyntheticNode<?>, Set<SyntheticNode<?>>> compute(CallGraph.Vertex vertex, Set<CallGraph.Vertex> predecessors) {
        saveDeclaration(vertex);
        return initialValue(vertex);
    }

    @Override
    protected Map<SyntheticNode<?>, Set<SyntheticNode<?>>> initialValue(CallGraph.Vertex vertex) {
        Map<SyntheticNode<?>, Set<SyntheticNode<?>>> value;
        if (vertexDataMap.containsKey(vertex)) {
            value = vertexDataMap.get(vertex);
        } else {
            value = new HashMap<>();
            for (var formalOut : getFormalOutNodes(vertex.getDeclaration()))
                value.put(formalOut, new HashSet<>());
        }
        value.replaceAll((key, oldValue) -> computeFormalIn(key));
        return value;
    }

    /** Generate all summary arcs for a given call. Arc generation should be idempotent:
     *  if this method is called repeatedly it should not create duplicate summary arcs. */
    protected void saveDeclaration(CallGraph.Vertex vertex) {
        var result = vertexDataMap.get(vertex);
        for (CallGraph.Edge<?> edge : graph.incomingEdgesOf(vertex)) {
            for (var entry : result.entrySet()) {
                var actualOutOpt = findOutputNode(edge, entry.getKey());
                if (actualOutOpt.isEmpty())
                    continue;
                for (var formalIn : entry.getValue()) {
                    var actualInOpt = findActualIn(edge, formalIn);
                    if (actualInOpt.isEmpty())
                        continue;
                    if (!sdg.containsEdge(actualInOpt.get(), actualOutOpt.get()))
                        sdg.addSummaryArc(actualInOpt.get(), actualOutOpt.get());
                }
            }
        }
    }

    protected Set<SyntheticNode<?>> getFormalOutNodes(CallableDeclaration<?> declaration) {
        Set<SyntheticNode<?>> set = new HashSet<>();
        Stream.concat(
                Stream.concat(
                        sdg.vertexSet().stream() // formal-out nodes
                                .filter(FormalIONode.class::isInstance)
                                .map(FormalIONode.class::cast)
                                .filter(FormalIONode::isOutput),
                        sdg.vertexSet().stream() // output nodes (the value returned)
                                .filter(OutputNode.class::isInstance)
                                .map(OutputNode.class::cast)),
                sdg.vertexSet().stream() // normal/exception exit nodes (for exception handling)
                        .filter(ExitNode.class::isInstance)
                        .map(ExitNode.class::cast))
                // Only nodes that match the current declaration
                .filter(node -> node.getAstNode() == declaration)
                .forEach(set::add);
        for (var node : Set.copyOf(set)) {
            if (node.getVariableActions().isEmpty())
                continue;
            assert node.getVariableActions().size() == 1;
            VariableAction action = node.getVariableActions().get(0);
            if (action.hasObjectTree()) {
                set.add(action.getObjectTree().getMemberNode());
                for (MemberNode memberNode : action.getObjectTree().nodeIterable())
                    set.add(memberNode);
            }
        }
        return set;
    }

    protected Set<SyntheticNode<?>> computeFormalIn(SyntheticNode<?> formalOut) {
        Set<SyntheticNode<?>> result = new HashSet<>();
        for (GraphNode<?> graphNode : sdg.createSlicingAlgorithm().traverseProcedure(formalOut).getGraphNodes())
            if (isFormalIn(graphNode) && graphNode instanceof SyntheticNode)
                result.add((SyntheticNode<?>) graphNode);
        return result;
    }

    protected Optional<? extends SyntheticNode<?>> findActualIn(CallGraph.Edge<?> edge, SyntheticNode<?> formalIn) {
        return sdg.incomingEdgesOf(formalIn).stream()
                .filter(Arc::isInterproceduralInputArc)
                .map(sdg::getEdgeSource)
                .filter(actualIn -> goToParent(actualIn).getAstNode() == edge.getCall())
                .map(node -> (SyntheticNode<?>) node)
                .findAny();
    }

    protected Optional<? extends SyntheticNode<?>> findOutputNode(CallGraph.Edge<?> edge, SyntheticNode<?> formalOut) {
        return sdg.outgoingEdgesOf(formalOut).stream()
                .filter(Arc::isInterproceduralOutputArc)
                .map(sdg::getEdgeTarget)
                .filter(actualOut -> goToParent(actualOut).getAstNode() == edge.getCall())
                .map(node -> (SyntheticNode<?>) node)
                .findAny();
    }

    private boolean isFormalIn(GraphNode<?> graphNode) {
        GraphNode<?> parent = goToParent(graphNode);
        return parent instanceof FormalIONode && ((FormalIONode) parent).isInput();
    }

    private GraphNode<?> goToParent(GraphNode<?> memberNode) {
        if (memberNode instanceof MemberNode)
            return goToParent(((MemberNode) memberNode).getParent());
        return memberNode;
    }
}