Search code examples
c++clangc++17abstract-syntax-treelibtooling

How do you obtain the instantiated CXXRecordDecl of a templated class in Clang?


For example, I have a class:

template<typename T>
class Foo {
public:
    T getBar();

private:
    T bar_;
};

It is instantiated with:

using FooBarT = Foo<Bar>;

How do I get the CXXRecordDecl with resolved fields and methods for Foo<bar>?


I tried:

const auto *typeAliasDecl = llvm::dyn_cast<clang::TypeAliasDecl>(decl);
typeAliasDecl->getUnderlyingType()->getAsCXXRecordDecl()->dump();

The output I get is:

ClassTemplateSpecializationDecl 0x0000000 class Foo
`-TemplateArgument type 'Bar'

However, I want the CXXRecordDecl with the fields and methods too so I can iterate through them. I've also tried:

for (const auto *contextDecl: typeAliasDecl->getUnderlyingType()->getUnqualifiedDesugaredType()->getAsCXXRecordDecl()->getDeclContext()->decls()) {
    const auto *classTemplateDecl = llvm::dyn_cast<clang::ClassTemplateDecl>(contextDecl);
    classTemplateDecl->dump();
}

The output:

ClassTemplateDecl Foo
|-TemplateTypeParmDecl 0x0000000 referenced typename depth 0 index 0 T
|-CXXRecordDecl class Foo definition
| ... 
| |-FieldDecl 0x0000000 referenced bar_ 'T'
|-ClassTemplateSpecializationDecl 0x0000000 class Foo
  `-TemplateArgument type 'Bar'

As you can see the CXXRecordDecl class Foo definition has access to the FieldDecl, but doesn't know about the type instantiation of bar_, while the ClassTemplateSpecializationDecl does.

I want the CXXRecordDecl with the instantiated type for FieldDecl bar_


Solution

  • FYI the CXXRecordDecl you wanted is just the ClassTemplateSpecializationDecl in the AST, since ClassTemplateSpecializationDecl is a subclass of CXXRecordDecl. The real thing you want is not the CXXRecordDecl which you already have, but is the FieldDecl in that CXXRecordDecl.

    The reason that you don't have FieldDecl under the ClassTemplateSpecializationDecl is that your template instantiation code doesn't use bar_. Try the bellow source:

    template<typename T>
    class Foo {
    public:
        T getBar() { return bar_; };
    
    private:
        T bar_;
    };
    using FooBarT = Foo<int>;
    void func() {
        FooBarT().getBar();
    }
    

    Then FieldDecl will be under ClassTemplateSpecializationDecl :

    | `-ClassTemplateSpecializationDecl 0x1fe7f2a9d80 <line:2:1, line:9:1> line:3:7 class Foo definition
    ...
    |   |-FieldDecl 0x1fe7f2aa3c8 <line:8:2, col:4> col:4 referenced bar_ 'int':'int'