clang::astconsumer 是 libtooling 的入口钩子,所有 ast 遍历逻辑由此启动;不重写 handletranslationunit 则代码静默跳过,不报错也无日志。

clang::ASTConsumer 干什么用,不实现它会怎样
它是 LibTooling 的入口钩子,所有 AST 遍历逻辑都从这里开始。没重写 HandleTranslationUnit,你的代码就完全不会触发——不是报错,而是静默跳过,连日志都不会打。
- 必须继承
clang::ASTConsumer,不能只声明一个空类 -
HandleTranslationUnit接收的是整个翻译单元的clang::ASTContext*,别试图在这里直接访问Decl或Stmt,它们还没构建完 - 常见错误:在构造函数里就 new 一个
RecursiveASTVisitor,但没把它和ASTContext绑定,导致 visitor 无法访问符号表或类型信息
RecursiveASTVisitor 派生类里 visitXXX 函数不被调用的原因
不是函数名写错了(比如写成 VisitFunctionDecl 而不是 VisitFunctionDecl),而是默认 visitor 不递归进入模板实例化、隐式生成代码、或未解析的依赖头文件中 —— 它只处理当前 TU 已完成语义分析的部分。
- 确保在 visitor 构造时传入了有效的
ASTContext*,否则getASTContext()返回 null,后续getTypeAsString()等调用会崩 - 想检查模板特化?得重载
TraverseTemplateInstantiations并返回 true;想进系统头?启动时加-ferror-limit=0 -isystem /usr/include/c++/11,但注意 clang 默认跳过系统头里的 AST - 调试技巧:在
VisitFunctionDecl开头加if (!D || !D->hasBody()) return true;,避免空指针或未定义行为
ClangTool.run() 卡住或不输出结果的典型配置问题
根本原因往往是编译数据库(compile_commands.json)路径不对,或者命令行参数没传给 ClangTool 实例,导致它用空参数去 parse 文件,直接 fallback 到预设的 minimal config,然后静默失败。
- 必须用
clang::tooling::CompilationDatabase::loadFromDirectory加载数据库,不能手动生成std::vector<compilecommand></compilecommand>后硬塞 - 调用
ClangTool.run()前,确认ClangTool构造时传入的ClangTool(Options, CompilationDatabase)中Options是有效指针(比如来自CommonOptionsParser) - 如果只分析单个文件且无数据库,用
clang::tooling::FixedCompilationDatabase::loadFromCommandLine,参数数组里至少包含"-x","c++","-std=c++17",否则 clang 认不出源码语言
拿到 Decl* 后怎么安全取函数名和参数类型
直接调 D->getNameAsString() 对模板函数或运算符重载会返回空字符串;直接 cast QualType 到 Type* 可能崩溃,因为有些类型是 TypedefType 或 ElaboratedType,需要先 getCanonicalType()。
- 函数名推荐用
D->getAsFunction()->getNameInfo().getAsString(),比getNameAsString()更稳 - 参数类型循环里别直接
Param->getType().getAsString(),先Param->getType().getCanonicalType().getAsString(),否则可能看到const std::string &这种带空格的字符串,后续匹配容易出错 - 获取返回类型?用
cast<functiondecl>(D)->getReturnType().getCanonicalType()</functiondecl>,别漏掉getCanonicalType(),不然模板别名(如using size_type = std::size_t;)会显示为原始别名而非底层类型
最麻烦的其实是跨文件符号解析——ASTContext 默认不加载其他 TU 的 AST,所以 findExplicitClassDefinition 类方法基本无效;真要查外部定义,得自己缓存 Decl* 和 SourceLocation,再靠 SourceManager 手动定位,这部分没标准 API,容易漏边界。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











