3

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_

Eric
  • 730
  • 4
  • 16
  • Hi, `ClassTemplateDecl` is the wrong one, but in the printout you can see that it has a reference to `ClassTemplateSpecializationDecl`, that's what you need. Just look through the methods of `ClassTemplateDecl` or even check how the printer works to see which getter to use. – Valeriy Savchenko Jun 28 '19 at 21:00
  • @ValeriySavchenko Hi, I'm able to get the `ClassTemplateSpecializationDecl`, but it doesn't contain any `FieldDecl`s. – Eric Jun 28 '19 at 21:29

2 Answers2

2

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'
jw_
  • 1,663
  • 18
  • 32
  • Yeah, we found out that Clang seems to be a lazy compiler, meaning it won’t instantiate types in the AST unless needed. – Eric Jan 01 '20 at 04:27
1

This worked for me:

  1. cast ClassTemplateSpecializationDecl to DeclContext,
  2. iterate over stored declarations with DeclContext::decls(),
  3. dyn_cast iterated Decls to FieldDecl and getType() - this will be an instantiated type of a member variable.
  4. dyn_cast to CXXMethodDecl for member functions and continue similarly - I haven't got to trying it for myself.

All this I learned by stepping through and studying how ASTDumper works.

Victor K
  • 529
  • 2
  • 16
  • When you mean cast `ClassTemplateSpecializationDecl` to `DeclContext`, do you mean `->getDeclContext()`? – Eric Jul 03 '19 at 14:54
  • It's not working. It gives a SIGSEGV. I dumped the `DeclContext` of the the `ClassTemplateSpecializationDecl`, and nothing is instantiated neither, so I don't see how iterating through the `decls()` would suddenly get that info. – Eric Jul 03 '19 at 15:02
  • I meant `llvm::dyn_cast(classTemplateSpecialization)` – Victor K Jul 03 '19 at 15:06
  • The difference may be that just right now I'm trying to solve a similar, but not exactly the same problem: I've got `class FooBar : public Foo`, not `using FooBarT = Foo`, but `ClassTemplateSpecializationDecl` I've got is also of `Foo` instantiation, so I hoped it would work in your case too. – Victor K Jul 03 '19 at 15:11
  • Ah thanks for trying. I guess the type aliasing is the limit here. I wonder what happens if you write a template metaprogram to compute factorials. Will the AST contain all the instantiated classes or will they be generated later? – Eric Jul 03 '19 at 15:25