package ai.cfg;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.Set;
import org.apache.log4j.Logger;
import org.eclipse.jdt.core.dom.IMethodBinding;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import ai.cfg.edges.CFGMultiTargetEdge.CFGSingleEdge;
import ai.common.DefaultHashMap;
public class Utils {
private final static Logger log = Logger.getLogger(Utils.class.getName());
// private static int methodIdxGen = 0;
// private static Map<MethodDeclaration, String> generatedNames = new HashMap<MethodDeclaration, String>();
//
// public static String getUniqueName(InterestingCodeFragment codeFragment) {
// MethodDeclaration node
// IMethodBinding binding = node.resolveBinding();
// if (binding == null) {
// log.error("Binding not resolved, probably project path is invalid: " + node);
// if (generatedNames.containsKey(node))
// return generatedNames.get(node);
// String name = "Dummy_method_location_" + methodIdxGen++ + ":" + node.getName();
// generatedNames.put(node, name);
// return name;
// }
// return binding.getDeclaringClass().getBinaryName() + ":" + node.getName();
// }
private static class VerticeNameGenerator {
private final Map<CFGVertice, String> names = new HashMap<CFGVertice, String>();
private final Set<String> usedNames = new HashSet<String>();
private final String prefix;
private int counter = 0;
public VerticeNameGenerator(String prefix) {
this.prefix = prefix;
}
public String getName(CFGVertice vertice) {
if (vertice.getDescription() != null)
return vertice.getDescription();
if (!names.containsKey(vertice)) {
String name = prefix + counter++;
if (usedNames.contains(name))
throw new RuntimeException("Error in vertice name generation");
names.put(vertice, name);
usedNames.add(name);
}
return names.get(vertice);
}
public void setName(CFGVertice vertice, String name) {
if (usedNames.contains(name))
throw new RuntimeException("Name already in use");
if (names.containsKey(vertice))
throw new RuntimeException("Vertice already has a name");
names.put(vertice, name);
}
}
public static Collection<CFGVertice> walkGraph(MethodControlFlowGraph graph, ControlFlowGraphVisitor visitor) {
Queue<CFGSingleEdge> queue = new LinkedList<CFGSingleEdge>();
queue.addAll(Arrays.asList(graph.getInput().singleEdges));
Set<CFGVertice> visited = new HashSet<CFGVertice>();
while (!queue.isEmpty()) {
CFGSingleEdge edge = queue.poll();
boolean visitTarget = visitor.visitEdge(edge);
if (!visitTarget)
continue;
CFGVertice vertice = edge.target;
if (visited.contains(vertice))
continue;
visited.add(vertice);
boolean visitOutgoingEdges = visitor.visitVertice(vertice);
if (!visitOutgoingEdges)
continue;
queue.addAll(vertice.getOutgoingEdges());
}
return visited;
}
public static void printCFG(MethodControlFlowGraph graph) {
final VerticeNameGenerator namesGen = new VerticeNameGenerator("Vertice_");
final StringBuffer buffer = new StringBuffer("Edges:\n");
namesGen.setName(graph.getStartVertice(), "IN");
namesGen.setName(graph.getEndVertice(), "OUT");
// initialise
ControlFlowGraphVisitor visitor = new ControlFlowGraphVisitor() {
@Override
public boolean visitVertice(CFGVertice vertice) {
return true;
}
@Override
public boolean visitEdge(CFGSingleEdge edge) {
if (edge.source != null)
buffer.append("[["+namesGen.getName(edge.source)+"]]");
buffer.append(" -> ");
buffer.append("[["+namesGen.getName(edge.target)+ "]]");
buffer.append(": ");
buffer.append(edge.toString());
buffer.append("\n");
return true;
}
};
System.out.print("Vertices:");
for (CFGVertice vertice : walkGraph(graph, visitor)) {
System.out.print(" ");
System.out.print("[["+namesGen.getName(vertice)+"]]\n");
}
System.out.println();
System.out.println(buffer.toString());
}
public static Map<CFGVertice, List<CFGSingleEdge>> computeInputEdges(MethodControlFlowGraph graph) {
final Map<CFGVertice, List<CFGSingleEdge>> inputs = new HashMap<CFGVertice, List<CFGSingleEdge>>();
walkGraph(graph, new ControlFlowGraphVisitor() {
@Override
public boolean visitVertice(CFGVertice vertice) {
return true;
}
@Override
public boolean visitEdge(CFGSingleEdge edge) {
CFGVertice target = edge.target;
if (!inputs.containsKey(target)) {
inputs.put(target, new LinkedList<CFGSingleEdge>());
}
inputs.get(target).add(edge);
return true;
}
});
return inputs;
}
private static void helper(CFGSingleEdge inputEdge, Set<CFGVertice> verticesAlreadyOnPath, Set<CFGVertice> visited,
DefaultHashMap<CFGVertice, Collection<CFGSingleEdge>> result) {
CFGVertice vertice = inputEdge.target;
if (verticesAlreadyOnPath.contains(vertice)) // loop
result.setDefault(vertice, new LinkedList<CFGSingleEdge>()).add(inputEdge);
if (visited.contains(vertice))
return;
verticesAlreadyOnPath.add(vertice);
visited.add(vertice);
for(CFGSingleEdge edge: vertice.getOutgoingEdges())
helper(edge, verticesAlreadyOnPath, visited, result);
verticesAlreadyOnPath.remove(vertice);
}
public static Map<CFGVertice, Collection<CFGSingleEdge>> findLoopVertices(MethodControlFlowGraph graph) {
DefaultHashMap<CFGVertice, Collection<CFGSingleEdge>> result = new DefaultHashMap<CFGVertice, Collection<CFGSingleEdge>>();
helper(graph.getInput().singleEdges[0], new HashSet<CFGVertice>(), new HashSet<CFGVertice>(), result);
return result;
}
}