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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 生成compile_commands.json
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
set(CLANG_TIDY_FIX OFF)

if (UNIX)
# Ubuntu路径为/usr/bin/,Centos路径为/opt/rh/llvm-toolset-7/root/usr/bin/
set(CLANG-TIDY-EXE "/usr/bin/clang-tidy")
endif()
if (EXISTS "${CLANG-TIDY-EXE}")
message(STATUS "use clang-tidy to check")
# 关闭所有默认规则,检查指向NULL/0的指针(如果-fix,则转化为nullptr)
# 指定CMake构建目录,用于读取compile_commands.json
# 导出建议修复文件到clang-tidy-fixes.yml
set(CMAKE_CXX_CLANG_TIDY "${CLANG-TIDY-EXE};-checks=-*,modernize-use-nullptr;-p=${CMAKE_BINARY_DIR};-export-fixes=clang-tidy-fixes.yml")
if(CLANG_TIDY_FIX)
message(STATUS "apply suggested fix" )
set(CMAKE_CXX_CLANG_TIDY "${CMAKE_CXX_CLANG_TIDY};-fix")
endif()
endif()

# 注意:需要把CMAKE_CXX_CLANG_TIDY赋值,放在add_executable或add_library前面

支持的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 替换.release()为 = nullptr
readability-uppercase-literal-suffix 要求整数后缀为大写字符
readability-use-anyofallof