clang-tools 20.0.0git
ClangdLSPServer.h
Go to the documentation of this file.
1//===--- ClangdLSPServer.h - LSP server --------------------------*- C++-*-===//
2//
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
6//
7//===----------------------------------------------------------------------===//
8
9#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_CLANGDLSPSERVER_H
10#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_CLANGDLSPSERVER_H
11
12#include "ClangdServer.h"
13#include "Diagnostics.h"
15#include "LSPBinder.h"
16#include "Protocol.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"
24#include <chrono>
25#include <cstddef>
26#include <cstdint>
27#include <memory>
28#include <optional>
29#include <vector>
30
31namespace clang {
32namespace clangd {
33
34/// This class exposes ClangdServer's capabilities via Language Server Protocol.
35///
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).
41public:
43 /// Supplies configuration (overrides ClangdServer::ContextProvider).
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;
53
54 /// Per-feature options. Generally ClangdServer lets these vary
55 /// per-request, but LSP allows limited/no customizations.
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.
62 };
63
64 /// Limit the number of references returned (0 means no limit).
65 size_t ReferencesLimit = 0;
66
67 /// Flag to hint the experimental modules support is enabled.
69 };
70
71 ClangdLSPServer(Transport &Transp, const ThreadsafeFS &TFS,
72 const ClangdLSPServer::Options &Opts);
73 /// The destructor blocks on any outstanding background tasks.
75
76 ClangdLSPServer(const ClangdLSPServer &other) = delete;
77 ClangdLSPServer &operator=(const ClangdLSPServer &other) = delete;
78
79 /// Run LSP server loop, communicating with the Transport provided in the
80 /// constructor. This method must not be executed more than once.
81 ///
82 /// \return Whether we shut down cleanly with a 'shutdown' -> 'exit' sequence.
83 bool run();
84
85 /// Profiles resource-usage.
86 void profile(MemoryTree &MT) const;
87
88private:
89 // Implement ClangdServer::Callbacks.
90 void onDiagnosticsReady(PathRef File, llvm::StringRef Version,
91 llvm::ArrayRef<Diag> Diagnostics) override;
92 void onFileUpdated(PathRef File, const TUStatus &Status) override;
93 void onBackgroundIndexProgress(const BackgroundQueue::Stats &Stats) override;
94 void onSemanticsMaybeChanged(PathRef File) override;
95 void onInactiveRegionsReady(PathRef File,
96 std::vector<Range> InactiveRegions) override;
97
98 // LSP methods. Notifications have signature void(const Params&).
99 // Calls have signature void(const Params&, Callback<Response>).
100 void onInitialize(const InitializeParams &, Callback<llvm::json::Value>);
101 void onInitialized(const InitializedParams &);
102 void onShutdown(const NoParams &, Callback<std::nullptr_t>);
103 void onSync(const NoParams &, Callback<std::nullptr_t>);
104 void onDocumentDidOpen(const DidOpenTextDocumentParams &);
105 void onDocumentDidChange(const DidChangeTextDocumentParams &);
106 void onDocumentDidClose(const DidCloseTextDocumentParams &);
107 void onDocumentDidSave(const DidSaveTextDocumentParams &);
108 void onAST(const ASTParams &, Callback<std::optional<ASTNode>>);
109 void onDocumentOnTypeFormatting(const DocumentOnTypeFormattingParams &,
110 Callback<std::vector<TextEdit>>);
111 void onDocumentRangeFormatting(const DocumentRangeFormattingParams &,
112 Callback<std::vector<TextEdit>>);
113 void onDocumentFormatting(const DocumentFormattingParams &,
114 Callback<std::vector<TextEdit>>);
115 // The results are serialized 'vector<DocumentSymbol>' if
116 // SupportsHierarchicalDocumentSymbol is true and 'vector<SymbolInformation>'
117 // otherwise.
118 void onDocumentSymbol(const DocumentSymbolParams &,
120 void onFoldingRange(const FoldingRangeParams &,
121 Callback<std::vector<FoldingRange>>);
122 void onCodeAction(const CodeActionParams &, Callback<llvm::json::Value>);
123 void onCompletion(const CompletionParams &, Callback<CompletionList>);
124 void onSignatureHelp(const TextDocumentPositionParams &,
126 void onGoToDeclaration(const TextDocumentPositionParams &,
127 Callback<std::vector<Location>>);
128 void onGoToDefinition(const TextDocumentPositionParams &,
129 Callback<std::vector<Location>>);
130 void onGoToType(const TextDocumentPositionParams &,
131 Callback<std::vector<Location>>);
132 void onGoToImplementation(const TextDocumentPositionParams &,
133 Callback<std::vector<Location>>);
134 void onReference(const ReferenceParams &, Callback<std::vector<ReferenceLocation>>);
135 void onSwitchSourceHeader(const TextDocumentIdentifier &,
136 Callback<std::optional<URIForFile>>);
137 void onDocumentHighlight(const TextDocumentPositionParams &,
138 Callback<std::vector<DocumentHighlight>>);
139 void onFileEvent(const DidChangeWatchedFilesParams &);
140 void onWorkspaceSymbol(const WorkspaceSymbolParams &,
141 Callback<std::vector<SymbolInformation>>);
142 void onPrepareRename(const TextDocumentPositionParams &,
144 void onRename(const RenameParams &, Callback<WorkspaceEdit>);
145 void onHover(const TextDocumentPositionParams &,
146 Callback<std::optional<Hover>>);
147 void onPrepareTypeHierarchy(const TypeHierarchyPrepareParams &,
148 Callback<std::vector<TypeHierarchyItem>>);
149 void onSuperTypes(const ResolveTypeHierarchyItemParams &,
150 Callback<std::optional<std::vector<TypeHierarchyItem>>>);
151 void onSubTypes(const ResolveTypeHierarchyItemParams &,
152 Callback<std::vector<TypeHierarchyItem>>);
153 void onTypeHierarchy(const TypeHierarchyPrepareParams &,
155 void onResolveTypeHierarchy(const ResolveTypeHierarchyItemParams &,
157 void onPrepareCallHierarchy(const CallHierarchyPrepareParams &,
158 Callback<std::vector<CallHierarchyItem>>);
159 void onCallHierarchyIncomingCalls(
161 Callback<std::vector<CallHierarchyIncomingCall>>);
162 void onCallHierarchyOutgoingCalls(
164 Callback<std::vector<CallHierarchyOutgoingCall>>);
165 void onClangdInlayHints(const InlayHintsParams &,
167 void onInlayHint(const InlayHintsParams &, Callback<std::vector<InlayHint>>);
168 void onChangeConfiguration(const DidChangeConfigurationParams &);
169 void onSymbolInfo(const TextDocumentPositionParams &,
170 Callback<std::vector<SymbolDetails>>);
171 void onSelectionRange(const SelectionRangeParams &,
172 Callback<std::vector<SelectionRange>>);
173 void onDocumentLink(const DocumentLinkParams &,
174 Callback<std::vector<DocumentLink>>);
175 void onSemanticTokens(const SemanticTokensParams &, Callback<SemanticTokens>);
176 void onSemanticTokensDelta(const SemanticTokensDeltaParams &,
178 /// This is a clangd extension. Provides a json tree representing memory usage
179 /// hierarchy.
180 void onMemoryUsage(const NoParams &, Callback<MemoryTree>);
181 void onCommand(const ExecuteCommandParams &, Callback<llvm::json::Value>);
182
183 /// Implement commands.
184 void onCommandApplyEdit(const WorkspaceEdit &, Callback<llvm::json::Value>);
185 void onCommandApplyTweak(const TweakArgs &, Callback<llvm::json::Value>);
186 void onCommandApplyRename(const RenameParams &, Callback<llvm::json::Value>);
187
188 /// Outgoing LSP calls.
191 ApplyWorkspaceEdit;
197 CreateWorkDoneProgress;
199 BeginWorkDoneProgress;
201 ReportWorkDoneProgress;
203 EndWorkDoneProgress;
205
206 void applyEdit(WorkspaceEdit WE, llvm::json::Value Success,
208
209 void bindMethods(LSPBinder &, const ClientCapabilities &Caps);
210 std::optional<ClangdServer::DiagRef> getDiagRef(StringRef File,
211 const clangd::Diagnostic &D);
212
213 /// Checks if completion request should be ignored. We need this due to the
214 /// limitation of the LSP. Per LSP, a client sends requests for all "trigger
215 /// character" we specify, but for '>' and ':' we need to check they actually
216 /// produce '->' and '::', respectively.
217 bool shouldRunCompletion(const CompletionParams &Params) const;
218
219 void applyConfiguration(const ConfigurationSettings &Settings);
220
221 /// Runs profiling and exports memory usage metrics if tracing is enabled and
222 /// profiling hasn't happened recently.
223 void maybeExportMemoryProfile();
224 PeriodicThrottler ShouldProfile;
225
226 /// Run the MemoryCleanup callback if it's time.
227 /// This method is thread safe.
228 void maybeCleanupMemory();
229 PeriodicThrottler ShouldCleanupMemory;
230
231 /// Since initialization of CDBs and ClangdServer is done lazily, the
232 /// following context captures the one used while creating ClangdLSPServer and
233 /// passes it to above mentioned object instances to make sure they share the
234 /// same state.
235 Context BackgroundContext;
236
237 /// Used to indicate that the 'shutdown' request was received from the
238 /// Language Server client.
239 bool ShutdownRequestReceived = false;
240
241 /// Used to indicate the ClangdLSPServer is being destroyed.
242 std::atomic<bool> IsBeingDestroyed = {false};
243
244 // FIXME: The caching is a temporary solution to get corresponding clangd
245 // diagnostic from a LSP diagnostic.
246 // Ideally, ClangdServer can generate an identifier for each diagnostic,
247 // emit them via the LSP's data field (which was newly added in LSP 3.16).
248 std::mutex DiagRefMutex;
249 struct DiagKey {
250 clangd::Range Rng;
251 std::string Message;
252 bool operator<(const DiagKey &Other) const {
253 return std::tie(Rng, Message) < std::tie(Other.Rng, Other.Message);
254 }
255 };
256 DiagKey toDiagKey(const clangd::Diagnostic &LSPDiag) {
257 return {LSPDiag.range, LSPDiag.message};
258 }
259 /// A map from LSP diagnostic to clangd-naive diagnostic.
260 typedef std::map<DiagKey, ClangdServer::DiagRef>
261 DiagnosticToDiagRefMap;
262 /// Caches the mapping LSP and clangd-naive diagnostics per file.
263 llvm::StringMap<DiagnosticToDiagRefMap>
264 DiagRefMap;
265
266 // Last semantic-tokens response, for incremental requests.
267 std::mutex SemanticTokensMutex;
268 llvm::StringMap<SemanticTokens> LastSemanticTokens;
269
270 // Most code should not deal with Transport, callMethod, notify directly.
271 // Use LSPBinder to handle incoming and outgoing calls.
272 clangd::Transport &Transp;
273 class MessageHandler;
274 std::unique_ptr<MessageHandler> MsgHandler;
275 std::mutex TranspWriter;
276
277 void callMethod(StringRef Method, llvm::json::Value Params,
278 Callback<llvm::json::Value> CB) override;
279 void notify(StringRef Method, llvm::json::Value Params) override;
280
281 LSPBinder::RawHandlers Handlers;
282
283 const ThreadsafeFS &TFS;
284 /// Options used for diagnostics.
285 ClangdDiagnosticOptions DiagOpts;
286 /// The supported kinds of the client.
287 SymbolKindBitset SupportedSymbolKinds;
288 /// The supported completion item kinds of the client.
289 CompletionItemKindBitset SupportedCompletionItemKinds;
290 // Whether the client supports CompletionItem.labelDetails.
291 bool SupportsCompletionLabelDetails = false;
292 /// Whether the client supports CodeAction response objects.
293 bool SupportsCodeAction = false;
294 /// From capabilities of textDocument/documentSymbol.
295 bool SupportsHierarchicalDocumentSymbol = false;
296 /// Whether the client supports showing file status.
297 bool SupportFileStatus = false;
298 /// Whether the client supports attaching a container string to references.
299 bool SupportsReferenceContainer = false;
300 /// Which kind of markup should we use in textDocument/hover responses.
301 MarkupKind HoverContentFormat = MarkupKind::PlainText;
302 /// Whether the client supports offsets for parameter info labels.
303 bool SupportsOffsetsInSignatureHelp = false;
304 /// Whether the client supports the versioned document changes.
305 bool SupportsDocumentChanges = false;
306 /// Whether the client supports change annotations on text edits.
307 bool SupportsChangeAnnotation = false;
308
309 std::mutex BackgroundIndexProgressMutex;
310 enum class BackgroundIndexProgress {
311 // Client doesn't support reporting progress. No transitions possible.
312 Unsupported,
313 // The queue is idle, and the client has no progress bar.
314 // Can transition to Creating when we have some activity.
315 Empty,
316 // We've requested the client to create a progress bar.
317 // Meanwhile, the state is buffered in PendingBackgroundIndexProgress.
318 Creating,
319 // The client has a progress bar, and we can send it updates immediately.
320 Live,
321 } BackgroundIndexProgressState = BackgroundIndexProgress::Unsupported;
322 // The progress to send when the progress bar is created.
323 // Only valid in state Creating.
324 BackgroundQueue::Stats PendingBackgroundIndexProgress;
325 /// LSP extension: skip WorkDoneProgressCreate, just send progress streams.
326 bool BackgroundIndexSkipCreate = false;
327
328 Options Opts;
329 // The CDB is created by the "initialize" LSP method.
330 std::unique_ptr<GlobalCompilationDatabase> BaseCDB;
331 // CDB is BaseCDB plus any commands overridden via LSP extensions.
332 std::optional<OverlayCDB> CDB;
333 // The ClangdServer is created by the "initialize" LSP method.
334 std::optional<ClangdServer> Server;
335 // Manages to build module files.
336 std::optional<ModulesBuilder> ModulesManager;
337};
338} // namespace clangd
339} // namespace clang
340
341#endif // LLVM_CLANG_TOOLS_EXTRA_CLANGD_CLANGDLSPSERVER_H
WantDiagnostics Diagnostics
This class exposes ClangdServer's capabilities via Language Server Protocol.
ClangdLSPServer & operator=(const ClangdLSPServer &other)=delete
~ClangdLSPServer()
The destructor blocks on any outstanding background tasks.
void profile(MemoryTree &MT) const
Profiles resource-usage.
bool run()
Run LSP server loop, communicating with the Transport provided in the constructor.
ClangdLSPServer(const ClangdLSPServer &other)=delete
Interface with hooks for users of ClangdServer to be notified of events.
Definition: ClangdServer.h:62
A context is an immutable container for per-request data that must be propagated through layers that ...
Definition: Context.h:69
LSPBinder collects a table of functions that handle LSP calls.
Definition: LSPBinder.h:34
llvm::unique_function< void(const P &)> OutgoingNotification
Definition: LSPBinder.h:90
llvm::unique_function< void(const P &, Callback< R >)> OutgoingMethod
Definition: LSPBinder.h:81
Used to guard an operation that should run at most every N seconds.
Definition: Threading.h:186
Wrapper for vfs::FileSystem for use in multithreaded programs like clangd.
Definition: ThreadsafeFS.h:26
An interface base for small context-sensitive refactoring actions.
Definition: Tweak.h:46
A source of configuration fragments.
std::bitset< SymbolKindMax+1 > SymbolKindBitset
Definition: Protocol.h:411
llvm::unique_function< void(llvm::Expected< T >)> Callback
A Callback<T> is a void function that accepts Expected<T>.
Definition: Function.h:28
bool operator<(const Ref &L, const Ref &R)
Definition: Ref.h:98
std::bitset< CompletionItemKindMax+1 > CompletionItemKindBitset
Definition: Protocol.h:372
llvm::StringRef PathRef
A typedef to represent a ref to file path.
Definition: Path.h:29
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Payload for textDocument/ast request.
Definition: Protocol.h:1996
The parameter of a callHierarchy/incomingCalls request.
Definition: Protocol.h:1605
The parameter of a callHierarchy/outgoingCalls request.
Definition: Protocol.h:1623
The parameter of a textDocument/prepareCallHierarchy request.
Definition: Protocol.h:1568
bool EnableExperimentalModulesSupport
Flag to hint the experimental modules support is enabled.
size_t ReferencesLimit
Limit the number of references returned (0 means no limit).
bool UseDirBasedCDB
Look for compilation databases, rather than using compile commands set via LSP (extensions) only.
std::function< void()> MemoryCleanup
If set, periodically called to release memory.
config::Provider * ConfigProvider
Supplies configuration (overrides ClangdServer::ContextProvider).
clangd::CodeCompleteOptions CodeComplete
Per-feature options.
std::function< bool(const Tweak &)> TweakFilter
Returns true if the tweak should be enabled.
std::optional< OffsetEncoding > Encoding
The offset-encoding to use, or std::nullopt to negotiate it over LSP.
Clangd extension: parameters configurable at any time, via the workspace/didChangeConfiguration notif...
Definition: Protocol.h:587
Parameters for the document link request.
Definition: Protocol.h:1918
A parameter literal used in inlay hint requests.
Definition: Protocol.h:1642
A tree that can be used to represent memory usage of nested components while preserving the hierarchy...
Definition: MemoryTree.h:30
Parameters for the typeHierarchy/resolve request.
Definition: Protocol.h:1551
Body of textDocument/semanticTokens/full/delta request.
Definition: Protocol.h:1853
Body of textDocument/semanticTokens/full request.
Definition: Protocol.h:1844
Arguments for the 'applyTweak' command.
Definition: Protocol.h:1034
The type hierarchy params is an extension of the TextDocumentPositionsParams with optional properties...
Definition: Protocol.h:1486
The edit should either provide changes or documentChanges.
Definition: Protocol.h:1013
The parameters of a Workspace Symbol Request.
Definition: Protocol.h:1180