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