【问题标题】:How do you obtain the instantiated CXXRecordDecl of a templated class in Clang?如何在 Clang 中获取模板化类的实例化 CXXRecordDecl?
【发布时间】:2019-06-28 20:47:17
【问题描述】:

例如,我有一个班级:

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

private:
    T bar_;
};

实例化为:

using FooBarT = Foo<Bar>;

如何获得CXXRecordDecl 以及Foo&lt;bar&gt; 的解析字段和方法?


我试过了:

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

我得到的输出是:

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

但是,我也想要带有字段和方法的 CXXRecordDecl,以便我可以遍历它们。我也试过:

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

输出:

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'

如您所见,CXXRecordDecl class Foo definition 可以访问FieldDecl,但不知道bar_ 的类型实例化,而ClassTemplateSpecializationDecl 知道。

我想要CXXRecordDecl 的实例化类型为FieldDecl bar_

【问题讨论】:

  • 嗨,ClassTemplateDecl 是错误的,但在打印输出中您可以看到它引用了ClassTemplateSpecializationDecl,这就是您需要的。只需查看ClassTemplateDecl 的方法,甚至检查打印机的工作原理,看看使用哪个 getter。
  • @ValeriySavchenko 嗨,我可以得到ClassTemplateSpecializationDecl,但它不包含任何FieldDecls。

标签: c++ clang c++17 abstract-syntax-tree libtooling


【解决方案1】:

仅供参考,您想要的 CXXRecordDecl 只是 AST 中的 ClassTemplateSpecializationDecl,因为 ClassTemplateSpecializationDecl 是 CXXRecordDecl 的子类。你真正想要的不是你已经拥有的 CXXRecordDecl,而是那个 CXXRecordDecl 中的 FieldDecl。

ClassTemplateSpecializationDecl下没有FieldDecl的原因是你的模板实例化代码没有使用bar_。试试下面的来源:

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

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

然后 FieldDecl 将在 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'

【讨论】:

  • 是的,我们发现 Clang 似乎是一个惰性编译器,这意味着它不会在 AST 中实例化类型,除非需要。
【解决方案2】:

这对我有用:

  1. ClassTemplateSpecializationDecl 转换为DeclContext
  2. 使用DeclContext::decls() 遍历存储的声明,
  3. dyn_cast 迭代 Decls 到 FieldDeclgetType() - 这将是成员变量的实例化类型。
  4. dyn_castCXXMethodDecl 用于成员函数并以类似方式继续 - 我没有 必须自己尝试一下。

所有这些都是我通过逐步研究ASTDumper 的工作原理而学到的。

【讨论】:

  • 当您的意思是将ClassTemplateSpecializationDecl 转换为DeclContext 时,您的意思是-&gt;getDeclContext()
  • 它不工作。它给出了一个 SIGSEGV。我丢弃了ClassTemplateSpecializationDeclDeclContext,也没有实例化任何东西,所以我看不出迭代decls() 会如何突然获得该信息。
  • 我的意思是llvm::dyn_cast&lt;clang::DeclContext&gt;(classTemplateSpecialization)
  • 不同之处可能是我现在正在尝试解决一个类似但不完全相同的问题:我有class FooBar : public Foo&lt;Bar&gt;,不是using FooBarT = Foo&lt;Bar&gt;,而是ClassTemplateSpecializationDecl我've got 也是 Foo&lt;Bar&gt; 实例化,所以我希望它也适用于你的情况。
  • 谢谢你的尝试。我猜类型别名是这里的限制。我想知道如果你编写一个模板元程序来计算阶乘会发生什么。 AST 会包含所有实例化的类还是会在以后生成?
猜你喜欢
  • 2017-06-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多