clang-tidy: 如何抑制警告?
clang-tidy: How to suppress warnings?
我最近开始尝试使用 llvm 的 clang-tidy
工具。现在我正试图抑制来自第三方库代码的错误警告。为此,我想使用命令行选项
-header-filter=<string>
或 -line-filter=<string>
但到目前为止还没有成功。所以对于时间有限的人,我会把问题放在一开始,然后再解释我已经尝试过的东西。
问题
我需要给 clang-tidy
工具什么选项来抑制来自特定行和文件的警告?
如果这不可能
什么选项可以抑制来自外部 header 文件的警告?
到目前为止我做了什么
我对 clang-tidy 的原始调用如下所示
clang-tidy-3.8 -checks=-*,clang-analyzer-*,-clang-analyzer-alpha* -p Generated/LinuxMakeClangNoPCH Sources/CodeAssistant/ModuleListsFileManipulator_fixtures.cpp
我想抑制的生成警告的第一行看起来像这样
.../gmock/gmock-spec-builders.h:1272:5: warning: Use of memory after it is freed [clang-analyzer-cplusplus.NewDelete]
return function_mocker_->AddNewExpectation(
gmock 的人告诉我这是误报所以我想压制它。首先,我尝试使用 -line-filter=<string>
选项。文档说:
-line-filter=<string> - List of files with line ranges to filter the
warnings. Can be used together with
-header-filter. The format of the list is a JSON
array of objects:
[
{"name":"file1.cpp","lines":[[1,3],[5,7]]},
{"name":"file2.h"}
]
我假设给定行中的警告已被过滤掉。但是文档没有说明它们是被过滤掉还是被过滤掉了。
经过一番摆弄之后,我创建了一个内容为
的 .json 文件
[
{"name":"gmock-spec-builders.h","lines":[[1272,1272]]}
]
并将命令行修改为
clang-tidy-3.8 -checks=-*,clang-analyzer-*,-clang-analyzer-alpha* -p Generated/LinuxMakeClangNoPCH -line-filter="$(< Sources/CodeAssistant/CodeAssistant_ClangTidySuppressions.json)" Sources/CodeAssistant/ModuleListsFileManipulator_fixtures.cpp
将文件内容写入参数。这会抑制警告,但不仅会抑制此警告,还会抑制 ModuleListsFileManipulator_fixtures.cpp 文件中的所有警告。我尝试了更多的东西,但我无法让它工作。
所以我尝试了 -header-filter=<string>
选项。 Here the documentation states that one has to give a regular expression that matches all header files from which diagnostics should be displayed. 这里的文档指出,必须给出一个正则表达式来匹配所有 header 文件,从中显示诊断信息。好的,我想,让我们使用一个正则表达式来匹配与分析的 .cpp 文件位于同一文件夹中的所有内容。我可以接受,尽管它可能会删除我使用外部 headers 错误导致的警告。
这里我不确定正则表达式必须匹配完整(绝对)文件名还是只匹配文件名的一部分。我试过了
-header-filter=.*\/CodeAssistant\/.*.h
它匹配 CodeAssistant 文件夹中的所有绝对 header 文件名,但它没有抑制来自 gmock-spec-builders.h 文件的警告。
所以最好我想单独抑制每个警告,这样我就可以确定每个警告是否是真正的问题,但如果这不可能,我也可以忍受抑制来自整个外部的警告 headers.
感谢您的宝贵时间。
我通过将 // NOLINT 添加到 gmock-spec-[=23 的第 1790 行解决了这个问题=]
差异如下:
--- gmock-spec-builders.orig.h 2016-09-17 09:46:48.527313088 +0200
+++ gmock-spec-builders.h 2016-09-17 09:46:58.958353697 +0200
@@ -1787,7 +1787,7 @@
#define ON_CALL(obj, call) GMOCK_ON_CALL_IMPL_(obj, call)
#define GMOCK_EXPECT_CALL_IMPL_(obj, call) \
- ((obj).gmock_##call).InternalExpectedAt(__FILE__, __LINE__, #obj, #call)
+ ((obj).gmock_##call).InternalExpectedAt(__FILE__, __LINE__, #obj, #call) // NOLINT
#define EXPECT_CALL(obj, call) GMOCK_EXPECT_CALL_IMPL_(obj, call)
#endif // GMOCK_INCLUDE_GMOCK_GMOCK_SPEC_BUILDERS_H_
最好将此补丁上游(我在代码中看到其他 NOLINT)或 post 与 clang-tidy 人员的错误报告。
我无法通过命令行选项实现我想要的,所以我将使用接受的答案提出的 cpp 文件中的 // NOLINT
注释。
我也会尝试将修复推送到 googletest。
我发现 -line-filter
选项中的行被过滤掉了。
但是无论如何,给出具体的线条并不能真正解决我的问题。
我更需要一个抑制机制,就像在 Valgrind 中实现的那样。
我找到了另一种非侵入式(无需向第三方库添加 // NOLINT
)抑制警告的方法。例如,当前版本的 Google 测试未通过某些 cppcoreguidelines-*
检查。以下代码允许您验证当前差异,但不包括包含 gtest 宏的行:
git diff -U3 | sed '
s/^+\( *TEST(\)/ /;
s/^+\( *EXPECT_[A-Z]*(\)/ /;
s/^+\( *ASSERT_[A-Z]*(\)/ /;
' | recountdiff | interdiff -U0 /dev/null /dev/stdin | clang-tidy-diff.py -p1 -path build
它假定文件 build/compile_commands.json
之前已生成并且 clang-tidy-diff.py
可从您的环境中获得。 patchutils 中的 recountdiff
和 interdiff
是处理补丁的标准工具。
脚本的工作原理如下:
git diff -U3
生成一个包含 3 个上下文行的补丁。
sed ...
从不需要的行中删除前缀 +
,即将它们转换为上下文。
recountdiff
块头中的正确偏移量(在第一个范围内)。
interdiff -U0 /dev/null /dev/stdin
只是从补丁中删除所有上下文行。结果,它分裂了最初的大块头。
clang-tidy-diff.py
仅从块头读取第二个范围,并通过 -line-filter
选项将它们传递给 clang-tidy
。
UPD: 为 interdiff
提供足够数量的上下文行很重要,否则可能会在结果中产生一些伪影。请参阅 man interdiff
中的引文:
For best results, the diffs must have at least three lines of context.
特别是,我发现 git diff -U0 | ... | interdiff
在拆分块后生成了一些虚假文字 $!otj
。
使用 -isystem
而不是 -I
来设置您的系统和第 3 方包含路径。 -I
应该只用于包含正在构建的项目中的代码。
这是使 clang-tidy
忽略外部代码中所有错误的唯一要求。所有其他答案(在撰写本文时)都只是用 -isystem
.
完美解决的问题的糟糕解决方法
如果您使用 CMake 或 Meson 等构建系统,它会自动为您正确设置 -I
和 -isystem
。
-isystem
也是用于告诉编译器(至少是 GCC 和 Clang)什么不是您的代码的机制。如果您开始使用 -isystem
,您还可以启用更多编译器警告,而不会从外部代码中获得“误报”。
我最近开始尝试使用 llvm 的 clang-tidy
工具。现在我正试图抑制来自第三方库代码的错误警告。为此,我想使用命令行选项
-header-filter=<string>
或 -line-filter=<string>
但到目前为止还没有成功。所以对于时间有限的人,我会把问题放在一开始,然后再解释我已经尝试过的东西。
问题
我需要给 clang-tidy
工具什么选项来抑制来自特定行和文件的警告?
如果这不可能
什么选项可以抑制来自外部 header 文件的警告?
到目前为止我做了什么
我对 clang-tidy 的原始调用如下所示
clang-tidy-3.8 -checks=-*,clang-analyzer-*,-clang-analyzer-alpha* -p Generated/LinuxMakeClangNoPCH Sources/CodeAssistant/ModuleListsFileManipulator_fixtures.cpp
我想抑制的生成警告的第一行看起来像这样
.../gmock/gmock-spec-builders.h:1272:5: warning: Use of memory after it is freed [clang-analyzer-cplusplus.NewDelete]
return function_mocker_->AddNewExpectation(
gmock 的人告诉我这是误报所以我想压制它。首先,我尝试使用 -line-filter=<string>
选项。文档说:
-line-filter=<string> - List of files with line ranges to filter the
warnings. Can be used together with
-header-filter. The format of the list is a JSON
array of objects:
[
{"name":"file1.cpp","lines":[[1,3],[5,7]]},
{"name":"file2.h"}
]
我假设给定行中的警告已被过滤掉。但是文档没有说明它们是被过滤掉还是被过滤掉了。 经过一番摆弄之后,我创建了一个内容为
的 .json 文件[
{"name":"gmock-spec-builders.h","lines":[[1272,1272]]}
]
并将命令行修改为
clang-tidy-3.8 -checks=-*,clang-analyzer-*,-clang-analyzer-alpha* -p Generated/LinuxMakeClangNoPCH -line-filter="$(< Sources/CodeAssistant/CodeAssistant_ClangTidySuppressions.json)" Sources/CodeAssistant/ModuleListsFileManipulator_fixtures.cpp
将文件内容写入参数。这会抑制警告,但不仅会抑制此警告,还会抑制 ModuleListsFileManipulator_fixtures.cpp 文件中的所有警告。我尝试了更多的东西,但我无法让它工作。
所以我尝试了 -header-filter=<string>
选项。 Here the documentation states that one has to give a regular expression that matches all header files from which diagnostics should be displayed. 这里的文档指出,必须给出一个正则表达式来匹配所有 header 文件,从中显示诊断信息。好的,我想,让我们使用一个正则表达式来匹配与分析的 .cpp 文件位于同一文件夹中的所有内容。我可以接受,尽管它可能会删除我使用外部 headers 错误导致的警告。
这里我不确定正则表达式必须匹配完整(绝对)文件名还是只匹配文件名的一部分。我试过了
-header-filter=.*\/CodeAssistant\/.*.h
它匹配 CodeAssistant 文件夹中的所有绝对 header 文件名,但它没有抑制来自 gmock-spec-builders.h 文件的警告。
所以最好我想单独抑制每个警告,这样我就可以确定每个警告是否是真正的问题,但如果这不可能,我也可以忍受抑制来自整个外部的警告 headers.
感谢您的宝贵时间。
我通过将 // NOLINT 添加到 gmock-spec-[=23 的第 1790 行解决了这个问题=]
差异如下:
--- gmock-spec-builders.orig.h 2016-09-17 09:46:48.527313088 +0200
+++ gmock-spec-builders.h 2016-09-17 09:46:58.958353697 +0200
@@ -1787,7 +1787,7 @@
#define ON_CALL(obj, call) GMOCK_ON_CALL_IMPL_(obj, call)
#define GMOCK_EXPECT_CALL_IMPL_(obj, call) \
- ((obj).gmock_##call).InternalExpectedAt(__FILE__, __LINE__, #obj, #call)
+ ((obj).gmock_##call).InternalExpectedAt(__FILE__, __LINE__, #obj, #call) // NOLINT
#define EXPECT_CALL(obj, call) GMOCK_EXPECT_CALL_IMPL_(obj, call)
#endif // GMOCK_INCLUDE_GMOCK_GMOCK_SPEC_BUILDERS_H_
最好将此补丁上游(我在代码中看到其他 NOLINT)或 post 与 clang-tidy 人员的错误报告。
我无法通过命令行选项实现我想要的,所以我将使用接受的答案提出的 cpp 文件中的 // NOLINT
注释。
我也会尝试将修复推送到 googletest。
我发现 -line-filter
选项中的行被过滤掉了。
但是无论如何,给出具体的线条并不能真正解决我的问题。
我更需要一个抑制机制,就像在 Valgrind 中实现的那样。
我找到了另一种非侵入式(无需向第三方库添加 // NOLINT
)抑制警告的方法。例如,当前版本的 Google 测试未通过某些 cppcoreguidelines-*
检查。以下代码允许您验证当前差异,但不包括包含 gtest 宏的行:
git diff -U3 | sed '
s/^+\( *TEST(\)/ /;
s/^+\( *EXPECT_[A-Z]*(\)/ /;
s/^+\( *ASSERT_[A-Z]*(\)/ /;
' | recountdiff | interdiff -U0 /dev/null /dev/stdin | clang-tidy-diff.py -p1 -path build
它假定文件 build/compile_commands.json
之前已生成并且 clang-tidy-diff.py
可从您的环境中获得。 patchutils 中的 recountdiff
和 interdiff
是处理补丁的标准工具。
脚本的工作原理如下:
git diff -U3
生成一个包含 3 个上下文行的补丁。sed ...
从不需要的行中删除前缀+
,即将它们转换为上下文。recountdiff
块头中的正确偏移量(在第一个范围内)。interdiff -U0 /dev/null /dev/stdin
只是从补丁中删除所有上下文行。结果,它分裂了最初的大块头。clang-tidy-diff.py
仅从块头读取第二个范围,并通过-line-filter
选项将它们传递给clang-tidy
。
UPD: 为 interdiff
提供足够数量的上下文行很重要,否则可能会在结果中产生一些伪影。请参阅 man interdiff
中的引文:
For best results, the diffs must have at least three lines of context.
特别是,我发现 git diff -U0 | ... | interdiff
在拆分块后生成了一些虚假文字 $!otj
。
使用 -isystem
而不是 -I
来设置您的系统和第 3 方包含路径。 -I
应该只用于包含正在构建的项目中的代码。
这是使 clang-tidy
忽略外部代码中所有错误的唯一要求。所有其他答案(在撰写本文时)都只是用 -isystem
.
如果您使用 CMake 或 Meson 等构建系统,它会自动为您正确设置 -I
和 -isystem
。
-isystem
也是用于告诉编译器(至少是 GCC 和 Clang)什么不是您的代码的机制。如果您开始使用 -isystem
,您还可以启用更多编译器警告,而不会从外部代码中获得“误报”。