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

基于Clang libTooling编写AST匹配器的技术问题咨询

Clang libTooling插桩工具开发问题解决方案

问题1:定位函数内最后一个未初始化局部变量的后续位置插入代码

当前实现直接在函数左大括号后插入代码,需调整为找到函数内最后一个未初始化局部变量的结束位置后插入。

实现步骤

  1. 编写AST匹配器,定位函数作用域内的未初始化局部变量;
  2. 获取该变量声明的结束位置,在其后插入目标插桩代码;
  3. 若函数内无未初始化局部变量,可保留原函数开头插入逻辑作为降级方案。

代码修改

新增处理类并注册匹配器:

// 新增处理最后一个未初始化局部变量的Handler
class LastUninitLocalHandler : public MatchFinder::MatchCallback {
public:
    explicit LastUninitLocalHandler(Rewriter& rewriter) : mRewriter(rewriter) {}

    void run(const MatchFinder::MatchResult& result) override {
        const auto var = result.Nodes.getNodeAs<VarDecl>("lastUninitLocal");
        if (!var) return;

        // 获取变量声明的结束位置,在其后插入代码
        SourceLocation endLoc = var->getEndLoc();
        mRewriter.InsertText(endLoc, "\n\t_sp(_co(0, 0, 0), 0);\n", true, true);
    }
private:
    Rewriter& mRewriter;
};

// 在MyASTConsumer中添加成员与匹配器注册
class MyASTConsumer : public ASTConsumer {
public:
    MyASTConsumer(Rewriter& r)
    : mEntryHandler(r)
    , mIfHandler(r)
    , mElseIfHandler(r)
    , mSwitchHandler(r)
    , mReturnHandler(r)
    , mLastUninitLocalHandler(r) { // 新增成员初始化
        // ... 原有匹配器 ...
        // 新增匹配器:定位函数内未初始化的局部变量
        mMatcher.addMatcher(varDecl(
            isLocalVarDecl(),
            hasParent(compoundStmt(hasParent(functionDecl()))),
            hasNoInitializer()
        ).bind("lastUninitLocal"), &mLastUninitLocalHandler);
    }
private:
    // ... 原有成员 ...
    LastUninitLocalHandler mLastUninitLocalHandler; // 新增成员
    MatchFinder mMatcher;
};

问题2:替换switch(expr)的expr为foo(expr)并保留原有文本

当前ReplaceText直接覆盖原有表达式导致内容丢失,需先提取原始表达式文本再包裹目标函数。

实现步骤

  1. 通过SwitchStmt的getCond()获取条件表达式节点;
  2. 使用Lexer工具提取表达式的原始源代码文本;
  3. 将文本包裹进目标函数后执行替换,该逻辑可直接复用至if语句处理。

代码修改

修改SwitchStmtHandler的run方法(需添加头文件#include <clang/Lex/Lexer.h>):

void run(const MatchFinder::MatchResult& result) override {
    const auto switchStmt = result.Nodes.getNodeAs<clang::SwitchStmt>("switchStmt");
    if (!switchStmt) return;

    Expr* condExpr = switchStmt->getCond();
    if (!condExpr) return;

    // 获取条件表达式的源码范围与原始文本
    CharSourceRange condRange = CharSourceRange::getTokenRange(condExpr->getSourceRange());
    StringRef condText = Lexer::getSourceText(
        condRange,
        *result.SourceManager,
        result.Context->getLangOpts()
    );

    // 替换为foo(原有表达式)
    mRewriter.ReplaceText(condRange, ("foo(" + condText.str() + ")").str());
}

复用至IfStmtHandler的修改示例:

void run(const MatchFinder::MatchResult& result) override {
    const auto ifStmt = result.Nodes.getNodeAs<IfStmt>("ifStmt");
    if (!ifStmt || !ifStmt->getCond()) return;

    Expr* condExpr = ifStmt->getCond();
    CharSourceRange condRange = CharSourceRange::getTokenRange(condExpr->getSourceRange());
    StringRef condText = Lexer::getSourceText(
        condRange,
        *result.SourceManager,
        result.Context->getLangOpts()
    );

    // 替换为插桩逻辑,保留原有条件
    mRewriter.ReplaceText(condRange, ("_sp(_co(" + condText.str() + ", 0, probeNum), probeNum)").str());
}

内容的提问来源于stack exchange,提问作者johnco3

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 09:04:50