Skip to content

[clang-tidy] NOLINT not working in macros in clang-tidy-14 (regression) #55134

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
paulaltin opened this issue Apr 27, 2022 · 18 comments
Closed
Assignees

Comments

@paulaltin
Copy link
Contributor

paulaltin commented Apr 27, 2022

Clang-tidy version 13 generates no warnings for this code:

#define CREATE_STRUCT(name)    \
struct name {	/* NOLINT */   \
    int a = 0;                 \
    int b;                     \
}; 				

CREATE_STRUCT(X)
CREATE_STRUCT(Y)
CREATE_STRUCT(Z)

when invoked as:

clang-tidy-13 test.cpp -checks=cppcoreguidelines-pro-type-member-init

Clang-tidy version 14 generates warnings on lines 7-9 when invoked the same way.

@paulaltin
Copy link
Contributor Author

It appears from the summary of this patch that the intention is for "clang-tidy [to] look at the line of macro invocation and every line of macro definition for a NOLINT comment."

https://reviews.llvm.org/D24845

@paulaltin
Copy link
Contributor Author

If anyone knows of a workaround for this (short of marking every use of the macro with NOLINT), I would be very grateful. Adding NOLINT to every line that uses the macro isn't possible in my case, but I can modify the macro definition.

@llvmbot
Copy link
Member

llvmbot commented Apr 27, 2022

@llvm/issue-subscribers-clang-tidy

@firewave
Copy link

I encountered a similar issue with NOLINTNEXTLINE quite a while ago - see #46511.

@paulaltin
Copy link
Contributor Author

@firewave – interesting, thanks for the info! Did you ever find a solution/workaround?

It looks like this issue is also specific to this check, and doesn't actually have anything to do with the macro having multiple lines – if I put the entire macro on one line the problem still occurs:

// NOLINTNEXTLINE
#define CREATE_STRUCT_ONELINE(name) struct name { int a = 0; int b; }; // NOLINT

Either of the NOLINTNEXTLINE and NOLINT comments were enough to suppress the warning in version 13, but neither works in version 14.

Other warnings can be suppressed as expected, even in multi-line macros, e.g. the NOLINT comment here works to suppress the readability-use-anyofallof warning in both versions:

#include <vector>

#define CREATE_FUNCTION(name)           \
bool name() {                           \
    std::vector<int> v;                 \
    for (auto el : v)  /* NOLINT */     \
        if (el != 0)                    \
            return false;               \
    return true;                        \
}

CREATE_FUNCTION(F)

@paulaltin paulaltin changed the title [clang-tidy] NOLINT not working in multi-line macros in clang-tidy-14 (regression) [clang-tidy] NOLINT does not suppress cppcoreguidelines-pro-type-member-init warnings in clang-tidy-14 (regression) Apr 28, 2022
@paulaltin paulaltin changed the title [clang-tidy] NOLINT does not suppress cppcoreguidelines-pro-type-member-init warnings in clang-tidy-14 (regression) [clang-tidy] NOLINT does not suppress cppcoreguidelines-pro-type-member-init warnings in macros using clang-tidy-14 (regression) Apr 28, 2022
@Skylion007
Copy link

I am encountering similar issues with google-explicit-constructor when trying to update clang-tidy to 14 for pybind11: https://github.com/pybind/pybind11/blob/2e331308d38a521c087e7fc0cfee227cd29f3f71/include/pybind11/pytypes.h#L1029 . NOLINTS are ignored. Interestingly, the 'bugprone-macro-*' NOLINT comments seem to work fine. Even NOLINTBEGIN NOLINTEND do not work when used in the multiline macro.

@Skylion007
Copy link

@paulaltin This implies the issue is not specific to this check, feel free to update the title.

@paulaltin paulaltin changed the title [clang-tidy] NOLINT does not suppress cppcoreguidelines-pro-type-member-init warnings in macros using clang-tidy-14 (regression) [clang-tidy] NOLINT not working in macros in clang-tidy-14 (regression) May 11, 2022
@paulaltin
Copy link
Contributor Author

paulaltin commented May 11, 2022

Checks known to have regressed in version 14:

  • cppcoreguidelines-pro-type-member-init
  • google-explicit-constructor

Checks known to have regressed in version 13:

  • google-explicit-constructor

Checks that were not working before version 13/14:

  • modernize-avoid-c-arrays

@Skylion007
Copy link

Skylion007 commented May 11, 2022

@paulaltin I have confirmed that the 'google-explicit ctor' seems to have actually regressed in version 13 as well (at least the latest minor release of it).

@paulaltin
Copy link
Contributor Author

Thanks @Skylion007 – I've updated the comment above.

@Skylion007
Copy link

I don't have that much experience in the clang-tidy code base, but trying to look around the codebase, I am bit suspicious of this commit: b9d9968, but I don't see anything obvious that changed in these checks that could have broken them between 12-13 and 13-14.

I also noticed a lot of the other checks that are working have preprocessor callbacks.

I am really not familiar with the codebase though so I am bit unsure where the regression is coming. Any thoughts @EugeneZelenko ?

@paulaltin
Copy link
Contributor Author

Looks like that commit was authored by @HighCommander4, perhaps they can help?

@HighCommander4
Copy link
Collaborator

HighCommander4 commented May 18, 2022

Stepping through the code suggests that this loop iterates twice, and checks the line CHECK_STRUCT(X) for a NOLINT comment both times, when the intention is clearly to check the CHECK_STRUCT(X) line in one iteration, and the struct Name { /* NOLINT */ line on the other.

@HighCommander4
Copy link
Collaborator

Looks to be a regression from 5da7c04, cc @salman-javed-nz

@HighCommander4
Copy link
Collaborator

HighCommander4 commented May 18, 2022

The regression is caused by a change made in that patch to how the location to be checked is updated from one iteration of the loop to the next.

Before the patch:

Loc = SM.getImmediateExpansionRange(Loc).getBegin();

After the patch:

DiagLoc = SrcMgr.getImmediateMacroCallerLoc(DiagLoc);

These two functions have slightly different behaviour, specifically in the case where getImmediateMacroCallerLoc() takes this early exit, which happens in this code example.

I'm not sure why the patch made this change; it seems unrelated to the purpose of the patch.

@salman-javed-nz
Copy link
Member

Thanks for the discovery. I'll see what I can do to fix this.

From a brief initial look, it looks like @HighCommander4 is right on the money with the line of code he has isolated this issue to.

There's a number of lit test cases regarding macro expansion so it's interesting that they didn't pick this up. Will have to update the tests to cover this regression. Please continue sharing any other code samples that exhibit this issue. They will help me make sure that the fix works for everyone.

@paulaltin
Copy link
Contributor Author

Thanks @HighCommander4 and @salman-javed-nz, really appreciate your quick responses and attention to this!

@salman-javed-nz salman-javed-nz self-assigned this May 24, 2022
Guzhu-AMD pushed a commit to GPUOpen-Drivers/llvm-project that referenced this issue May 26, 2022
Local branch amd-gfx 15127a3 Merged main:6f215ca680fd into amd-gfx:e4c95cb9a7ae
Remote branch main 9ff4f2d [clang-tidy] Fix llvm#55134 (regression introduced by 5da7c04)
@Skylion007
Copy link

Skylion007 commented May 26, 2022

@paulaltin @salman-javed-nz Did we miss the opportunity for this to be backported in to the 14.x branch?

tstellar pushed a commit that referenced this issue Jun 3, 2022
5da7c04 introduced a regression in the NOLINT macro checking loop, replacing the
call to `getImmediateExpansionRange().getBegin()` with
`getImmediateMacroCallerLoc()`, which has similar but subtly different
behaviour.

The consequence is that NOLINTs cannot suppress diagnostics when they are
attached to a token that came from a macro **argument**, rather than elsewhere
in the macro expansion.

Revert to pre-patch behaviour and add test cases to cover this issue.

Differential Revision: https://reviews.llvm.org/D126138

(cherry picked from commit 9ff4f2d)
tarunprabhu pushed a commit to tarunprabhu/kitsune that referenced this issue Apr 4, 2023
5da7c04 introduced a regression in the NOLINT macro checking loop, replacing the
call to `getImmediateExpansionRange().getBegin()` with
`getImmediateMacroCallerLoc()`, which has similar but subtly different
behaviour.

The consequence is that NOLINTs cannot suppress diagnostics when they are
attached to a token that came from a macro **argument**, rather than elsewhere
in the macro expansion.

Revert to pre-patch behaviour and add test cases to cover this issue.

Differential Revision: https://reviews.llvm.org/D126138

(cherry picked from commit 9ff4f2d)
tarunprabhu pushed a commit to tarunprabhu/kitsune that referenced this issue Oct 12, 2023
5da7c04 introduced a regression in the NOLINT macro checking loop, replacing the
call to `getImmediateExpansionRange().getBegin()` with
`getImmediateMacroCallerLoc()`, which has similar but subtly different
behaviour.

The consequence is that NOLINTs cannot suppress diagnostics when they are
attached to a token that came from a macro **argument**, rather than elsewhere
in the macro expansion.

Revert to pre-patch behaviour and add test cases to cover this issue.

Differential Revision: https://reviews.llvm.org/D126138

(cherry picked from commit 9ff4f2d)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants