diff --git a/clang-tools-extra/clangd/ClangdServer.cpp b/clang-tools-extra/clangd/ClangdServer.cpp --- a/clang-tools-extra/clangd/ClangdServer.cpp +++ b/clang-tools-extra/clangd/ClangdServer.cpp @@ -238,11 +238,16 @@ } } } + ParseInputs ParseInput{IP->Command, FS, IP->Contents.str()}; + ParseInput.Index = Index; + ParseInput.Opts.BuildRecoveryAST = BuildRecoveryAST; + ParseInput.Opts.PreserveRecoveryASTType = PreserveRecoveryASTType; + // FIXME(ibiryukov): even if Preamble is non-null, we may want to check // both the old and the new version in case only one of them matches. CodeCompleteResult Result = clangd::codeComplete( - File, IP->Command, IP->Preamble, IP->Contents, Pos, FS, - CodeCompleteOpts, SpecFuzzyFind ? SpecFuzzyFind.getPointer() : nullptr); + File, Pos, IP->Preamble, ParseInput, CodeCompleteOpts, + SpecFuzzyFind ? SpecFuzzyFind.getPointer() : nullptr); { clang::clangd::trace::Span Tracer("Completion results callback"); CB(std::move(Result)); @@ -281,8 +286,11 @@ return CB(llvm::createStringError(llvm::inconvertibleErrorCode(), "Failed to parse includes")); - CB(clangd::signatureHelp(File, IP->Command, *PreambleData, IP->Contents, - Pos, FS, Index)); + ParseInputs ParseInput{IP->Command, FS, IP->Contents.str()}; + ParseInput.Index = Index; + ParseInput.Opts.BuildRecoveryAST = BuildRecoveryAST; + ParseInput.Opts.PreserveRecoveryASTType = PreserveRecoveryASTType; + CB(clangd::signatureHelp(File, Pos, *PreambleData, ParseInput)); }; // Unlike code completion, we wait for a preamble here. diff --git a/clang-tools-extra/clangd/CodeComplete.h b/clang-tools-extra/clangd/CodeComplete.h --- a/clang-tools-extra/clangd/CodeComplete.h +++ b/clang-tools-extra/clangd/CodeComplete.h @@ -15,6 +15,7 @@ #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_CODECOMPLETE_H #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_CODECOMPLETE_H +#include "Compiler.h" #include "Headers.h" #include "Protocol.h" #include "Quality.h" @@ -270,21 +271,16 @@ /// the speculative result is used by code completion (e.g. speculation failed), /// the speculative result is not consumed, and `SpecFuzzyFind` is only /// destroyed when the async request finishes. -CodeCompleteResult codeComplete(PathRef FileName, - const tooling::CompileCommand &Command, +CodeCompleteResult codeComplete(PathRef FileName, Position Pos, const PreambleData *Preamble, - StringRef Contents, Position Pos, - IntrusiveRefCntPtr VFS, + const ParseInputs &ParseInput, CodeCompleteOptions Opts, SpeculativeFuzzyFind *SpecFuzzyFind = nullptr); /// Get signature help at a specified \p Pos in \p FileName. -SignatureHelp signatureHelp(PathRef FileName, - const tooling::CompileCommand &Command, - const PreambleData &Preamble, StringRef Contents, - Position Pos, - IntrusiveRefCntPtr VFS, - const SymbolIndex *Index); +SignatureHelp signatureHelp(PathRef FileName, Position Pos, + const PreambleData &Preamble, + const ParseInputs &ParseInput); // For index-based completion, we only consider: // * symbols in namespaces or translation unit scopes (e.g. no class diff --git a/clang-tools-extra/clangd/CodeComplete.cpp b/clang-tools-extra/clangd/CodeComplete.cpp --- a/clang-tools-extra/clangd/CodeComplete.cpp +++ b/clang-tools-extra/clangd/CodeComplete.cpp @@ -1029,12 +1029,10 @@ struct SemaCompleteInput { PathRef FileName; - const tooling::CompileCommand &Command; + size_t Offset; const PreambleData &Preamble; llvm::Optional Patch; - llvm::StringRef Contents; - size_t Offset; - llvm::IntrusiveRefCntPtr VFS; + const ParseInputs &ParseInput; }; void loadMainFilePreambleMacros(const Preprocessor &PP, @@ -1062,17 +1060,12 @@ const SemaCompleteInput &Input, IncludeStructure *Includes = nullptr) { trace::Span Tracer("Sema completion"); - llvm::IntrusiveRefCntPtr VFS = Input.VFS; + llvm::IntrusiveRefCntPtr VFS = Input.ParseInput.FS; if (Input.Preamble.StatCache) VFS = Input.Preamble.StatCache->getConsumingFS(std::move(VFS)); - ParseInputs ParseInput; - ParseInput.CompileCommand = Input.Command; - ParseInput.FS = VFS; - ParseInput.Contents = std::string(Input.Contents); - // FIXME: setup the recoveryAST and recoveryASTType in ParseInput properly. IgnoreDiagnostics IgnoreDiags; - auto CI = buildCompilerInvocation(ParseInput, IgnoreDiags); + auto CI = buildCompilerInvocation(Input.ParseInput, IgnoreDiags); if (!CI) { elog("Couldn't create CompilerInvocation"); return false; @@ -1090,10 +1083,11 @@ FrontendOpts.CodeCompletionAt.FileName = std::string(Input.FileName); std::tie(FrontendOpts.CodeCompletionAt.Line, FrontendOpts.CodeCompletionAt.Column) = - offsetToClangLineColumn(Input.Contents, Input.Offset); + offsetToClangLineColumn(Input.ParseInput.Contents, Input.Offset); std::unique_ptr ContentsBuffer = - llvm::MemoryBuffer::getMemBufferCopy(Input.Contents, Input.FileName); + llvm::MemoryBuffer::getMemBufferCopy(Input.ParseInput.Contents, + Input.FileName); // The diagnostic options must be set before creating a CompilerInstance. CI->getDiagnosticOpts().IgnoreWarnings = true; // We reuse the preamble whether it's valid or not. This is a @@ -1260,9 +1254,9 @@ CodeCompleteResult run(const SemaCompleteInput &SemaCCInput) && { trace::Span Tracer("CodeCompleteFlow"); - HeuristicPrefix = - guessCompletionPrefix(SemaCCInput.Contents, SemaCCInput.Offset); - populateContextWords(SemaCCInput.Contents); + HeuristicPrefix = guessCompletionPrefix(SemaCCInput.ParseInput.Contents, + SemaCCInput.Offset); + populateContextWords(SemaCCInput.ParseInput.Contents); if (Opts.Index && SpecFuzzyFind && SpecFuzzyFind->CachedReq.hasValue()) { assert(!SpecFuzzyFind->Result.valid()); SpecReq = speculativeFuzzyFindRequestForCompletion( @@ -1278,13 +1272,14 @@ assert(Recorder && "Recorder is not set"); CCContextKind = Recorder->CCContext.getKind(); IsUsingDeclaration = Recorder->CCContext.isUsingDeclaration(); - auto Style = getFormatStyleForFile( - SemaCCInput.FileName, SemaCCInput.Contents, SemaCCInput.VFS.get()); + auto Style = getFormatStyleForFile(SemaCCInput.FileName, + SemaCCInput.ParseInput.Contents, + SemaCCInput.ParseInput.FS.get()); // If preprocessor was run, inclusions from preprocessor callback should // already be added to Includes. Inserter.emplace( - SemaCCInput.FileName, SemaCCInput.Contents, Style, - SemaCCInput.Command.Directory, + SemaCCInput.FileName, SemaCCInput.ParseInput.Contents, Style, + SemaCCInput.ParseInput.CompileCommand.Directory, &Recorder->CCSema->getPreprocessor().getHeaderSearchInfo()); for (const auto &Inc : Includes.MainFileIncludes) Inserter->addExisting(Inc); @@ -1750,12 +1745,12 @@ return Result; } -CodeCompleteResult -codeComplete(PathRef FileName, const tooling::CompileCommand &Command, - const PreambleData *Preamble, llvm::StringRef Contents, - Position Pos, llvm::IntrusiveRefCntPtr VFS, - CodeCompleteOptions Opts, SpeculativeFuzzyFind *SpecFuzzyFind) { - auto Offset = positionToOffset(Contents, Pos); +CodeCompleteResult codeComplete(PathRef FileName, Position Pos, + const PreambleData *Preamble, + const ParseInputs &ParseInput, + CodeCompleteOptions Opts, + SpeculativeFuzzyFind *SpecFuzzyFind) { + auto Offset = positionToOffset(ParseInput.Contents, Pos); if (!Offset) { elog("Code completion position was invalid {0}", Offset.takeError()); return CodeCompleteResult(); @@ -1764,21 +1759,18 @@ FileName, Preamble ? Preamble->Includes : IncludeStructure(), SpecFuzzyFind, Opts); return (!Preamble || Opts.RunParser == CodeCompleteOptions::NeverParse) - ? std::move(Flow).runWithoutSema(Contents, *Offset, VFS) - : std::move(Flow).run({FileName, Command, *Preamble, + ? std::move(Flow).runWithoutSema(ParseInput.Contents, *Offset, + ParseInput.FS) + : std::move(Flow).run({FileName, *Offset, *Preamble, // We want to serve code completions with // low latency, so don't bother patching. - /*PreamblePatch=*/llvm::None, Contents, - *Offset, VFS}); + /*PreamblePatch=*/llvm::None, ParseInput}); } -SignatureHelp signatureHelp(PathRef FileName, - const tooling::CompileCommand &Command, +SignatureHelp signatureHelp(PathRef FileName, Position Pos, const PreambleData &Preamble, - llvm::StringRef Contents, Position Pos, - llvm::IntrusiveRefCntPtr VFS, - const SymbolIndex *Index) { - auto Offset = positionToOffset(Contents, Pos); + const ParseInputs &ParseInput) { + auto Offset = positionToOffset(ParseInput.Contents, Pos); if (!Offset) { elog("Signature help position was invalid {0}", Offset.takeError()); return SignatureHelp(); @@ -1789,16 +1781,12 @@ Options.IncludeMacros = false; Options.IncludeCodePatterns = false; Options.IncludeBriefComments = false; - - ParseInputs PI; - PI.CompileCommand = Command; - PI.Contents = Contents.str(); - PI.FS = std::move(VFS); semaCodeComplete( - std::make_unique(Options, Index, Result), Options, - {FileName, Command, Preamble, - PreamblePatch::create(FileName, PI, Preamble), Contents, *Offset, - std::move(PI.FS)}); + std::make_unique(Options, ParseInput.Index, + Result), + Options, + {FileName, *Offset, Preamble, + PreamblePatch::create(FileName, ParseInput, Preamble), ParseInput}); return Result; } diff --git a/clang-tools-extra/clangd/Compiler.h b/clang-tools-extra/clangd/Compiler.h --- a/clang-tools-extra/clangd/Compiler.h +++ b/clang-tools-extra/clangd/Compiler.h @@ -54,7 +54,7 @@ bool ForceRebuild = false; // Used to recover from diagnostics (e.g. find missing includes for symbol). const SymbolIndex *Index = nullptr; - ParseOptions Opts; + ParseOptions Opts = ParseOptions(); }; /// Builds compiler invocation that could be used to build AST or preamble. diff --git a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp --- a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp +++ b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp @@ -117,8 +117,11 @@ } auto Preamble = buildPreamble(testPath(TU.Filename), *CI, Inputs, /*InMemory=*/true, /*Callback=*/nullptr); - return codeComplete(testPath(TU.Filename), Inputs.CompileCommand, - Preamble.get(), TU.Code, Point, Inputs.FS, Opts); + ParseInputs ParseInput{Inputs.CompileCommand, Inputs.FS, TU.Code}; + ParseInput.Opts.BuildRecoveryAST = true; + ParseInput.Opts.PreserveRecoveryASTType = true; + return codeComplete(testPath(TU.Filename), Point, Preamble.get(), ParseInput, + Opts); } // Runs code completion. @@ -148,8 +151,10 @@ MockFSProvider FS; Annotations Test(Text); - return codeComplete(FilePath, tooling::CompileCommand(), /*Preamble=*/nullptr, - Test.code(), Test.point(), FS.getFileSystem(), Opts); + ParseInputs ParseInput{tooling::CompileCommand(), FS.getFileSystem(), + Test.code().str()}; + return codeComplete(FilePath, Test.point(), /*Preamble=*/nullptr, ParseInput, + Opts); } Symbol withReferences(int N, Symbol S) { @@ -753,8 +758,7 @@ EXPECT_THAT(Results, ElementsAre(Named("ifndef"))); } -// FIXME: enable it. -TEST(CompletionTest, DISABLED_CompletionRecoveryASTType) { +TEST(CompletionTest, CompletionRecoveryASTType) { auto Results = completions(R"cpp( struct S { int member; }; S overloaded(int); @@ -1067,8 +1071,11 @@ ADD_FAILURE() << "Couldn't build Preamble"; return {}; } - return signatureHelp(testPath(TU.Filename), Inputs.CompileCommand, *Preamble, - Text, Point, Inputs.FS, Index.get()); + ParseInputs ParseInput{Inputs.CompileCommand, Inputs.FS, Text.str()}; + ParseInput.Index = Index.get(); + ParseInput.Opts.BuildRecoveryAST = true; + ParseInput.Opts.PreserveRecoveryASTType = true; + return signatureHelp(testPath(TU.Filename), Point, *Preamble, ParseInput); } SignatureHelp signatures(llvm::StringRef Text, @@ -1219,9 +1226,10 @@ void bar() { foo(^2); })cpp"); TU.Code = Test.code().str(); Inputs = TU.inputs(); - auto Results = - signatureHelp(testPath(TU.Filename), Inputs.CompileCommand, - *EmptyPreamble, TU.Code, Test.point(), Inputs.FS, nullptr); + + ParseInputs ParseInput{Inputs.CompileCommand, Inputs.FS, TU.Code}; + auto Results = signatureHelp(testPath(TU.Filename), Test.point(), + *EmptyPreamble, ParseInput); EXPECT_THAT(Results.signatures, ElementsAre(Sig("foo([[int x]]) -> int"))); EXPECT_EQ(0, Results.activeSignature); EXPECT_EQ(0, Results.activeParameter);