如何克隆或创建 clang 的 AST Stmt 节点?

How to clone or create an AST Stmt node of clang?

我想通过 clang LibTooling 修改 AST。如何克隆 AST 节点或添加新节点,例如我想用 ADD opcode

创建一个 BinaryOperator

在 Clang 中创建新的 AST 节点非常麻烦,不推荐使用 libTooling。相反,您应该 "read" AST 并返回代码或代码更改(重写、替换等)。

请参阅 this article 和从中链接的其他文章(和代码示例),了解有关正确执行此操作的更多信息。

一些 clang 的 AST 节点(classes)有一个静态的 Create 方法用于分配一个该节点的实例,其内存由传递给它的 ASTContext 实例管理。对于这些 classes,您可以使用此方法进行实例化。例如检查 clang::DeclRefExpr class。

其他 classes 缺少此方法,但具有 public 构造函数,您可以使用它来实例化对象。但是,vanilla newdelete 运算符是有意隐藏的,因此您不能使用它们来实例化堆上的对象。相反,您必须使用 placement new/delete 运算符提供 ASTContext 实例作为参数。

就个人而言,我更喜欢使用 ASTContext 实例分配所有与 clang 相关的对象,并让它在内部管理内存,这样我就不必费心了(当 ASTContext 实例被销毁时,所有内存都会被释放)。

这是一个简单的class,它使用放置新运算符和 ASTContext 实例为 clang 对象分配内存:

#ifndef CLANG_ALLOCATOR_H
#define CLANG_ALLOCATOR_H

#include <clang/AST/ASTContext.h>

/// Allocator that relies on clang's AST context for actual memory
/// allocation. Any class that wishes to allocated an AST node may
/// create an instance of this class for that purpose
class ClangAllocator
{
public:

    explicit ClangAllocator(clang::ASTContext& ast_context)
        : m_ast_context(ast_context)
    {
    }

    template<class ClassType, class ... Args>
    inline ClassType* Alloc(Args&& ... args)
    {
        return new (m_ast_context) ClassType(std::forward<Args&&>(args)...);
    }

private:

    clang::ASTContext& m_ast_context;
};

#endif /// CLANG_ALLOCATOR_H

关于 AST 修改,实现此目的的最佳方法可能是继承 TreeTransform class 并覆盖其Rebuild 调用这些方法来为各种 AST 节点生成新语句。

如果您只需要用另一个 AST 节点替换一个 AST 节点,实现这一点的非常简单的方法是找到它的直接父语句,然后在它的子节点上使用 std::replace。例如:

/// immediate_parent is immediate parent of the old_stmt
std::replace(
    immediate_parent->child_begin()
    , immediate_parent->child_end()
    , old_stmt
    , new_stmt);