Clang-Tidy
相关工具推荐
| 工具 | 说明 |
|---|---|
| ClangFormat | C/C++/Java/ObjC 代码格式化工具,与 Clang-Tidy 互补 |
| Cppcheck | C/C++ 静态分析工具,独立于编译器的轻量级检查 |
| CodeQL | GitHub 官方代码分析引擎,支持 C/C++ 安全分析 |
| Pre-commit | 多语言 Git 钩子管理框架,Clang-Tidy 的主流集成方式之一 |
1. 简介
Clang-Tidy 是基于 Clang 编译器的 C/C++ 静态分析与代码检查工具,属于 LLVM/Clang 工具链的一部分(代码位于 llvm-project 仓库的 clang-tools-extra 目录)。它提供了一个可扩展的框架,用于诊断和修复典型的编程错误,包括代码风格违规、接口误用以及可通过静态分析推断出的 Bug。
- 主要检查语言:C、C++
- 主要检查能力:检测 C/C++ 代码中的 Bug、性能问题、代码异味、安全漏洞;涵盖质量类检查(bugprone、cert)、风格类检查(readability、google、llvm)、性能检查(performance)、现代化迁移(modernize)、安全检查(cert、concurrency)
- 核心检查原理:基于 Clang AST 深度分析,模块化检查器架构
- 检查规则/选项:数百个 check(随 LLVM 版本动态变化,按 abseil、bugprone、modernize、performance、readability 等 20+ 模块分组),全量 check 列表
- GitHub 仓库:https://github.com/llvm/llvm-project(LLVM 子项目,38,776 stars,LLVM 主仓库,Clang-Tidy 无独立仓库)
- 开源协议:Apache-2.0 with LLVM Exceptions
- 最新稳定版本:随 LLVM 22.1.0 发布(2026-02-24,无独立版本号)
- 运行环境要求:需 LLVM/Clang 工具链;随 LLVM 版本发布
- 误报率:中
2. 官方文档
3. 社区优秀实践
3.1 LLVM
LLVM 项目自身就是 Clang-Tidy 的开发项目,自然也是其最重要的实践者。LLVM 在项目根目录维护了 .clang-tidy 配置文件,启用 llvm-*、misc-*、readability-identifier-naming 等检查组,并通过 CMAKE_CXX_CLANG_TIDY 集成到构建流程中。LLVM 还提供了 run-clang-tidy.py 和 clang-tidy-diff.py 等官方辅助脚本。
- 仓库:https://github.com/llvm/llvm-project
- 配置文件:
.clang-tidy - 特点:自举式开发、提供官方自动化脚本、规则覆盖全面
3.2 Chromium
Chromium 是全球最大的 C++ 开源项目之一,在项目根目录维护了 .clang-tidy 配置文件,将 Clang-Tidy 深度集成到代码审查流程中。Chromium 通过 PRESUBMIT.py 脚本在代码提交前自动运行 Clang-Tidy 检查,确保代码质量。
- 源码仓库:https://chromium.googlesource.com/chromium/src/
- 配置文件:项目根目录
.clang-tidy - 特点:大规模代码库实践、与 CI/CD 深度集成、自定义检查规则
3.3 WebKit
WebKit 是另一个大型 C++ 开源项目,在项目中使用了 Clang-Tidy 进行代码质量检查。WebKit 项目维护了自己的 .clang-tidy 配置,针对浏览器引擎的特殊需求定制了检查规则。
- GitHub 仓库:https://github.com/WebKit/WebKit
- 配置文件:项目根目录
.clang-tidy - 特点:针对渲染引擎场景优化、跨平台代码检查
4. 工具配置说明
4.1 配置文件说明
Clang-Tidy 使用 YAML 格式的 .clang-tidy 配置文件。
| 配置文件 | 用途 | 使用场景 |
|---|---|---|
.clang-tidy |
项目级检查规则配置 | 放置在项目根目录,Clang-Tidy 从源文件最近的父目录中查找 |
文件查找与继承机制:
- 从源文件所在目录向上逐级查找
.clang-tidy文件 - 支持子目录覆盖父目录配置(通过
InheritParentConfig: true) - 命令行
-config参数可内联指定配置
4.2 .clang-tidy 配置详解
配置项说明:
| 配置项 | 类型 | 说明 |
|---|---|---|
Checks |
string | 启用/禁用的检查规则(逗号分隔的通配符列表,- 前缀表示禁用) |
WarningsAsErrors |
string | 将指定警告升级为错误的规则列表 |
HeaderFilterRegex |
string | 头文件过滤正则(控制哪些头文件中的诊断会被显示) |
ExcludeHeaderFilterRegex |
string | 排除头文件过滤正则 |
FormatStyle |
string | 代码修复时的格式化风格(file、llvm、google 等) |
InheritParentConfig |
bool | 是否继承父目录的配置文件 |
HeaderFileExtensions |
string[] | 头文件扩展名列表 |
ImplementationFileExtensions |
string[] | 实现文件扩展名列表 |
SystemHeaders |
bool | 是否显示系统头文件中的诊断 |
UseColor |
bool | 是否使用颜色输出 |
ExtraArgs |
string[] | 额外的编译参数(追加在命令行末尾) |
ExtraArgsBefore |
string[] | 额外的编译参数(追加在命令行开头) |
RemovedArgs |
string[] | 需要移除的编译参数 |
CheckOptions |
list | 检查特定选项(键值对列表,每项含 key 和 value) |
User |
string | 运行 clang-tidy 的用户名(用于 TODO 注释等) |
最小配置示例:
---
Checks: "bugprone-*,modernize-*"
HeaderFilterRegex: ".*"
FormatStyle: file
推荐配置示例(适合大多数 C++ 项目):
---
# .clang-tidy
# 通用 C++ 项目推荐配置
# 策略:先禁用所有默认检查,再按需启用推荐规则组
Checks: >
-*,
bugprone-*,
-bugprone-easily-swappable-parameters,
-bugprone-narrowing-conversions,
-bugprone-assignment-in-if-condition,
modernize-*,
-modernize-use-trailing-return-type,
-modernize-avoid-c-arrays,
performance-*,
readability-*,
-readability-magic-numbers,
-readability-function-cognitive-complexity,
-readability-identifier-length,
cppcoreguidelines-*,
-cppcoreguidelines-avoid-magic-numbers,
-cppcoreguidelines-pro-bounds-pointer-arithmetic,
-cppcoreguidelines-pro-type-reinterpret-cast,
-cppcoreguidelines-avoid-c-arrays,
cert-*,
-cert-err58-cpp,
concurrency-*
HeaderFilterRegex: ".*"
FormatStyle: file
WarningsAsErrors: ""
CheckOptions:
# modernize-use-nullptr: 指定需要替换的 NULL 宏
- key: modernize-use-nullptr.NullMacros
value: "NULL"
# modernize-use-override: 是否忽略类中无虚函数的记录
- key: modernize-use-override.IgnoreDestructors
value: true
# readability-identifier-naming: 命名规范
- key: readability-identifier-naming.ClassCase
value: "CamelCase"
- key: readability-identifier-naming.StructCase
value: "CamelCase"
- key: readability-identifier-naming.FunctionCase
value: "camelBack"
- key: readability-identifier-naming.VariableCase
value: "camelBack"
- key: readability-identifier-naming.PrivateMemberSuffix
value: "_"
- key: readability-identifier-naming.ParameterCase
value: "camelBack"
- key: readability-identifier-naming.ConstexprVariableCase
value: "UPPER_CASE"
- key: readability-identifier-naming.GlobalConstantCase
value: "UPPER_CASE"
- key: readability-identifier-naming.EnumConstantCase
value: "UPPER_CASE"
- key: readability-identifier-naming.NamespaceCase
value: "lower_case"
# performance-*: 性能相关选项
- key: performance-unnecessary-value-param.AllowedTypes
value: ""
4.3 规则说明
bugprone-*(Bug 倾向检查)
检测容易出错的代码构造,是发现实际 Bug 最有效的规则组。
| 规则 | 说明 | 建议启用 |
|---|---|---|
bugprone-argument-comment |
检测参数注释与实际参数不匹配 | 是 |
bugprone-assert-side-effect |
检测 assert 中的副作用 | 是 |
bugprone-bool-pointer-implicit-conversion |
检测 bool 指针的隐式转换 | 是 |
bugprone-copy-constructor-init |
检测拷贝构造函数中的初始化问题 | 是 |
bugprone-dangling-handle |
检测悬空句柄 | 是 |
bugprone-easily-swappable-parameters |
检测容易混淆的参数顺序 | 视情况 |
bugprone-exception-escape |
检测不应抛出异常的函数中存在异常 | 是 |
bugprone-inc-dec-in-conditions |
检测条件中的自增/自减操作 | 是 |
bugprone-inaccurate-erase |
检测不正确的 erase 用法 | 是 |
bugprone-incorrect-roundings |
检测不正确的四舍五入 | 是 |
bugprone-integer-division |
检测整数除法截断 | 是 |
bugprone-macro-parentheses |
检测宏定义缺少括号 | 是 |
bugprone-macro-repeated-side-effects |
检测宏中的重复副作用 | 是 |
bugprone-misplaced-operator-in-strlen-in-alloc |
检测 strlen/malloc 中的运算符错误 | 是 |
bugprone-move-forwarding-reference |
检测转发引用的错误移动 | 是 |
bugprone-narrowing-conversions |
检测窄化转换 | 视情况 |
bugprone-parent-virtual-call |
检测构造/析构中的虚函数调用 | 是 |
bugprone-redundant-branch-condition |
检测冗余的分支条件 | 是 |
bugprone-redundant-string-cstr |
检测多余的 string.c_str() | 是 |
bugprone-signal-handler |
检测信号处理函数中的不安全操作 | 是 |
bugprone-sizeof-container |
检测对容器使用 sizeof | 是 |
bugprone-string-constructor |
检测低效的字符串构造 | 是 |
bugprone-suspicious-include |
检测可疑的 #include | 是 |
bugprone-suspicious-memset |
检测可疑的 memset 用法 | 是 |
bugprone-suspicious-missing-comma |
检测缺少逗号导致的错误 | 是 |
bugprone-suspicious-semicolon |
检测可疑的分号 | 是 |
bugprone-suspicious-string-compare |
检测可疑的字符串比较 | 是 |
bugprone-swapped-arguments |
检测参数顺序颠倒 | 是 |
bugprone-throw-keyword-missing |
检测缺少 throw 关键字 | 是 |
bugprone-unchecked-optional-access |
检测未检查的 optional 访问 | 是 |
bugprone-unique-ptr-array-mismatch |
检测 unique_ptr 数组不匹配 | 是 |
bugprone-unused-return-value |
检测未使用的返回值 | 是 |
bugprone-use-after-move |
检测移动后的使用 | 是 |
modernize-*(现代化检查)
倡导使用现代 C++(C++11 及以上)语言特性,帮助代码迁移到现代 C++ 标准。
| 规则 | 说明 | 建议启用 |
|---|---|---|
modernize-use-auto |
使用 auto 替代冗长的类型声明 | 是 |
modernize-use-nullptr |
使用 nullptr 替代 NULL/0 | 是 |
modernize-use-override |
使用 override 关键字 | 是 |
modernize-use-using |
使用 using 替代 typedef | 是 |
modernize-use-enum-class |
使用 enum class | 是 |
modernize-use-noexcept |
使用 noexcept | 是 |
modernize-use-default-member-init |
使用默认成员初始化器 | 是 |
modernize-use-emplace |
使用 emplace 替代 push_back + 构造 | 是 |
modernize-use-equals-default |
使用 = default | 是 |
modernize-use-equals-delete |
使用 = delete | 是 |
modernize-use-nodiscard |
添加 [[nodiscard]] 属性 | 是 |
modernize-use-trailing-return-type |
使用尾置返回类型 | 视情况 |
modernize-loop-convert |
将 for 循环转换为 range-for | 是 |
modernize-make-shared |
使用 std::make_shared | 是 |
modernize-make-unique |
使用 std::make_unique | 是 |
modernize-redundant-void-arg |
移除冗余的 void 参数 | 是 |
modernize-shrink-to-fit |
使用 shrink_to_fit | 是 |
modernize-replace-auto-ptr |
替换 auto_ptr | 是 |
modernize-deprecated-headers |
使用 C++ 头文件替代 C 头文件 | 是 |
modernize-avoid-c-arrays |
避免使用 C 风格数组 | 视情况 |
modernize-avoid-bind |
使用 lambda 替代 std::bind | 是 |
modernize-pass-by-value |
对仅移动参数使用按值传递 | 视情况 |
performance-*(性能检查)
检测与性能相关的问题。
| 规则 | 说明 | 建议启用 |
|---|---|---|
performance-unnecessary-value-param |
检测不必要的值传递参数 | 是 |
performance-unnecessary-copy-initialization |
检测不必要的拷贝初始化 | 是 |
performance-for-range-copy |
检测 range-for 中不必要的拷贝 | 是 |
performance-inefficient-string-concatenation |
检测低效的字符串拼接 | 是 |
performance-inefficient-vector-operation |
检测低效的 vector 操作 | 是 |
performance-faster-string-find |
使用更快的字符串查找方法 | 是 |
performance-no-int-to-ptr |
检测整数到指针的转换 | 是 |
performance-type-promotion-in-math-fn |
检测数学函数中的类型提升 | 是 |
performance-move-const-arg |
检测对 const 值的移动 | 是 |
performance-noexcept-swap |
swap 函数应标记 noexcept | 是 |
performance-implicit-conversion-in-loop |
检测循环中的隐式转换 | 是 |
readability-*(可读性检查)
提升代码可读性,不关联特定代码风格。
| 规则 | 说明 | 建议启用 |
|---|---|---|
readability-identifier-naming |
统一命名规范 | 是 |
readability-braces-around-statements |
控制语句使用大括号 | 是 |
readability-const-return-type |
移除返回类型中的 const | 是 |
readability-container-size-empty |
使用 empty() 替代 size() == 0 | 是 |
readability-else-after-return |
移除 return 后的 else | 是 |
readability-redundant-control-flow |
移除冗余的控制流 | 是 |
readability-redundant-string-cstr |
移除多余的 c_str() | 是 |
readability-redundant-preprocessor |
检测冗余的预处理器指令 | 是 |
readability-simplify-boolean-expr |
简化布尔表达式 | 是 |
readability-simplify-subscript-expr |
简化下标表达式 | 是 |
readability-static-accessed-through-instance |
通过实例访问静态成员 | 是 |
readability-string-compare |
简化字符串比较 | 是 |
readability-uniqueptr-delete-release |
用 reset() 替代 delete + release | 是 |
readability-implicit-bool-conversion |
检测隐式布尔转换 | 是 |
readability-function-cognitive-complexity |
函数认知复杂度 | 视情况 |
readability-function-size |
函数长度限制 | 视情况 |
readability-magic-numbers |
魔法数字检测 | 视情况 |
readability-identifier-length |
标识符长度 | 视情况 |
readability-duplicate-include |
检测重复的 #include | 是 |
readability-misleading-indentation |
检测误导性缩进 | 是 |
readability-redundant-declaration |
检测冗余声明 | 是 |
readability-inconsistent-declaration-parameter-name |
参数名不一致 | 是 |
cppcoreguidelines-*(C++ Core Guidelines 检查)
基于 C++ Core Guidelines 的检查规则。
| 规则 | 说明 | 建议启用 |
|---|---|---|
cppcoreguidelines-avoid-goto |
避免 goto | 是 |
cppcoreguidelines-prefer-member-initializer |
使用成员初始化器 | 是 |
cppcoreguidelines-pro-type-static-cast-downcast |
使用 static_cast 替代向下转换 | 是 |
cppcoreguidelines-pro-type-reinterpret-cast |
警告 reinterpret_cast 使用 | 视情况 |
cppcoreguidelines-pro-type-const-cast |
警告 const_cast 使用 | 视情况 |
cppcoreguidelines-pro-type-cstyle-cast |
避免 C 风格转换 | 是 |
cppcoreguidelines-pro-bounds-pointer-arithmetic |
避免指针算术 | 视情况 |
cppcoreguidelines-pro-bounds-constant-array-index |
避免非常量数组索引 | 是 |
cppcoreguidelines-slicing |
检测对象切片 | 是 |
cppcoreguidelines-owning-memory |
检测资源所有权问题 | 是 |
cppcoreguidelines-special-member-functions |
检测特殊成员函数的一致性 | 是 |
cppcoreguidelines-init-variables |
变量应被初始化 | 是 |
cppcoreguidelines-rvalue-reference-param-not-moved |
右值引用参数未被移动 | 是 |
cert-*(CERT 安全编码检查)
基于 CERT Secure Coding Standards 的安全检查。
| 规则 | 说明 | 建议启用 |
|---|---|---|
cert-dcl50-cpp |
禁止动态异常规范 | 是 |
cert-dcl58-cpp |
禁止在未导出的命名空间中定义 | 是 |
cert-err33-c |
检测未处理的返回值 | 是 |
cert-err52-cpp |
检测多次移动 | 是 |
cert-err60-cpp |
检测解引用已移动的对象 | 是 |
cert-flp30-c |
检测循环中的浮点比较 | 是 |
cert-msc50-cpp |
检测不安全的随机数生成 | 是 |
cert-msc51-cpp |
检测不准确的随机数 | 是 |
cert-oop57-cpp |
检测在构造/析构中的虚调用 | 是 |
cert-oop58-cpp |
检测拷贝构造函数中修改参数 | 是 |
concurrency-*(并发检查)
检测与并发编程相关的问题。
| 规则 | 说明 | 建议启用 |
|---|---|---|
concurrency-mt-unsafe |
检测非线程安全的函数调用 | 是 |
concurrency-thread-canceltype-asynchronous |
检测异步取消类型 | 是 |
4.4 渐进式引入策略
对于已有的大型项目,建议采用渐进式引入策略:
- 第一阶段:仅启用
bugprone-*和modernize-use-auto、modernize-use-nullptr、modernize-use-override等高频低风险检查 - 第二阶段:逐步启用
performance-*和readability-*中的核心规则 - 第三阶段:启用
cppcoreguidelines-*和cert-*安全相关规则 - 第四阶段:启用
clang-analyzer-*深度静态分析(注意性能开销)
---
# .clang-tidy - 第一阶段(入门)
Checks: >
-*,
bugprone-*,
-bugprone-easily-swappable-parameters,
modernize-use-auto,
modernize-use-nullptr,
modernize-use-override,
modernize-use-using,
modernize-use-enum-class,
modernize-loop-convert,
modernize-make-shared,
modernize-make-unique,
modernize-redundant-void-arg,
modernize-deprecated-headers,
modernize-replace-auto-ptr,
readability-braces-around-statements,
readability-else-after-return,
readability-container-size-empty,
readability-redundant-string-cstr,
readability-simplify-boolean-expr,
performance-for-range-copy,
performance-move-const-arg,
performance-noexcept-swap
HeaderFilterRegex: ".*"
FormatStyle: file
WarningsAsErrors: ""
5. 主流集成方式
5.1 CMake 集成(生态主流)
CMake 是 C/C++ 项目的主流构建工具,也是 Clang-Tidy 最常见的集成方式。Clang-Tidy 依赖 compile_commands.json 编译数据库来获取编译参数。
方式一:通过 CMAKE_CXX_CLANG_TIDY 变量
在 CMakeLists.txt 中设置,使 Clang-Tidy 在每次编译时自动运行:
# CMakeLists.txt
cmake_minimum_required(VERSION 3.18)
project(MyProject LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# 导出编译命令数据库(Clang-Tidy 依赖此文件)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
# 查找 clang-tidy 并设置
find_program(CLANG_TIDY_COMMAND NAMES "clang-tidy" "clang-tidy-18" "clang-tidy-17")
if(CLANG_TIDY_COMMAND)
set(CMAKE_CXX_CLANG_TIDY
${CLANG_TIDY_COMMAND}
--config-file=${CMAKE_SOURCE_DIR}/.clang-tidy
)
message(STATUS "Clang-Tidy enabled: ${CLANG_TIDY_COMMAND}")
endif()
方式二:通过自定义 target
# CMakeLists.txt - 定义独立的 tidy target
find_program(CLANG_TIDY_EXE NAMES "clang-tidy")
if(CLANG_TIDY_EXE)
add_custom_target(
clang-tidy
COMMAND ${CLANG_TIDY_EXE} -p ${CMAKE_BINARY_DIR} ${CMAKE_SOURCE_DIR}/src
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
COMMENT "Running Clang-Tidy..."
VERBATIM
)
endif()
生成编译数据库:
cmake -S . -B build -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
5.2 pre-commit 集成
使用 pocc/pre-commit-hooks 仓库提供的预置 hook,可在 Git 提交前自动运行 Clang-Tidy 检查暂存文件。
依赖说明:此 hook 依赖本地安装的
clang-tidy(需在 PATH 中可用),以及项目的compile_commands.json编译数据库。hook 使用language: python,但实际调用的是系统中的 clang-tidy 二进制。
# .pre-commit-config.yaml
fail_fast: false
repos:
- repo: https://github.com/pocc/pre-commit-hooks
rev: v1.3.5
hooks:
- id: clang-tidy
args: [-p, build]
# 可选:锁定 clang-tidy 版本,确保团队一致
# args: [--version=18.1.0, -p, build]
安装 pre-commit hooks:
pip install pre-commit
pre-commit install
限制变更文件:pre-commit 框架默认仅将暂存区中的变更文件传给 hook,因此无需额外配置即可实现文件级增量检查。
5.3 IDE 集成
VS Code
通过 clangd 扩展实现 Clang-Tidy 集成(官方推荐方式):
// .vscode/settings.json
{
"clangd.arguments": [
"--clang-tidy",
"--background-index",
"--header-insertion=iwyu",
"--completion-style=detailed",
"-j=12"
],
"clangd.fallbackFlags": ["-std=c++17"]
}
也可使用独立的 Clang-Tidy 扩展(notskm.clang-tidy)。
CLion
CLion 内置 Clang-Tidy 支持,默认启用:
- 进入
Settings | Editor | Inspections | C/C++ | Static Analysis Tools | Clang-Tidy - 配置启用的检查规则列表
- 支持从编辑器中快速禁用/抑制特定检查
- 支持通过状态栏小部件管理
.clang-tidy配置文件
参考文档:https://www.jetbrains.com/help/clion/clang-tidy-checks-support.html
Vim/Neovim
方式一:通过 clangd(推荐)
使用 coc-clangd 或 Neovim 内置 LSP 配置:
-- Neovim init.lua
vim.lsp.config.clangd = {
cmd = {
"clangd",
"--clang-tidy",
"--background-index",
"--header-insertion=iwyu",
},
}
方式二:通过 ALE
" .vimrc
let g:ale_linters = {
\ 'cpp': ['clangtidy'],
\ 'c': ['clangtidy'],
\}
let g:ale_cpp_clangtidy_options = '-p build'
5.4 命令行使用方式
# 基本检查(使用编译数据库)
clang-tidy -p build src/main.cpp
# 基本检查(手动指定编译参数)
clang-tidy src/main.cpp -- -std=c++17 -I./include
# 指定检查规则
clang-tidy -p build src/main.cpp -checks='bugprone-*,modernize-*'
# 自动修复问题
clang-tidy -p build src/main.cpp -fix
# 自动修复(包括编译错误)
clang-tidy -p build src/main.cpp -fix -fix-errors
# 导出修复建议到 YAML 文件
clang-tidy -p build src/main.cpp -export-fixes=fixes.yaml
# 列出所有可用检查
clang-tidy -list-checks -checks='*'
# 列出默认启用的检查
clang-tidy -list-checks
# 验证配置文件是否正确
clang-tidy -p build --verify-config
# 导出当前生效的配置
clang-tidy -p build --dump-config
# 并行检查整个项目(使用 run-clang-tidy.py)
run-clang-tidy.py -p build -j 8
# 指定头文件过滤
clang-tidy -p build src/main.cpp -header-filter='src/.*\.h'
# 排除特定头文件
clang-tidy -p build src/main.cpp -header-filter='src/.*\.h' -exclude-header-filter='third_party/.*'
增量检查 -- Clang-Tidy 提供多种增量检查方式:
使用 clang-tidy-diff.py(官方脚本) -- Clang-Tidy 自带 clang-tidy-diff.py 脚本,可仅对 Git diff 中的变更行进行检查:
# 检查工作目录中的变更(相对于上一个 commit)
git diff -U0 --no-color HEAD | clang-tidy-diff.py -p1
# 检查暂存区的变更
git diff -U0 --no-color --cached | clang-tidy-diff.py -p1
# 检查两个 commit 之间的差异
git diff -U0 --no-color HEAD~2 HEAD | clang-tidy-diff.py -p1
# 指定检查规则并自动修复
git diff -U0 --no-color HEAD | clang-tidy-diff.py -p1 -fix -checks='-*,bugprone-*,modernize-*'
注意:
clang-tidy-diff.py仍然会分析整个文件,只是在输出时过滤掉未变更行的诊断。因此它不会提升分析性能,但能让输出更聚焦于变更代码。
使用 run-clang-tidy.py 并行检查:
# 并行检查整个项目(默认使用所有 CPU 核心)
run-clang-tidy.py -p build -j 8
# 仅检查指定目录
run-clang-tidy.py -p build -j 8 src/
# 检查并自动修复
run-clang-tidy.py -p build -j 8 -fix
基于 Git 的命令行增量方案:
# 获取相对于 HEAD 的 C++ 变更文件
git diff --name-only --diff-filter=ACMR HEAD -- '*.cpp' '*.h' '*.cc' '*.cxx' '*.hpp' | \
xargs -I{} clang-tidy -p build {}
# 获取相对于 main 分支的变更文件
git diff --name-only --diff-filter=ACMR main...HEAD -- '*.cpp' '*.h' | \
xargs -I{} clang-tidy -p build {}
使用 --line-filter 仅检查特定行范围:
# 使用 --line-filter 指定文件和行范围(JSON 格式)
clang-tidy -p build src/main.cpp --line-filter='[{"name":"src/main.cpp","lines":[[10,50],[100,120]]}]'
CI 脚本调用:
GitHub Actions
# .github/workflows/clang-tidy.yml
name: Clang-Tidy
on: [push, pull_request]
jobs:
clang-tidy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Clang-Tidy
run: sudo apt-get update && sudo apt-get install -y clang-tidy
- name: Configure CMake
run: cmake -S . -B build -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
- name: Run Clang-Tidy
run: |
cd build
run-clang-tidy.py -p . -checks='-*,bugprone-*,modernize-*,readability-*,performance-*' 2>&1 | tee clang-tidy-report.txt
continue-on-error: true
- name: Upload Report
if: always()
uses: actions/upload-artifact@v4
with:
name: clang-tidy-report
path: build/clang-tidy-report.txt
GitLab CI
# .gitlab-ci.yml
clang-tidy:
stage: test
image: ubuntu:latest
before_script:
- apt-get update && apt-get install -y clang-tidy cmake build-essential
- cmake -S . -B build -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
script:
- run-clang-tidy.py -p build -quiet
artifacts:
paths:
- clang-tidy-report.txt
when: always
增量检查 -- 按 PR 变更文件触发增量扫描:
GitHub Actions(按 PR 变更文件触发)
# .github/workflows/clang-tidy.yml
name: Clang-Tidy (Incremental)
on: [pull_request]
jobs:
clang-tidy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install Clang-Tidy
run: sudo apt-get update && sudo apt-get install -y clang-tidy
- name: Configure CMake
run: cmake -S . -B build -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
- name: Run Clang-Tidy on changed files
run: |
CHANGED_FILES=$(git diff --name-only --diff-filter=ACMR origin/${{ github.base_ref }}...HEAD -- '*.cpp' '*.h' '*.cc' '*.cxx' '*.hpp')
if [ -n "$CHANGED_FILES" ]; then
echo "$CHANGED_FILES" | xargs -I{} clang-tidy -p build {}
else
echo "No C/C++ files changed."
fi
6. 告警抑制(屏蔽)方法
Clang-Tidy 提供了多种告警抑制机制,从代码级注释到配置文件级别均可控制。
6.1 通过代码注释屏蔽(NOLINT)
// NOLINT -- 抑制当前行所有警告
int x = 1; // NOLINT
// NOLINT(check-name) -- 抑制当前行指定检查
int x = 1; // NOLINT(bugprone-narrowing-conversions)
// NOLINTNEXTLINE -- 抑制下一行的警告
// NOLINTNEXTLINE(bugprone-easily-swappable-parameters)
void f(int a, int b, int c);
// NOLINTNEXTLINE(check-name) -- 抑制下一行指定检查
// NOLINTNEXTLINE(google-explicit-constructor, google-runtime-int)
Foo(bool param);
// NOLINTBEGIN ... // NOLINTEND -- 抑制多行警告
// NOLINTBEGIN(google-explicit-constructor)
Foo(short param);
Foo(long param);
Foo(unsigned param);
// NOLINTEND(google-explicit-constructor)
使用通配符批量抑制
// 抑制当前行所有 google 模块的检查
Foo(bool param); // NOLINT(google*)
// 抑制下一行所有以 -avoid-c-arrays 结尾的检查
// NOLINTNEXTLINE(*-avoid-c-arrays)
int array[10];
附带原因说明(推荐)
// NOLINT: Allow implicit conversion from char, because legacy API requires it
Foo(char param);
语法要求:
NOLINT/NOLINTNEXTLINE/NOLINTBEGIN/NOLINTEND与左括号之间不允许有空格,否则会被视为无参数的注释- 括号内的检查名列表中,空格会被忽略
NOLINTBEGIN和NOLINTEND必须成对出现,且参数必须匹配
6.2 通过 .clang-tidy 配置文件屏蔽
在配置文件中使用负通配符排除特定检查,或通过 HeaderFilterRegex 排除特定目录:
# 在 Checks 中使用负通配符排除特定检查
Checks: >
-*,
bugprone-*,
-bugprone-easily-swappable-parameters,
-bugprone-narrowing-conversions
# 通过 HeaderFilterRegex 排除特定头文件
HeaderFilterRegex: "src/.*"
ExcludeHeaderFilterRegex: "third_party/.*|generated/.*"
6.3 通过命令行参数屏蔽
# 使用 -checks 排除特定检查
clang-tidy -p build src/main.cpp -checks='-*,bugprone-*,-bugprone-easily-swappable-parameters'
# 使用 --header-filter 控制头文件诊断
clang-tidy -p build src/main.cpp --header-filter='src/.*' --exclude-header-filter='third_party/.*'
# 使用 --line-filter 限制检查范围
clang-tidy -p build src/main.cpp --line-filter='[{"name":"src/main.cpp","lines":[[1,50]]}]'
参考文档:https://releases.llvm.org/22.1.0/tools/clang/tools/extra/docs/clang-tidy/index.html#using-clang-tidy
6.4 通过 IDE 屏蔽
在 CLion 中,可以通过右键点击警告选择 Suppress 'check_name' for line,IDE 会自动添加 // NOLINT 注释。也可通过 #pragma clang diagnostic 实现更精细的控制。
参考文档:https://www.jetbrains.com/help/clion/clang-tidy-checks-support.html