Commit 1f463363 authored by Carlos Galindo's avatar Carlos Galindo
Browse files

joinACFGs: overhaul

- The previous logic did not handle methods with the same name across classes
- Much quicker, using the callGraph.
parent d8c52b4d
Loading
Loading
Loading
Loading
+19 −39
Original line number Diff line number Diff line
@@ -38,6 +38,8 @@ import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;

import static es.upv.mist.slicing.util.SingletonCollector.toSingleton;

public class I_ACFG extends Graph {

    protected static final Map<CallableDeclaration<?>, CFG> acfgMap = ASTUtils.newIdentityHashMap();
@@ -237,46 +239,24 @@ public class I_ACFG extends Graph {


    protected void joinACFGs() {
        List<GraphNode<?>> enterNodes = new LinkedList<>();
        List<GraphNode<?>> exitNodes = new LinkedList<>();

        for (GraphNode<?> graphNode : Set.copyOf(vertexSet())) {
            if(isEnter(graphNode) && graphNode.getAstNode() instanceof MethodDeclaration) {
                enterNodes.add(graphNode);
            }
            if(isExit(graphNode)) {
                exitNodes.add(graphNode);
            }
        }

        enterNodes.sort(Comparator.comparingLong(GraphNode::getId));
        exitNodes.sort(Comparator.comparingLong(GraphNode::getId));

        enterNodes.remove(0);
        exitNodes.remove(0);

        for (GraphNode<?> graphNode : Set.copyOf(vertexSet())) {
            if(graphNode instanceof CallNode) {
                CallNode callNode = (CallNode) graphNode;
                enterNodes.forEach(enterNode -> {
                    if(isSameAstNode(enterNode, callNode)){
        for (CallGraph.Edge<?> call : callGraph.edgeSet()) {
            // Nodes to be paired up
            GraphNode<?> callNode  = vertexSet().stream()
                    .filter(n -> n instanceof CallNode)
                    .filter(n -> n.getAstNode().equals(call.getCall()))
                    .collect(toSingleton());
            GraphNode<?> returnNode = vertexSet().stream()
                    .filter(n -> n instanceof CallNode.Return)
                    .filter(n -> n.getAstNode().equals(call.getCall()))
                    .collect(toSingleton());
            GraphNode<?> enterNode = acfgMap.get(callGraph.getEdgeTarget(call).getDeclaration()).getRootNode();
            GraphNode<?> exitNode  = acfgMap.get(callGraph.getEdgeTarget(call).getDeclaration()).getExitNode();
            // Connections
            addControlFlowArc(callNode, enterNode);
                    }
                });
            }
            if(graphNode instanceof CallNode.Return) {
                SyntheticNode<?> returnNode = (SyntheticNode<?>) graphNode;
                exitNodes.forEach(exitNode -> {
                    if(isSameAstNode(exitNode, returnNode)){
            addControlFlowArc(exitNode, returnNode);
            // TODO: move this arc creation to expandCalls
            addEdge(callNode, returnNode, new ControlFlowArc.NonExecutable());
        }
                });
            }
        }
    }

    private boolean isSameAstNode(GraphNode<?> comparableNode, GraphNode<?> graphNode ) {
        return Objects.equals(((MethodDeclaration) comparableNode.getAstNode()).getName().getTokenRange().get().getBegin().getText(), ((MethodCallExpr) graphNode.getAstNode()).getName().getTokenRange().get().getBegin().getText());
    }

    private static boolean isExit(GraphNode<?> graphNode) {
+18 −0
Original line number Diff line number Diff line
package es.upv.mist.slicing.util;

import java.util.stream.Collector;
import java.util.stream.Collectors;

public class SingletonCollector {
    public static <T> Collector<T, ?, T> toSingleton() {
        return Collectors.collectingAndThen(
                Collectors.toList(),
                list -> {
                    if (list.size() != 1) {
                        throw new IllegalStateException("Stream should contain exactly one element");
                    }
                    return list.get(0);
                }
        );
    }
}