JavaParser—在AST级别从表达式中删除操作符.如何用子节点替换父节点?



我正在做一些在抽象语法树级别的突变测试工作。到目前为止,我已经处理了Operator Replacement突变,使用JavaParser库(https://github.com/javaparser/javaparser)很容易实现。下面是简单的示例代码,我将其解析为AST并尝试对其执行更改。我知道if语句没有意义,但它不是这里的重点:

公共类示例{

public static void main(String[] args) {
int a=2;
int b=3;
if (a==2 & b==2)
doSomething();
}

}

我的程序将我拥有的java代码(在本例中为Example.java)解析为CompilationUnit形式的AST。然后遍历CompilationUnit查找特定表达式,例如二进制表达式BinaryExpr。找到它后,我尝试从该表达式中删除二进制操作符BinaryExpr.Operator.<Operator>。当删除二进制操作符时,必须同时删除操作数,以使表达式保持可编译性。因此,从上述a==2 & b==2表达式中删除二进制操作符将导致两个突变:

  1. a==2
  2. b==2

因此,似乎我必须用其中一个子节点替换父节点。

然而,我现在正在努力与这部分,我不知道如何实现。到目前为止,我已经尝试了以下操作:

  • childNode.replace(parentNode)->替换parentNode (a==2 &B ==2)及其子节点之一(a==2或B ==2) ->这不会产生错误,但是父节点没有改变。为什么?
  • childNode.setParentNode(childNode)->没有例外,但是父节点不改变
  • BinaryExpr.replace(leftChild, rightChild)—>这是唯一一个实际工作并改变父节点的,但显然操作符仍然在那里。

谁能提出解决这个问题的办法?我希望能够从表达式中删除操作符,但我不确定如何做到这一点。

这也是我在StackOverflow上问的第一个问题,所以如果它有点乱的话,我很抱歉。

谢谢!

根据ModifierVisitor的文档:

此访问器可用于在需要更改某些特定节点时节省时间。要做到这一点,只需扩展该类并覆盖需要更改的节点的方法,返回更改后的节点。返回null将删除该节点。

在您的示例中,如果找到了应该替换的节点,则"更改节点";将是左/右节点,因此您应该相应地返回它们。

n.replace(leftChild)工作正常。您只需要返回该位置上的新节点,您可能没有这样做。

下面是一个例子:

SourceRoot sourceRoot = new SourceRoot(Paths.get("Foo.java"));
CompilationUnit cu = sourceRoot.parse("", "Foo.java");
cu.accept(new ModifierVisitor<Void>() {
@Override
public Visitable visit(BinaryExpr n, Void arg) {
if (n.getOperator() == Operator.BINARY_AND) {
n.replace(n.getLeft());
return n.getLeft(); // note this line!
}
return super.visit(n, arg);
}
}, null);
sourceRoot.saveAll(Paths.get("Foo.java"));

最新更新