diff --git a/clang-tools-extra/clangd/Diagnostics.h b/clang-tools-extra/clangd/Diagnostics.h --- a/clang-tools-extra/clangd/Diagnostics.h +++ b/clang-tools-extra/clangd/Diagnostics.h @@ -180,7 +180,8 @@ /// Determine whether a (non-clang-tidy) diagnostic is suppressed by config. bool isBuiltinDiagnosticSuppressed(unsigned ID, - const llvm::StringSet<> &Suppressed); + const llvm::StringSet<> &Suppressed, + const LangOptions &); /// Take a user-specified diagnostic code, and convert it to a normalized form /// stored in the config and consumed by isBuiltinDiagnosticsSuppressed. /// diff --git a/clang-tools-extra/clangd/Diagnostics.cpp b/clang-tools-extra/clangd/Diagnostics.cpp --- a/clang-tools-extra/clangd/Diagnostics.cpp +++ b/clang-tools-extra/clangd/Diagnostics.cpp @@ -879,7 +879,14 @@ } bool isBuiltinDiagnosticSuppressed(unsigned ID, - const llvm::StringSet<> &Suppress) { + const llvm::StringSet<> &Suppress, + const LangOptions &LangOpts) { + // Don't complain about header-only stuff in mainfiles if it's a header. + // FIXME: would be cleaner to suppress in clang, once we decide whether the + // behavior should be to silently-ignore or respect the pragma. + if (ID == diag::pp_pragma_sysheader_in_main_file && LangOpts.IsHeaderFile) + return true; + if (const char *CodePtr = getDiagnosticCode(ID)) { if (Suppress.contains(normalizeSuppressedCode(CodePtr))) return true; diff --git a/clang-tools-extra/clangd/ParsedAST.cpp b/clang-tools-extra/clangd/ParsedAST.cpp --- a/clang-tools-extra/clangd/ParsedAST.cpp +++ b/clang-tools-extra/clangd/ParsedAST.cpp @@ -445,7 +445,8 @@ ASTDiags.setLevelAdjuster([&](DiagnosticsEngine::Level DiagLevel, const clang::Diagnostic &Info) { if (Cfg.Diagnostics.SuppressAll || - isBuiltinDiagnosticSuppressed(Info.getID(), Cfg.Diagnostics.Suppress)) + isBuiltinDiagnosticSuppressed(Info.getID(), Cfg.Diagnostics.Suppress, + Clang->getLangOpts())) return DiagnosticsEngine::Ignored; auto It = OverriddenSeverity.find(Info.getID()); diff --git a/clang-tools-extra/clangd/Preamble.cpp b/clang-tools-extra/clangd/Preamble.cpp --- a/clang-tools-extra/clangd/Preamble.cpp +++ b/clang-tools-extra/clangd/Preamble.cpp @@ -350,7 +350,8 @@ PreambleDiagnostics.setLevelAdjuster([&](DiagnosticsEngine::Level DiagLevel, const clang::Diagnostic &Info) { if (Cfg.Diagnostics.SuppressAll || - isBuiltinDiagnosticSuppressed(Info.getID(), Cfg.Diagnostics.Suppress)) + isBuiltinDiagnosticSuppressed(Info.getID(), Cfg.Diagnostics.Suppress, + *CI.getLangOpts())) return DiagnosticsEngine::Ignored; switch (Info.getID()) { case diag::warn_no_newline_eof: diff --git a/clang-tools-extra/clangd/unittests/ConfigCompileTests.cpp b/clang-tools-extra/clangd/unittests/ConfigCompileTests.cpp --- a/clang-tools-extra/clangd/unittests/ConfigCompileTests.cpp +++ b/clang-tools-extra/clangd/unittests/ConfigCompileTests.cpp @@ -277,19 +277,20 @@ "unreachable-code", "unused-variable", "typecheck_bool_condition", "unexpected_friend", "warn_alloca")); - EXPECT_TRUE(isBuiltinDiagnosticSuppressed(diag::warn_unreachable, - Conf.Diagnostics.Suppress)); + EXPECT_TRUE(isBuiltinDiagnosticSuppressed( + diag::warn_unreachable, Conf.Diagnostics.Suppress, LangOptions())); // Subcategory not respected/suppressed. - EXPECT_FALSE(isBuiltinDiagnosticSuppressed(diag::warn_unreachable_break, - Conf.Diagnostics.Suppress)); - EXPECT_TRUE(isBuiltinDiagnosticSuppressed(diag::warn_unused_variable, - Conf.Diagnostics.Suppress)); + EXPECT_FALSE(isBuiltinDiagnosticSuppressed( + diag::warn_unreachable_break, Conf.Diagnostics.Suppress, LangOptions())); + EXPECT_TRUE(isBuiltinDiagnosticSuppressed( + diag::warn_unused_variable, Conf.Diagnostics.Suppress, LangOptions())); EXPECT_TRUE(isBuiltinDiagnosticSuppressed(diag::err_typecheck_bool_condition, - Conf.Diagnostics.Suppress)); - EXPECT_TRUE(isBuiltinDiagnosticSuppressed(diag::err_unexpected_friend, - Conf.Diagnostics.Suppress)); - EXPECT_TRUE(isBuiltinDiagnosticSuppressed(diag::warn_alloca, - Conf.Diagnostics.Suppress)); + Conf.Diagnostics.Suppress, + LangOptions())); + EXPECT_TRUE(isBuiltinDiagnosticSuppressed( + diag::err_unexpected_friend, Conf.Diagnostics.Suppress, LangOptions())); + EXPECT_TRUE(isBuiltinDiagnosticSuppressed( + diag::warn_alloca, Conf.Diagnostics.Suppress, LangOptions())); Frag.Diagnostics.Suppress.emplace_back("*"); EXPECT_TRUE(compileAndApply()); diff --git a/clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp b/clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp --- a/clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp +++ b/clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp @@ -771,6 +771,17 @@ Not(WithFix(_))))); } +TEST(DiagnosticsTest, PragmaSystemHeader) { + Annotations Test("#pragma clang [[system_header]]\n"); + auto TU = TestTU::withCode(Test.code()); + EXPECT_THAT( + *TU.build().getDiagnostics(), + ElementsAre(AllOf( + Diag(Test.range(), "#pragma system_header ignored in main file")))); + TU.Filename = "TestTU.h"; + EXPECT_THAT(*TU.build().getDiagnostics(), IsEmpty()); +} + TEST(ClangdTest, MSAsm) { // Parsing MS assembly tries to use the target MCAsmInfo, which we don't link. // We used to crash here. Now clang emits a diagnostic, which we filter out.