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 @@ -672,14 +672,14 @@ void StoreDiags::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, const clang::Diagnostic &Info) { - // If the diagnostic was generated for a different SourceManager, skip it. + bool FromModule = false; + // If the diagnostic was generated for a different SourceManager. // This happens when a module is imported and needs to be implicitly built. // The compilation of that module will use the same StoreDiags, but different - // SourceManager. + // SourceManager. Treat them as coming from command line. if (OrigSrcMgr && Info.hasSourceManager() && OrigSrcMgr != &Info.getSourceManager()) { - IgnoreDiagnostics::log(DiagLevel, Info); - return; + FromModule = true; } DiagnosticConsumer::HandleDiagnostic(DiagLevel, Info); @@ -687,7 +687,7 @@ Info.getDiags()->getDiagnosticIDs()->isDefaultMappingAsError( Info.getID()); - if (Info.getLocation().isInvalid()) { + if (Info.getLocation().isInvalid() || FromModule) { // Handle diagnostics coming from command-line arguments. The source manager // is *not* available at this point, so we cannot use it. if (!OriginallyError) { @@ -702,6 +702,11 @@ LastDiagOriginallyError = OriginallyError; LastDiag->ID = Info.getID(); fillNonLocationData(DiagLevel, Info, *LastDiag); + // Update message to mention original location. + const char *Prefix = + FromModule ? "in implicitly built module" : "in command line"; + LastDiag->Message = llvm::formatv("{0}: {1}", Prefix, LastDiag->Message); + LastDiag->InsideMainFile = true; // Put it at the start of the main file, for a lack of a better place. LastDiag->Range.start = Position{0, 0}; diff --git a/clang-tools-extra/clangd/unittests/ModulesTests.cpp b/clang-tools-extra/clangd/unittests/ModulesTests.cpp --- a/clang-tools-extra/clangd/unittests/ModulesTests.cpp +++ b/clang-tools-extra/clangd/unittests/ModulesTests.cpp @@ -18,6 +18,12 @@ namespace clangd { namespace { +using ::testing::ElementsAre; + +MATCHER_P(diag, Desc, "") { + return llvm::StringRef(arg.Message).contains(Desc); +} + TEST(Modules, TextualIncludeInPreamble) { TestTU TU = TestTU::withCode(R"cpp( #include "Textual.h" @@ -88,7 +94,13 @@ )modulemap"; // Test that we do not crash. - TU.build(); + auto AST = TU.build(); + + // Test expected diagnostics. + EXPECT_THAT(AST.getDiagnostics(), + ElementsAre(diag("in implicitly built module: module M does not " + "depend on a module exporting 'non-modular.h'"), + diag("could not build module 'M'"))); } // Unknown module formats are a fatal failure for clang. Ensure we don't crash. diff --git a/clang-tools-extra/clangd/unittests/TUSchedulerTests.cpp b/clang-tools-extra/clangd/unittests/TUSchedulerTests.cpp --- a/clang-tools-extra/clangd/unittests/TUSchedulerTests.cpp +++ b/clang-tools-extra/clangd/unittests/TUSchedulerTests.cpp @@ -1079,7 +1079,8 @@ ElementsAre(AllOf( Field(&Diag::ID, Eq(diag::err_drv_unknown_argument)), Field(&Diag::Name, Eq("drv_unknown_argument")), - Field(&Diag::Message, "unknown argument: '-fsome-unknown-flag'")))); + Field(&Diag::Message, + "in command line: unknown argument: '-fsome-unknown-flag'")))); } TEST_F(TUSchedulerTests, CommandLineWarnings) {