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