【问题标题】:clang-tidy: How to suppress warnings?clang-tidy:如何抑制警告?
【发布时间】:2017-01-24 10:15:24
【问题描述】:

我最近开始尝试 llvm 的 clang-tidy 工具。现在我试图抑制来自第三方库代码的错误警告。为此,我想使用命令行选项

-header-filter=<string>-line-filter=<string>

但到目前为止还没有成功。所以对于时间有限的人,我会把问题放在开头,稍后再解释我已经尝试过的内容。

问题

我需要为clang-tidy 工具提供什么选项来禁止来自特定行和文件的警告?

如果这是不可能的

什么选项可以抑制来自外部头文件的警告?


到目前为止我做了什么

我最初对 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=&lt;string&gt; 选项。此处文档指出,必须提供一个正则表达式,该表达式与应显示诊断的所有头文件匹配。好的,我想,让我们使用一个正则表达式来匹配与分析的 .cpp 文件位于同一文件夹中的所有内容。我可以忍受,尽管它可能会删除因我使用错误的外部标头而导致的警告。

这里我不确定正则表达式是必须匹配完整(绝对)文件名还是只匹配文件名的一部分。我试过了

-header-filter=.*\/CodeAssistant\/.*.h

它匹配 CodeAssistant 文件夹中的所有绝对头文件名,但它没有抑制来自 gmock-spec-builders.h 文件的警告。

所以最好我想单独抑制每个警告,这样我就可以确定每个警告是否是一个真正的问题,但如果这不可能,我也可以抑制来自整个外部标题的警告。

感谢您的宝贵时间。

【问题讨论】:

    标签: suppress-warnings clang-static-analyzer clang-tidy


    【解决方案1】:

    我通过在 gmock-spec-builders.h

    1790 行添加 // NOLINT 解决了这个问题

    这里是差异:

    --- 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)或与 clang-tidy 的人一起发布错误报告。

    【讨论】:

    • Here 是我在 github 上与 googletest 人员的讨论。他们本可以提到他们已经压制了警告。我懒得注册 llvm 邮件列表来发布误报。哪些工具理解 // NOLINT 注释?
    • // NOLINT 由 clang 工具拾取。通过阅读讨论,我认为这并不是真正的误报,它更像是“永远”不会发生的事情。所以我认为最好的方法是 NOLINT 解决方案。
    • 奇怪的是,您的修复并不能在所有情况下为我解决问题。我还必须将 // NOLINT 放在第 1272 行 return function_mocker_-&gt;AddNewExpectation( // NOLINT 后面
    • 我想我还是会建议对 googletest 进行更改,因为我无法使用命令行选项抑制警告。但是如果依赖关系不能改变怎么办。然后你必须把 // NOLINT 到处都是有点难看的地方。
    【解决方案2】:

    我无法通过命令行选项实现我想要的,所以我将在 cpp 文件中使用// NOLINT cmets,这是由接受的答案提出的。

    我也会尝试将修复推送到 googletest。

    我发现-line-filter 选项中的行被过滤了。 但无论如何,给出具体的线条并不能真正解决我的问题。 我宁愿需要一种抑制机制,就像在 Valgrind 中实现的那样。

    【讨论】:

      【解决方案3】:

      我发现了另一种非侵入式(不向第三方库添加// NOLINT)方法来抑制警告。例如,当前版本的 Google 测试未通过某些 cppcoreguidelines-* 检查。以下代码允许您验证当前差异,不包括包含 gtest 宏的行:

      git diff -U3 | sed '
          s/^+\( *TEST(\)/ \1/;
          s/^+\( *EXPECT_[A-Z]*(\)/ \1/;
          s/^+\( *ASSERT_[A-Z]*(\)/ \1/;
      ' | recountdiff | interdiff -U0 /dev/null /dev/stdin | clang-tidy-diff.py -p1 -path build
      

      它假定文件build/compile_commands.json 是之前生成的,并且clang-tidy-diff.py 在您的环境中可用。来自patchutilsrecountdiffinterdiff 是处理补丁的标准工具。

      脚本的工作方式如下:

      1. git diff -U3 生成一个包含 3 个上下文行的补丁。
      2. sed ... 从不需要的行中删除前缀 +,即将它们转换为上下文。
      3. recountdiff 块头中的正确偏移量(在第一个范围内)。
      4. interdiff -U0 /dev/null /dev/stdin 只是从补丁中删除所有上下文行。结果,它分裂了最初的大块。
      5. clang-tidy-diff.py 仅从块头读取第二个范围,并通过 -line-filter 选项将它们传递给 clang-tidy

      UPD:interdiff 提供足够数量的上下文行非常重要,否则可能会在结果中产生一些伪影。参见man interdiff的引用:

      为获得最佳结果,差异必须至少包含三行上下文。

      特别是,我发现git diff -U0 | ... | interdiff 在拆分块后会生成一些虚假的文字$!otj

      【讨论】:

        【解决方案4】:

        使用-isystem 而不是-I 来设置您的系统和第3 方包含路径。 -I 只能用于包含正在构建的项目中的代码。

        这是使clang-tidy 忽略外部代码中的所有错误的唯一要求。对于-isystem 完美解决的问题,所有其他答案(在撰写本文时)只是糟糕的解决方法。

        如果您使用 CMake 或 Meson 等构建系统,它会自动为您正确设置 -I-isystem

        -isystem 也是用于告诉编译器(至少是 GCC 和 Clang)什么不是您的代码的机制。如果您开始使用-isystem,您还可以启用更多编译器警告,而不会从外部代码中获得“误报”。

        【讨论】:

        • 这听起来很有趣。我将无法立即检查它是否有效。但也许在圣诞假期。
        • 我遇到的唯一问题是如何从这些系统标头中禁用扩展宏的错误和警告。
        猜你喜欢
        • 2021-09-04
        • 2021-06-03
        • 2018-04-10
        • 2019-05-08
        • 1970-01-01
        • 2011-06-24
        • 2019-02-25
        • 2011-03-18
        相关资源
        最近更新 更多