0

所以我有一个方法

public modifiers Foo foo(Bar bar){
    blah;
    blah;
    veryInterestingStmt;
    moreBlah();
    return XYZ;
}

我现在想拆分此方法,将其主体中的所有内容提取到一个单独的方法中(以编程方式)。

IE

public modifiers Foo foo(Bar bar){
    return trulyFoo(bar);
}

public modifiers Foo trulyFoo(Bar bar){
    blah;
    blah;
    veryInterestingStmt;
    moreBlah();
    return XYZ;
}

不过,我该怎么做呢?

天真的

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}
        }
    }
}

不工作。如果我跑,说

DirectedGraph dg = new ExceptionalUnitGraph(auxMethod.getActiveBody());

我得到一个

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)
4

2 回答 2

0

似乎移动 stmts 是行不通的。相比之下,完全更换机身

        Body originalBody = sm.getActiveBody();
        originalBody.setMethod(auxMethod);
        auxMethod.setActiveBody(originalBody);
        Body newBody = Jimple.v().newBody(sm);
        sm.setActiveBody(newBody);

然后重新生成本地人、身份 stmts(以及您可能需要的其他 stmts),newBody看起来像是一个明智的选择。

于 2018-03-17T14:44:20.320 回答
0

在不改变代码行为的情况下移动代码的技术被称为Refactoring并在 Martin Fowler 的书中得到了很好的介绍。

在您的情况下,我将采取以下多步骤方法:

  1. 在您希望拆分的函数中,在您希望移动的代码行上方建立一个“什么都不做”函数。
  2. 将其中一两行代码从周围的函数中移到“什么都不做”函数中,拆分函数,但拆分是嵌套调用。
  3. 将分割函数向上(或向下)移动到环绕函数中块的边缘。
  4. 将 slpit 函数移出块,在每次调用原始函数之前或每次调用原始函数之后对其进行新调用。请注意,您可能需要重新处理返回参数的处理,具体取决于详细信息。

强烈建议您首先编写一组测试来验证该块的部分(如果不是大部分)整体功能。然后,在每次更改后运行您的测试以验证您没有更改行为。

您现在看到的是行为的变化,它是通过以确实改变行为的方式修改代码文本来实现的。源代码的安全转换集可能比您之前认为的要小,或者您可能只是犯了一个简单的错误。但是,您正在尝试的工作需要比 StackOverflow 样式、问题/答案、格式表达的更多的知识。这就是为什么我做这本书的参考。

如果您可以缩小范围,您可能会在以后的重新提交中得到更好的响应。

于 2018-03-17T13:36:03.840 回答