xref: /llvm-project/clang-tools-extra/clangd/ClangdLSPServer.h (revision f59b600c21add076d6a876f29f94990b24b8e321)
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"
14 #include "GlobalCompilationDatabase.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 
31 namespace clang {
32 namespace 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).
39 class ClangdLSPServer : private ClangdServer::Callbacks,
40                         private LSPBinder::RawOutgoing {
41 public:
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;
53 
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.
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.
68     bool EnableExperimentalModulesSupport = false;
69   };
70 
71   ClangdLSPServer(Transport &Transp, const ThreadsafeFS &TFS,
72                   const ClangdLSPServer::Options &Opts);
73   /// The destructor blocks on any outstanding background tasks.
74   ~ClangdLSPServer();
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 
88 private:
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 &,
119                         Callback<llvm::json::Value>);
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 &,
125                        Callback<SignatureHelp>);
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 &,
143                        Callback<PrepareRenameResult>);
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 &,
154                        Callback<llvm::json::Value>);
155   void onResolveTypeHierarchy(const ResolveTypeHierarchyItemParams &,
156                               Callback<llvm::json::Value>);
157   void onPrepareCallHierarchy(const CallHierarchyPrepareParams &,
158                               Callback<std::vector<CallHierarchyItem>>);
159   void onCallHierarchyIncomingCalls(
160       const CallHierarchyIncomingCallsParams &,
161       Callback<std::vector<CallHierarchyIncomingCall>>);
162   void onCallHierarchyOutgoingCalls(
163       const CallHierarchyOutgoingCallsParams &,
164       Callback<std::vector<CallHierarchyOutgoingCall>>);
165   void onClangdInlayHints(const InlayHintsParams &,
166                           Callback<llvm::json::Value>);
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 &,
177                              Callback<SemanticTokensOrDelta>);
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.
189   LSPBinder::OutgoingMethod<ApplyWorkspaceEditParams,
190                             ApplyWorkspaceEditResponse>
191       ApplyWorkspaceEdit;
192   LSPBinder::OutgoingNotification<ShowMessageParams> ShowMessage;
193   LSPBinder::OutgoingNotification<PublishDiagnosticsParams> PublishDiagnostics;
194   LSPBinder::OutgoingNotification<FileStatus> NotifyFileStatus;
195   LSPBinder::OutgoingNotification<InactiveRegionsParams> PublishInactiveRegions;
196   LSPBinder::OutgoingMethod<WorkDoneProgressCreateParams, std::nullptr_t>
197       CreateWorkDoneProgress;
198   LSPBinder::OutgoingNotification<ProgressParams<WorkDoneProgressBegin>>
199       BeginWorkDoneProgress;
200   LSPBinder::OutgoingNotification<ProgressParams<WorkDoneProgressReport>>
201       ReportWorkDoneProgress;
202   LSPBinder::OutgoingNotification<ProgressParams<WorkDoneProgressEnd>>
203       EndWorkDoneProgress;
204   LSPBinder::OutgoingMethod<NoParams, std::nullptr_t> SemanticTokensRefresh;
205 
206   void applyEdit(WorkspaceEdit WE, llvm::json::Value Success,
207                  Callback<llvm::json::Value> Reply);
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
342