For example, I have the following class:
template<typename T>
class Foo {
public:
T getBar();
private:
T bar_;
};
It is instantiated as:
Foo<Bar> foo;
I extract the clang::CXXRecordDecl
node of class Foo
, and iterate through its fields:
for (const clang::FieldDecl *fieldDecl: fooRecordDecl->fields()) {
// fieldDecl->getType() gives T
// fieldDecl->getNameAsString() gives bar_
}
I want something that does fieldDecl->getInstantiatedType()
that gives Bar
I understand that the AST for the CXXRecordDecl
of Foo
shouldn't contain any information on the instantiated type. I was wondering if this linking information was stored somewhere else in the AST, and how I could retrieve it.
My current solution involves getting uninitialized template parameters in order, say {A, B, C}
for template<typename A, typename B, typename C> class Baz {};
and storing them in an std::vector
. Then finding the instantiation call Baz<Foo, Bar, Baz>
, and store the instantiated types in order in another std::vector
, and link them together by index to get:
{ A: Foo, B: Bar, C: Baz}
This seems very convoluted and "un-Clang" like.
It is an "un-Clang" way indeed. Clang usually stores all instantiations separately and it is important to get to the right class declaration. In your case, I guess you took a wrong turn somewhere in the "I extract clang::CXXRecordDecl
..." part.
I put a small visitor solution, it is a bit campy, but it's easy to adapt it for your needs:
bool VisitVarDecl(VarDecl *VD) {
// VD->getType() dump would look like smth like this:
//
// > TemplateSpecializationType 0x7ffbed018180 'Foo<class Bar>' sugar Foo
// > |-TemplateArgument type 'class Bar'
// > `-RecordType 0x7ffbed018160 'class Foo<class Bar>'
// > `-ClassTemplateSpecialization 0x7ffbed018078 'Foo'
//
// The following code unwraps types to get to that ClassTemplateSpecialization
auto SpecializationDecl = VD->getType()
->getAs<TemplateSpecializationType>()
->desugar()
->getAs<RecordType>()
->getDecl();
// these fields will have specialized types
for (const auto *Field : SpecializationDecl->fields()) {
Field->getType().dump();
}
return true;
}
For the following snippet:
// test.cpp
class Bar {};
template <typename T> class Foo {
public:
T getBar();
private:
T bar_;
};
int main() { Foo<Bar> foo; }
it produces this ouput:
SubstTemplateTypeParmType 0x7ffbed0183b0 'class Bar' sugar
|-TemplateTypeParmType 0x7ffbed017900 'T' dependent depth 0 index 0
| `-TemplateTypeParm 0x7ffbed017890 'T'
`-RecordType 0x7ffbed017750 'class Bar'
`-CXXRecord 0x7ffbed0176b0 'Bar'
As you can see, it has a sugared version of T
that contains a reference to Bar
.
I hope this is what you are looking for. Happy hacking with Clang!