Warm tip: This article is reproduced from stackoverflow.com, please click
abstract-syntax-tree c++ c++17 clang libtooling

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

发布于 2020-03-27 10:19:03

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_

Questioner
Eric
Viewed
150
jw_ 2019-12-31 10:54

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'