如何使用Clang AST库获取显式模板实例化的完整SourceRange
实现方法
你可以通过遍历词法Token的方式补全整条显式实例化语句的范围,具体步骤如下:
- 基于已拿到的实例化点位置(即
foo标识符起始位置),反向遍历当前文件的Token,找到最近的template关键字起始位置作为范围起点 - 正向遍历Token找到最近的分号结束位置作为范围终点
- 组合两个位置得到完整的
SourceRange
示例实现代码
#include "clang/Lex/Lexer.h" // 已有上下文变量 clang::FunctionDecl* FS; clang::ASTContext& Ctx = FS->getASTContext(); const clang::SourceManager& SM = Ctx.getSourceManager(); const clang::LangOptions& LO = Ctx.getLangOpts(); if(const clang::FunctionTemplateSpecializationInfo* TSI = FS->getTemplateSpecializationInfo()) { // 过滤非显式实例化的场景 auto SpecKind = TSI->getTemplateSpecializationKind(); if (SpecKind != clang::TSK_ExplicitInstantiationDeclaration && SpecKind != clang::TSK_ExplicitInstantiationDefinition) { return; } clang::SourceLocation InstPoint = TSI->getPointOfInstantiation(); if (InstPoint.isInvalid() || InstPoint.isMacroID()) { // 宏展开场景可额外调用getExpansionLoc/getSpellingLoc处理,此处省略 return; } // 反向查找template关键字,确定起始位置 clang::SourceLocation StartLoc; clang::SourceLocation CurLoc = InstPoint; while (CurLoc.isValid() && SM.isInSameFile(CurLoc, InstPoint)) { clang::Token Tok; if (clang::Lexer::getRawToken(CurLoc.getLocWithOffset(-1), Tok, SM, LO)) { break; } if (Tok.is(clang::tok::kw_template)) { StartLoc = Tok.getLocation(); break; } CurLoc = Tok.getLocation(); } // 正向查找分号,确定结束位置 clang::SourceLocation EndLoc; CurLoc = InstPoint; while (CurLoc.isValid() && SM.isInSameFile(CurLoc, InstPoint)) { clang::Token Tok; if (clang::Lexer::getRawToken(CurLoc, Tok, SM, LO)) { break; } if (Tok.is(clang::tok::semi)) { EndLoc = Tok.getEndLoc(); break; } CurLoc = Tok.getEndLoc(); } if (StartLoc.isValid() && EndLoc.isValid()) { clang::SourceRange FullInstRange(StartLoc, EndLoc); // FullInstRange即为整条显式实例化语句的完整范围 } }
可选简化方案
如果可以调整AST匹配逻辑,直接用Matcher匹配显式实例化节点即可直接拿到范围,匹配器写法如下:
auto explicitInstMatcher = functionTemplateSpecializationDecl( isExplicitInstantiation(), hasName("foo"), hasTemplateArgument(0, refersToType(asString("double"))) ).bind("explicit_inst");
匹配到的FunctionTemplateSpecializationDecl节点直接调用getSourceRange()即可得到对应范围,仅需在少数边界场景下补充Token遍历逻辑修正范围即可。
内容的提问来源于stack exchange,提问作者mpeschke
相关产品推荐
相关产品推荐

