clang-tidy 必须依赖 compile_commands.json 提供编译上下文(如头文件路径、宏定义、c++标准),否则会误报“未声明标识符”或模板解析失败;不配置则几乎无法正常工作。

clang-tidy 不会自动工作,不配 compile_commands.json 就基本等于没跑;它报的很多“未声明标识符”或“模板无法实例化”,根本不是代码问题,而是你没给它编译上下文。
为什么 clang-tidy 报一堆头文件找不到或模板解析失败
clang-tidy 本身不编译代码,但它必须模拟编译过程才能理解 #include、宏定义、std::vector<t></t> 的具体类型。它靠 compile_commands.json 获取每个源文件的真实编译参数(比如 -Iinclude -D_DEBUG -std=c++20)。没有这个文件,它就按默认系统头路径硬猜,99% 的项目都会崩。
- CMake 项目:配置时加
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON,例如cmake -B build -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_CXX_STANDARD=17 - 生成后,
compile_commands.json必须在build/目录下,运行时用-p build/显式指定 - 别在源码根目录直接执行
clang-tidy src/*.cpp—— 这样它根本读不到你的-I或-D - 非 CMake 项目可用
compdb -p . generate(配合 Ninja)或bear --make,但不如 CMake 原生导出稳定
怎么选检查项才不被 warning 刷屏又不漏真问题
开 -checks='*' 是最常见错误,它会把所有命名风格、注释格式、using namespace std; 全标红,反而掩盖 bugprone-use-after-move 这类真正危险的问题。
- 优先启用
bugprone-*和performance-*:它们对应真实 bug 或性能退化,比如bugprone-unused-return-value(漏检std::regex_match返回值)、performance-unnecessary-copy-initialization - 现代写法用
modernize-use-auto、modernize-use-nullptr,但先关掉modernize-loop-convert(它对 range-for 改写有时误判) - 禁用干扰项:如
-cppcoreguidelines-pro-type-vararg(C 风格可变参在某些 SDK 中无法避免)、-readability-magic-numbers(除非团队明确定义了 magic number 规则) - 推荐命令行起点:
clang-tidy -p build/ -checks='-*,bugprone-*,performance-*,modernize-use-auto,modernize-use-nullptr' src/*.cpp --
如何用 .clang-tidy 文件统一管理规则而不每次敲长命令
.clang-tidy 必须放在项目根目录(即 clang-tidy -p build/ 执行时能自动找到),且只在使用 -p 模式时生效;单独检查单个文件(如 clang-tidy foo.cpp)不会读它。
- 内容示例(YAML 格式):
Checks: >- -*, bugprone-*, performance-*, modernize-use-auto, modernize-use-nullptr, cppcoreguidelines-owning-memoryWarningsAsErrors: 'bugprone-*'HeaderFilterRegex: '^(src|include)/'
-
WarningsAsErrors: 'bugprone-*'表示这类警告在 CI 中直接导致构建失败,防止带已知隐患的代码合入 -
HeaderFilterRegex控制只检查你自己的头文件,避免第三方库(如boost/、fmt/format.h)污染报告 - 修改后无需重启编辑器或重新生成
compile_commands.json,下次运行即生效
哪些问题 clang-tidy 能自动修复,哪些必须人工判断
加 -fix 参数确实能改一部分,但它的安全边界很窄——只动语法等价、无副作用的替换。别指望它帮你重构逻辑或加 RAII 封装。
- 安全自动修复:
NULL → nullptr、std::vector<int> v; → auto v = std::vector<int>{};</int></int>、补override - 不能自动修复:
raw pointer → std::unique_ptr、std::string +拼接 →std::format、循环内重复计算 → 提取到外面 - 用
-fix-errors可让修复失败时直接报错退出,适合 CI 流水线中做门禁 - 修复前务必
git add -p确认,尤其注意模板特化或宏展开后的实际效果
最易被忽略的是 HeaderFilterRegex 和 WarningsAsErrors 的组合:不设过滤,第三方头文件的 warning 会占满报告;不设错误升级,CI 就拦不住 bugprone-use-after-move 这类高危问题。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











