diff --git a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h --- a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h +++ b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h @@ -194,6 +194,7 @@ ClangTidyOptions CurrentOptions; std::unique_ptr CheckFilter; + std::unique_ptr SuppressedCheckFilter; std::unique_ptr WarningAsErrorFilter; LangOptions LangOpts; 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 @@ -212,6 +212,8 @@ CurrentFile = std::string(File); CurrentOptions = getOptionsForFile(CurrentFile); CheckFilter = std::make_unique(*getOptions().Checks); + SuppressedCheckFilter = + std::make_unique(*getOptions().SuppressedChecks); WarningAsErrorFilter = std::make_unique(*getOptions().WarningsAsErrors); } @@ -252,7 +254,9 @@ bool ClangTidyContext::isCheckEnabled(StringRef CheckName) const { assert(CheckFilter != nullptr); - return CheckFilter->contains(CheckName); + assert(SuppressedCheckFilter != nullptr); + return CheckFilter->contains(CheckName) && + !SuppressedCheckFilter->contains(CheckName); } bool ClangTidyContext::treatAsError(StringRef CheckName) const { diff --git a/clang-tools-extra/clang-tidy/ClangTidyOptions.h b/clang-tools-extra/clang-tidy/ClangTidyOptions.h --- a/clang-tools-extra/clang-tidy/ClangTidyOptions.h +++ b/clang-tools-extra/clang-tidy/ClangTidyOptions.h @@ -69,6 +69,9 @@ /// Checks filter. llvm::Optional Checks; + /// Suppressed checks filter. + llvm::Optional SuppressedChecks; + /// WarningsAsErrors filter. llvm::Optional WarningsAsErrors; diff --git a/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp b/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp --- a/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp +++ b/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp @@ -87,6 +87,7 @@ IO, Options.CheckOptions); bool Ignored = false; IO.mapOptional("Checks", Options.Checks); + IO.mapOptional("SuppressedChecks", Options.SuppressedChecks); IO.mapOptional("WarningsAsErrors", Options.WarningsAsErrors); IO.mapOptional("HeaderFilterRegex", Options.HeaderFilterRegex); IO.mapOptional("AnalyzeTemporaryDtors", Ignored); // legacy compatibility @@ -109,6 +110,7 @@ ClangTidyOptions ClangTidyOptions::getDefaults() { ClangTidyOptions Options; Options.Checks = ""; + Options.SuppressedChecks = ""; Options.WarningsAsErrors = ""; Options.HeaderFilterRegex = ""; Options.SystemHeaders = false; @@ -145,6 +147,7 @@ ClangTidyOptions &ClangTidyOptions::mergeWith(const ClangTidyOptions &Other, unsigned Order) { mergeCommaSeparatedLists(Checks, Other.Checks); + mergeCommaSeparatedLists(SuppressedChecks, Other.SuppressedChecks); mergeCommaSeparatedLists(WarningsAsErrors, Other.WarningsAsErrors); overrideValue(HeaderFilterRegex, Other.HeaderFilterRegex); overrideValue(SystemHeaders, Other.SystemHeaders); diff --git a/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp b/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp --- a/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp +++ b/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp @@ -298,6 +298,7 @@ ClangTidyOptions DefaultOptions; DefaultOptions.Checks = DefaultChecks; + DefaultOptions.SuppressedChecks = ""; DefaultOptions.WarningsAsErrors = ""; DefaultOptions.HeaderFilterRegex = HeaderFilter; DefaultOptions.SystemHeaders = SystemHeaders; diff --git a/clang-tools-extra/unittests/clang-tidy/ClangTidyDiagnosticConsumerTest.cpp b/clang-tools-extra/unittests/clang-tidy/ClangTidyDiagnosticConsumerTest.cpp --- a/clang-tools-extra/unittests/clang-tidy/ClangTidyDiagnosticConsumerTest.cpp +++ b/clang-tools-extra/unittests/clang-tidy/ClangTidyDiagnosticConsumerTest.cpp @@ -24,6 +24,19 @@ } }; +// Test that has name == "test-check-noisy" and outputs exactly one diagnostic. +class NoisyCheck : public ClangTidyCheck { +public: + NoisyCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck("test-check-noisy", Context) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override { + Finder->addMatcher(ast_matchers::varDecl().bind("var"), this); + } + void check(const ast_matchers::MatchFinder::MatchResult &Result) override { + diag("Some diagnostic"); + } +}; + class HighlightTestCheck : public ClangTidyCheck { public: HighlightTestCheck(StringRef Name, ClangTidyContext *Context) @@ -75,6 +88,27 @@ EXPECT_EQ("variable", Errors[2].Message.Message); } +TEST(ClangTidyDiagnosticConsumer, SkipsSuppressedChecks) { + std::vector Errors; + ClangTidyOptions CustomOptions; + CustomOptions.SuppressedChecks = "*noisy*"; + runCheckOnCode("int a;", &Errors, "input.cc", None, + CustomOptions); + // 4 comming from TestCheck, 0 from NoisyCheck (since it's suppressed). + EXPECT_EQ(3ul, Errors.size()); +} + +TEST(ClangTidyDiagnosticConsumer, ChecksIfNotSuppressed) { + std::vector Errors; + ClangTidyOptions CustomOptions; + CustomOptions.SuppressedChecks = "*different_glob*"; + runCheckOnCode("int a;", &Errors, "input.cc", None, + CustomOptions); + + // 4 comming from TestCheck, 1 from NoisyCheck. + EXPECT_EQ(4ul, Errors.size()); +} + TEST(ClangTidyDiagnosticConsumer, HandlesSourceRangeHighlight) { std::vector Errors; runCheckOnCode("int abc;", &Errors); diff --git a/clang-tools-extra/unittests/clang-tidy/ClangTidyOptionsTest.cpp b/clang-tools-extra/unittests/clang-tidy/ClangTidyOptionsTest.cpp --- a/clang-tools-extra/unittests/clang-tidy/ClangTidyOptionsTest.cpp +++ b/clang-tools-extra/unittests/clang-tidy/ClangTidyOptionsTest.cpp @@ -76,12 +76,14 @@ TEST(ParseConfiguration, ValidConfiguration) { llvm::ErrorOr Options = parseConfiguration(llvm::MemoryBufferRef("Checks: \"-*,misc-*\"\n" + "SuppressedChecks: \"noisy-*\"\n" "HeaderFilterRegex: \".*\"\n" "AnalyzeTemporaryDtors: true\n" "User: some.user", "Options")); EXPECT_TRUE(!!Options); EXPECT_EQ("-*,misc-*", *Options->Checks); + EXPECT_EQ("noisy-*", *Options->SuppressedChecks); EXPECT_EQ(".*", *Options->HeaderFilterRegex); EXPECT_EQ("some.user", *Options->User); } @@ -90,6 +92,7 @@ llvm::ErrorOr Options1 = parseConfiguration(llvm::MemoryBufferRef(R"( Checks: "check1,check2" + SuppressedChecks: "noisycheck1,noisycheck2" HeaderFilterRegex: "filter1" AnalyzeTemporaryDtors: true User: user1 @@ -102,6 +105,7 @@ llvm::ErrorOr Options2 = parseConfiguration(llvm::MemoryBufferRef(R"( Checks: "check3,check4" + SuppressedChecks: "noisycheck3,noisycheck4" HeaderFilterRegex: "filter2" AnalyzeTemporaryDtors: false User: user2 @@ -113,6 +117,8 @@ ASSERT_TRUE(!!Options2); ClangTidyOptions Options = Options1->merge(*Options2, 0); EXPECT_EQ("check1,check2,check3,check4", *Options.Checks); + EXPECT_EQ("noisycheck1,noisycheck2,noisycheck3,noisycheck4", + *Options.SuppressedChecks); EXPECT_EQ("filter2", *Options.HeaderFilterRegex); EXPECT_EQ("user2", *Options.User); ASSERT_TRUE(Options.ExtraArgs.hasValue());