基于Clang libTooling编写AST匹配器的技术问题咨询
Clang libTooling插桩工具开发问题解决方案
问题1:定位函数内最后一个未初始化局部变量的后续位置插入代码
当前实现直接在函数左大括号后插入代码,需调整为找到函数内最后一个未初始化局部变量的结束位置后插入。
实现步骤
- 编写AST匹配器,定位函数作用域内的未初始化局部变量;
- 获取该变量声明的结束位置,在其后插入目标插桩代码;
- 若函数内无未初始化局部变量,可保留原函数开头插入逻辑作为降级方案。
代码修改
新增处理类并注册匹配器:
// 新增处理最后一个未初始化局部变量的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直接覆盖原有表达式导致内容丢失,需先提取原始表达式文本再包裹目标函数。
实现步骤
- 通过
SwitchStmt的getCond()获取条件表达式节点; - 使用
Lexer工具提取表达式的原始源代码文本; - 将文本包裹进目标函数后执行替换,该逻辑可直接复用至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
相关产品推荐
相关产品推荐

