// Now create new methods in the given class for methods that
// exist in the super class, but not in the given class.
// Invoke the super class.
for (Iterator methods = superClass.getMethods().iterator(); methods
.hasNext();) {
SootMethod oldMethod = (SootMethod) methods.next();
if (theClass.declaresMethod(oldMethod.getSubSignature())) {
continue;
}
oldMethod.retrieveActiveBody();
SootMethod newMethod = new SootMethod(oldMethod.getName(),
oldMethod.getParameterTypes(), oldMethod.getReturnType(),
oldMethod.getModifiers(), oldMethod.getExceptions());
theClass.addMethod(newMethod);
JimpleBody newBody = Jimple.v().newBody(newMethod);
newMethod.setActiveBody(newBody);
newBody.insertIdentityStmts();
//System.out.println("method = " + newMethod);
//System.out.println("oldMethod = " + oldMethod);
// Call the super method
Chain units = newBody.getUnits();
// get a list of the locals that reference
// the parameters of the
// constructor.
List parameterList = new ArrayList();
parameterList.addAll(newBody.getLocals());
Stmt invokeStmt = null;
// Invoke the method...
// handling static and void methods differently
if (oldMethod.getReturnType() == VoidType.v()) {
InvokeExpr invokeExpr;
if (newMethod.isStatic()) {
invokeExpr = Jimple.v().newStaticInvokeExpr(
oldMethod.makeRef(), parameterList);
} else {
Local thisLocal = newBody.getThisLocal();
parameterList.remove(thisLocal);
invokeExpr = Jimple.v().newVirtualInvokeExpr(thisLocal,
oldMethod.makeRef(), parameterList);
}
invokeStmt = Jimple.v().newInvokeStmt(invokeExpr);
units.add(invokeStmt);
// return void
units.add(Jimple.v().newReturnVoidStmt());
} else {
InvokeExpr invokeExpr;
// Create a new local for the return value.
Local returnValueLocal = Jimple.v().newLocal("returnValue",
oldMethod.getReturnType());
newBody.getLocals().add(returnValueLocal);
if (newMethod.isStatic()) {
invokeExpr = Jimple.v().newStaticInvokeExpr(
oldMethod.makeRef(), parameterList);
} else {
Local thisLocal = newBody.getThisLocal();
parameterList.remove(thisLocal);
invokeExpr = Jimple.v().newVirtualInvokeExpr(thisLocal,
oldMethod.makeRef(), parameterList);
}
invokeStmt = Jimple.v().newAssignStmt(returnValueLocal,
invokeExpr);
units.add(invokeStmt);
// return the value
units.add(Jimple.v().newReturnStmt(returnValueLocal));
}
}
// Loop through all the methods again, this time looking for
// method invocations on the old superClass... Inline these calls.
// This code is similar to inlineCallsToMethod, but avoids iterating
// over all the methods in the class twice, which could get
// very expensive.
for (Iterator methods = theClass.getMethods().iterator(); methods
.hasNext();) {
SootMethod newMethod = (SootMethod) methods.next();
Body newBody = newMethod.retrieveActiveBody();
// use a snapshotIterator since we are going to be manipulating
// the statements.
Iterator j = newBody.getUnits().snapshotIterator();
while (j.hasNext()) {
Stmt stmt = (Stmt) j.next();
System.out.println("stmt = " + stmt);
Iterator boxes = stmt.getUseAndDefBoxes().iterator();
while (boxes.hasNext()) {
ValueBox box = (ValueBox) boxes.next();
Value value = box.getValue();
if (value instanceof FieldRef) {
// Fix references to fields
FieldRef r = (FieldRef) value;
SootFieldRef fieldRef = r.getFieldRef();
if (r.getField().getDeclaringClass() != superClass
&& fieldRef.declaringClass() == superClass) {
// We might also have a reference to a method
// which is not actually declared in the
// superclass, in which case, we just fix up
// the ref to point to the new super class
r.setFieldRef(Scene.v().makeFieldRef(
superClass.getSuperclass(),
fieldRef.name(), fieldRef.type(),
fieldRef.isStatic()));
}
}
}
if (stmt.containsInvokeExpr()) {
InvokeExpr invoke = stmt.getInvokeExpr();
SootMethodRef invokeMethodRef = invoke.getMethodRef();
SootMethod invokeMethod = invoke.getMethod();
if (invokeMethod.getDeclaringClass() == superClass) {
// Force the body of the thing we are inlining to be
// loaded
try {
if (invokeMethod.isConcrete()) {
invokeMethod.retrieveActiveBody();
} else {
System.out.println("SootUtilities."
+ "foldClass() " + invokeMethod
+ " is not concrete!");
// javac -target 1.2 and greater
// ends up causing problems here when
// calling super on a method, but the
// direct parent does not have a
// method by that name.
//
// If I have 3 classes A, B and C,
// where C extends B which extends A
// and A and C define a method foo and
// C calls super.foo, then under javac
// -target 1.2 the constant pool ends
// up with a reference to
// [2] methodref=soot/coffi/B.foo
// and under javac -target 1.1, we end up with
// [2] methodref=soot/coffi/A.foo
// So, we look for the method in the superclass
SootClass scratchClass = invokeMethod
.getDeclaringClass();
while (scratchClass.hasSuperclass()) {
SootClass superC = scratchClass
.getSuperclass();
if (superC.declaresMethod(invokeMethod
.getSubSignature())) {
invokeMethod = superC
.getMethod(invokeMethod
.getSubSignature());
System.out.println("SootUtilties."
+ "foldClass() " + "found "
+ superC + " " + invokeMethod);
invokeMethod.retrieveActiveBody();
break;
}
scratchClass = superC;
}