【发布时间】:2019-06-05 10:30:13
【问题描述】:
我正在使用RecursiveASTVisitor 来捕获变量声明。对于如下模板,如何使用 clang 工具获取每个参数在源代码中的位置?
TMyTemplate<t1, t2> foo;
尝试1:创建VisitVarDecl访问者
使用这种方法,我能够识别变量是否是模板并将类型设为clang::TemplateSpecializationType。它允许我使用 getArg 迭代参数,但是返回类型 (TemplateArgument) 没有实现 getLocation。
virtual bool VisitVarDecl(VarDecl *var) {
const TemplateSpecializationType *ts = var->getType()->getAs<TemplateSpecializationType>();
if( ts != nullptr ) {
for(uint32_t i=0; i< ts->getNumArgs(); i++) {
TemplateArgument arg = ts->getArg(i);
// I want to get arg.getLocation() - but no getLocation in TemplateArgument.
}
}
}
我尝试将类型 TemplateArgument 转换为 TemplateArgumentLoc,但任何方法都会导致我进入一个虚拟位置(即:总是返回第 1 行和第 1 列,甚至是段错误)。
尝试2:使用VisitVarTemplateSpecializationDecl访问者
在 Clang 中,VarTemplateSpecializationDecl 类型允许我将模板参数获取为 clang::TemplateArgumentListInfo。这种类型似乎更方便,因为我们可以通过函数getArgumentArray 得到TemplateArgumentLoc。
问题在于模板声明不会触发此访问者。我不太明白原因。
尝试 3: 将 VarDecl 设为 TemplateSpecializationTypeLoc
我也尝试将VarDecl 设为TemplateSpecializationTypeLoc,但失败了。
TemplateSpecializationTypeLoc loc = var->getTypeSourceInfo()->getTypeLoc().getAs<TemplateSpecializationTypeLoc>();
快速参考
- 我正在使用来自blog 的参考代码,这里是full code。
- clang::VarTemplateSpecializationDecl
- clang::TemplateArgumentListInfo
- clang::TemplateArgumentLoc
- clang::TemplateArgument
- clang::TemplateSpecializationType
麻烦的测试用例
Valeriy 提供的解决方案几乎可以完美运行。他的解决方案可以捕获变量声明 TemplateType<ABC, XYZ> Decl; 的位置,但如果我明确命名空间:FOO::TemplateType<ABC, XYZ> Decl;,它将失败。
这是一个简单的测试用例。变量 Decl 在他的解决方案中找到,但 Decl2 不是。演员 auto Specialization = DeclarationTypeLoc.getAs<clang::TemplateSpecializationTypeLoc>() 因某种原因失败(返回 nullptr)。
namespace FOO {
class ABC {};
class XYZ {};
template <class T, class U> class TemplateType {};
}
using namespace FOO;
int main() {
TemplateType<ABC, XYZ> Decl;
FOO::TemplateType<ABC, XYZ> Decl2;
return 0;
}
【问题讨论】: