Как получить фактический тип типизированного члена класса с Clang? - PullRequest
2 голосов
/ 27 июня 2019

Например, у меня есть следующий класс:

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

private:
    T bar_;
};

Он создается как:

Foo<Bar> foo;

Я извлекаю clang::CXXRecordDecl узел class Foo и перебираю его поля:

for (const clang::FieldDecl *fieldDecl: fooRecordDecl->fields()) {
    // fieldDecl->getType() gives T
    // fieldDecl->getNameAsString() gives bar_
}

Я хочу что-то, что делает fieldDecl->getInstantiatedType(), что дает Bar

Я понимаю, что AST для CXXRecordDecl из Foo не должен содержать никакой информации об экземпляре типа. Мне было интересно, была ли эта информация о связях храниться где-то еще в AST, и как мне ее получить.


Мое текущее решение включает в себя приведение неинициализированных параметров шаблона в порядок, скажем, {A, B, C} для template<typename A, typename B, typename C> class Baz {}; и сохранение их в std::vector. Затем найдите вызов экземпляра Baz<Foo, Bar, Baz> и сохраните экземпляры типов по порядку в другом std::vector и свяжите их вместе по индексу, чтобы получить:

{ A: Foo, B: Bar, C: Baz}

Это кажется очень запутанным и "не-лязгом".

1 Ответ

2 голосов
/ 27 июня 2019

Это действительно "не-лязг". Clang обычно хранит все экземпляры отдельно, и важно найти правильное объявление класса. В вашем случае, я полагаю, вы совершили неправильный поворот где-то в части «Я извлекаю clang::CXXRecordDecl ...».

Я поставил небольшое решение для посетителей, оно немного вежливое, но его легко адаптировать под ваши нужды:

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;
}

Для следующего фрагмента:

// test.cpp
class Bar {};

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

private:
  T bar_;
};

int main() { Foo<Bar> foo; }

это производит этот вывод:

SubstTemplateTypeParmType 0x7ffbed0183b0 'class Bar' sugar
|-TemplateTypeParmType 0x7ffbed017900 'T' dependent depth 0 index 0
| `-TemplateTypeParm 0x7ffbed017890 'T'
`-RecordType 0x7ffbed017750 'class Bar'
  `-CXXRecord 0x7ffbed0176b0 'Bar'

Как видите, у него есть подслащенная версия T, которая содержит ссылку на Bar.

Надеюсь, это то, что вы ищете. Счастливого взлома с Clang!

...