Skip to content

Commit 2935737

Browse files
committed
[clang][tooling] Create SourceManager for DiagnosticsEngine before command-line parsing
In D84673, we started using `DiagnosticsEngine` during command-line parsing in more contexts. When using `ToolInvocation`, a custom `DiagnosticsConsumer` can be specified and it might expect `SourceManager` to be present on the emitted diagnostics. This patch ensures the `SourceManager` is set up in such scenarios. Test authored by Jordan Rupprecht. Reviewed By: rupprecht Differential Revision: https://reviews.llvm.org/D99414
1 parent b7ef804 commit 2935737

File tree

2 files changed

+41
-0
lines changed

2 files changed

+41
-0
lines changed

clang/lib/Tooling/Tooling.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,10 @@ bool ToolInvocation::run() {
334334
DiagnosticsEngine Diagnostics(
335335
IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), &*DiagOpts,
336336
DiagConsumer ? DiagConsumer : &DiagnosticPrinter, false);
337+
// Although `Diagnostics` are used only for command-line parsing, the custom
338+
// `DiagConsumer` might expect a `SourceManager` to be present.
339+
SourceManager SrcMgr(Diagnostics, *Files);
340+
Diagnostics.setSourceManager(&SrcMgr);
337341

338342
const std::unique_ptr<driver::Driver> Driver(
339343
newDriver(&Diagnostics, BinaryName, &Files->getVirtualFileSystem()));

clang/unittests/Tooling/ToolingTest.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,43 @@ TEST(ToolInvocation, TestVirtualModulesCompilation) {
221221
EXPECT_TRUE(Invocation.run());
222222
}
223223

224+
struct DiagnosticConsumerExpectingSourceManager : public DiagnosticConsumer {
225+
bool SawSourceManager;
226+
227+
DiagnosticConsumerExpectingSourceManager() : SawSourceManager(false) {}
228+
229+
void HandleDiagnostic(clang::DiagnosticsEngine::Level,
230+
const clang::Diagnostic &info) override {
231+
SawSourceManager = info.hasSourceManager();
232+
}
233+
};
234+
235+
TEST(ToolInvocation, DiagConsumerExpectingSourceManager) {
236+
llvm::IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> OverlayFileSystem(
237+
new llvm::vfs::OverlayFileSystem(llvm::vfs::getRealFileSystem()));
238+
llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
239+
new llvm::vfs::InMemoryFileSystem);
240+
OverlayFileSystem->pushOverlay(InMemoryFileSystem);
241+
llvm::IntrusiveRefCntPtr<FileManager> Files(
242+
new FileManager(FileSystemOptions(), OverlayFileSystem));
243+
std::vector<std::string> Args;
244+
Args.push_back("tool-executable");
245+
// Note: intentional error; user probably meant -ferror-limit=0.
246+
Args.push_back("-ferror-limit=-1");
247+
Args.push_back("-fsyntax-only");
248+
Args.push_back("test.cpp");
249+
clang::tooling::ToolInvocation Invocation(
250+
Args, std::make_unique<SyntaxOnlyAction>(), Files.get());
251+
InMemoryFileSystem->addFile(
252+
"test.cpp", 0, llvm::MemoryBuffer::getMemBuffer("int main() {}\n"));
253+
254+
DiagnosticConsumerExpectingSourceManager Consumer;
255+
Invocation.setDiagnosticConsumer(&Consumer);
256+
257+
EXPECT_TRUE(Invocation.run());
258+
EXPECT_TRUE(Consumer.SawSourceManager);
259+
}
260+
224261
struct VerifyEndCallback : public SourceFileCallbacks {
225262
VerifyEndCallback() : BeginCalled(0), EndCalled(0), Matched(false) {}
226263
bool handleBeginSource(CompilerInstance &CI) override {

0 commit comments

Comments
 (0)