1 //===--- ClangdLSPServer.h - LSP server --------------------------*- C++-*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_CLANGDLSPSERVER_H
10 #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_CLANGDLSPSERVER_H
12 #include "ClangdServer.h"
13 #include "Diagnostics.h"
14 #include "GlobalCompilationDatabase.h"
15 #include "LSPBinder.h"
17 #include "Transport.h"
18 #include "support/Context.h"
19 #include "support/MemoryTree.h"
20 #include "support/Path.h"
21 #include "support/Threading.h"
22 #include "llvm/ADT/ArrayRef.h"
23 #include "llvm/Support/JSON.h"
34 /// This class exposes ClangdServer's capabilities via Language Server Protocol.
36 /// MessageHandler binds the implemented LSP methods (e.g. onInitialize) to
37 /// corresponding JSON-RPC methods ("initialize").
38 /// The server also supports $/cancelRequest (MessageHandler provides this).
39 class ClangdLSPServer
: private ClangdServer::Callbacks
,
40 private LSPBinder::RawOutgoing
{
42 struct Options
: ClangdServer::Options
{
43 /// Supplies configuration (overrides ClangdServer::ContextProvider).
44 config::Provider
*ConfigProvider
= nullptr;
45 /// Look for compilation databases, rather than using compile commands
46 /// set via LSP (extensions) only.
47 bool UseDirBasedCDB
= true;
48 /// The offset-encoding to use, or std::nullopt to negotiate it over LSP.
49 std::optional
<OffsetEncoding
> Encoding
;
50 /// If set, periodically called to release memory.
51 /// Consider malloc_trim(3)
52 std::function
<void()> MemoryCleanup
= nullptr;
54 /// Per-feature options. Generally ClangdServer lets these vary
55 /// per-request, but LSP allows limited/no customizations.
56 clangd::CodeCompleteOptions CodeComplete
;
57 MarkupKind SignatureHelpDocumentationFormat
= MarkupKind::PlainText
;
58 clangd::RenameOptions Rename
;
59 /// Returns true if the tweak should be enabled.
60 std::function
<bool(const Tweak
&)> TweakFilter
= [](const Tweak
&T
) {
61 return !T
.hidden(); // only enable non-hidden tweaks.
64 /// Limit the number of references returned (0 means no limit).
65 size_t ReferencesLimit
= 0;
68 ClangdLSPServer(Transport
&Transp
, const ThreadsafeFS
&TFS
,
69 const ClangdLSPServer::Options
&Opts
);
70 /// The destructor blocks on any outstanding background tasks.
73 /// Run LSP server loop, communicating with the Transport provided in the
74 /// constructor. This method must not be executed more than once.
76 /// \return Whether we shut down cleanly with a 'shutdown' -> 'exit' sequence.
79 /// Profiles resource-usage.
80 void profile(MemoryTree
&MT
) const;
83 // Implement ClangdServer::Callbacks.
84 void onDiagnosticsReady(PathRef File
, llvm::StringRef Version
,
85 llvm::ArrayRef
<Diag
> Diagnostics
) override
;
86 void onFileUpdated(PathRef File
, const TUStatus
&Status
) override
;
87 void onBackgroundIndexProgress(const BackgroundQueue::Stats
&Stats
) override
;
88 void onSemanticsMaybeChanged(PathRef File
) override
;
89 void onInactiveRegionsReady(PathRef File
,
90 std::vector
<Range
> InactiveRegions
) override
;
92 // LSP methods. Notifications have signature void(const Params&).
93 // Calls have signature void(const Params&, Callback<Response>).
94 void onInitialize(const InitializeParams
&, Callback
<llvm::json::Value
>);
95 void onInitialized(const InitializedParams
&);
96 void onShutdown(const NoParams
&, Callback
<std::nullptr_t
>);
97 void onSync(const NoParams
&, Callback
<std::nullptr_t
>);
98 void onDocumentDidOpen(const DidOpenTextDocumentParams
&);
99 void onDocumentDidChange(const DidChangeTextDocumentParams
&);
100 void onDocumentDidClose(const DidCloseTextDocumentParams
&);
101 void onDocumentDidSave(const DidSaveTextDocumentParams
&);
102 void onAST(const ASTParams
&, Callback
<std::optional
<ASTNode
>>);
103 void onDocumentOnTypeFormatting(const DocumentOnTypeFormattingParams
&,
104 Callback
<std::vector
<TextEdit
>>);
105 void onDocumentRangeFormatting(const DocumentRangeFormattingParams
&,
106 Callback
<std::vector
<TextEdit
>>);
107 void onDocumentFormatting(const DocumentFormattingParams
&,
108 Callback
<std::vector
<TextEdit
>>);
109 // The results are serialized 'vector<DocumentSymbol>' if
110 // SupportsHierarchicalDocumentSymbol is true and 'vector<SymbolInformation>'
112 void onDocumentSymbol(const DocumentSymbolParams
&,
113 Callback
<llvm::json::Value
>);
114 void onFoldingRange(const FoldingRangeParams
&,
115 Callback
<std::vector
<FoldingRange
>>);
116 void onCodeAction(const CodeActionParams
&, Callback
<llvm::json::Value
>);
117 void onCompletion(const CompletionParams
&, Callback
<CompletionList
>);
118 void onSignatureHelp(const TextDocumentPositionParams
&,
119 Callback
<SignatureHelp
>);
120 void onGoToDeclaration(const TextDocumentPositionParams
&,
121 Callback
<std::vector
<Location
>>);
122 void onGoToDefinition(const TextDocumentPositionParams
&,
123 Callback
<std::vector
<Location
>>);
124 void onGoToType(const TextDocumentPositionParams
&,
125 Callback
<std::vector
<Location
>>);
126 void onGoToImplementation(const TextDocumentPositionParams
&,
127 Callback
<std::vector
<Location
>>);
128 void onReference(const ReferenceParams
&, Callback
<std::vector
<ReferenceLocation
>>);
129 void onSwitchSourceHeader(const TextDocumentIdentifier
&,
130 Callback
<std::optional
<URIForFile
>>);
131 void onDocumentHighlight(const TextDocumentPositionParams
&,
132 Callback
<std::vector
<DocumentHighlight
>>);
133 void onFileEvent(const DidChangeWatchedFilesParams
&);
134 void onWorkspaceSymbol(const WorkspaceSymbolParams
&,
135 Callback
<std::vector
<SymbolInformation
>>);
136 void onPrepareRename(const TextDocumentPositionParams
&,
137 Callback
<std::optional
<Range
>>);
138 void onRename(const RenameParams
&, Callback
<WorkspaceEdit
>);
139 void onHover(const TextDocumentPositionParams
&,
140 Callback
<std::optional
<Hover
>>);
141 void onPrepareTypeHierarchy(const TypeHierarchyPrepareParams
&,
142 Callback
<std::vector
<TypeHierarchyItem
>>);
143 void onSuperTypes(const ResolveTypeHierarchyItemParams
&,
144 Callback
<std::optional
<std::vector
<TypeHierarchyItem
>>>);
145 void onSubTypes(const ResolveTypeHierarchyItemParams
&,
146 Callback
<std::vector
<TypeHierarchyItem
>>);
147 void onTypeHierarchy(const TypeHierarchyPrepareParams
&,
148 Callback
<llvm::json::Value
>);
149 void onResolveTypeHierarchy(const ResolveTypeHierarchyItemParams
&,
150 Callback
<llvm::json::Value
>);
151 void onPrepareCallHierarchy(const CallHierarchyPrepareParams
&,
152 Callback
<std::vector
<CallHierarchyItem
>>);
153 void onCallHierarchyIncomingCalls(
154 const CallHierarchyIncomingCallsParams
&,
155 Callback
<std::vector
<CallHierarchyIncomingCall
>>);
156 void onClangdInlayHints(const InlayHintsParams
&,
157 Callback
<llvm::json::Value
>);
158 void onInlayHint(const InlayHintsParams
&, Callback
<std::vector
<InlayHint
>>);
159 void onChangeConfiguration(const DidChangeConfigurationParams
&);
160 void onSymbolInfo(const TextDocumentPositionParams
&,
161 Callback
<std::vector
<SymbolDetails
>>);
162 void onSelectionRange(const SelectionRangeParams
&,
163 Callback
<std::vector
<SelectionRange
>>);
164 void onDocumentLink(const DocumentLinkParams
&,
165 Callback
<std::vector
<DocumentLink
>>);
166 void onSemanticTokens(const SemanticTokensParams
&, Callback
<SemanticTokens
>);
167 void onSemanticTokensDelta(const SemanticTokensDeltaParams
&,
168 Callback
<SemanticTokensOrDelta
>);
169 /// This is a clangd extension. Provides a json tree representing memory usage
171 void onMemoryUsage(const NoParams
&, Callback
<MemoryTree
>);
172 void onCommand(const ExecuteCommandParams
&, Callback
<llvm::json::Value
>);
174 /// Implement commands.
175 void onCommandApplyEdit(const WorkspaceEdit
&, Callback
<llvm::json::Value
>);
176 void onCommandApplyTweak(const TweakArgs
&, Callback
<llvm::json::Value
>);
178 /// Outgoing LSP calls.
179 LSPBinder::OutgoingMethod
<ApplyWorkspaceEditParams
,
180 ApplyWorkspaceEditResponse
>
182 LSPBinder::OutgoingNotification
<ShowMessageParams
> ShowMessage
;
183 LSPBinder::OutgoingNotification
<PublishDiagnosticsParams
> PublishDiagnostics
;
184 LSPBinder::OutgoingNotification
<FileStatus
> NotifyFileStatus
;
185 LSPBinder::OutgoingNotification
<InactiveRegionsParams
> PublishInactiveRegions
;
186 LSPBinder::OutgoingMethod
<WorkDoneProgressCreateParams
, std::nullptr_t
>
187 CreateWorkDoneProgress
;
188 LSPBinder::OutgoingNotification
<ProgressParams
<WorkDoneProgressBegin
>>
189 BeginWorkDoneProgress
;
190 LSPBinder::OutgoingNotification
<ProgressParams
<WorkDoneProgressReport
>>
191 ReportWorkDoneProgress
;
192 LSPBinder::OutgoingNotification
<ProgressParams
<WorkDoneProgressEnd
>>
194 LSPBinder::OutgoingMethod
<NoParams
, std::nullptr_t
> SemanticTokensRefresh
;
196 void applyEdit(WorkspaceEdit WE
, llvm::json::Value Success
,
197 Callback
<llvm::json::Value
> Reply
);
199 void bindMethods(LSPBinder
&, const ClientCapabilities
&Caps
);
200 std::optional
<ClangdServer::DiagRef
> getDiagRef(StringRef File
,
201 const clangd::Diagnostic
&D
);
203 /// Checks if completion request should be ignored. We need this due to the
204 /// limitation of the LSP. Per LSP, a client sends requests for all "trigger
205 /// character" we specify, but for '>' and ':' we need to check they actually
206 /// produce '->' and '::', respectively.
207 bool shouldRunCompletion(const CompletionParams
&Params
) const;
209 void applyConfiguration(const ConfigurationSettings
&Settings
);
211 /// Runs profiling and exports memory usage metrics if tracing is enabled and
212 /// profiling hasn't happened recently.
213 void maybeExportMemoryProfile();
214 PeriodicThrottler ShouldProfile
;
216 /// Run the MemoryCleanup callback if it's time.
217 /// This method is thread safe.
218 void maybeCleanupMemory();
219 PeriodicThrottler ShouldCleanupMemory
;
221 /// Since initialization of CDBs and ClangdServer is done lazily, the
222 /// following context captures the one used while creating ClangdLSPServer and
223 /// passes it to above mentioned object instances to make sure they share the
225 Context BackgroundContext
;
227 /// Used to indicate that the 'shutdown' request was received from the
228 /// Language Server client.
229 bool ShutdownRequestReceived
= false;
231 /// Used to indicate the ClangdLSPServer is being destroyed.
232 std::atomic
<bool> IsBeingDestroyed
= {false};
234 // FIXME: The caching is a temporary solution to get corresponding clangd
235 // diagnostic from a LSP diagnostic.
236 // Ideally, ClangdServer can generate an identifier for each diagnostic,
237 // emit them via the LSP's data field (which was newly added in LSP 3.16).
238 std::mutex DiagRefMutex
;
242 bool operator<(const DiagKey
&Other
) const {
243 return std::tie(Rng
, Message
) < std::tie(Other
.Rng
, Other
.Message
);
246 DiagKey
toDiagKey(const clangd::Diagnostic
&LSPDiag
) {
247 return {LSPDiag
.range
, LSPDiag
.message
};
249 /// A map from LSP diagnostic to clangd-naive diagnostic.
250 typedef std::map
<DiagKey
, ClangdServer::DiagRef
>
251 DiagnosticToDiagRefMap
;
252 /// Caches the mapping LSP and clangd-naive diagnostics per file.
253 llvm::StringMap
<DiagnosticToDiagRefMap
>
256 // Last semantic-tokens response, for incremental requests.
257 std::mutex SemanticTokensMutex
;
258 llvm::StringMap
<SemanticTokens
> LastSemanticTokens
;
260 // Most code should not deal with Transport, callMethod, notify directly.
261 // Use LSPBinder to handle incoming and outgoing calls.
262 clangd::Transport
&Transp
;
263 class MessageHandler
;
264 std::unique_ptr
<MessageHandler
> MsgHandler
;
265 std::mutex TranspWriter
;
267 void callMethod(StringRef Method
, llvm::json::Value Params
,
268 Callback
<llvm::json::Value
> CB
) override
;
269 void notify(StringRef Method
, llvm::json::Value Params
) override
;
271 LSPBinder::RawHandlers Handlers
;
273 const ThreadsafeFS
&TFS
;
274 /// Options used for diagnostics.
275 ClangdDiagnosticOptions DiagOpts
;
276 /// The supported kinds of the client.
277 SymbolKindBitset SupportedSymbolKinds
;
278 /// The supported completion item kinds of the client.
279 CompletionItemKindBitset SupportedCompletionItemKinds
;
280 // Whether the client supports CompletionItem.labelDetails.
281 bool SupportsCompletionLabelDetails
= false;
282 /// Whether the client supports CodeAction response objects.
283 bool SupportsCodeAction
= false;
284 /// From capabilities of textDocument/documentSymbol.
285 bool SupportsHierarchicalDocumentSymbol
= false;
286 /// Whether the client supports showing file status.
287 bool SupportFileStatus
= false;
288 /// Whether the client supports attaching a container string to references.
289 bool SupportsReferenceContainer
= false;
290 /// Which kind of markup should we use in textDocument/hover responses.
291 MarkupKind HoverContentFormat
= MarkupKind::PlainText
;
292 /// Whether the client supports offsets for parameter info labels.
293 bool SupportsOffsetsInSignatureHelp
= false;
294 /// Whether the client supports the versioned document changes.
295 bool SupportsDocumentChanges
= false;
296 /// Whether the client supports change annotations on text edits.
297 bool SupportsChangeAnnotation
= false;
299 std::mutex BackgroundIndexProgressMutex
;
300 enum class BackgroundIndexProgress
{
301 // Client doesn't support reporting progress. No transitions possible.
303 // The queue is idle, and the client has no progress bar.
304 // Can transition to Creating when we have some activity.
306 // We've requested the client to create a progress bar.
307 // Meanwhile, the state is buffered in PendingBackgroundIndexProgress.
309 // The client has a progress bar, and we can send it updates immediately.
311 } BackgroundIndexProgressState
= BackgroundIndexProgress::Unsupported
;
312 // The progress to send when the progress bar is created.
313 // Only valid in state Creating.
314 BackgroundQueue::Stats PendingBackgroundIndexProgress
;
315 /// LSP extension: skip WorkDoneProgressCreate, just send progress streams.
316 bool BackgroundIndexSkipCreate
= false;
319 // The CDB is created by the "initialize" LSP method.
320 std::unique_ptr
<GlobalCompilationDatabase
> BaseCDB
;
321 // CDB is BaseCDB plus any commands overridden via LSP extensions.
322 std::optional
<OverlayCDB
> CDB
;
323 // The ClangdServer is created by the "initialize" LSP method.
324 std::optional
<ClangdServer
> Server
;
326 } // namespace clangd
329 #endif // LLVM_CLANG_TOOLS_EXTRA_CLANGD_CLANGDLSPSERVER_H