如何用Clang-Tidy对c++代码进行静态分析? (配置与实践)

Clang-Tidy 是基于 Clang 的可扩展 C++ 静态分析工具,能发现潜在 bug、风格违规、性能隐患及不符合现代 C++ 标准的写法,如裸指针所有权混乱或忽略返回值。

Clang-Tidy 是什么,它能帮你发现哪些问题

Clang-Tidy 不是编译器,而是一个基于 Clang 的 C++ 静态分析工具,专为可扩展的代码检查设计。它能识别潜在的 bug、风格违规(比如命名不一致)、性能隐患(如冗余拷贝)、以及不符合现代 C++ 标准(如 modernize-use-auto)的写法。它不替代编译器报错,但能提前暴露编译器不会警告的问题——比如 cppcoreguidelines-owning-memory 检查裸指针所有权混乱,或 bugprone-unused-return-value 提醒你漏了 std::regex_match

的返回值检查。

如何让 Clang-Tidy 识别你的项目结构(CMake + compile_commands.json)

Clang-Tidy 需要知道每个源文件的完整编译命令(含宏定义、头文件路径、C++ 标准等),否则会误报“未声明的标识符”或跳过模板实例化检查。最可靠的方式是生成 compile_commands.json

  • 用 CMake 时,在配置阶段加 -DCMAKE_EXPORT_COMPILE_COMMANDS=ON,例如:
    cmake -B build -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_CXX_STANDARD=17
  • 确保构建目录下生成了 build/compile_commands.json;如果项目用 Ninja 或 Make,该文件必须存在且路径正确
  • 运行 Clang-Tidy 时,必须通过 -p 参数指定该路径,否则它默认按系统头路径解析,几乎必然失败

常见错误:直接在源码根目录执行 clang-tidy *.cpp —— 这样没有编译上下文,#include "my_header.h" 会报找不到,所有依赖模板的检查(如 cppcoreguidelines-pro-bounds-array-to-pointer-decay)也会失效。

怎么启用和禁用具体检查项(.clang-tidy 配置文件)

靠命令行传一堆 --checks 很难维护。推荐用项目根目录下的 .clang-tidy 文件统一管理:

Checks: '-*,cppcoreguidelines-*,modernize-*,performance-*,bugprone-*,misc-*'
WarningsAsErrors: ['*']
HeaderFilterRegex: '^(src|include)/'
CheckOptions:
  - key: modernize-use-auto.MinTypeNameLength
    value: '5'
  - key: readability-identifier-naming.VariableNameStyle
    value: lower_case

说明:

  • -* 先禁用全部检查,再显式启用需要的类别,避免继承 clang-tidy 默认启用的过时规则
  • WarningsAsErrors 把所有检查结果当 error 处理(CI 中可配合 --quiet 和退出码判断)
  • HeaderFilterRegex 控制只检查匹配路径的头文件,避免对第三方库(如 /usr/include)误报
  • CheckOptions 调整具体规则行为,比如 modernize-use-auto 默认只对类型名长度 ≥ 3 的变量触发,这里改成 ≥ 5

注意:.clang-tidy 文件必须 UTF-8 编码且无 BOM,Windows 上用记事本保存易出错,建议用 VS Code 或 Vim。

实际运行与集成到开发流程(命令与 CI 示例)

本地快速扫描单个文件:

clang-tidy -p build/ src/foo.cpp --fix --header-filter='^(src|include)/'

关键参数说明:

  • --fix 自动修复支持的检查(如添加 override、替换 auto),但不会改逻辑,也不保证 100% 安全,务必配合 git diff 查看
  • --header-filter.clang-tidy 中的 HeaderFilterRegex 作用一致,命令行优先级更高
  • 想只看某类问题?用 --checks='-*,modernize-*' 临时覆盖配置文件

CI 中常用组合(以 GitHub Actions 为例):

clang-tidy -p build/ $(find src/ -name '*.cpp') --export-fixes=clang-tidy-fixes.yaml 2>&1 | grep -E "(warning|error):"
# 后续可用 clang-apply-replacements 工具批量应用 fixes

容易被忽略的一点:Clang-Tidy 对模板深度 > 10 的代码(如嵌套 std::tuple)可能超时或崩溃,默认限制是 256 —— 如果遇到 fatal error: too many errors emitted, stopping now,需加 -ferror-limit=0 并检查是否真有大量模板实例化问题。