1

Clang Static Analyzer (4) Clang-Tidy

 1 year ago
source link: https://ost.51cto.com/posts/19857
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

#盲盒+码# Clang Static Analyzer (4) Clang-Tidy 原创 精华

Clang Static Analyzer (4) Clang-Tidy

【本文正在参加「盲盒」+码有奖征文活动】https://ost.51cto.com/posts/19288
前文介绍CodeChecker时,使用到了Clang-Tidy,我们来看看这个工具是什么,如何使用。主要是为了了解下背后的知识点,使用CodeChecker已经很好用了。

1、Clang-Tidy介绍

Clang-Tidy是一个基于Clang的C++ “linter” 工具。绝大部分lint工具只能在出现问题的代码地方给出提示,之后需要人为修改,而clang-tidy则能够自动修复功能。当然这个如何修复,需要该check作者提供。clang-tidy 的目的是为诊断和修复典型编程错误提供一个可扩展的框架,如样式违规、接口滥用或可以通过静态分析推断的缺陷。clang-tidy 是模块化的,提供了便利的接口来增加新的check检查器。如果用户想往clang-tidy添加一个新的检测功能,只需要编写一个clang-tidy check实现。每一个check检测一种问题,例如检测某个违反Code style的模式,检测某些API不正确使用的方法等。

2、Clang-Tidy使用入门

clang-tidy是一个基于LibTooling的工具,如果为项目设置编译命令数据库,clang-tidy更容易工作。如何设置编译命令数据的例子,请参阅如何设置 LLVM 的工具。您还可以在命令行--符号之后指定编译选项

clang-tidy test.cpp -- -Imy_project/include -DMY_DEFINES ...

clang-tidy有自己的checks检查器,也可以运行Clang Static Analyzer的checks检查器。每个check检查器都有一个名称,可以使用选项-checks=选择要运行的检查,该选项指定了以逗号分隔的正和 负(前缀为-)的globs模式。正模式为要添加的检查器集合,负的模式会删除检查器集合。例如,下面的例子将禁用所有的检查(-*),并且启用除 clang-analyzer-cplusplus* 之外的所有匹配clang-analyzer-*模式的检查器。

$ clang-tidy test.cpp -checks=-*,clang-analyzer-*,-clang-analyzer-cplusplus*

命令行选项-list-checks会列出所有已启用的检查。当不带选项-checks=时,它会显示默认启用的检查器。使用-checks=*时,会查看所有可用的检查器;指定具体值-checks=XXX时,会查看匹配该模式值的检查器。可用自己体验下。

clang-tidy -list-checks
clang-tidy -list-checks -checks=*
clang-tidy -list-checks -checks=-*,clang-analyzer-*,-clang-analyzer-cplusplus*

目前有以下检查组:

2.1 具体示例

可以使用之前的hello.c,看下怎么使用。如上文所说,一般不会直接使用clang-tidy,使用CodeChecker更好一些,需要了解下即可。

int main() {
  int x = 7 / 0; // bug here
  return 0;
}

执行如下命令:

clang-tidy hello.c
clang-tidy --checks=* hello.c

选择一条命令执行,输出类似下文的输出。可以看到输出了被各种检查器诊断出来的缺陷或者告警信息。

zhushangyuan@DESKTOP-RPE9R4O:~/CSA$ clang-tidy --checks=* hello.c
5 warnings generated.
/home/zhushangyuan/CSA/hello.c:2:7: warning: Value stored to 'x' during its initialization is never read [clang-analyzer-deadcode.DeadStores]
  int x = 7 / 0; // bug here
      ^
/home/zhushangyuan/CSA/hello.c:2:7: note: Value stored to 'x' during its initialization is never read
/home/zhushangyuan/CSA/hello.c:2:11: warning: 7 is a magic number; consider replacing it with a named constant [cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers]
  int x = 7 / 0; // bug here
          ^
/home/zhushangyuan/CSA/hello.c:2:13: warning: Division by zero [clang-analyzer-core.DivideZero]
  int x = 7 / 0; // bug here
            ^
/home/zhushangyuan/CSA/hello.c:2:13: note: Division by zero
/home/zhushangyuan/CSA/hello.c:2:13: warning: division by zero is undefined [clang-diagnostic-division-by-zero]
  int x = 7 / 0; // bug here
            ^

3、检查器分组

目前有以下检查器分组。不同的分组针对不同的检查对象,不同的开源项目Android、Fuchsia等,不同的编码规范等,可以针对性启用。

Name prefix Description
abseil- Checks related to Abseil library.
altera- Checks related to OpenCL programming for FPGAs.
android- Checks related to Android.
boost- Checks related to Boost library.
bugprone- Checks that target bug-prone code constructs.
cert- Checks related to CERT Secure Coding Guidelines.
clang-analyzer- Clang Static Analyzer checks.
concurrency- Checks related to concurrent programming (including threads, fibers, coroutines, etc.).
cppcoreguidelines- Checks related to C++ Core Guidelines.
darwin- Checks related to Darwin coding conventions.
fuchsia- Checks related to Fuchsia coding conventions.
google- Checks related to Google coding conventions.
hicpp- Checks related to High Integrity C++ Coding Standard.
linuxkernel- Checks related to the Linux Kernel coding conventions.
llvm- Checks related to the LLVM coding conventions.
llvmlibc- Checks related to the LLVM-libc coding standards.
misc- Checks that we didn’t have a better category for.
modernize- Checks that advocate usage of modern (currently “modern” means “C++11”) language constructs.
mpi- Checks related to MPI (Message Passing Interface).
objc- Checks related to Objective-C coding conventions.
openmp- Checks related to OpenMP API.
performance- Checks that target performance-related issues.
portability- Checks that target portability-related issues that don’t relate to any particular coding style.
readability- Checks that target readability-related issues that don’t relate to any particular coding style.
zircon- Checks related to Zircon kernel coding conventions.

Clang语言的静态分析和clang-tidy检查器的静态分析类似。Clang的静态分析会被clang-tidy展示,也会通过选项-checks=被过滤掉。然而,这些检查器的过滤不会影响编译参考,因此它不能打开已经在构建配置中关闭的Clang告警开关。-warnings-as-errors= 选项会把-checks=选项的检查器检测出的告警信息升级为错误信息。

Clang静态分析诊断的检查器名称以clang-diagnostic-开头。对应每一个告警选项的分析诊断,其名称格式为are named clang-diagnostic-<warning-option>。例如,被编译选项-Wliteral-conversion控制的Clang告警,会被名为clang-diagnostic-literal-conversion的检查器来分析并报告。

The -fix flag instructs clang-tidy to fix found errors if supported by corresponding checks.

有个比较重要的选项,--fix,开启这个选项clang-tidy会修复发现的错误,在对应的检查器支持的情况下。哪些检查器支持自动修复,可以参考下文中检查器列表中的Offers fixes字段。使用clang-tidy --help可以查看帮助信息,我们这里主要看下--fix相关的帮助信息。开启这个选项--fix,clang-tidy会修复发现的错误。没有指定--fix-errors选项时,如果发现编译错误,clang-tidy会跳过修复。在指定--fix-errors选项时,即使发现编译错误,也会继续修复。

  --fix                          -
                                   Apply suggested fixes. Without -fix-errors
                                   clang-tidy will bail out if any compilation
                                   errors were found.
  --fix-errors                   -
                                   Apply suggested fixes even if compilation
                                   errors were found. If compiler errors have
                                   attached fix-its, clang-tidy will apply them as
                                   well.

没有亲自体验过,执行下面的命令,如果发现示例文件中的未使用的声明using declarations的告警信息,就会自动修复删除掉。

// 找出simple.cc中所有没有用到的using declarations并自动fix(删除掉)
$ clang-tidy -checks="-*,misc-unused-using-decls" -fix path/to/simple.cc --

4、检查器列表

Clang-Tidy 现在支持<mark>四五百个</mark>Checks检查器,详细列表可以访问clang-tidy - Clang-Tidy Checks — Extra Clang Tools 16.0.0git documentation获取。可以看到对于这些检查器,是否支持自动修复错误。对于这些检查器,也是很好的学习资源,可以看看这些检查器的会修复什么类型的缺陷,以后写代码的时候,避免编写这些的缺陷,提升编程能力和素养。

  • Clang-Tidy Checks列表片段

5、学习些检查器

在使用clang-tidy检查报告,可以详细了解下检查器的知识,可以有助于我们理解这些检查规则,有助于如何修复。挑选几个学习下。

5.1 readability-duplicate-include

详细链接在https://clang.llvm.org/extra/clang-tidy/checks/readability/duplicate-include.html。

Looks for duplicate includes and removes them. The check maintains a list of included files and looks for duplicates. If a macro is defined or undefined then the list of included files is cleared.

查找重复的include语句并删除它们。该检查器维护一个include文件列表,然后查找重复项。如果已定义或取消定义宏,include文件列表会被清理。

示例如下:

#include <memory>
#include <vector>
#include <memory>

修复方法:

#include <memory>
#include <vector>

如下示例,因为中间出现宏定义,不会识别出重复include,代码不会被自动修复。

#undef NDEBUG
#include "assertion.h"
// ...code with assertions enabled

#define NDEBUG
#include "assertion.h"
// ...code with assertions disabled

5.2 readability-delete-null-pointer

详细链接在https://clang.llvm.org/extra/clang-tidy/checks/readability/delete-null-pointer.html。

在if语句里,如果检测指针是否存在,然后删除。这样的检查是没有必要的,因为删除空指针没有任何左右,属于可以删除的冗余代码。

int *p;
if (p)
  delete p;

5.3 misc-unused-parameters

详细链接在https://clang.llvm.org/extra/clang-tidy/checks/misc/unused-parameters.html。

查找未使用的函数参数。未使用的参数可能意味着代码缺陷,例如,当使用不同的参数代替时。建议的修复要么是注释参数名称或完全删除参数,只要函数的调用方位于同一翻译单元中,并且可以修改。

该检查器类似于编译器诊断选项-Wunused-parameter,可以用于准备代码库以启用该诊断。默认情况下,该检查器比较宽松。

void a(int i) { /*some code that doesn't use `i`*/ }

// becomes

void a(int  /*i*/) { /*some code that doesn't use `i`*/ }
static void staticFunctionA(int i);
static void staticFunctionA(int i) { /*some code that doesn't use `i`*/ }

// becomes

static void staticFunctionA()
static void staticFunctionA() { /*some code that doesn't use `i`*/ }

6、参考站点

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
标签

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK