【问题标题】:JavaParser- Removing an operator from the expression at the AST level. How to replace a parent node with its child?JavaParser - 从 AST 级别的表达式中删除运算符。如何用子节点替换父节点?
【发布时间】:2021-08-21 19:53:45
【问题描述】:

我正在做一些抽象语法树级别的突变测试工作。 到目前为止,我已经处理了运算符替换突变,使用 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) -> 用它的一个子节点(a==2 或 b==2)替换父节点(a==2 和 b==2)-> 这不会出错,但父节点不会改变。为什么?
  • childNode.setParentNode(childNode) -> 没有例外,但父母也没有改变
  • BinaryExpr.replace(leftChild, rightChild) --> 这一个是唯一一个真正起作用的并且改变了父节点,但显然操作员还在。

任何人都可以提出解决此问题的方法吗?我希望能够从表达式中删除运算符,但我不知道该怎么做。

这也是我在 StackOverflow 上提出的第一个问题,如果有点乱,请见谅。

谢谢!

【问题讨论】:

  • "我想在突变后得到的表达式是 a==2 b==2" 但根据 Java 的语法,这不是一个表达式。它甚至在语法上都不是有效的。与其说你想要什么表达式,你能描述一下你想要得到的 AST 吗?
  • 刚刚编辑,谢谢!
  • 哦,我明白了。所以你想把a==2 & b==2 变成a==2b==2
  • 是的。最明显的做法是childNode.replace(parentNode)childNode.setParentNode(childNode),但这似乎不起作用。
  • 我建议您将您使用的代码添加到您的问题中。

标签: java operators abstract-syntax-tree mutation javaparser


【解决方案1】:

根据ModifierVisitordocumentation

当某些特定节点需要更改时,此访问者可用于节省时间。为此,只需扩展此类并覆盖需要更改的节点的方法,返回已更改的节点。返回 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"));

【讨论】:

  • 这成功了,谢谢你的帮助!我的错误是(如您所料)我没有返回新代码。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-06-26
  • 1970-01-01
  • 2013-02-04
  • 2018-07-18
  • 2021-05-30
相关资源
最近更新 更多