-->

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

2020-08-05 09:51发布

问题:

I want to modify the AST by clang LibTooling. How can I clone an AST node or add a new one, e.g. I'd like to create a BinaryOperator with ADD opcode

回答1:

Creating new AST nodes is quite cumbersome in Clang, and it's not the recommended way to use libTooling. Rather, you should "read" the AST and emit back code, or code changes (rewritings, replacements, etc).

See this article and other articles (and code samples) linked from it for more information on the right way to do this.



回答2:

Some of the clang's AST nodes (classes) have a static Create method that is used to allocate an instance of that node whose memory is managed by the ASTContext instance passed to it. For these classes you may use this method for instantiation purposes. Check clang::DeclRefExpr class for instance.

Other classes miss this method but have public constructor that you may be used to instantiate the object. However, the vanilla new and delete operators are purposely hidden so you cannot use them to instantiate the objects on the heap. Instead, you must use placement new/delete operators providing ASTContext instance as an argument.

Personally, I prefer to allocate all clang related objects using ASTContext instance and let it manage the memory internally so I don't have to bother with it (all memory will get released when ASTContext instance gets destroyed).

Here is a simple class that allocates the memory for the clang object using the placement new operator and ASTContext instance:

#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

Regarding the AST modifications, probably the best way to accomplish this is to inherit the TreeTransform class and override its Rebuild methods that are invoked to produce new statements for various AST nodes.

If all you require is to replace one AST node with another, very simple way to achieve this is to find its immediate parent statement and then use std::replace on its children. For example:

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


标签: clang llvm