Reputation: 8219
So I have a Method
public modifiers Foo foo(Bar bar){
blah;
blah;
veryInterestingStmt;
moreBlah();
return XYZ;
}
I now want to split this method s.t. everything in its body is extracted into a separate method (programmatically).
I.e.
public modifiers Foo foo(Bar bar){
return trulyFoo(bar);
}
public modifiers Foo trulyFoo(Bar bar){
blah;
blah;
veryInterestingStmt;
moreBlah();
return XYZ;
}
How do I do that, though?
The naive
private void fracture(SootMethod sm) {
SootClass sc = sm.getDeclaringClass();
String auxMethodName = sm.getName() + FRACTURE_SUFFIX;
Type auxReturnType = sm.getReturnType();
List<Type>auxParamTypes = new LinkedList<>(sm.getParameterTypes());
int auxModifiers = sm.getModifiers();
SootMethod auxMethod = sc.addMethod(new SootMethod(auxMethodName,auxParamTypes,auxReturnType,auxModifiers));
Body body = sm.getActiveBody();
Body auxBody = Jimple.v().newBody(auxMethod);
auxMethod.setActiveBody(auxBody);
for(Local l : body.getLocals()){
auxBody.getLocals().add(l);
}
PatchingChain<Unit> units = body.getUnits();
PatchingChain<Unit> auxUnits = auxBody.getUnits();
Iterator<Unit> it = body.getUnits().snapshotIterator();
boolean passedFirstNonidentity = false;
while(it.hasNext()){
Stmt stmt = (Stmt) it.next();
if(!passedFirstNonidentity && !(stmt instanceof IdentityStmt)) {
passedFirstNonidentity = true;
//TODO: if added more parameters than original method had, add their identity stmts here
}
auxUnits.add(stmt);
// if(passedFirstNonidentity) units.remove(stmt); //TODO: uncomment this and later add call to {@code auxMethod}
}
}
}
Doesn't work. If I run, say
DirectedGraph dg = new ExceptionalUnitGraph(auxMethod.getActiveBody());
I get a
java.lang.RuntimeException: Unit graph contains jump to non-existing target
at soot.toolkits.graph.UnitGraph.buildUnexceptionalEdges(UnitGraph.java:128)
at soot.toolkits.graph.ExceptionalUnitGraph.initialize(ExceptionalUnitGraph.java:258)
at soot.toolkits.graph.ExceptionalUnitGraph.<init>(ExceptionalUnitGraph.java:159)
at soot.toolkits.graph.ExceptionalUnitGraph.<init>(ExceptionalUnitGraph.java:192)
Upvotes: 0
Views: 88
Reputation: 8219
It seems that moving stmts just doesn't work. In contrast, completely replacing the body
Body originalBody = sm.getActiveBody();
originalBody.setMethod(auxMethod);
auxMethod.setActiveBody(originalBody);
Body newBody = Jimple.v().newBody(sm);
sm.setActiveBody(newBody);
and then regenerating the locals, identity stmts (and other stmts you may need) in the newBody
looks like a sensible way to go.
Upvotes: 0
Reputation: 70949
The technique of moving code without altering the behavior of the code is called Refactoring
and is nicely covered in a book by Martin Fowler.
In your case, I would take the following multi-step approach:
It is strongly suggested that you write a set of tests to validate some, if not most, of the overall functionality of this block first. Then, after each change run your tests to verify that you didn't change behavior.
What you are seeing now is a change in behavior which came about by modifying the text of the code in such a manner that it did change behavior. The set of safe transformations of source code is likely smaller than you previously believed, or maybe you just made a simple error. However, the work you are attempting requires more knowledge than can be expressed in a StackOverflow style, question / answer, format. That's why I made the book reference.
If you can narrow the scope, you might get a better response in a future resubmission.
Upvotes: 0