- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在使用 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
.这种类型似乎更方便,因为我们可以得到 TemplateArgumentLoc
使用函数 getArgumentArray
.
问题是模板声明不会触发此访问者。我不太明白原因。
尝试 3: 得到 VarDecl
作为TemplateSpecializationTypeLoc
我还尝试获取 VarDecl
作为TemplateSpecializationTypeLoc
但它失败了。
TemplateSpecializationTypeLoc loc = var->getTypeSourceInfo()->getTypeLoc().getAs<TemplateSpecializationTypeLoc>();
快速引用
麻烦的测试用例
Valeriy 提供的解决方案几乎可以完美运行。他的解决方案可以捕获变量声明的位置 TemplateType<ABC, XYZ> Decl;
但是如果我显式命名空间它会失败:FOO::TemplateType<ABC, XYZ> Decl;
.
这是一个简单的测试用例。变量 Decl
在他的解决方案中找到但是Decl2
不是。 Actor 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;
}
最佳答案
第一次尝试最接近您的需求。您要查找的节点是 VarDecl
并且它是类型位置。 VarTemplateSpecializationDecl
是一个变量模板 (C++14 feature) 特化。
Represents a variable template specialization, which refers to a variable template with a given set of template arguments.
Variable template specializations represent both explicit specializations of variable templates, as in the example below, and implicit instantiations of variable templates.
Clang 区分类型和类型位置。 Type更像是一个抽象的实体,而TypeLoc代表了一个类型在源代码中的实际入口。当您在代码中多次写入类型 A
时,它都是不同的 TypeLoc,但是相同的 Type。
这是一个如何为您的声明获取 TypeLoc 的示例:
bool VisitVarDecl(clang::VarDecl *Decl) {
auto DeclarationTypeLoc = Decl->getTypeSourceInfo()->getTypeLoc();
if (auto Specialization =
DeclarationTypeLoc.getAs<clang::TemplateSpecializationTypeLoc>()) {
for (auto i : llvm::seq<unsigned>(0, Specialization.getNumArgs())) {
auto ArgumentLoc = Specialization.getArgLoc(i);
auto &SM = Context.getSourceManager();
llvm::errs() << ArgumentLoc.getLocation().printToString(SM) << "\n";
}
}
return true;
}
在以下代码段上运行此代码
// main.cpp
template <class T, class U> class TemplateType {};
class ABC {};
class XYZ {};
int main() {
TemplateType<ABC, XYZ> Decl;
return 0;
}
产生这个结果:
.../main.cpp:9:16
.../main.cpp:9:21
注意 1:根据 Clang 的版本,您可能使用的不是 Decl->getTypeSourceInfo()->getTypeLoc()
,而是 Decl->getTypeLoc ()
。
注意 2:小提示 - 不要让访问者功能虚拟化。 Clang的访客是CRTP .
对于更新后的测试片段,声明的 TypeLoc 不完全是 TemplateSpecializationTypeLoc,而是它的包装器。手动获取它可能很麻烦且容易出错,因此最好根据 Clang 的遍历器来实现它。
这是更新后的代码(请注意,SpecificationArgumentVisitor 是主要访问者内部的嵌套类):
class SpecificationArgumentVisitor
: public clang::RecursiveASTVisitor<SpecificationArgumentVisitor> {
public:
SpecificationArgumentVisitor(clang::ASTContext &Context)
: SM(Context.getSourceManager()) {}
bool VisitTemplateSpecializationTypeLoc(
clang::TemplateSpecializationTypeLoc Specialization) {
for (auto i : llvm::seq<unsigned>(0, Specialization.getNumArgs())) {
auto ArgumentLoc = Specialization.getArgLoc(i);
llvm::errs() << ArgumentLoc.getLocation().printToString(SM) << "\n";
}
return true;
}
private:
SourceManager &SM;
};
bool VisitVarDecl(clang::VarDecl *Decl) {
SpecificationArgumentVisitor ArgumentVisitor(Context);
ArgumentVisitor.TraverseDecl(Decl);
return true;
}
对于新的测试片段:
// main.cpp
namespace FOO {
class ABC {};
class XYZ {};
template <class T, class U> class TemplateType {};
} // namespace FOO
using namespace FOO;
int main() {
TemplateType<ABC, XYZ> Decl;
FOO::TemplateType<ABC, XYZ> Decl2;
return 0;
}
它产生以下输出:
.../main.cpp:13:16
.../main.cpp:13:21
.../main.cpp:14:21
.../main.cpp:14:26
注意 3:它是一个嵌套的 RecursiveASTVisitor,因为在最初的问题中,您只想为变量声明中的类型遍历模板特化。如果您希望它适用于所有情况,只需使用此访问功能并且只有一个访问者。
希望这些信息对您有用。祝您使用 Clang 愉快!
关于c++ - ClangTool如何在变量声明中获取模板参数的位置?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56458731/
简而言之:我想从可变参数模板参数中提取各种选项,但不仅通过标签而且通过那些参数的索引,这些参数是未知的 标签。我喜欢 boost 中的方法(例如 heap 或 lockfree 策略),但想让它与 S
我可以对单元格中的 excel IF 语句提供一些帮助吗? 它在做什么? 对“BaselineAmount”进行了哪些评估? =IF(BaselineAmount, (Variance/Baselin
我正在使用以下方法: public async Task Save(Foo foo,out int param) { ....... MySqlParameter prmparamID
我正在使用 CodeGear RAD Studio IDE。 为了使用命令行参数测试我的应用程序,我多次使用了“运行 -> 参数”菜单中的“参数”字段。 但是每次我给它提供一个新值时,它都无法从“下拉
我已经为信用卡类编写了一些代码,粘贴在下面。我有一个接受上述变量的构造函数,并且正在研究一些方法将这些变量格式化为字符串,以便最终输出将类似于 号码:1234 5678 9012 3456 截止日期:
MySql IN 参数 - 在存储过程中使用时,VarChar IN 参数 val 是否需要单引号? 我已经像平常一样创建了经典 ASP 代码,但我没有更新该列。 我需要引用 VarChar 参数吗?
给出了下面的开始,但似乎不知道如何完成它。本质上,如果我调用 myTest([one, Two, Three], 2); 它应该返回元素 third。必须使用for循环来找到我的解决方案。 funct
将 1113355579999 作为参数传递时,该值在函数内部变为 959050335。 调用(main.c): printf("%d\n", FindCommonDigit(111335557999
这个问题在这里已经有了答案: Is Java "pass-by-reference" or "pass-by-value"? (92 个回答) 关闭9年前。 public class StackOve
我真的很困惑,当像 1 == scanf("%lg", &entry) 交换为 scanf("%lg", &entry) == 1 没有区别。我的实验书上说的是前者,而我觉得后者是可以理解的。 1 =
我正在尝试使用调用 SetupDiGetDeviceRegistryProperty 的函数使用德尔福 7。该调用来自示例函数 SetupEnumAvailableComPorts .它看起来像这样:
我需要在现有项目上实现一些事件的显示。我无法更改数据库结构。 在我的 Controller 中,我(从 ajax 请求)传递了一个时间戳,并且我需要显示之前的 8 个事件。因此,如果时间戳是(转换后)
rails 新手。按照多态关联的教程,我遇到了这个以在create 和destroy 中设置@client。 @client = Client.find(params[:client_id] || p
通过将 VM 参数设置为 -Xmx1024m,我能够通过 Eclipse 运行 Java 程序-Xms256M。现在我想通过 Windows 中的 .bat 文件运行相同的 Java 程序 (jar)
我有一个 Delphi DLL,它在被 Delphi 应用程序调用时工作并导出声明为的方法: Procedure ProduceOutput(request,inputs:widestring; va
浏览完文档和示例后,我还没有弄清楚 schema.yaml 文件中的参数到底用在哪里。 在此处使用 AWS 代码示例:https://github.com/aws-samples/aws-proton
程序参数: procedure get_user_profile ( i_attuid in ras_user.attuid%type, i_data_group in data_g
我有一个字符串作为参数传递给我的存储过程。 dim AgentString as String = " 'test1', 'test2', 'test3' " 我想在 IN 中使用该参数声明。 AND
这个问题已经有答案了: When should I use "this" in a class? (17 个回答) 已关闭 6 年前。 我运行了一些java代码,我看到了一些我不太明白的东西。为什么下
我输入 scroll(0,10,200,10);但是当它运行时,它会传递字符串“xxpos”或“yypos”,我确实在没有撇号的情况下尝试过,但它就是行不通。 scroll = function(xp
我是一名优秀的程序员,十分优秀!