【发布时间】:2015-05-26 06:54:59
【问题描述】:
我想通过 clang LibTooling 修改 AST。如何克隆 AST 节点或添加新节点,例如我想用 ADD 操作码创建一个BinaryOperator
【问题讨论】:
我想通过 clang LibTooling 修改 AST。如何克隆 AST 节点或添加新节点,例如我想用 ADD 操作码创建一个BinaryOperator
【问题讨论】:
clang 的一些 AST 节点(类)有一个静态的 Create 方法,用于分配该节点的实例,其内存由传递的 ASTContext 实例管理给它。对于这些类,您可以将此方法用于实例化目的。例如检查 clang::DeclRefExpr 类。
其他类没有这个方法,但有公共构造函数,你可以用来实例化对象。但是,普通的 new 和 delete 运算符是故意隐藏的,因此您不能使用它们来实例化堆上的对象。相反,您必须使用提供 ASTContext 实例作为参数的 placement new/delete 运算符。
就个人而言,我更喜欢使用 ASTContext 实例分配所有与 clang 相关的对象,并让它在内部管理内存,这样我就不必费心了(当 ASTContext 实例被销毁时,所有内存都会被释放)。
这是一个简单的类,它使用placement new 运算符和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 类并覆盖其 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 中创建新的 AST 节点非常麻烦,并且不推荐使用 libTooling。相反,您应该“阅读” AST 并返回代码或代码更改(重写、替换等)。
请参阅this article 和与其链接的其他文章(和代码示例),了解有关正确方法的更多信息。
【讨论】: