如何克隆或创建 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 new 和 delete 运算符是有意隐藏的,因此您不能使用它们来实例化堆上的对象。相反,您必须使用 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);
我想通过 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 new 和 delete 运算符是有意隐藏的,因此您不能使用它们来实例化堆上的对象。相反,您必须使用 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);