JavaParser- 从 AST 级别的表达式中删除运算符。如何用 child 替换 parent 节点?
JavaParser- Removing an operator from the expression at the AST level. How to replace a parent node with its child?
我正在抽象语法树级别做一些变异测试的工作。
到目前为止,我已经处理了运算符替换突变,使用 JavaParser 库 (https://github.com/javaparser/javaparser) 可以很容易地实现这些突变。
下面是我解析为 AST 并尝试对其执行突变的简单示例代码。我知道 if 语句没有意义,但这不是重点:
public class 示例 {
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
表达式中删除二元运算符将导致两个突变体:
a==2
b==2
因此,我似乎必须将 parent 替换为 children.
之一
但是,我现在正在为这部分而苦苦挣扎,我不知道如何实现它。到目前为止,我已经尝试了以下方法:
childNode.replace(parentNode)
-> 将 parent 节点(a==2 和 b==2)替换为其 children 之一(a==2 或 b== 2) -> 这没有错误,但 parent 没有改变。为什么?
childNode.setParentNode(childNode)
-> 没有例外,但 parent 也没有改变
BinaryExpr.replace(leftChild, rightChild)
--> 这个是唯一一个实际工作并更改了 parent 节点的,但显然操作员仍然在那里。
任何人都可以提出解决此问题的方法吗?我希望能够从表达式中删除运算符,但我不确定该怎么做。
这也是我在 Whosebug 上提出的第一个问题,如果有点乱,请见谅。
谢谢!
根据ModifierVisitor
的documentation:
This visitor can be used to save time when some specific nodes needs to be changed. To do that just extend this class and override the methods from the nodes who needs to be changed, returning the changed node. Returning null will remove the node.
在您的情况下,如果找到应替换的节点,“已更改的节点”将是 left/right 节点,因此您应该相应地 return 那些节点。
n.replace(leftChild)
工作正常。您只需要 return 位于其位置的新节点,您可能没有这样做。
这是一个例子:
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"));
我正在抽象语法树级别做一些变异测试的工作。 到目前为止,我已经处理了运算符替换突变,使用 JavaParser 库 (https://github.com/javaparser/javaparser) 可以很容易地实现这些突变。 下面是我解析为 AST 并尝试对其执行突变的简单示例代码。我知道 if 语句没有意义,但这不是重点:
public class 示例 {
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
表达式中删除二元运算符将导致两个突变体:
a==2
b==2
因此,我似乎必须将 parent 替换为 children.
之一但是,我现在正在为这部分而苦苦挣扎,我不知道如何实现它。到目前为止,我已经尝试了以下方法:
childNode.replace(parentNode)
-> 将 parent 节点(a==2 和 b==2)替换为其 children 之一(a==2 或 b== 2) -> 这没有错误,但 parent 没有改变。为什么?childNode.setParentNode(childNode)
-> 没有例外,但 parent 也没有改变BinaryExpr.replace(leftChild, rightChild)
--> 这个是唯一一个实际工作并更改了 parent 节点的,但显然操作员仍然在那里。
任何人都可以提出解决此问题的方法吗?我希望能够从表达式中删除运算符,但我不确定该怎么做。
这也是我在 Whosebug 上提出的第一个问题,如果有点乱,请见谅。
谢谢!
根据ModifierVisitor
的documentation:
This visitor can be used to save time when some specific nodes needs to be changed. To do that just extend this class and override the methods from the nodes who needs to be changed, returning the changed node. Returning null will remove the node.
在您的情况下,如果找到应替换的节点,“已更改的节点”将是 left/right 节点,因此您应该相应地 return 那些节点。
n.replace(leftChild)
工作正常。您只需要 return 位于其位置的新节点,您可能没有这样做。
这是一个例子:
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"));