使用#pragma基于clang check来消除clang警告

4

我希望移除/忽略一段代码的clang警告,发现多个使用指令(pragama)的例子。例如,如果警告是unused-variable,您可以通过以下方式禁用它:

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-variable"

int a;

#pragma clang diagnostic pop

然而问题在于,当构建存储库时,输出中没有任何警告,我只知道哪个clang检查会给出警告......我找不到其他任何问题或文档与此相符。这是我的输出结果:
warning: Use of memory after it is freed [clang-analyzer-cplusplus.NewDelete]

我尝试了数百种忽略此问题的不同组合,但都无效(使用// NOLINT不是可行的选项)。以下是我尝试过的一些方法:

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Winline-new-delete"
#pragma clang diagnostic ignored "-Wmost"
#pragma clang diagnostic ignored "-Weverything"
#pragma clang diagnostic ignored "clang-analyzer-cplusplus.NewDelete"
#pragma clang diagnostic ignored "-Wclang-analyzer-cplusplus.NewDelete"
#pragma clang diagnostic ignored "-clang-analyzer-cplusplus.NewDelete"
#pragma clang diagnostic ignored "-W-NewDelete"
#pragma clang diagnostic ignored "-W-new-delete"

// code

#pragma clang diagnostic pop

请注意,修复代码也不是一个选项,因为它是第三方代码。

顺便提一下,即使是为了一个变量而禁用这个警告也是很危险的,你确定要这样做吗? - Afshin
@Afshin 确实是这样...但这不是我的代码,我也没有意图去改变它...我从未遇到过问题,并且查看源代码似乎警告根本不可能发生。我对clang还很陌生,但它似乎并不总是完全符合实际情况,关于哪些事件实际上可能发生。 - JakobVinkas
你的构建系统是什么?CMake? - Afshin
@Afshin 我正在使用CMake和Ninja。 - JakobVinkas
3个回答

3

如评论所述,#pragma clang diagnostic方法只能用于禁止编译器警告。您提到的警告来自clang-static-analyzer,现在已经成为clang-tidy的一部分。

通过代码禁用特定的clang-tidy检查只有两个选项://NOLINT//NOLINTNEXTLINE宏。

由于您提到的代码是第三方的,我将假设您没有兴趣对其进行分析。既然您正在使用CMake,那么可以通过.clang-tidy文件轻松实现。您可以将.clang-tidy文件放置在项目的根目录中,并在其中列出/配置所需的检查,例如:

Checks: '-*,cppcoreguidelines-*'

这将启用所有的 Cpp 核心指南检查。

在第三方代码所在的目录中,您可以通过放置一个名为 .clang-tidy 的文件来禁用 clang-tidy 分析。由于 .clang-tidy 文件不能是空的或指定不进行任何检查,您可以通过“错误配置”一个检查来实现此操作,例如:

Checks: '-*,misc-definitions-in-headers'
CheckOptions:
  - { key: HeaderFileExtensions,          value: "x" }

有关这种方法的更多详细信息,请参见此答案

或者,您可以使用第三方目录中的.clang-tidy文件仅禁用某些检查。


2
根据这个链接,对于Clang静态分析器,您需要使用以下内容:
#ifndef __clang_analyzer__
// code
#endif

1
这似乎完全“删除”了代码,现在我收到其他检查([clang-analyzer-deadcode.DeadStores])的警告,声称上方代码块中的代码现在有未使用的变量。这是它应该做的吗?还是我实现有误? - JakobVinkas

0
我脑海中想到的最佳方法有点依赖于您的构建系统。假设您有这样的示例代码:
主文件:
int main()
{
    // ...
    int *a = new int;
    *a = 10;
    delete a;

    if (::rand() < 10) {
        std::cout  << *a; //<-- clang tidy warning here
    }
    //...
}

这会在提到的行创建clang tidy警告。现在你能做什么呢?将你的代码分成两个文件:

文件A:

void foo() {
    int *a = new int;
    *a = 10;
    delete a;

    if (::rand() < 10) {
        std::cout  << *a; //<-- clang tidy warning here
    }
}

主文件:

int main()
{
    // ...
    foo();
    //...
}

现在禁用 cland-tidy 对于 文件A。这只是一个示例,但我想你理解我的一般想法。你不能禁用 clang-tidy,因为它在另一个库中,而且由于几个原因,你不能触及那段代码。 //NOLINT 在函数上也不起作用。所以只需在单个文件中创建一个包装器来使用该库,并在该包装器文件中禁用整个文件的 clang-tidy


那么没有办法使用#pragma方法来消除我得到的警告类型吗?我非常希望不要改变太多的结构和#pragma似乎是完美的解决方案,但我不明白何时使用它,因为我从未收到过像#pragma示例中呈现的警告。 - JakobVinkas
@JakobVinkas 我认为你有些误解。你得到的警告来自于 clang-tidy,而不是 clang(我在启用 clang-tidy 之前没有收到你的警告)。另一方面,#pragma clang diagnostic 可以禁用 clang 的警告,但不能禁用 clang-tidy 的警告。唯一禁用 clang-tidy 警告的方法是使用 //NOLINT 注释,因此您无法使用 #pragma 来禁用 clang-tidy 警告。 - Afshin
那么,当警告来自对第三方代码库的函数调用时,重构代码和文件忽略是唯一可行的选择? - JakobVinkas
@JakobVinkas 这是我能想到的唯一方法。更具体地说,我自己没有测试过,但理论上应该可以工作。您可以在一个小示例(例如我的示例)上进行测试,然后再应用于整个项目。另一种方法是禁用整个项目或使用库的文件的clang-tidy。但是,如果这样做,您可能会错过其他clang-tidy警告。但是,如果它已经启用,您可能希望它:D - Afshin
我该如何禁用 clang-tidy 中的单个文件检查?显然我对 clang-tidy 还很陌生 ;) 我有一个 CMake 文件,其中包含 set(CLANG_TIDY_ARGS --checks=clang-analyzer-cplusplus.*),但这是一个相当大的项目,我找不到在哪里选择应该被检查的文件... - JakobVinkas
@JakobVinkas 在CMake中禁用单个文件可能是一种有点巧妙的方法。但是,你从CMake发送给我的那行代码似乎是运行clang-tidy的自定义方式。你需要检查整个CMake文件以了解它们如何集成它。 - Afshin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接