diff --git a/clang/lib/Tooling/Tooling.cpp b/clang/lib/Tooling/Tooling.cpp --- a/clang/lib/Tooling/Tooling.cpp +++ b/clang/lib/Tooling/Tooling.cpp @@ -334,6 +334,10 @@ DiagnosticsEngine Diagnostics( IntrusiveRefCntPtr(new DiagnosticIDs()), &*DiagOpts, DiagConsumer ? DiagConsumer : &DiagnosticPrinter, false); + // Although `Diagnostics` are used only for command-line parsing, the custom + // `DiagConsumer` might expect a `SourceManager` to be present. + SourceManager SrcMgr(Diagnostics, *Files); + Diagnostics.setSourceManager(&SrcMgr); const std::unique_ptr Driver( newDriver(&Diagnostics, BinaryName, &Files->getVirtualFileSystem())); diff --git a/clang/unittests/Tooling/ToolingTest.cpp b/clang/unittests/Tooling/ToolingTest.cpp --- a/clang/unittests/Tooling/ToolingTest.cpp +++ b/clang/unittests/Tooling/ToolingTest.cpp @@ -221,6 +221,43 @@ EXPECT_TRUE(Invocation.run()); } +struct DiagnosticConsumerExpectingSourceManager : public DiagnosticConsumer { + bool SawSourceManager; + + DiagnosticConsumerExpectingSourceManager() : SawSourceManager(false) {} + + void HandleDiagnostic(clang::DiagnosticsEngine::Level, + const clang::Diagnostic &info) override { + SawSourceManager = info.hasSourceManager(); + } +}; + +TEST(ToolInvocation, DiagConsumerExpectingSourceManager) { + llvm::IntrusiveRefCntPtr OverlayFileSystem( + new llvm::vfs::OverlayFileSystem(llvm::vfs::getRealFileSystem())); + llvm::IntrusiveRefCntPtr InMemoryFileSystem( + new llvm::vfs::InMemoryFileSystem); + OverlayFileSystem->pushOverlay(InMemoryFileSystem); + llvm::IntrusiveRefCntPtr Files( + new FileManager(FileSystemOptions(), OverlayFileSystem)); + std::vector Args; + Args.push_back("tool-executable"); + // Note: intentional error; user probably meant -ferror-limit=0. + Args.push_back("-ferror-limit=-1"); + Args.push_back("-fsyntax-only"); + Args.push_back("test.cpp"); + clang::tooling::ToolInvocation Invocation( + Args, std::make_unique(), Files.get()); + InMemoryFileSystem->addFile( + "test.cpp", 0, llvm::MemoryBuffer::getMemBuffer("int main() {}\n")); + + DiagnosticConsumerExpectingSourceManager Consumer; + Invocation.setDiagnosticConsumer(&Consumer); + + EXPECT_TRUE(Invocation.run()); + EXPECT_TRUE(Consumer.SawSourceManager); +} + struct VerifyEndCallback : public SourceFileCallbacks { VerifyEndCallback() : BeginCalled(0), EndCalled(0), Matched(false) {} bool handleBeginSource(CompilerInstance &CI) override {