diff --git a/clang-tools-extra/clangd/ClangdLSPServer.h b/clang-tools-extra/clangd/ClangdLSPServer.h --- a/clang-tools-extra/clangd/ClangdLSPServer.h +++ b/clang-tools-extra/clangd/ClangdLSPServer.h @@ -60,6 +60,25 @@ /// Limit the number of references returned (0 means no limit). size_t ReferencesLimit = 0; + + /// Options used for diagnostics. + ClangdDiagnosticOptions DiagOpts; + /// Set of symbol kinds to use. + SymbolKindBitset SymbolKinds; + /// Set of completion item kinds to use. + CompletionItemKindBitset CompletionItemKinds; + /// Whether to emit code actions or commands as code action responses. + bool EmitCodeAction = false; + /// Whether to emit hierarchical or flat document symbol responses. + bool HierarchicalDocumentSymbol = false; + /// Whether to send file status updates. + bool EmitFileStatus = false; + /// Which kind of markup should we use in textDocument/hover responses. + MarkupKind HoverContentFormat = MarkupKind::PlainText; + /// Whether to have offsets for parameter info labels. + bool OffsetsInSignatureHelp = false; + /// LSP extension: skip WorkDoneProgressCreate, just send progress streams. + bool BackgroundIndexSkipCreate = false; }; ClangdLSPServer(Transport &Transp, const ThreadsafeFS &TFS, @@ -250,22 +269,6 @@ LSPBinder::RawHandlers Handlers; const ThreadsafeFS &TFS; - /// Options used for diagnostics. - ClangdDiagnosticOptions DiagOpts; - /// The supported kinds of the client. - SymbolKindBitset SupportedSymbolKinds; - /// The supported completion item kinds of the client. - CompletionItemKindBitset SupportedCompletionItemKinds; - /// Whether the client supports CodeAction response objects. - bool SupportsCodeAction = false; - /// From capabilities of textDocument/documentSymbol. - bool SupportsHierarchicalDocumentSymbol = false; - /// Whether the client supports showing file status. - bool SupportFileStatus = false; - /// Which kind of markup should we use in textDocument/hover responses. - MarkupKind HoverContentFormat = MarkupKind::PlainText; - /// Whether the client supports offsets for parameter info labels. - bool SupportsOffsetsInSignatureHelp = false; std::mutex BackgroundIndexProgressMutex; enum class BackgroundIndexProgress { // Client doesn't support reporting progress. No transitions possible. @@ -282,8 +285,6 @@ // The progress to send when the progress bar is created. // Only valid in state Creating. BackgroundQueue::Stats PendingBackgroundIndexProgress; - /// LSP extension: skip WorkDoneProgressCreate, just send progress streams. - bool BackgroundIndexSkipCreate = false; Options Opts; // The CDB is created by the "initialize" LSP method. diff --git a/clang-tools-extra/clangd/ClangdLSPServer.cpp b/clang-tools-extra/clangd/ClangdLSPServer.cpp --- a/clang-tools-extra/clangd/ClangdLSPServer.cpp +++ b/clang-tools-extra/clangd/ClangdLSPServer.cpp @@ -441,8 +441,9 @@ return Modifiers; } -void ClangdLSPServer::onInitialize(const InitializeParams &Params, - Callback Reply) { +// Set server options to align with client capabilities. +static void updateServerOptions(ClangdLSPServer::Options &Opts, + const InitializeParams &Params) { // Determine character encoding first as it affects constructed ClangdServer. if (Params.capabilities.offsetEncoding && !Opts.Encoding) { Opts.Encoding = OffsetEncoding::UTF16; // fallback @@ -463,9 +464,6 @@ Opts.WorkspaceRoot = std::string(Params.rootUri->file()); else if (Params.rootPath && !Params.rootPath->empty()) Opts.WorkspaceRoot = *Params.rootPath; - if (Server) - return Reply(llvm::make_error("server already initialized", - ErrorCode::InvalidRequest)); Opts.CodeComplete.EnableSnippets = Params.capabilities.CompletionSnippets; Opts.CodeComplete.IncludeFixIts = Params.capabilities.CompletionFixes; @@ -475,25 +473,34 @@ Params.capabilities.CompletionDocumentationFormat; Opts.SignatureHelpDocumentationFormat = Params.capabilities.SignatureHelpDocumentationFormat; - DiagOpts.EmbedFixesInDiagnostics = Params.capabilities.DiagnosticFixes; - DiagOpts.SendDiagnosticCategory = Params.capabilities.DiagnosticCategory; - DiagOpts.EmitRelatedLocations = + Opts.DiagOpts.EmbedFixesInDiagnostics = Params.capabilities.DiagnosticFixes; + Opts.DiagOpts.SendDiagnosticCategory = Params.capabilities.DiagnosticCategory; + Opts.DiagOpts.EmitRelatedLocations = Params.capabilities.DiagnosticRelatedInformation; + Opts.LineFoldingOnly = Params.capabilities.LineFoldingOnly; + Opts.ImplicitCancellation = !Params.capabilities.CancelsStaleRequests; + if (Params.capabilities.WorkspaceSymbolKinds) - SupportedSymbolKinds |= *Params.capabilities.WorkspaceSymbolKinds; + Opts.SymbolKinds |= *Params.capabilities.WorkspaceSymbolKinds; if (Params.capabilities.CompletionItemKinds) - SupportedCompletionItemKinds |= *Params.capabilities.CompletionItemKinds; - SupportsCodeAction = Params.capabilities.CodeActionStructure; - SupportsHierarchicalDocumentSymbol = + Opts.CompletionItemKinds |= *Params.capabilities.CompletionItemKinds; + Opts.EmitCodeAction = Params.capabilities.CodeActionStructure; + Opts.HierarchicalDocumentSymbol = Params.capabilities.HierarchicalDocumentSymbol; - SupportFileStatus = Params.initializationOptions.FileStatus; - HoverContentFormat = Params.capabilities.HoverContentFormat; - Opts.LineFoldingOnly = Params.capabilities.LineFoldingOnly; - SupportsOffsetsInSignatureHelp = Params.capabilities.OffsetsInSignatureHelp; + Opts.EmitFileStatus = Params.initializationOptions.FileStatus; + Opts.HoverContentFormat = Params.capabilities.HoverContentFormat; + Opts.OffsetsInSignatureHelp = Params.capabilities.OffsetsInSignatureHelp; + Opts.BackgroundIndexSkipCreate = Params.capabilities.ImplicitProgressCreation; +} + +void ClangdLSPServer::onInitialize(const InitializeParams &Params, + Callback Reply) { + if (Server) + return Reply(llvm::make_error("server already initialized", + ErrorCode::InvalidRequest)); + updateServerOptions(Opts, Params); if (Params.capabilities.WorkDoneProgress) BackgroundIndexProgressState = BackgroundIndexProgress::Empty; - BackgroundIndexSkipCreate = Params.capabilities.ImplicitProgressCreation; - Opts.ImplicitCancellation = !Params.capabilities.CancelsStaleRequests; if (Opts.UseDirBasedCDB) { DirectoryBasedGlobalCompilationDatabase::Options CDBOpts(TFS); @@ -615,7 +622,6 @@ CodeAction::INFO_KIND}}} : llvm::json::Value(true); - std::vector Commands; for (llvm::StringRef Command : Handlers.CommandHandlers.keys()) Commands.push_back(Command); @@ -800,7 +806,7 @@ if (!Items) return Reply(Items.takeError()); for (auto &Sym : *Items) - Sym.kind = adjustKindToCapability(Sym.kind, SupportedSymbolKinds); + Sym.kind = adjustKindToCapability(Sym.kind, Opts.SymbolKinds); Reply(std::move(*Items)); }); @@ -936,8 +942,8 @@ llvm::Expected> Items) mutable { if (!Items) return Reply(Items.takeError()); - adjustSymbolKinds(*Items, SupportedSymbolKinds); - if (SupportsHierarchicalDocumentSymbol) + adjustSymbolKinds(*Items, Opts.SymbolKinds); + if (Opts.HierarchicalDocumentSymbol) return Reply(std::move(*Items)); return Reply(flattenSymbolHierarchy(*Items, FileURI)); }); @@ -1021,7 +1027,7 @@ OnlyFix->diagnostics = {Diags.front()}; } - if (SupportsCodeAction) + if (Opts.EmitCodeAction) return Reply(llvm::json::Array(Actions)); std::vector Commands; for (const auto &Action : Actions) { @@ -1059,7 +1065,7 @@ for (const auto &R : List->Completions) { CompletionItem C = R.render(Opts); C.kind = adjustKindToCapability( - C.kind, SupportedCompletionItemKinds); + C.kind, this->Opts.CompletionItemKinds); LSPList.items.push_back(std::move(C)); } return Reply(std::move(LSPList)); @@ -1074,7 +1080,7 @@ llvm::Expected Signature) mutable { if (!Signature) return Reply(Signature.takeError()); - if (SupportsOffsetsInSignatureHelp) + if (Opts.OffsetsInSignatureHelp) return Reply(std::move(*Signature)); // Strip out the offsets from signature help for // clients that only support string labels. @@ -1176,9 +1182,9 @@ return Reply(llvm::None); Hover R; - R.contents.kind = HoverContentFormat; + R.contents.kind = Opts.HoverContentFormat; R.range = (*H)->SymRange; - switch (HoverContentFormat) { + switch (Opts.HoverContentFormat) { case MarkupKind::PlainText: R.contents.value = (*H)->present().asPlainText(); return Reply(std::move(R)); @@ -1558,9 +1564,9 @@ ShouldCleanupMemory(/*Period=*/std::chrono::minutes(1), /*Delay=*/std::chrono::minutes(1)), BackgroundContext(Context::current().clone()), Transp(Transp), - MsgHandler(new MessageHandler(*this)), TFS(TFS), - SupportedSymbolKinds(defaultSymbolKinds()), - SupportedCompletionItemKinds(defaultCompletionItemKinds()), Opts(Opts) { + MsgHandler(new MessageHandler(*this)), TFS(TFS), Opts(Opts) { + this->Opts.SymbolKinds = defaultSymbolKinds(); + this->Opts.CompletionItemKinds = defaultCompletionItemKinds(); if (Opts.ConfigProvider) { assert(!Opts.ContextProvider && "Only one of ConfigProvider and ContextProvider allowed!"); @@ -1703,7 +1709,7 @@ Notification.uri = URIForFile::canonicalize(File, /*TUPath=*/File); DiagnosticToReplacementMap LocalFixIts; // Temporary storage for (auto &Diag : Diagnostics) { - toLSPDiags(Diag, Notification.uri, DiagOpts, + toLSPDiags(Diag, Notification.uri, Opts.DiagOpts, [&](clangd::Diagnostic Diag, llvm::ArrayRef Fixes) { auto &FixItsForDiagnostic = LocalFixIts[Diag]; llvm::copy(Fixes, std::back_inserter(FixItsForDiagnostic)); @@ -1763,7 +1769,7 @@ PendingBackgroundIndexProgress = Stats; return; case BackgroundIndexProgress::Empty: { - if (BackgroundIndexSkipCreate) { + if (Opts.BackgroundIndexSkipCreate) { NotifyProgress(Stats); break; } @@ -1794,7 +1800,7 @@ } void ClangdLSPServer::onFileUpdated(PathRef File, const TUStatus &Status) { - if (!SupportFileStatus) + if (!Opts.EmitFileStatus) return; // FIXME: we don't emit "BuildingFile" and `RunningAction`, as these // two statuses are running faster in practice, which leads the UI constantly