diff --git a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp --- a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp +++ b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp @@ -361,7 +361,21 @@ // Check if there's a NOLINTNEXTLINE on the previous line. StringRef PrevLine = Buffer->substr(0, Offset).rsplit('\n').first.rsplit('\n').second; - return IsNOLINTFound("NOLINTNEXTLINE", PrevLine, DiagID, Context); + if (IsNOLINTFound("NOLINTNEXTLINE", PrevLine, DiagID, Context)) + return true; + + // Check if there's an open NOLINTBEGIN ... NOLINTEND block on the previous + // lines. + SmallVector PrevLines; + Buffer->substr(0, Offset).rsplit('\n').first.split(PrevLines, '\n'); + for (auto I = PrevLines.rbegin(), E = PrevLines.rend(); I != E; ++I) { + if (IsNOLINTFound("NOLINTEND", *I, DiagID, Context)) + return false; + if (IsNOLINTFound("NOLINTBEGIN", *I, DiagID, Context)) + return true; + } + + return false; } static bool LineIsMarkedWithNOLINTinMacro(const SourceManager &SM, diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -67,7 +67,7 @@ Improvements to clang-tidy -------------------------- -The improvements are... +- Added support for `NOLINTBEGIN` ... `NOLINTEND` comments to suppress ClangTidy warnings over multiple lines. New checks ^^^^^^^^^^ diff --git a/clang-tools-extra/docs/clang-tidy/index.rst b/clang-tools-extra/docs/clang-tidy/index.rst --- a/clang-tools-extra/docs/clang-tidy/index.rst +++ b/clang-tools-extra/docs/clang-tidy/index.rst @@ -295,17 +295,19 @@ If a specific suppression mechanism is not available for a certain warning, or its use is not desired for some reason, :program:`clang-tidy` has a generic -mechanism to suppress diagnostics using ``NOLINT`` or ``NOLINTNEXTLINE`` -comments. +mechanism to suppress diagnostics using ``NOLINT``, ``NOLINTNEXTLINE``, and +``NOLINTBEGIN`` ... ``NOLINTEND`` comments. The ``NOLINT`` comment instructs :program:`clang-tidy` to ignore warnings on the *same line* (it doesn't apply to a function, a block of code or any other language construct, it applies to the line of code it is on). If introducing the comment in the same line would change the formatting in undesired way, the ``NOLINTNEXTLINE`` comment allows to suppress clang-tidy warnings on the *next -line*. +line*. The ``NOLINTBEGIN`` and ``NOLINTEND`` comments allow suppressing +clang-tidy warnings on *multiple lines* (affecting all lines between the two +comments). -Both comments can be followed by an optional list of check names in parentheses +All comments can be followed by an optional list of check names in parentheses (see below for the formal syntax). For example: @@ -325,9 +327,16 @@ // Silence only the specified diagnostics for the next line // NOLINTNEXTLINE(google-explicit-constructor, google-runtime-int) Foo(bool param); + + // Silence only the specified diagnostics for all lines between NOLINTBEGIN/END. + // NOLINTBEGIN(google-explicit-constructor, google-runtime-int) + Foo(short param); + Foo(long param); + // NOLINTEND(google-explicit-constructor, google-runtime-int) }; -The formal syntax of ``NOLINT``/``NOLINTNEXTLINE`` is the following: +The formal syntax of ``NOLINT``, ``NOLINTNEXTLINE``, and ``NOLINTBEGIN`` ... +``NOLINTEND`` is the following: .. parsed-literal:: @@ -345,11 +354,14 @@ lint-command: **NOLINT** **NOLINTNEXTLINE** - -Note that whitespaces between ``NOLINT``/``NOLINTNEXTLINE`` and the opening -parenthesis are not allowed (in this case the comment will be treated just as -``NOLINT``/``NOLINTNEXTLINE``), whereas in check names list (inside the -parenthesis) whitespaces can be used and will be ignored. + **NOLINTBEGIN** + **NOLINTEND** + +Note that whitespaces between ``NOLINT``/``NOLINTNEXTLINE``/``NOLINTBEGIN``/``NOLINTEND`` +and the opening parenthesis are not allowed (in this case the comment will be +treated just as ``NOLINT``/``NOLINTNEXTLINE``/``NOLINTBEGIN``/``NOLINTEND``), +whereas in check names list (inside the parenthesis) whitespaces can be used and +will be ignored. .. _LibTooling: https://clang.llvm.org/docs/LibTooling.html .. _How To Setup Tooling For LLVM: https://clang.llvm.org/docs/HowToSetupToolingForLLVM.html diff --git a/clang-tools-extra/test/clang-tidy/infrastructure/Inputs/nolintbeginend/error_in_include.inc b/clang-tools-extra/test/clang-tidy/infrastructure/Inputs/nolintbeginend/error_in_include.inc new file mode 100644 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/infrastructure/Inputs/nolintbeginend/error_in_include.inc @@ -0,0 +1 @@ +class F { F(int i); }; diff --git a/clang-tools-extra/test/clang-tidy/infrastructure/Inputs/nolintbeginend/nolint_in_include.inc b/clang-tools-extra/test/clang-tidy/infrastructure/Inputs/nolintbeginend/nolint_in_include.inc new file mode 100644 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/infrastructure/Inputs/nolintbeginend/nolint_in_include.inc @@ -0,0 +1,3 @@ +// NOLINTBEGIN +class G { G(int i); }; +// NOLINTEND diff --git a/clang-tools-extra/test/clang-tidy/infrastructure/nolintbeginend.cpp b/clang-tools-extra/test/clang-tidy/infrastructure/nolintbeginend.cpp new file mode 100644 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/infrastructure/nolintbeginend.cpp @@ -0,0 +1,90 @@ +// RUN: %check_clang_tidy %s google-explicit-constructor %t -- --header-filter=.* -system-headers -- -isystem %S/Inputs/nolintbeginend + +class A { A(int i); }; +// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: single-argument constructors must be marked explicit + +// NOLINTEND +class B1 { B1(int i); }; +// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: single-argument constructors must be marked explicit + +// NOLINTBEGIN +class B2 { B2(int i); }; +// NOLINTEND + +// NOLINTBEGIN +// NOLINTEND +// NOLINTBEGIN +class B3 { B3(int i); }; +// NOLINTEND + +// NOLINTBEGIN +// NOLINTEND +class B4 { B4(int i); }; +// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: single-argument constructors must be marked explicit + +// NOLINTBEGIN(google-explicit-constructor) +class C1 { C1(int i); }; +// NOLINTEND(google-explicit-constructor) + +// NOLINTBEGIN(*) +class C2 { C2(int i); }; +// NOLINTEND(*) + +// NOLINTBEGIN(some-other-check) +class C3 { C3(int i); }; +// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: single-argument constructors must be marked explicit +// NOLINTEND(some-other-check) + +// NOLINTBEGIN(some-other-check, google-explicit-constructor) +class C4 { C4(int i); }; +// NOLINTEND(some-other-check, google-explicit-constructor) + +// NOLINTBEGIN(some-other-check, google-explicit-constructor) +// NOLINTEND(some-other-check) +class C5 { C5(int i); }; +// NOLINTEND(google-explicit-constructor) + +// NOLINTBEGIN(some-other-check, google-explicit-constructor) +// NOLINTEND(google-explicit-constructor) +class C6 { C6(int i); }; +// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: single-argument constructors must be marked explicit +// NOLINTEND(some-other-check) + +// NOLINTBEGIN(google-explicit-constructor) +// NOLINTBEGIN(some-other-check) +class C7 { C7(int i); }; +// NOLINTEND(some-other-check) +// NOLINTEND(google-explicit-constructor) + +// NOLINTBEGIN(not-closed-bracket-is-treated-as-skip-all +class C8 { C8(int i); }; +// NOLINTEND(not-closed-bracket-is-treated-as-skip-all + +// NOLINTBEGIN without-brackets-skip-all, another-check +class C9 { C9(int i); }; +// NOLINTEND without-brackets-skip-all, another-check + +#define MACRO(X) class X { X(int i); }; + +MACRO(D1) +// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: single-argument constructors must be marked explicit + +// NOLINTBEGIN +MACRO(D2) +// NOLINTEND + +#define MACRO_NOARG class E { E(int i); }; +// NOLINTBEGIN +MACRO_NOARG +// NOLINTEND + +#include "error_in_include.inc" +// CHECK-MESSAGES: warning: single-argument constructors must be marked explicit + +#include "nolint_in_include.inc" + +// NOLINTBEGIN +class H1 { H1(int i); }; +class H2 { H2(int i); }; + +// CHECK-MESSAGES: Suppressed 14 warnings (14 NOLINT)