/**
*
*/
package soottocfg.soot.util;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import soot.Body;
import soot.Hierarchy;
import soot.Local;
import soot.RefType;
import soot.Scene;
import soot.SootClass;
import soot.Type;
import soot.Unit;
import soot.Value;
import soot.jimple.AnyNewExpr;
import soot.jimple.CastExpr;
import soot.jimple.DefinitionStmt;
import soot.jimple.FieldRef;
import soot.jimple.InvokeExpr;
import soot.jimple.ParameterRef;
import soot.jimple.ThisRef;
import soot.toolkits.graph.DirectedGraph;
import soot.toolkits.scalar.ForwardFlowAnalysis;
/**
* @author schaef
*
*/
public class LocalTypeFinder extends ForwardFlowAnalysis<Unit, Map<Local, Set<Type>>> {
private final Hierarchy hierarchy;
private final Body body;
public LocalTypeFinder(DirectedGraph<Unit> graph, Body b) {
super(graph);
this.body = b;
hierarchy = Scene.v().getActiveHierarchy();
this.doAnalysis();
}
public Set<Type> getLocalTypesBefore(Unit u, Local l) {
Set<Type> ret = new HashSet<Type>(this.getFlowBefore(u).get(l));
if (ret.isEmpty()) {
//can only happen if l is not initialized.
ret.add(l.getType());
}
return ret;
}
@Override
protected void flowThrough(Map<Local, Set<Type>> in, Unit u, Map<Local, Set<Type>> out) {
copy(in, out);
if (u instanceof DefinitionStmt) {
DefinitionStmt ds = (DefinitionStmt) u;
if (ds.getLeftOp() instanceof Local) {
Local l = (Local) ds.getLeftOp();
// out.put(l, getPossibleRhsTypes(u, ds.getRightOp(), in));
out.get(l).addAll(getPossibleRhsTypes(u, ds.getRightOp(), in));
}
}
}
private Set<Type> getPossibleRhsTypes(Unit u, Value rhs, Map<Local, Set<Type>> in) {
Set<Type> res = new HashSet<Type>();
if (rhs instanceof Local) {
// just use the set of the other local.
if (in.get(rhs).isEmpty()) {
res.add(rhs.getType());
} else {
res.addAll(in.get(rhs));
}
} else if (rhs instanceof AnyNewExpr) {
// only add the type of the NewExpr.
res.add(rhs.getType());
} else if (rhs instanceof ThisRef) {
// TODO: do we need to add the sub types as well?
res.add(rhs.getType());
} else if (rhs instanceof ParameterRef || rhs instanceof FieldRef || rhs instanceof CastExpr
|| rhs instanceof InvokeExpr) {
if (rhs.getType() instanceof RefType) {
SootClass sc = ((RefType) rhs.getType()).getSootClass();
List<SootClass> classes = null;
if (sc.isInterface()) {
classes = hierarchy.getImplementersOf(sc);
} else {
try {
classes = hierarchy.getSubclassesOfIncluding(sc);
} catch (Throwable e) {
SootClass exceptionClass = Scene.v().getSootClass("java.lang.Exception");
System.err.print("There is a bug ...");
classes = hierarchy.getSubclassesOfIncluding(exceptionClass);
}
}
for (SootClass s : classes) {
res.add(s.getType());
}
} else {
res.add(rhs.getType());
}
} else {
res.add(rhs.getType());
}
return res;
}
@Override
protected void copy(Map<Local, Set<Type>> from, Map<Local, Set<Type>> to) {
for (Entry<Local, Set<Type>> entry : from.entrySet()) {
to.put(entry.getKey(), new HashSet<Type>(entry.getValue()));
}
}
@Override
protected void merge(Map<Local, Set<Type>> in1, Map<Local, Set<Type>> in2, Map<Local, Set<Type>> out) {
out.clear();
for (Entry<Local, Set<Type>> entry : in1.entrySet()) {
out.put(entry.getKey(), new HashSet<Type>(entry.getValue()));
}
for (Entry<Local, Set<Type>> entry : in2.entrySet()) {
if (out.containsKey(entry.getKey())) {
out.get(entry.getKey()).addAll(entry.getValue());
} else {
out.put(entry.getKey(), new HashSet<Type>(entry.getValue()));
}
}
}
@Override
protected Map<Local, Set<Type>> newInitialFlow() {
Map<Local, Set<Type>> ret = new HashMap<Local, Set<Type>>();
for (Local l : body.getLocals()) {
ret.put(l, new HashSet<Type>());
}
return ret;
}
}