blob: 7815d4e467952d478d829d9e3ff90bf7ecf22ea1 [file] [log] [blame]
Ilya Biryukov38d79772017-05-16 09:38:59 +00001//===--- ClangdLSPServer.h - LSP server --------------------------*- C++-*-===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// 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
Ilya Biryukov38d79772017-05-16 09:38:59 +00006//
Kirill Bobyrev8e35f1e2018-08-14 16:03:32 +00007//===----------------------------------------------------------------------===//
Ilya Biryukov38d79772017-05-16 09:38:59 +00008
9#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_CLANGDLSPSERVER_H
10#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_CLANGDLSPSERVER_H
11
12#include "ClangdServer.h"
Simon Marchi9569fd52018-03-16 14:30:42 +000013#include "DraftStore.h"
Saleem Abdulrasoole1b9b9d2019-04-10 16:48:52 +000014#include "Features.inc"
Marc-Andre Laperleb387b6e2018-04-23 20:00:52 +000015#include "FindSymbols.h"
Ilya Biryukov103c9512017-06-13 15:59:43 +000016#include "GlobalCompilationDatabase.h"
Ilya Biryukov38d79772017-05-16 09:38:59 +000017#include "Protocol.h"
Sam McCall2c30fbc2018-10-18 12:32:04 +000018#include "Transport.h"
Sam McCallad97ccf2020-04-28 17:49:17 +020019#include "support/Context.h"
20#include "support/Path.h"
Ilya Biryukov38d79772017-05-16 09:38:59 +000021#include "clang/Tooling/Core/Replacement.h"
Krasimir Georgiev0dcb48e2017-07-19 15:43:35 +000022#include "llvm/ADT/Optional.h"
David Goldman60249c22020-01-13 17:01:10 -050023#include "llvm/ADT/StringSet.h"
Sam McCall2cd33e62020-03-04 00:33:29 +010024#include "llvm/Support/JSON.h"
Ilya Biryukov652364b2018-09-26 05:48:29 +000025#include <memory>
Ilya Biryukov38d79772017-05-16 09:38:59 +000026
27namespace clang {
28namespace clangd {
29
Haojian Wuba28e9a2018-01-10 14:44:34 +000030class SymbolIndex;
Ilya Biryukov38d79772017-05-16 09:38:59 +000031
Sam McCall45be5cf2018-09-13 12:58:36 +000032/// This class exposes ClangdServer's capabilities via Language Server Protocol.
33///
Sam McCall2c30fbc2018-10-18 12:32:04 +000034/// MessageHandler binds the implemented LSP methods (e.g. onInitialize) to
35/// corresponding JSON-RPC methods ("initialize").
36/// The server also supports $/cancelRequest (MessageHandler provides this).
Sam McCall6ef1cce2020-01-24 14:08:56 +010037class ClangdLSPServer : private ClangdServer::Callbacks {
Ilya Biryukov38d79772017-05-16 09:38:59 +000038public:
Ilya Biryukov0c1ca6b2017-10-02 15:13:20 +000039 /// If \p CompileCommandsDir has a value, compile_commands.json will be
40 /// loaded only from \p CompileCommandsDir. Otherwise, clangd will look
41 /// for compile_commands.json in all parent directories of each file.
Sam McCallc55d09a2018-11-02 13:09:36 +000042 /// If UseDirBasedCDB is false, compile commands are not read from disk.
43 // FIXME: Clean up signature around CDBs.
Kadir Cetinkaya8d654df2020-06-17 18:09:54 +020044 ClangdLSPServer(Transport &Transp, const ThreadsafeFS &TFS,
Haojian Wu1ca0c582019-01-22 09:39:05 +000045 const clangd::CodeCompleteOptions &CCOpts,
Haojian Wu34d0e1b2020-02-19 15:37:36 +010046 const clangd::RenameOptions &RenameOpts,
Sam McCallc55d09a2018-11-02 13:09:36 +000047 llvm::Optional<Path> CompileCommandsDir, bool UseDirBasedCDB,
Sam McCalla69698f2019-03-27 17:47:49 +000048 llvm::Optional<OffsetEncoding> ForcedOffsetEncoding,
Sam McCallc55d09a2018-11-02 13:09:36 +000049 const ClangdServer::Options &Opts);
Sam McCall8bda5f22019-10-23 11:11:18 +020050 /// The destructor blocks on any outstanding background tasks.
Sam McCall2c30fbc2018-10-18 12:32:04 +000051 ~ClangdLSPServer();
Ilya Biryukov38d79772017-05-16 09:38:59 +000052
Sam McCalldc8f3cf2018-10-17 07:32:05 +000053 /// Run LSP server loop, communicating with the Transport provided in the
54 /// constructor. This method must not be executed more than once.
Ilya Biryukov0d9b8a32017-10-25 08:45:41 +000055 ///
Sam McCalldc8f3cf2018-10-17 07:32:05 +000056 /// \return Whether we shut down cleanly with a 'shutdown' -> 'exit' sequence.
57 bool run();
Ilya Biryukov38d79772017-05-16 09:38:59 +000058
59private:
Sam McCall6ef1cce2020-01-24 14:08:56 +010060 // Implement ClangdServer::Callbacks.
Sam McCall2cd33e62020-03-04 00:33:29 +010061 void onDiagnosticsReady(PathRef File, llvm::StringRef Version,
62 std::vector<Diag> Diagnostics) override;
Haojian Wub6188492018-12-20 15:39:12 +000063 void onFileUpdated(PathRef File, const TUStatus &Status) override;
Haojian Wu0a6000f2019-08-26 08:38:45 +000064 void
Sam McCall2cd33e62020-03-04 00:33:29 +010065 onHighlightingsReady(PathRef File, llvm::StringRef Version,
Haojian Wu0a6000f2019-08-26 08:38:45 +000066 std::vector<HighlightingToken> Highlightings) override;
Sam McCall7d20e802020-01-22 19:41:45 +010067 void onBackgroundIndexProgress(const BackgroundQueue::Stats &Stats) override;
Ilya Biryukov103c9512017-06-13 15:59:43 +000068
Sam McCall2c30fbc2018-10-18 12:32:04 +000069 // LSP methods. Notifications have signature void(const Params&).
70 // Calls have signature void(const Params&, Callback<Response>).
71 void onInitialize(const InitializeParams &, Callback<llvm::json::Value>);
Sam McCall8a2d2942020-03-03 12:12:14 +010072 void onInitialized(const InitializedParams &);
Sam McCall2c30fbc2018-10-18 12:32:04 +000073 void onShutdown(const ShutdownParams &, Callback<std::nullptr_t>);
Sam McCall422c8282018-11-26 16:00:11 +000074 void onSync(const NoParams &, Callback<std::nullptr_t>);
Sam McCall2c30fbc2018-10-18 12:32:04 +000075 void onDocumentDidOpen(const DidOpenTextDocumentParams &);
76 void onDocumentDidChange(const DidChangeTextDocumentParams &);
77 void onDocumentDidClose(const DidCloseTextDocumentParams &);
Sam McCall596b63a2020-04-10 03:27:37 +020078 void onDocumentDidSave(const DidSaveTextDocumentParams &);
Sam McCall2c30fbc2018-10-18 12:32:04 +000079 void onDocumentOnTypeFormatting(const DocumentOnTypeFormattingParams &,
80 Callback<std::vector<TextEdit>>);
81 void onDocumentRangeFormatting(const DocumentRangeFormattingParams &,
82 Callback<std::vector<TextEdit>>);
83 void onDocumentFormatting(const DocumentFormattingParams &,
84 Callback<std::vector<TextEdit>>);
Ilya Biryukov19d75602018-11-23 15:21:19 +000085 // The results are serialized 'vector<DocumentSymbol>' if
86 // SupportsHierarchicalDocumentSymbol is true and 'vector<SymbolInformation>'
87 // otherwise.
Sam McCall2c30fbc2018-10-18 12:32:04 +000088 void onDocumentSymbol(const DocumentSymbolParams &,
Ilya Biryukov19d75602018-11-23 15:21:19 +000089 Callback<llvm::json::Value>);
Kirill Bobyrev7a514c92020-07-14 09:28:38 +020090 void onFoldingRange(const FoldingRangeParams &,
91 Callback<std::vector<FoldingRange>>);
Sam McCall2c30fbc2018-10-18 12:32:04 +000092 void onCodeAction(const CodeActionParams &, Callback<llvm::json::Value>);
Ilya Biryukovb0826bd2019-01-03 13:37:12 +000093 void onCompletion(const CompletionParams &, Callback<CompletionList>);
Sam McCall2c30fbc2018-10-18 12:32:04 +000094 void onSignatureHelp(const TextDocumentPositionParams &,
95 Callback<SignatureHelp>);
Sam McCall866ba2c2019-02-01 11:26:13 +000096 void onGoToDeclaration(const TextDocumentPositionParams &,
97 Callback<std::vector<Location>>);
Sam McCall2c30fbc2018-10-18 12:32:04 +000098 void onGoToDefinition(const TextDocumentPositionParams &,
99 Callback<std::vector<Location>>);
100 void onReference(const ReferenceParams &, Callback<std::vector<Location>>);
101 void onSwitchSourceHeader(const TextDocumentIdentifier &,
Sam McCallb9ec3e92019-05-07 08:30:32 +0000102 Callback<llvm::Optional<URIForFile>>);
Sam McCall2c30fbc2018-10-18 12:32:04 +0000103 void onDocumentHighlight(const TextDocumentPositionParams &,
104 Callback<std::vector<DocumentHighlight>>);
105 void onFileEvent(const DidChangeWatchedFilesParams &);
106 void onCommand(const ExecuteCommandParams &, Callback<llvm::json::Value>);
107 void onWorkspaceSymbol(const WorkspaceSymbolParams &,
108 Callback<std::vector<SymbolInformation>>);
Haojian Wuf429ab62019-07-24 07:49:23 +0000109 void onPrepareRename(const TextDocumentPositionParams &,
110 Callback<llvm::Optional<Range>>);
Sam McCall2c30fbc2018-10-18 12:32:04 +0000111 void onRename(const RenameParams &, Callback<WorkspaceEdit>);
112 void onHover(const TextDocumentPositionParams &,
113 Callback<llvm::Optional<Hover>>);
Kadir Cetinkaya86658022019-03-19 09:27:04 +0000114 void onTypeHierarchy(const TypeHierarchyParams &,
115 Callback<llvm::Optional<TypeHierarchyItem>>);
Nathan Ridge087b0442019-07-13 03:24:48 +0000116 void onResolveTypeHierarchy(const ResolveTypeHierarchyItemParams &,
117 Callback<llvm::Optional<TypeHierarchyItem>>);
Sam McCall2c30fbc2018-10-18 12:32:04 +0000118 void onChangeConfiguration(const DidChangeConfigurationParams &);
Jan Korousb4067012018-11-27 16:40:46 +0000119 void onSymbolInfo(const TextDocumentPositionParams &,
120 Callback<std::vector<SymbolDetails>>);
Utkarsh Saxena55925da2019-09-24 13:38:33 +0000121 void onSelectionRange(const SelectionRangeParams &,
122 Callback<std::vector<SelectionRange>>);
Sam McCall8d7ecc12019-12-16 19:08:51 +0100123 void onDocumentLink(const DocumentLinkParams &,
124 Callback<std::vector<DocumentLink>>);
Sam McCall71177ac2020-03-24 02:24:47 +0100125 void onSemanticTokens(const SemanticTokensParams &, Callback<SemanticTokens>);
Sam McCall5fea54b2020-07-10 16:08:14 +0200126 void onSemanticTokensDelta(const SemanticTokensDeltaParams &,
127 Callback<SemanticTokensOrDelta>);
Ilya Biryukov38d79772017-05-16 09:38:59 +0000128
Ilya Biryukov71028b82018-03-12 15:28:22 +0000129 std::vector<Fix> getFixes(StringRef File, const clangd::Diagnostic &D);
Ilya Biryukovafb55542017-05-16 14:40:30 +0000130
Ilya Biryukovb0826bd2019-01-03 13:37:12 +0000131 /// Checks if completion request should be ignored. We need this due to the
132 /// limitation of the LSP. Per LSP, a client sends requests for all "trigger
133 /// character" we specify, but for '>' and ':' we need to check they actually
134 /// produce '->' and '::', respectively.
135 bool shouldRunCompletion(const CompletionParams &Params) const;
136
Sam McCall596b63a2020-04-10 03:27:37 +0200137 /// Requests a reparse of currently opened files using their latest source.
138 /// This will typically only rebuild if something other than the source has
139 /// changed (e.g. the CDB yields different flags, or files included in the
140 /// preamble have been modified).
141 void reparseOpenFilesIfNeeded(
142 llvm::function_ref<bool(llvm::StringRef File)> Filter);
Sam McCallbc904612018-10-25 04:22:52 +0000143 void applyConfiguration(const ConfigurationSettings &Settings);
Simon Marchi9569fd52018-03-16 14:30:42 +0000144
Johan Vikstroma848dab2019-07-04 07:53:12 +0000145 /// Sends a "publishSemanticHighlighting" notification to the LSP client.
Sam McCalledf6a192020-03-24 00:31:14 +0100146 void
147 publishTheiaSemanticHighlighting(const TheiaSemanticHighlightingParams &);
Johan Vikstroma848dab2019-07-04 07:53:12 +0000148
Ilya Biryukov49c10712019-03-25 10:15:11 +0000149 /// Sends a "publishDiagnostics" notification to the LSP client.
Sam McCall6525a6b2020-03-03 12:44:40 +0100150 void publishDiagnostics(const PublishDiagnosticsParams &);
Ilya Biryukov49c10712019-03-25 10:15:11 +0000151
Kadir Cetinkayab1817062019-10-15 14:59:08 +0000152 /// Since initialization of CDBs and ClangdServer is done lazily, the
153 /// following context captures the one used while creating ClangdLSPServer and
154 /// passes it to above mentioned object instances to make sure they share the
155 /// same state.
Kadir Cetinkaya9d662472019-10-15 14:20:52 +0000156 Context BackgroundContext;
157
Ilya Biryukovafb55542017-05-16 14:40:30 +0000158 /// Used to indicate that the 'shutdown' request was received from the
159 /// Language Server client.
Ilya Biryukov0d9b8a32017-10-25 08:45:41 +0000160 bool ShutdownRequestReceived = false;
161
Haojian Wuf2516342019-08-05 12:48:09 +0000162 /// Used to indicate the ClangdLSPServer is being destroyed.
163 std::atomic<bool> IsBeingDestroyed = {false};
164
Ilya Biryukov38d79772017-05-16 09:38:59 +0000165 std::mutex FixItsMutex;
Ilya Biryukov71028b82018-03-12 15:28:22 +0000166 typedef std::map<clangd::Diagnostic, std::vector<Fix>, LSPDiagnosticCompare>
Ilya Biryukov38d79772017-05-16 09:38:59 +0000167 DiagnosticToReplacementMap;
168 /// Caches FixIts per file and diagnostics
169 llvm::StringMap<DiagnosticToReplacementMap> FixItsMap;
Johan Vikstromc2653ef22019-08-01 08:08:44 +0000170 std::mutex HighlightingsMutex;
171 llvm::StringMap<std::vector<HighlightingToken>> FileToHighlightings;
Sam McCall9e3063e2020-04-01 16:21:44 +0200172 // Last semantic-tokens response, for incremental requests.
173 std::mutex SemanticTokensMutex;
174 llvm::StringMap<SemanticTokens> LastSemanticTokens;
Ilya Biryukov103c9512017-06-13 15:59:43 +0000175
Sam McCall2c30fbc2018-10-18 12:32:04 +0000176 // Most code should not deal with Transport directly.
177 // MessageHandler deals with incoming messages, use call() etc for outgoing.
Sam McCalldc8f3cf2018-10-17 07:32:05 +0000178 clangd::Transport &Transp;
Sam McCall2c30fbc2018-10-18 12:32:04 +0000179 class MessageHandler;
180 std::unique_ptr<MessageHandler> MsgHandler;
Sam McCall2c30fbc2018-10-18 12:32:04 +0000181 std::mutex TranspWriter;
Haojian Wuf2516342019-08-05 12:48:09 +0000182
Sam McCallfa69b602020-09-24 01:14:12 +0200183 template <typename T>
184 static Expected<T> parse(const llvm::json::Value &Raw,
185 llvm::StringRef PayloadName,
186 llvm::StringRef PayloadKind) {
187 T Result;
188 llvm::json::Path::Root Root;
189 if (!fromJSON(Raw, Result, Root)) {
190 elog("Failed to decode {0} {1}", PayloadName, PayloadKind);
191 // Dump the relevant parts of the broken message.
192 std::string Context;
193 llvm::raw_string_ostream OS(Context);
194 Root.printErrorContext(Raw, OS);
195 vlog("{0}", OS.str());
196 // Report the error (e.g. to the client).
197 return llvm::make_error<LSPError>(
198 llvm::formatv("failed to decode {0} {1}", PayloadName, PayloadKind),
199 ErrorCode::InvalidParams);
200 }
201 return std::move(Result);
202 }
203
Haojian Wuf2516342019-08-05 12:48:09 +0000204 template <typename Response>
205 void call(StringRef Method, llvm::json::Value Params, Callback<Response> CB) {
206 // Wrap the callback with LSP conversion and error-handling.
Benjamin Kramer9880b5d2019-08-15 14:16:06 +0000207 auto HandleReply =
Sam McCallfa69b602020-09-24 01:14:12 +0200208 [CB = std::move(CB), Ctx = Context::current().clone(),
209 Method = Method.str()](
Benjamin Kramer9880b5d2019-08-15 14:16:06 +0000210 llvm::Expected<llvm::json::Value> RawResponse) mutable {
Sam McCallfa69b602020-09-24 01:14:12 +0200211 if (!RawResponse)
212 return CB(RawResponse.takeError());
213 CB(parse<Response>(*RawResponse, Method, "response"));
Benjamin Kramer9880b5d2019-08-15 14:16:06 +0000214 };
215 callRaw(Method, std::move(Params), std::move(HandleReply));
Haojian Wuf2516342019-08-05 12:48:09 +0000216 }
217 void callRaw(StringRef Method, llvm::json::Value Params,
218 Callback<llvm::json::Value> CB);
Sam McCall2c30fbc2018-10-18 12:32:04 +0000219 void notify(StringRef Method, llvm::json::Value Params);
Sam McCall7d20e802020-01-22 19:41:45 +0100220 template <typename T> void progress(const llvm::json::Value &Token, T Value) {
221 ProgressParams<T> Params;
222 Params.token = Token;
223 Params.value = std::move(Value);
224 notify("$/progress", Params);
225 }
Sam McCall2c30fbc2018-10-18 12:32:04 +0000226
Kadir Cetinkaya8d654df2020-06-17 18:09:54 +0200227 const ThreadsafeFS &TFS;
Ilya Biryukovd3b04e32017-12-05 10:42:57 +0000228 /// Options used for code completion
229 clangd::CodeCompleteOptions CCOpts;
Haojian Wu34d0e1b2020-02-19 15:37:36 +0100230 /// Options used for rename.
231 clangd::RenameOptions RenameOpts;
Alex Lorenz8626d362018-08-10 17:25:07 +0000232 /// Options used for diagnostics.
233 ClangdDiagnosticOptions DiagOpts;
Marc-Andre Laperleb387b6e2018-04-23 20:00:52 +0000234 /// The supported kinds of the client.
235 SymbolKindBitset SupportedSymbolKinds;
Kadir Cetinkaya133d46f2018-09-27 17:13:07 +0000236 /// The supported completion item kinds of the client.
237 CompletionItemKindBitset SupportedCompletionItemKinds;
Haojian Wub6188492018-12-20 15:39:12 +0000238 /// Whether the client supports CodeAction response objects.
Sam McCall20841d42018-10-16 16:29:41 +0000239 bool SupportsCodeAction = false;
Ilya Biryukov19d75602018-11-23 15:21:19 +0000240 /// From capabilities of textDocument/documentSymbol.
241 bool SupportsHierarchicalDocumentSymbol = false;
Haojian Wub6188492018-12-20 15:39:12 +0000242 /// Whether the client supports showing file status.
243 bool SupportFileStatus = false;
Ilya Biryukovf9169d02019-05-29 10:01:00 +0000244 /// Which kind of markup should we use in textDocument/hover responses.
245 MarkupKind HoverContentFormat = MarkupKind::PlainText;
Ilya Biryukov4ef0f822019-06-04 09:36:59 +0000246 /// Whether the client supports offsets for parameter info labels.
247 bool SupportsOffsetsInSignatureHelp = false;
Sam McCall7d20e802020-01-22 19:41:45 +0100248 std::mutex BackgroundIndexProgressMutex;
249 enum class BackgroundIndexProgress {
250 // Client doesn't support reporting progress. No transitions possible.
251 Unsupported,
252 // The queue is idle, and the client has no progress bar.
253 // Can transition to Creating when we have some activity.
254 Empty,
255 // We've requested the client to create a progress bar.
256 // Meanwhile, the state is buffered in PendingBackgroundIndexProgress.
257 Creating,
258 // The client has a progress bar, and we can send it updates immediately.
259 Live,
260 } BackgroundIndexProgressState = BackgroundIndexProgress::Unsupported;
261 // The progress to send when the progress bar is created.
262 // Only valid in state Creating.
263 BackgroundQueue::Stats PendingBackgroundIndexProgress;
264 /// LSP extension: skip WorkDoneProgressCreate, just send progress streams.
265 bool BackgroundIndexSkipCreate = false;
Ilya Biryukov4ef0f822019-06-04 09:36:59 +0000266 // Store of the current versions of the open documents.
Simon Marchi9569fd52018-03-16 14:30:42 +0000267 DraftStore DraftMgr;
268
Sam McCalld1c9d112018-10-23 14:19:54 +0000269 // The CDB is created by the "initialize" LSP method.
Sam McCallc55d09a2018-11-02 13:09:36 +0000270 bool UseDirBasedCDB; // FIXME: make this a capability.
Sam McCall4b86bb02018-10-25 02:22:53 +0000271 llvm::Optional<Path> CompileCommandsDir; // FIXME: merge with capability?
Sam McCallc55d09a2018-11-02 13:09:36 +0000272 std::unique_ptr<GlobalCompilationDatabase> BaseCDB;
Kazuaki Ishizakib7ecf1c2020-01-04 10:28:41 -0500273 // CDB is BaseCDB plus any commands overridden via LSP extensions.
Sam McCallc55d09a2018-11-02 13:09:36 +0000274 llvm::Optional<OverlayCDB> CDB;
Sam McCall3d0adbe2018-10-18 14:41:50 +0000275 ClangdServer::Options ClangdServerOpts;
Sam McCalla69698f2019-03-27 17:47:49 +0000276 llvm::Optional<OffsetEncoding> NegotiatedOffsetEncoding;
Sam McCall8bda5f22019-10-23 11:11:18 +0200277 // The ClangdServer is created by the "initialize" LSP method.
278 llvm::Optional<ClangdServer> Server;
Kadir Cetinkaya689bf932018-08-24 13:09:41 +0000279};
Ilya Biryukov38d79772017-05-16 09:38:59 +0000280} // namespace clangd
281} // namespace clang
282
Kirill Bobyrev8e35f1e2018-08-14 16:03:32 +0000283#endif // LLVM_CLANG_TOOLS_EXTRA_CLANGD_CLANGDLSPSERVER_H