Index: clang-tools-extra/trunk/clangd/ClangdServer.cpp =================================================================== --- clang-tools-extra/trunk/clangd/ClangdServer.cpp +++ clang-tools-extra/trunk/clangd/ClangdServer.cpp @@ -80,6 +80,11 @@ }); } + void onFailedAST(PathRef Path, std::vector Diags, + PublishFn Publish) override { + Publish([&]() { DiagConsumer.onDiagnosticsReady(Path, Diags); }); + } + void onFileUpdated(PathRef File, const TUStatus &Status) override { DiagConsumer.onFileUpdated(File, Status); } Index: clang-tools-extra/trunk/clangd/ClangdUnit.h =================================================================== --- clang-tools-extra/trunk/clangd/ClangdUnit.h +++ clang-tools-extra/trunk/clangd/ClangdUnit.h @@ -25,6 +25,7 @@ #include "clang/Tooling/CompilationDatabase.h" #include "clang/Tooling/Core/Replacement.h" #include "clang/Tooling/Syntax/Tokens.h" +#include "llvm/ADT/ArrayRef.h" #include #include #include @@ -76,10 +77,11 @@ /// it is reused during parsing. static llvm::Optional build(std::unique_ptr CI, + llvm::ArrayRef CompilerInvocationDiags, std::shared_ptr Preamble, std::unique_ptr Buffer, - IntrusiveRefCntPtr VFS, const SymbolIndex *Index, - const ParseOptions &Opts); + llvm::IntrusiveRefCntPtr VFS, + const SymbolIndex *Index, const ParseOptions &Opts); ParsedAST(ParsedAST &&Other); ParsedAST &operator=(ParsedAST &&Other); @@ -174,6 +176,7 @@ /// result of calling buildPreamble. llvm::Optional buildAST(PathRef FileName, std::unique_ptr Invocation, + llvm::ArrayRef CompilerInvocationDiags, const ParseInputs &Inputs, std::shared_ptr Preamble); Index: clang-tools-extra/trunk/clangd/ClangdUnit.cpp =================================================================== --- clang-tools-extra/trunk/clangd/ClangdUnit.cpp +++ clang-tools-extra/trunk/clangd/ClangdUnit.cpp @@ -292,7 +292,8 @@ } llvm::Optional -ParsedAST::build(std::unique_ptr CI, +ParsedAST::build(std::unique_ptr CI, + llvm::ArrayRef CompilerInvocationDiags, std::shared_ptr Preamble, std::unique_ptr Buffer, llvm::IntrusiveRefCntPtr VFS, @@ -459,10 +460,15 @@ // So just inform the preprocessor of EOF, while keeping everything alive. Clang->getPreprocessor().EndSourceFile(); - std::vector Diags = ASTDiags.take(CTContext.getPointer()); + std::vector Diags = CompilerInvocationDiags; // Add diagnostics from the preamble, if any. if (Preamble) - Diags.insert(Diags.begin(), Preamble->Diags.begin(), Preamble->Diags.end()); + Diags.insert(Diags.end(), Preamble->Diags.begin(), Preamble->Diags.end()); + // Finally, add diagnostics coming from the AST. + { + std::vector D = ASTDiags.take(CTContext.getPointer()); + Diags.insert(Diags.end(), D.begin(), D.end()); + } return ParsedAST(std::move(Preamble), std::move(Clang), std::move(Action), std::move(Tokens), std::move(ParsedDecls), std::move(Diags), std::move(Includes), std::move(CanonIncludes)); @@ -646,6 +652,7 @@ llvm::Optional buildAST(PathRef FileName, std::unique_ptr Invocation, + llvm::ArrayRef CompilerInvocationDiags, const ParseInputs &Inputs, std::shared_ptr Preamble) { trace::Span Tracer("BuildAST"); @@ -661,7 +668,8 @@ } return ParsedAST::build( - std::make_unique(*Invocation), Preamble, + std::make_unique(*Invocation), + CompilerInvocationDiags, Preamble, llvm::MemoryBuffer::getMemBufferCopy(Inputs.Contents, FileName), std::move(VFS), Inputs.Index, Inputs.Opts); } Index: clang-tools-extra/trunk/clangd/CodeComplete.cpp =================================================================== --- clang-tools-extra/trunk/clangd/CodeComplete.cpp +++ clang-tools-extra/trunk/clangd/CodeComplete.cpp @@ -1053,7 +1053,9 @@ ParseInput.FS = VFS; ParseInput.Contents = Input.Contents; ParseInput.Opts = ParseOptions(); - auto CI = buildCompilerInvocation(ParseInput); + + IgnoreDiagnostics IgnoreDiags; + auto CI = buildCompilerInvocation(ParseInput, IgnoreDiags); if (!CI) { elog("Couldn't create CompilerInvocation"); return false; @@ -1084,12 +1086,11 @@ bool CompletingInPreamble = PreambleRegion.Size > Input.Offset; // NOTE: we must call BeginSourceFile after prepareCompilerInstance. Otherwise // the remapped buffers do not get freed. - IgnoreDiagnostics DummyDiagsConsumer; auto Clang = prepareCompilerInstance( std::move(CI), (Input.Preamble && !CompletingInPreamble) ? &Input.Preamble->Preamble : nullptr, - std::move(ContentsBuffer), std::move(VFS), DummyDiagsConsumer); + std::move(ContentsBuffer), std::move(VFS), IgnoreDiags); Clang->getPreprocessorOpts().SingleFileParseMode = CompletingInPreamble; Clang->setCodeCompletionConsumer(Consumer.release()); Index: clang-tools-extra/trunk/clangd/Compiler.h =================================================================== --- clang-tools-extra/trunk/clangd/Compiler.h +++ clang-tools-extra/trunk/clangd/Compiler.h @@ -52,7 +52,8 @@ /// Builds compiler invocation that could be used to build AST or preamble. std::unique_ptr -buildCompilerInvocation(const ParseInputs &Inputs); +buildCompilerInvocation(const ParseInputs &Inputs, + clang::DiagnosticConsumer &D); /// Creates a compiler instance, configured so that: /// - Contents of the parsed file are remapped to \p MainFile. Index: clang-tools-extra/trunk/clangd/Compiler.cpp =================================================================== --- clang-tools-extra/trunk/clangd/Compiler.cpp +++ clang-tools-extra/trunk/clangd/Compiler.cpp @@ -41,7 +41,8 @@ } std::unique_ptr -buildCompilerInvocation(const ParseInputs &Inputs) { +buildCompilerInvocation(const ParseInputs &Inputs, + clang::DiagnosticConsumer &D) { std::vector ArgStrs; for (const auto &S : Inputs.CompileCommand.CommandLine) ArgStrs.push_back(S.c_str()); @@ -52,12 +53,8 @@ // dirs. } - // FIXME(ibiryukov): store diagnostics from CommandLine when we start - // reporting them. - IgnoreDiagnostics IgnoreDiagnostics; llvm::IntrusiveRefCntPtr CommandLineDiagsEngine = - CompilerInstance::createDiagnostics(new DiagnosticOptions, - &IgnoreDiagnostics, false); + CompilerInstance::createDiagnostics(new DiagnosticOptions, &D, false); std::unique_ptr CI = createInvocationFromCommandLine( ArgStrs, CommandLineDiagsEngine, Inputs.FS, /*ShouldRecoverOnErrors=*/true); Index: clang-tools-extra/trunk/clangd/Diagnostics.cpp =================================================================== --- clang-tools-extra/trunk/clangd/Diagnostics.cpp +++ clang-tools-extra/trunk/clangd/Diagnostics.cpp @@ -16,11 +16,13 @@ #include "clang/Basic/Diagnostic.h" #include "clang/Basic/DiagnosticIDs.h" #include "clang/Basic/FileManager.h" +#include "clang/Basic/SourceLocation.h" #include "clang/Basic/SourceManager.h" #include "clang/Lex/Lexer.h" #include "clang/Lex/Token.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" #include "llvm/Support/Capacity.h" @@ -393,6 +395,9 @@ } std::vector StoreDiags::take(const clang::tidy::ClangTidyContext *Tidy) { + // Do not forget to emit a pending diagnostic if there is one. + flushLastDiag(); + // Fill in name/source now that we have all the context needed to map them. for (auto &Diag : Output) { if (const char *ClangDiag = getDiagnosticCode(Diag.ID)) { @@ -448,7 +453,6 @@ } void StoreDiags::EndSourceFile() { - flushLastDiag(); LangOpts = None; } @@ -467,10 +471,46 @@ OS << "…"; } +/// Fills \p D with all information, except the location-related bits. +/// Also note that ID and Name are not part of clangd::DiagBase and should be +/// set elsewhere. +static void fillNonLocationData(DiagnosticsEngine::Level DiagLevel, + const clang::Diagnostic &Info, + clangd::DiagBase &D) { + llvm::SmallString<64> Message; + Info.FormatDiagnostic(Message); + + D.Message = Message.str(); + D.Severity = DiagLevel; + D.Category = DiagnosticIDs::getCategoryNameFromID( + DiagnosticIDs::getCategoryNumberForDiag(Info.getID())) + .str(); +} + void StoreDiags::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, const clang::Diagnostic &Info) { DiagnosticConsumer::HandleDiagnostic(DiagLevel, Info); + if (Info.getLocation().isInvalid()) { + // Handle diagnostics coming from command-line arguments. The source manager + // is *not* available at this point, so we cannot use it. + if (DiagLevel < DiagnosticsEngine::Level::Error) { + IgnoreDiagnostics::log(DiagLevel, Info); + return; // non-errors add too much noise, do not show them. + } + + flushLastDiag(); + + LastDiag = Diag(); + LastDiag->ID = Info.getID(); + fillNonLocationData(DiagLevel, Info, *LastDiag); + 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}; + LastDiag->Range.end = Position{0, 0}; + return; + } + if (!LangOpts || !Info.hasSourceManager()) { IgnoreDiagnostics::log(DiagLevel, Info); return; @@ -480,18 +520,13 @@ SourceManager &SM = Info.getSourceManager(); auto FillDiagBase = [&](DiagBase &D) { - D.Range = diagnosticRange(Info, *LangOpts); - llvm::SmallString<64> Message; - Info.FormatDiagnostic(Message); - D.Message = Message.str(); + fillNonLocationData(DiagLevel, Info, D); + D.InsideMainFile = InsideMainFile; + D.Range = diagnosticRange(Info, *LangOpts); D.File = SM.getFilename(Info.getLocation()); D.AbsFile = getCanonicalPath( SM.getFileEntryForID(SM.getFileID(Info.getLocation())), SM); - D.Severity = DiagLevel; - D.Category = DiagnosticIDs::getCategoryNameFromID( - DiagnosticIDs::getCategoryNumberForDiag(Info.getID())) - .str(); return D; }; @@ -564,7 +599,6 @@ LastDiag = Diag(); LastDiag->ID = Info.getID(); FillDiagBase(*LastDiag); - LastDiagWasAdjusted = false; if (!InsideMainFile) LastDiagWasAdjusted = adjustDiagFromHeader(*LastDiag, Info, *LangOpts); @@ -617,6 +651,7 @@ vlog("Dropped diagnostic: {0}: {1}", LastDiag->File, LastDiag->Message); } LastDiag.reset(); + LastDiagWasAdjusted = false; } } // namespace clangd Index: clang-tools-extra/trunk/clangd/TUScheduler.h =================================================================== --- clang-tools-extra/trunk/clangd/TUScheduler.h +++ clang-tools-extra/trunk/clangd/TUScheduler.h @@ -10,8 +10,10 @@ #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_TUSCHEDULER_H #include "ClangdUnit.h" +#include "Diagnostics.h" #include "Function.h" #include "GlobalCompilationDatabase.h" +#include "Path.h" #include "Threading.h" #include "index/CanonicalIncludes.h" #include "llvm/ADT/Optional.h" @@ -125,6 +127,11 @@ /// Publish() may never run in this case). virtual void onMainAST(PathRef Path, ParsedAST &AST, PublishFn Publish) {} + /// Called whenever the AST fails to build. \p Diags will have the diagnostics + /// that led to failure. + virtual void onFailedAST(PathRef Path, std::vector Diags, + PublishFn Publish) {} + /// Called whenever the TU status is updated. virtual void onFileUpdated(PathRef File, const TUStatus &Status) {} }; Index: clang-tools-extra/trunk/clangd/TUScheduler.cpp =================================================================== --- clang-tools-extra/trunk/clangd/TUScheduler.cpp +++ clang-tools-extra/trunk/clangd/TUScheduler.cpp @@ -44,6 +44,7 @@ #include "TUScheduler.h" #include "Cancellation.h" #include "Compiler.h" +#include "Diagnostics.h" #include "GlobalCompilationDatabase.h" #include "Logger.h" #include "Trace.h" @@ -365,6 +366,14 @@ void ASTWorker::update(ParseInputs Inputs, WantDiagnostics WantDiags) { llvm::StringRef TaskName = "Update"; auto Task = [=]() mutable { + auto RunPublish = [&](llvm::function_ref Publish) { + // Ensure we only publish results from the worker if the file was not + // removed, making sure there are not race conditions. + std::lock_guard Lock(PublishMu); + if (CanPublishResults) + Publish(); + }; + // Get the actual command as `Inputs` does not have a command. // FIXME: some build systems like Bazel will take time to preparing // environment to build the file, it would be nice if we could emit a @@ -394,8 +403,11 @@ Inputs.CompileCommand.Directory, llvm::join(Inputs.CompileCommand.CommandLine, " ")); // Rebuild the preamble and the AST. + StoreDiags CompilerInvocationDiagConsumer; std::unique_ptr Invocation = - buildCompilerInvocation(Inputs); + buildCompilerInvocation(Inputs, CompilerInvocationDiagConsumer); + std::vector CompilerInvocationDiags = + CompilerInvocationDiagConsumer.take(); if (!Invocation) { elog("Could not build CompilerInvocation for file {0}", FileName); // Remove the old AST if it's still in cache. @@ -403,6 +415,9 @@ TUStatus::BuildDetails Details; Details.BuildFailed = true; emitTUStatus({TUAction::BuildingPreamble, TaskName}, &Details); + // Report the diagnostics we collected when parsing the command line. + Callbacks.onFailedAST(FileName, std::move(CompilerInvocationDiags), + RunPublish); // Make sure anyone waiting for the preamble gets notified it could not // be built. PreambleWasBuilt.notify(); @@ -468,7 +483,8 @@ llvm::Optional> AST = IdleASTs.take(this); if (!AST) { llvm::Optional NewAST = - buildAST(FileName, std::move(Invocation), Inputs, NewPreamble); + buildAST(FileName, std::move(Invocation), CompilerInvocationDiags, + Inputs, NewPreamble); AST = NewAST ? std::make_unique(std::move(*NewAST)) : nullptr; if (!(*AST)) { // buildAST fails. TUStatus::BuildDetails Details; @@ -481,22 +497,22 @@ Details.ReuseAST = true; emitTUStatus({TUAction::BuildingFile, TaskName}, &Details); } + // We want to report the diagnostics even if this update was cancelled. // It seems more useful than making the clients wait indefinitely if they // spam us with updates. // Note *AST can still be null if buildAST fails. if (*AST) { trace::Span Span("Running main AST callback"); - auto RunPublish = [&](llvm::function_ref Publish) { - // Ensure we only publish results from the worker if the file was not - // removed, making sure there are not race conditions. - std::lock_guard Lock(PublishMu); - if (CanPublishResults) - Publish(); - }; Callbacks.onMainAST(FileName, **AST, RunPublish); RanASTCallback = true; + } else { + // Failed to build the AST, at least report diagnostics from the command + // line if there were any. + // FIXME: we might have got more errors while trying to build the AST, + // surface them too. + Callbacks.onFailedAST(FileName, CompilerInvocationDiags, RunPublish); } // Stash the AST in the cache for further use. IdleASTs.put(this, std::move(*AST)); @@ -513,14 +529,16 @@ llvm::Optional> AST = IdleASTs.take(this); auto CurrentInputs = getCurrentFileInputs(); if (!AST) { - std::unique_ptr Invocation = - buildCompilerInvocation(*CurrentInputs); + StoreDiags CompilerInvocationDiagConsumer; + std::unique_ptr Invocation = buildCompilerInvocation( + *CurrentInputs, CompilerInvocationDiagConsumer); // Try rebuilding the AST. llvm::Optional NewAST = Invocation ? buildAST(FileName, std::make_unique(*Invocation), - *CurrentInputs, getPossiblyStalePreamble()) + CompilerInvocationDiagConsumer.take(), *CurrentInputs, + getPossiblyStalePreamble()) : None; AST = NewAST ? std::make_unique(std::move(*NewAST)) : nullptr; } Index: clang-tools-extra/trunk/clangd/index/Background.cpp =================================================================== --- clang-tools-extra/trunk/clangd/index/Background.cpp +++ clang-tools-extra/trunk/clangd/index/Background.cpp @@ -369,11 +369,11 @@ Inputs.FS = std::move(FS); Inputs.FS->setCurrentWorkingDirectory(Cmd.Directory); Inputs.CompileCommand = std::move(Cmd); - auto CI = buildCompilerInvocation(Inputs); + IgnoreDiagnostics IgnoreDiags; + auto CI = buildCompilerInvocation(Inputs, IgnoreDiags); if (!CI) return llvm::createStringError(llvm::inconvertibleErrorCode(), "Couldn't build compiler invocation"); - IgnoreDiagnostics IgnoreDiags; auto Clang = prepareCompilerInstance(std::move(CI), /*Preamble=*/nullptr, std::move(*Buf), Inputs.FS, IgnoreDiags); if (!Clang) Index: clang-tools-extra/trunk/clangd/unittests/ClangdUnitTests.cpp =================================================================== --- clang-tools-extra/trunk/clangd/unittests/ClangdUnitTests.cpp +++ clang-tools-extra/trunk/clangd/unittests/ClangdUnitTests.cpp @@ -10,6 +10,7 @@ #include "Annotations.h" #include "ClangdUnit.h" #include "Compiler.h" +#include "Diagnostics.h" #include "SourceCode.h" #include "TestFS.h" #include "TestTU.h" @@ -252,12 +253,13 @@ Inputs.FS = buildTestFS({{testPath("foo.cpp"), "void test() {}"}}); Inputs.CompileCommand.CommandLine = {"clang", "-fsome-unknown-flag", testPath("foo.cpp")}; - EXPECT_NE(buildCompilerInvocation(Inputs), nullptr); + IgnoreDiagnostics IgnoreDiags; + EXPECT_NE(buildCompilerInvocation(Inputs, IgnoreDiags), nullptr); // Unknown forwarded to -cc1 should not a failure either. Inputs.CompileCommand.CommandLine = { "clang", "-Xclang", "-fsome-unknown-flag", testPath("foo.cpp")}; - EXPECT_NE(buildCompilerInvocation(Inputs), nullptr); + EXPECT_NE(buildCompilerInvocation(Inputs, IgnoreDiags), nullptr); } } // namespace Index: clang-tools-extra/trunk/clangd/unittests/FileIndexTests.cpp =================================================================== --- clang-tools-extra/trunk/clangd/unittests/FileIndexTests.cpp +++ clang-tools-extra/trunk/clangd/unittests/FileIndexTests.cpp @@ -9,6 +9,7 @@ #include "AST.h" #include "Annotations.h" #include "ClangdUnit.h" +#include "Compiler.h" #include "SyncAPI.h" #include "TestFS.h" #include "TestTU.h" @@ -280,7 +281,8 @@ )cpp"; // Rebuild the file. - auto CI = buildCompilerInvocation(PI); + IgnoreDiagnostics IgnoreDiags; + auto CI = buildCompilerInvocation(PI, IgnoreDiags); FileIndex Index; bool IndexUpdated = false; Index: clang-tools-extra/trunk/clangd/unittests/HeadersTests.cpp =================================================================== --- clang-tools-extra/trunk/clangd/unittests/HeadersTests.cpp +++ clang-tools-extra/trunk/clangd/unittests/HeadersTests.cpp @@ -46,7 +46,7 @@ ParseInputs PI; PI.CompileCommand = *Cmd; PI.FS = VFS; - auto CI = buildCompilerInvocation(PI); + auto CI = buildCompilerInvocation(PI, IgnoreDiags); EXPECT_TRUE(static_cast(CI)); // The diagnostic options must be set before creating a CompilerInstance. CI->getDiagnosticOpts().IgnoreWarnings = true; Index: clang-tools-extra/trunk/clangd/unittests/TUSchedulerTests.cpp =================================================================== --- clang-tools-extra/trunk/clangd/unittests/TUSchedulerTests.cpp +++ clang-tools-extra/trunk/clangd/unittests/TUSchedulerTests.cpp @@ -14,6 +14,9 @@ #include "Path.h" #include "TUScheduler.h" #include "TestFS.h" +#include "Threading.h" +#include "clang/Basic/DiagnosticDriver.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/ScopeExit.h" #include "gmock/gmock.h" @@ -28,6 +31,9 @@ using ::testing::AnyOf; using ::testing::Each; using ::testing::ElementsAre; +using ::testing::Eq; +using ::testing::Field; +using ::testing::IsEmpty; using ::testing::Pointee; using ::testing::UnorderedElementsAre; @@ -60,12 +66,22 @@ /// in updateWithDiags. static std::unique_ptr captureDiags() { class CaptureDiags : public ParsingCallbacks { + public: void onMainAST(PathRef File, ParsedAST &AST, PublishFn Publish) override { - auto Diags = AST.getDiagnostics(); + reportDiagnostics(File, AST.getDiagnostics(), Publish); + } + + void onFailedAST(PathRef File, std::vector Diags, + PublishFn Publish) override { + reportDiagnostics(File, Diags, Publish); + } + + private: + void reportDiagnostics(PathRef File, llvm::ArrayRef Diags, + PublishFn Publish) { auto D = Context::current().get(DiagsCallbackKey); if (!D) return; - Publish([&]() { const_cast< llvm::unique_function)> &> (*D)( @@ -720,6 +736,53 @@ TUState(TUAction::Idle, /*No action*/ ""))); } +TEST_F(TUSchedulerTests, CommandLineErrors) { + // We should see errors from command-line parsing inside the main file. + CDB.ExtraClangFlags = {"-fsome-unknown-flag"}; + + TUScheduler S(CDB, /*AsyncThreadsCount=*/getDefaultAsyncThreadsCount(), + /*StorePreambleInMemory=*/true, /*ASTCallbacks=*/captureDiags(), + /*UpdateDebounce=*/std::chrono::steady_clock::duration::zero(), + ASTRetentionPolicy()); + + Notification Ready; + std::vector Diagnostics; + updateWithDiags(S, testPath("foo.cpp"), "void test() {}", + WantDiagnostics::Yes, [&](std::vector D) { + Diagnostics = std::move(D); + Ready.notify(); + }); + Ready.wait(); + + EXPECT_THAT( + Diagnostics, + 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'")))); +} + +TEST_F(TUSchedulerTests, CommandLineWarnings) { + // We should not see warnings from command-line parsing. + CDB.ExtraClangFlags = {"-Wsome-unknown-warning"}; + + TUScheduler S(CDB, /*AsyncThreadsCount=*/getDefaultAsyncThreadsCount(), + /*StorePreambleInMemory=*/true, /*ASTCallbacks=*/captureDiags(), + /*UpdateDebounce=*/std::chrono::steady_clock::duration::zero(), + ASTRetentionPolicy()); + + Notification Ready; + std::vector Diagnostics; + updateWithDiags(S, testPath("foo.cpp"), "void test() {}", + WantDiagnostics::Yes, [&](std::vector D) { + Diagnostics = std::move(D); + Ready.notify(); + }); + Ready.wait(); + + EXPECT_THAT(Diagnostics, IsEmpty()); +} + } // namespace } // namespace clangd } // namespace clang Index: clang-tools-extra/trunk/clangd/unittests/TestTU.cpp =================================================================== --- clang-tools-extra/trunk/clangd/unittests/TestTU.cpp +++ clang-tools-extra/trunk/clangd/unittests/TestTU.cpp @@ -7,6 +7,8 @@ //===----------------------------------------------------------------------===// #include "TestTU.h" +#include "Compiler.h" +#include "Diagnostics.h" #include "TestFS.h" #include "index/FileIndex.h" #include "index/MemIndex.h" @@ -59,14 +61,16 @@ Inputs.Index = ExternalIndex; if (Inputs.Index) Inputs.Opts.SuggestMissingIncludes = true; - auto CI = buildCompilerInvocation(Inputs); + StoreDiags Diags; + auto CI = buildCompilerInvocation(Inputs, Diags); assert(CI && "Failed to build compilation invocation."); auto Preamble = buildPreamble(FullFilename, *CI, /*OldPreamble=*/nullptr, /*OldCompileCommand=*/Inputs.CompileCommand, Inputs, /*StoreInMemory=*/true, /*PreambleCallback=*/nullptr); - auto AST = buildAST(FullFilename, std::move(CI), Inputs, Preamble); + auto AST = + buildAST(FullFilename, std::move(CI), Diags.take(), Inputs, Preamble); if (!AST.hasValue()) { ADD_FAILURE() << "Failed to build code:\n" << Code; llvm_unreachable("Failed to build TestTU!");