Clang-Tidy静态代码分析框架
描述
clang-tidy是一个基于clang的静态代码分析框架,支持C++/C/Objective-C;
clang-tidy不仅可以做静态检查,还可以做一些自动修复工作。
安装clang-tidy和clang编译工具
1.ubantu20安装(默认安装clang-tidy-10版本)
sudo apt install clang-tidy clang
2.centos安装(只有clang-tidy)
# 安装 SCL 的 yum 源
# (它可以支持系统同时安装多个版本的软件,然后通过scl enable命令来激活相应软件环境,而不会对原始的软件环境产生影响。)
sudo yum install centos-release-scl
sudo yum install llvm-toolset-7
sudo yum install llvm-toolset-7-clang-analyzer llvm-toolset-7-clang-tools-extra
scl enable llvm-toolset-7 "clang -v"
scl enable llvm-toolset-7 "lldb -v"
# 在新的 Bash 中启用 llvm-toolset-7
#(注意,SCL 是在保证不与原有软件冲突的情况下运行的,也就意味着用户默认 Bash 是无法调用 SCL 的)
scl enable llvm-toolset-7 bash
2.1.centos如果需要系统重启后,能够自动启动最新版本软件环境
# 通过bash环境来设定,对当前用户启用
vim ~/.bashrc
# 加入
source scl_source enable llvm-toolset-7
2.2.centos如果需要批量检查
下载 run-clang-tidy.py
建议放在/opt/rh/llvm-toolset-7/root/usr/bin/
命令使用
列出默认执行的检查
clang-tidy -list-checks
列出它可以执行的所有检查
clang-tidy -list-checks -checks="*"
使用默认启用的所有检查来检查文件
clang-tidy test.cpp
使用默认启用的所有检查来检查文件并使用建议的修复来修复错误
clang-tidy -fix test.cpp
clang-tidy -fix-errors test.cpp
后面的--
表示这个文件不在compilation database(compile_commands.json)里面,可以直接单独编译;
clang-tidy -checks="-*,modernize-use-nullptr" src/test.cpp --
找出test.cpp中指向NULL/0的指针,并自动转化为nullptr)
clang-tidy -checks="-*,misc-unused-nullptr" -fix src/test.cpp --
run-clang-tidy.py脚本能够对每个compilation database中的每个文件都运行clang-tidy(使用多进程方法)
# 这里的"-*"就是要使目前所有的默认规则失效(只做modernize-use-nullptr检查并修复)
/usr/bin/run-clang-tidy.py -checks="-*,modernize-use-nullptr" -fix
cmake使用
1 |
|
支持的check
规则 | 描述 |
---|---|
abseil- | 与 Abseil 库相关的检查 |
altera- | 与 FPGA 的 OpenCL 编程相关的检查 |
android- | 与 Android 相关的检查 |
boost- | 与 Boost 库相关的检查 |
bugprone- | 检查目标容易出错的代码结构 |
cert- | 与 CERT 安全编码指南相关的检查 |
clang-analyzer- | Clang 静态分析器检查 |
concurrency- | 与并发编程相关的检查(包括线程、纤程、协程等) |
cppcoreguidelines- | 与 C++ 核心指南相关的检查 |
darwin- | 与达尔文编码约定相关的检查 |
fuchsia- | 与 Fuchsia 编码约定相关的检查 |
google- | 与 Google 编码约定相关的检查 |
hicpp- | 与高完整性 C++ 编码标准相关的检查 |
linuxkernel- | 与 Linux 内核编码约定相关的检查 |
llvm- | 与 LLVM 编码约定相关的检查 |
llvmlibc- | 与 LLVM-libc 编码标准相关的检查 |
misc- | 检查我们没有更好的类别 |
modernize- | 提倡使用现代(当前“现代”表示“C++11”)语言结构的检查 |
mpi- | 与 MPI(消息传递接口)相关的检查 |
objc- | 与 Objective-C 编码约定相关的检查 |
openmp- | 与 OpenMP API 相关的检查 |
performance- | 检查是否针对与性能相关的问题 |
portability- | 检查与任何特定编码风格无关的可移植性相关问题 |
readability- | 检查针对与任何特定编码风格无关的可读性相关问题 |
zircon- | 与 Zircon 内核编码约定相关的检查 |
自动检查转换C++代码
自动地把老的C++03代码替换成C++11代码
需要指定 -fix
标志 | 描述 |
---|---|
modernize-avoid-bind | 使用lambda替换std::binding |
modernize-deprecated-headers | 将C标准库的头文件include替换成C++style,#include <assert.h> => #include |
modernize-loop-convert | 使用for-range loop替换for(…;…;…;), 并更新for语句的相关变量 |
modernize-make-shared | 找出所有显式创建std::shared_ptr变量的表达式,并使用make_shared替换 |
modernize-make-unique | 跟make-shared一样,使用std::make_unique替换所有std::unique_ptr显式创建表达式 |
modernize-pass-by-value | 在构造函数中使用move语义 |
modernize-raw-string-literal | 用C++11的raw string literal(R”…”)替换原来的string literal, 这样的好处就是不用再添加转义符\了 |
modernize-redundant-void-arg | 去掉void函数参数 |
modernize-replace-auto-ptr | 用std::unique_ptr替换std::shared_ptr, std::shared_ptr是不推荐使用的,即使在C++98 |
modernize-shrink-to-fit | 在C++03中,如果我们想修改STL容器的capacity,只能通过copy & swap的方式,C++11提供了shink_to_fit的方法 |
modernize-use-auto | 在变量定义的时候,使用auto代替显式的类型声明,这个在定义STL容器类的Iterator特别方便 |
modernize-use-bool-literals | 找出所有隐式从int转成bool的literal, 使用true或者false代替 |
modernize-use-default | 对于没有任何自定义行为(定义为{})的特殊的成员函数,构造函数,析构函数,移动/复制构造函数,用=default代替掉{} |
modernize-use-emplace | 使用STL容器中的emplace代替push_back |
modernize-use-equals-delete | 在C++98中,类设计为了实现禁止调用某些特殊的成员函数,通常把它们声明成private;在C++11中,只需要在声明中体检=delete,找出所有private的特殊成员函数,并将它们标记成=delete |
modernize-use-nullptr | 用nullptr代替NULL |
modernize-use-override | 对于子类改写父类的virtual方法,在方法后面添加override, 并删掉virtual前缀,即virtual void NewOveride() => void NewOverride() override {} |
modernize-use-using | 用using代替typedef, 如typedef int V => using V = int |
注意
cmake使用clang-tidy时需要把CMAKE_CXX_CLANG_TIDY赋值,放在add_executable或add_library前面
CMAKE_CXX_CLANG_TIDY是 cmake 3.6版本之后的功能
详细检查项
规则 | 描述 |
---|---|
boost-use-to-string | 从整数类型转换为字符串默认使用std::to_string |
bugprone-argument-comment | 参数注释 |
bugprone-branch-clone | 要求相同分支合并 |
bugprone-copy-constructor-init | 基类拷贝构造函数初始化 |
bugprone-dynamic-static-initializers | 禁止返回动态初始化的静态变量 |
bugprone-exception-escape | 禁止在一些函数内抛出异常,避免带来一些风险(析构函数、移动构造函数、移动赋值运算符、main函数、swap函数等) |
bugprone-fold-init-type | 检查截断和溢出的情况 |
bugprone-forward-declaration-namespace | 检查同名但未定义的命名空间 |
bugprone-incorrect-roundings | 排除不正确舍入问题 |
bugprone-infinite-loop | 检查容易出错的无限循环 |
bugprone-integer-division | 检查会导致精度损失的整数除法 |
bugprone-macro-parentheses | 查找由于缺少括号而可能具有意外行为的宏 |
bugprone-misplaced-operator-in-strlen-in-alloc | 检查字符串操作的不当行为 |
bugprone-misplaced-pointer-arithmetic-in-alloc | 检查错误的指针动态分配内存 |
bugprone-misplaced-widening-cast | 类型转换造成的精度损失 |
bugprone-move-forwarding-reference | 检查std::move()的错误使用 |
bugprone-multiple-statement-macro | 检查多语句宏定义 |
bugprone-no-escape | 查找容易出错的noescape |
bugprone-not-null-terminated-result | 检查可能导致非空终止结果的函数调用,使用strcpy()、strncpy()、strcpy_s()、 strncpy_s()代替memcpy()和memcpy_s() |
bugprone-parent-virtual-call | 检查对父虚函数的调用 |
bugprone-posix-return | 检查对pthread_*或posix_*函数调用是否判断负返回值 |
bugprone-redundant-branch-condition | 检查逻辑if的重复判断冗余 |
bugprone-reserved-identifier | 检查不规范的下划线使用 |
bugprone-signal-handler | 检查容易出错的信号处理程序 |
bugprone-signed-char-misuse | 检查错误的字符型与字符型、整型之间的强制转换和比较 |
bugprone-sizeof-container | 检查可能出错的sizeof使用 |
bugprone-sizeof-expression | |
bugprone-spuriously-wake-up-functions | 检查唤醒函数的错误使用 |
bugprone-string-constructor | 检查容易出错的字符串初始化 |
bugprone-string-integer-assignment | 检查容易出错的字符串赋值(可能导致误判) |
bugprone-string-literal-with-embedded-nul | 检查带有嵌入\0字符的字符串 |
bugprone-suspicious-enum-usage | 容易出错的枚举用法 |
bugprone-suspicious-include.HeaderFileExtensions | 检查错误的文件包含(只包含头文件) |
bugprone-suspicious-memset-usage | 检查错误的memset的使用 |
bugprone-suspicious-missing-comma | 检查可疑的逗号丢失 |
bugprone-suspicious-semicolon | 检查容易出错的可以分号 |
bugprone-suspicious-string-compare | 检查可疑的字符串比较 |
bugprone-swapped-arguments | 检查容易出错的交换参数 |
bugprone-terminating-continue | 检查do-while常为false时的continue使用 |
bugprone-throw-keyword-missing | 检查可能缺失的throw关键字 |
bugprone-too-small-loop-variable | 检查容易出错的循环变量 |
bugprone-undefined-memory-manipulation | 查找容易出错的未定义内存操作 |
bugprone-undelegated-constructor | 检查容易出错的委托构造函数 |
bugprone-unhandled-exception-at-new | 检查未对new进行异常处理 |
bugprone-unhandled-self-assignment | 检查容易出错的未处理自赋值 |
bugprone-unused-raii | 检查看起来像RAII对象的临时对象。 |
bugprone-unused-return-value | 检查未使用的一些返回值(如返回指针) |
bugprone-use-after-move | 禁止使用std::move之后的对象仍被使用 |
bugprone-virtual-near-miss | 检查函数名与基类虚函数类似的函数声明 |
cert-dcl21-cpp | 会报未知的警告 |
cert-dcl50-cpp | |
cert-env33-c | |
cert-dcl58-cpp | 检查对std posix等命名空间的修改 |
cert-err34-c | 检查不验证转换字符串到数字的有效性的代码,如c语言atoi() |
cert-flp30-c | 检查浮点类型的循环 |
clang-analyzer-core.DynamicTypePropagation | 生成动态类型信息 |
clang-analyzer-core.uninitialized.CapturedBlockVariable | 检查未初始化的块 |
clang-analyzer-cplusplus.InnerPointer | 检查释放后的内部指针的使用 |
clang-analyzer-nullability.NullableReturnedFromNonnull | 检查从非空返回类型 返回 可能空的指针 |
clang-analyzer-optin.osx.OSObjectCStyleCast | |
clang-analyzer-optin.performance.GCDAntipattern | |
clang-analyzer-osx.MIG | |
clang-analyzer-optin.performance.Padding | 检查过度填充的结构 |
clang-analyzer-osx.OSObjectRetainCount | |
clang-analyzer-osx.ObjCProperty | 检查objc |
clang-analyzer-osx.cocoa | AutoreleaseWrite |
-clang-analyzer-osx.cocoa-* | cocoa相关 |
clang-analyzer-valist- | va_lists相关 |
concurrency-mt-unsafe | mt安全 |
concurrency-thread-canceltype-asynchronous | 并发线程 |
cppcoreguidelines-avoid-goto | 避免使用goto |
cppcoreguidelines-avoid-non-const-global-variables | 禁止非常量全局变量 |
cppcoreguidelines-interfaces-global-init | 检查extern对象的全局变量的初始值设定项初始化顺序问题 |
-cppcoreguidelines-macro-usage | 检查可能被认为有问题的宏用法 |
-cppcoreguidelines-narrowing-conversions | |
cppcoreguidelines-no-malloc | 对c风格内存分配的检查 |
-cppcoreguidelines-owning-memory | 检查内存分配时是否使用gsl的方法 |
cppcoreguidelines-prefer-member-initializer | |
cppcoreguidelines-pro-bounds-array-to-pointer-decay | |
cppcoreguidelines-pro-bounds-constant-array-index | |
-cppcoreguidelines-pro-bounds-pointer-arithmetic | 标记指针的算法使用 |
-cppcoreguidelines-pro-type-const-cast | 标记const_cast的使用 |
-cppcoreguidelines-pro-type-cstyle-cast | |
-cppcoreguidelines-pro-type-member-init | |
-cppcoreguidelines-pro-type-reinterpret-cast | 标记reinterpret_cast的使用 |
-cppcoreguidelines-pro-type-static-cast-downcast | 标记static_cast的使用 |
-cppcoreguidelines-pro-type-union-access | 标记union成员的访问权限 |
cppcoreguidelines-pro-type-vararg | 标记对c样式可变参数函数调用以及对va_arg的使用 |
cppcoreguidelines-slicing | 检查导致slice的情况 |
cppcoreguidelines-special-member-functions | |
darwin-avoid-spinlock | |
darwin-dispatch-once-nonstatic | |
-fuchsia-default-arguments-calls | 使用默认参数时发出警告 |
-fuchsia-default-arguments-declarations | 函数定义默认参数时发出警告 |
-fuchsia-multiple-inheritance | 继承自多个非纯虚类发出警告 |
-fuchsia-overloaded-operator | 检查已被重载的运算符 |
fuchsia-statically-constructed-objects | 限制创建静态对象(除非构造函数是constexpr类型或没有显式构造函数) |
fuchsia-trailing-return | |
fuchsia-virtual-inheritance | 对虚继承类发出警告(报错) |
google-build-explicit-make-pair | 检查make_pair是否推断出模板类型 |
google-build-using-namespace | 检查是否使用using namespace |
google-default-arguments | 为虚函数参数添加默认值 |
-google-explicit-constructor | 检查显式构造函数,避免隐式转换带来的风险 |
google-global-names-in-headers | 在头文件中标记全局命名空间污染 |
-google-objc-avoid-nsobject-new | objc |
-google-objc-avoid-throwing-exception | |
-google-objc-function-naming | |
-google-objc-global-variable-declaration | |
google-readability-avoid-underscore-in-googletest-name | 检查googletest的测试以及测试示例名称是否有下划线(测试名称和测试用例名称中不允许使用下划线) |
google-readability-casting | 查找 C 风格强制转换的用法 |
google-readability-todo | 查找TODO有没有署用户名、邮件等 |
-google-runtime-int | 检查整数定义,将short, long,long long改为intxx_类型 |
google-runtime-operator | 检查用户自定义表述的重载运算符 |
google-upgrade-googletest-case | 用户自定义函数名中,将带有case字符改为suite |
-hicpp-avoid-goto | 要求goto只跳过块的一部分(不使用goto) |
hicpp-exception-baseclass | 确保throw表达式中的每个值都是std::exception的实例 |
hicpp-multiway-paths-covered | 有if和else if一定要包含else(即使内容为空),有switch要包含default,少量case用if代替。 |
hicpp-no-assembler | 检查汇编语句 |
hicpp-signed-bitwise | 检查对有符号整数类型的按位运算的使用,避免风险 |
linuxkernel-must-use-errs | 检查linux内核代码 |
llvm-header-guard | 检查不符合LLVM风格的头文件 |
llvm-include-order | 检查include的正确顺序(llvm风格) |
llvm-namespace-comment | 长命名空间结束注释 |
llvm-prefer-isa-or-dyn-cast-in-conditionals | cast的一些变换 |
llvm-prefer-register-over-unsigned | unsigned用Register代替 |
llvm-twine-local | Twine方法使用后面加.str() |
llvmlibc-callee-namespace | 检查调用解析为__llvm_libc命名空间内的函数 |
llvmlibc-implementation-in-namespace | |
llvmlibc-restrict-system-libc-headers | 查找编译器未提供的系统 libc 头文件,如stdio.h |
-misc-definitions-in-headers | 在头文件中查找非 extern 非内联函数和变量定义 |
misc-misplaced-const | 检查const的错误使用 |
misc-new-delete-overloads | 检查new和delete |
misc-no-recursion | 检查函数递归错误 |
misc-non-copyable-objects | 检查一些对象,不允许复制,比如FILE |
-misc-non-private-member-variables-in-classes | 规定类成员变量必须为private |
misc-redundant-expression | 检查冗余表达式 |
misc-static-assert | 用static_assert()代替assert() |
misc-throw-by-value-catch-by-reference | 查找违反“按值抛出,按引用捕捉”的规则 |
misc-unconventional-assign-operator | 检查重载运算符的错误返回类型 |
misc-uniqueptr-reset-release | 将unique_ptr::reset(release())替换为std::move() |
misc-unused-alias-decls | 查找未使用的命名空间别名声明 |
misc-unused-parameters | 查找未使用的参数并报错(可能代码有误) |
misc-unused-using-decls | 查找未使用的using声明 |
modernize-avoid-bind | 替换std::bind()的使用 |
modernize-avoid-c-arrays | 避免使用c语言的array |
modernize-concat-nested-namespaces | 嵌套命名空间的简化(可以简化时) |
modernize-deprecated-headers | 检查c++中弃用的c头文件 |
modernize-deprecated-ios-base-aliases | 检查弃用的类方法 |
modernize-loop-convert | 避免有风险的循环,替换为c++11风格 |
modernize-make-shared | 对于share_ptr的一些更改 |
modernize-make-unique | 对于unique_ptr的一些更改 |
modernize-pass-by-value | |
modernize-raw-string-literal | 字符串初始化的风格检查 |
modernize-redundant-void-arg | 检查冗余的void |
modernize-replace-auto-ptr | 用unique_ptr替换auto_ptr |
modernize-replace-disallow-copy-and-assign-macro | |
modernize-replace-random-shuffle | 将std::random_shuffle替换为std::shuffle |
modernize-return-braced-init-list | 用花括号初始化器列表替换返回中对构造函数的显式调用 |
modernize-shrink-to-fit | 关于缩放的使用 |
modernize-unary-static-assert | 关于static_assert空字符串的检查 |
modernize-use-auto | 检查auto的使用风格 |
modernize-use-bool-literals | 检查bool类型,用true和false表示 |
modernize-use-default-member-init | 构造函数初始化的设定值风格 |
-modernize-use-emplace | 在std::vector、std::deque、std::list中插入的使用限制 |
modernize-use-equals-default | 将特殊成员函数的默认主体替换为显式默认函数声明 |
modernize-use-equals-delete | 将删除的特殊成员函数显式表示 |
-modernize-use-nodiscard | const成员函数的使用风格 |
modernize-use-noexcept | 函数定义的throw替换为noexcept |
-modernize-use-nullptr | 将空指针NULL改为nullptr |
modernize-use-override | 在重载虚函数中添加override声明 |
-modernize-use-trailing-return-type | 使用尾随返回类型 |
modernize-use-transparent-functors | |
modernize-use-uncaught-exceptions | |
modernize-use-using | 将typedef转换为using |
mpi-buffer-deref | 关于消息传递接口的检查 |
mpi-type-mismatch | 检查消息传递接口不匹配问题 |
objc-avoid-nserror-init | objc相关 |
objc-dealloc-in-category | |
objc-forbidden-subclassing | |
objc-missing-hash | |
objc-nsinvocation-argument-lifetime | |
objc-property-declaration | |
objc-super-self | |
openmp-exception-escape | openmp相关 |
openmp-use-default-none | |
performance-faster-string-find | 优化find的效率 |
performance-for-range-copy | 不使用for循环里使用auto的警告 |
performance-implicit-conversion-in-loop | for循环中,变量的隐式表示(auto)代替显式表示 |
performance-inefficient-algorithm | 检查关联容器中的低效使用 |
performance-inefficient-string-concatenation | 检查性能低效的字符串连接,字符串拼接改为append,而不是操作符+ |
-performance-inefficient-vector-operation | 查找可能导致不必要的内存重新分配的低效vector操作 |
performance-move-const-arg | 关于std::move的一些警告 |
performance-move-constructor-init | 标记移动构造函数初始化 |
performance-no-automatic-move | |
performance-no-int-to-ptr | 限制整数到指针的转换 |
performance-noexcept-move-constructor | 检查移动构造函数没有标记noexcept或者为false的情况 |
performance-trivially-destructible | 检查外部可破坏析构函数的情况 |
performance-type-promotion-in-math-fn | 数学库,从c到c++的转换 |
performance-unnecessary-copy-initialization | |
performance-unnecessary-value-param | 使用参数的移动(std::move),而不是复制 |
portability-restrict-system-includes | 检查以选择性地允许或禁止系统标头的可配置列表 |
portability-simd-intrinsics | |
-readability-avoid-const-params-in-decls | 检查函数声明是否具有顶级参数 const |
readability-braces-around-statements | 在逻辑语句是否添加大括号 |
readability-const-return-type | 常量返回值的限制 |
readability-container-size-empty | 检查对size()调用是否可以用empty()来代替 |
readability-convert-member-functions-to-static | 将不使用this的非静态成员函数转换为静态成员函数 |
-readability-delete-null-pointer | 查找检查指针是否存在的语句 |
readability-else-after-return | 检查多余的else使用 |
readability-function-cognitive-complexity | 检查功能认知复杂性指标 |
readability-function-size | 根据各种指标检查大型函数 |
readability-identifier-naming | 标识符命名方式限制 |
readability-implicit-bool-conversion | 检查bool与int之间的转换 |
readability-inconsistent-declaration-parameter-name | 查找参数名称不一致的声明 |
readability-isolate-declaration | 将连续的变量声明拆分成逐一声明 |
readability-magic-numbers | magic numbers检查 |
readability-make-member-function-const | 检查可以被定义为const的非静态成员函数 |
readability-misleading-indentation | 检查误导性缩进 |
readability-misplaced-array-index | 检查出错的索引 |
readability-named-parameter | 查找带有未命名参数的函数 |
readability-non-const-parameter | 检查可以更改为指向常量类型的指针类型的函数参数 |
readability-qualified-auto | 将指针限定添加到auto推导为指针的类型变量 |
readability-redundant-access-specifiers | 删除冗余的访问类型说明 |
readability-redundant-control-flow | 删除无用的return和continue |
readability-redundant-declaration | 删除冗余的变量和函数声明 |
readability-redundant-function-ptr-dereference | 删除多余的指针冗余 |
readability-redundant-member-init | 查找多余的成员初始化 |
readability-redundant-preprocessor | 查找潜在的冗余预处理器指令 |
readability-redundant-smartptr-get | 删除对智能指针.get()方法的冗余调用 |
readability-redundant-string-cstr | 检查不必要的调用:std::string::c_str()和std::string::data() |
readability-redundant-string-init | 查找不必要的字符串初始化 |
readability-simplify-boolean-expr | 简化对bool类型的使用 |
readability-simplify-subscript-expr | 简化下标表达式 |
readability-static-accessed-through-instance | 优化类静态成员的访问方式 |
readability-static-definition-in-anonymous-namespace | 检查匿名命名空间中的静态成员定义 |
readability-string-compare | 优化字符串比较的使用,尽量使用==或者!= |
readability-suspicious-call-argument | 传参缩写检查 |
readability-uniqueptr-delete-release | 替换 |
readability-uppercase-literal-suffix | 要求整数后缀为大写字符 |
readability-use-anyofallof |
Clang-Tidy静态代码分析框架
https://www.inktea.eu.org/2022/b47a.html