You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Clang AST库获取显式模板实例化的完整SourceRange

实现方法

你可以通过遍历词法Token的方式补全整条显式实例化语句的范围,具体步骤如下:

  1. 基于已拿到的实例化点位置(即foo标识符起始位置),反向遍历当前文件的Token,找到最近的template关键字起始位置作为范围起点
  2. 正向遍历Token找到最近的分号结束位置作为范围终点
  3. 组合两个位置得到完整的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 08:24:04