MLIR 24.0.0git
LSPServer.cpp
Go to the documentation of this file.
1//===- LSPServer.cpp - MLIR Language Server -------------------------------===//
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#include "LSPServer.h"
10#include "MLIRServer.h"
11#include "Protocol.h"
12#include "llvm/Support/LSP/Logging.h"
13#include "llvm/Support/LSP/Transport.h"
14#include <optional>
15
16#define DEBUG_TYPE "mlir-lsp-server"
17
18using namespace mlir;
19using namespace mlir::lsp;
20
21using llvm::lsp::Callback;
22using llvm::lsp::CodeAction;
23using llvm::lsp::CodeActionParams;
24using llvm::lsp::CompletionList;
25using llvm::lsp::CompletionParams;
26using llvm::lsp::DidChangeTextDocumentParams;
27using llvm::lsp::DidCloseTextDocumentParams;
28using llvm::lsp::DidOpenTextDocumentParams;
29using llvm::lsp::DocumentSymbol;
30using llvm::lsp::DocumentSymbolParams;
31using llvm::lsp::Hover;
32using llvm::lsp::InitializedParams;
33using llvm::lsp::InitializeParams;
34using llvm::lsp::JSONTransport;
35using llvm::lsp::Logger;
36using llvm::lsp::MessageHandler;
39using llvm::lsp::NoParams;
40using llvm::lsp::OutgoingNotification;
41using llvm::lsp::PublishDiagnosticsParams;
42using llvm::lsp::ReferenceParams;
43using llvm::lsp::TextDocumentPositionParams;
44using llvm::lsp::TextDocumentSyncKind;
45using llvm::lsp::URIForFile;
46
47//===----------------------------------------------------------------------===//
48// LSPServer
49//===----------------------------------------------------------------------===//
50
51namespace {
52struct LSPServer {
53 LSPServer(MLIRServer &server) : server(server) {}
54
55 //===--------------------------------------------------------------------===//
56 // Initialization
57
58 void onInitialize(const InitializeParams &params,
59 Callback<llvm::json::Value> reply);
60 void onInitialized(const InitializedParams &params);
61 void onShutdown(const NoParams &params, Callback<std::nullptr_t> reply);
62
63 //===--------------------------------------------------------------------===//
64 // Document Change
65
66 void onDocumentDidOpen(const DidOpenTextDocumentParams &params);
67 void onDocumentDidClose(const DidCloseTextDocumentParams &params);
68 void onDocumentDidChange(const DidChangeTextDocumentParams &params);
69
70 //===--------------------------------------------------------------------===//
71 // Definitions and References
72
73 void onGoToDefinition(const TextDocumentPositionParams &params,
74 Callback<std::vector<llvm::lsp::Location>> reply);
75 void onReference(const ReferenceParams &params,
76 Callback<std::vector<llvm::lsp::Location>> reply);
77
78 //===--------------------------------------------------------------------===//
79 // Hover
80
81 void onHover(const TextDocumentPositionParams &params,
82 Callback<std::optional<Hover>> reply);
83
84 //===--------------------------------------------------------------------===//
85 // Document Symbols
86
87 void onDocumentSymbol(const DocumentSymbolParams &params,
88 Callback<std::vector<DocumentSymbol>> reply);
89
90 //===--------------------------------------------------------------------===//
91 // Code Completion
92
93 void onCompletion(const CompletionParams &params,
94 Callback<CompletionList> reply);
95
96 //===--------------------------------------------------------------------===//
97 // Code Action
98
99 void onCodeAction(const CodeActionParams &params,
100 Callback<llvm::json::Value> reply);
101
102 //===--------------------------------------------------------------------===//
103 // Bytecode
104
105 void onConvertFromBytecode(const MLIRConvertBytecodeParams &params,
106 Callback<MLIRConvertBytecodeResult> reply);
107 void onConvertToBytecode(const MLIRConvertBytecodeParams &params,
108 Callback<MLIRConvertBytecodeResult> reply);
109
110 //===--------------------------------------------------------------------===//
111 // Fields
112 //===--------------------------------------------------------------------===//
113
114 MLIRServer &server;
115
116 /// An outgoing notification used to send diagnostics to the client when they
117 /// are ready to be processed.
118 OutgoingNotification<PublishDiagnosticsParams> publishDiagnostics;
119
120 /// Used to indicate that the 'shutdown' request was received from the
121 /// Language Server client.
122 bool shutdownRequestReceived = false;
123};
124} // namespace
125
126//===----------------------------------------------------------------------===//
127// Initialization
128//===----------------------------------------------------------------------===//
129
130void LSPServer::onInitialize(const InitializeParams &params,
131 Callback<llvm::json::Value> reply) {
132 // Configure the workspace root if it was provided.
133 if (params.rootUri) {
134 llvm::Expected<URIForFile> rootURI = URIForFile::fromURI(*params.rootUri);
135 if (rootURI)
136 server.setWorkspaceRoot(rootURI->file());
137 else
138 consumeError(rootURI.takeError());
139 } else if (params.rootPath) {
140 server.setWorkspaceRoot(*params.rootPath);
141 }
142
143 // Send a response with the capabilities of this server.
144 llvm::json::Object serverCaps{
145 {"textDocumentSync",
146 llvm::json::Object{
147 {"openClose", true},
148 {"change", (int)TextDocumentSyncKind::Full},
149 {"save", true},
150 }},
151 {"completionProvider",
152 llvm::json::Object{
153 {"allCommitCharacters",
154 {
155 "\t",
156 ";",
157 ",",
158 ".",
159 "=",
160 }},
161 {"resolveProvider", false},
162 {"triggerCharacters",
163 {".", "%", "^", "!", "#", "(", ",", "<", ":", "[", " ", "\"", "/"}},
164 }},
165 {"definitionProvider", true},
166 {"referencesProvider", true},
167 {"hoverProvider", true},
168
169 // For now we only support documenting symbols when the client supports
170 // hierarchical symbols.
171 {"documentSymbolProvider",
172 params.capabilities.hierarchicalDocumentSymbol},
173 };
174
175 // Per LSP, codeActionProvider can be either boolean or CodeActionOptions.
176 // CodeActionOptions is only valid if the client supports action literal
177 // via textDocument.codeAction.codeActionLiteralSupport.
178 serverCaps["codeActionProvider"] =
179 params.capabilities.codeActionStructure
180 ? llvm::json::Object{{"codeActionKinds",
181 {CodeAction::kQuickFix, CodeAction::kRefactor,
182 CodeAction::kInfo}}}
183 : llvm::json::Value(true);
184
185 llvm::json::Object result{
186 {{"serverInfo",
187 llvm::json::Object{{"name", "mlir-lsp-server"}, {"version", "0.0.0"}}},
188 {"capabilities", std::move(serverCaps)}}};
189 reply(std::move(result));
190}
191void LSPServer::onInitialized(const InitializedParams &) {}
192void LSPServer::onShutdown(const NoParams &, Callback<std::nullptr_t> reply) {
193 shutdownRequestReceived = true;
194 reply(nullptr);
195}
196
197//===----------------------------------------------------------------------===//
198// Document Change
199//===----------------------------------------------------------------------===//
200
201void LSPServer::onDocumentDidOpen(const DidOpenTextDocumentParams &params) {
202 PublishDiagnosticsParams diagParams(params.textDocument.uri,
203 params.textDocument.version);
204 server.addOrUpdateDocument(params.textDocument.uri, params.textDocument.text,
205 params.textDocument.version,
206 diagParams.diagnostics);
207
208 // Publish any recorded diagnostics.
209 publishDiagnostics(diagParams);
210}
211void LSPServer::onDocumentDidClose(const DidCloseTextDocumentParams &params) {
212 std::optional<int64_t> version =
213 server.removeDocument(params.textDocument.uri);
214 if (!version)
215 return;
216
217 // Empty out the diagnostics shown for this document. This will clear out
218 // anything currently displayed by the client for this document (e.g. in the
219 // "Problems" pane of VSCode).
220 publishDiagnostics(
221 PublishDiagnosticsParams(params.textDocument.uri, *version));
222}
223void LSPServer::onDocumentDidChange(const DidChangeTextDocumentParams &params) {
224 // TODO: We currently only support full document updates, we should refactor
225 // to avoid this.
226 if (params.contentChanges.size() != 1)
227 return;
228 PublishDiagnosticsParams diagParams(params.textDocument.uri,
229 params.textDocument.version);
230 server.addOrUpdateDocument(
231 params.textDocument.uri, params.contentChanges.front().text,
232 params.textDocument.version, diagParams.diagnostics);
233
234 // Publish any recorded diagnostics.
235 publishDiagnostics(diagParams);
236}
237
238//===----------------------------------------------------------------------===//
239// Definitions and References
240//===----------------------------------------------------------------------===//
241
242void LSPServer::onGoToDefinition(
243 const TextDocumentPositionParams &params,
244 Callback<std::vector<llvm::lsp::Location>> reply) {
245 std::vector<llvm::lsp::Location> locations;
246 server.getLocationsOf(params.textDocument.uri, params.position, locations);
247 reply(std::move(locations));
248}
249
250void LSPServer::onReference(const ReferenceParams &params,
251 Callback<std::vector<llvm::lsp::Location>> reply) {
252 std::vector<llvm::lsp::Location> locations;
253 server.findReferencesOf(params.textDocument.uri, params.position, locations);
254 reply(std::move(locations));
255}
256
257//===----------------------------------------------------------------------===//
258// Hover
259//===----------------------------------------------------------------------===//
260
261void LSPServer::onHover(const TextDocumentPositionParams &params,
262 Callback<std::optional<Hover>> reply) {
263 reply(server.findHover(params.textDocument.uri, params.position));
264}
265
266//===----------------------------------------------------------------------===//
267// Document Symbols
268//===----------------------------------------------------------------------===//
269
270void LSPServer::onDocumentSymbol(const DocumentSymbolParams &params,
271 Callback<std::vector<DocumentSymbol>> reply) {
272 std::vector<DocumentSymbol> symbols;
273 server.findDocumentSymbols(params.textDocument.uri, symbols);
274 reply(std::move(symbols));
275}
276
277//===----------------------------------------------------------------------===//
278// Code Completion
279//===----------------------------------------------------------------------===//
280
281void LSPServer::onCompletion(const CompletionParams &params,
282 Callback<CompletionList> reply) {
283 reply(server.getCodeCompletion(params.textDocument.uri, params.position));
284}
285
286//===----------------------------------------------------------------------===//
287// Code Action
288//===----------------------------------------------------------------------===//
289
290void LSPServer::onCodeAction(const CodeActionParams &params,
291 Callback<llvm::json::Value> reply) {
292 URIForFile uri = params.textDocument.uri;
293
294 // Check whether a particular CodeActionKind is included in the response.
295 auto isKindAllowed = [only(params.context.only)](StringRef kind) {
296 if (only.empty())
297 return true;
298 return llvm::any_of(only, [&](StringRef base) {
299 return kind.consume_front(base) &&
300 (kind.empty() || kind.starts_with("."));
301 });
302 };
303
304 // We provide a code action for fixes on the specified diagnostics.
305 std::vector<CodeAction> actions;
306 if (isKindAllowed(CodeAction::kQuickFix))
307 server.getCodeActions(uri, params.range.start, params.context, actions);
308 reply(std::move(actions));
309}
310
311//===----------------------------------------------------------------------===//
312// Bytecode
313//===----------------------------------------------------------------------===//
314
315void LSPServer::onConvertFromBytecode(
316 const MLIRConvertBytecodeParams &params,
317 Callback<MLIRConvertBytecodeResult> reply) {
318 reply(server.convertFromBytecode(params.uri));
319}
320
321void LSPServer::onConvertToBytecode(const MLIRConvertBytecodeParams &params,
322 Callback<MLIRConvertBytecodeResult> reply) {
323 reply(server.convertToBytecode(params.uri));
324}
325
326//===----------------------------------------------------------------------===//
327// Entry point
328//===----------------------------------------------------------------------===//
329
330LogicalResult lsp::runMlirLSPServer(MLIRServer &server,
331 JSONTransport &transport) {
332 LSPServer lspServer(server);
333 MessageHandler messageHandler(transport);
334
335 // Initialization
336 messageHandler.method("initialize", &lspServer, &LSPServer::onInitialize);
337 messageHandler.notification("initialized", &lspServer,
338 &LSPServer::onInitialized);
339 messageHandler.method("shutdown", &lspServer, &LSPServer::onShutdown);
340
341 // Document Changes
342 messageHandler.notification("textDocument/didOpen", &lspServer,
343 &LSPServer::onDocumentDidOpen);
344 messageHandler.notification("textDocument/didClose", &lspServer,
345 &LSPServer::onDocumentDidClose);
346 messageHandler.notification("textDocument/didChange", &lspServer,
347 &LSPServer::onDocumentDidChange);
348
349 // Definitions and References
350 messageHandler.method("textDocument/definition", &lspServer,
351 &LSPServer::onGoToDefinition);
352 messageHandler.method("textDocument/references", &lspServer,
353 &LSPServer::onReference);
354
355 // Hover
356 messageHandler.method("textDocument/hover", &lspServer, &LSPServer::onHover);
357
358 // Document Symbols
359 messageHandler.method("textDocument/documentSymbol", &lspServer,
360 &LSPServer::onDocumentSymbol);
361
362 // Code Completion
363 messageHandler.method("textDocument/completion", &lspServer,
364 &LSPServer::onCompletion);
365
366 // Code Action
367 messageHandler.method("textDocument/codeAction", &lspServer,
368 &LSPServer::onCodeAction);
369
370 // Bytecode
371 messageHandler.method("mlir/convertFromBytecode", &lspServer,
372 &LSPServer::onConvertFromBytecode);
373 messageHandler.method("mlir/convertToBytecode", &lspServer,
374 &LSPServer::onConvertToBytecode);
375
376 // Diagnostics
377 lspServer.publishDiagnostics =
378 messageHandler.outgoingNotification<PublishDiagnosticsParams>(
379 "textDocument/publishDiagnostics");
380
381 // Run the main loop of the transport.
382 LogicalResult result = success();
383 if (llvm::Error error = transport.run(messageHandler)) {
384 Logger::error("Transport error: {0}", error);
385 llvm::consumeError(std::move(error));
386 result = failure();
387 } else {
388 result = success(lspServer.shutdownRequestReceived);
389 }
390 return result;
391}
return success()
This class implements all of the MLIR related functionality necessary for a language server.
Definition MLIRServer.h:38
void addOrUpdateDocument(const URIForFile &uri, StringRef contents, int64_t version, std::vector< Diagnostic > &diagnostics)
Add or update the document, with the provided version, at the given URI.
std::optional< int64_t > removeDocument(const URIForFile &uri)
Remove the document with the given uri.
void findReferencesOf(const URIForFile &uri, const Position &pos, std::vector< Location > &references)
Find all references of the object pointed at by the given position.
void getLocationsOf(const URIForFile &uri, const Position &defPos, std::vector< Location > &locations)
Return the locations of the object pointed at by the given position.
std::optional< Hover > findHover(const URIForFile &uri, const Position &hoverPos)
Find a hover description for the given hover position, or std::nullopt if one couldn't be found.
llvm::Expected< MLIRConvertBytecodeResult > convertFromBytecode(const URIForFile &uri)
Convert the given bytecode file to the textual format.
llvm::Expected< MLIRConvertBytecodeResult > convertToBytecode(const URIForFile &uri)
Convert the given textual file to the bytecode format.
void setWorkspaceRoot(StringRef root)
Set the workspace root for the server.
CompletionList getCodeCompletion(const URIForFile &uri, const Position &completePos)
Get the code completion list for the position within the given file.
void findDocumentSymbols(const URIForFile &uri, std::vector< DocumentSymbol > &symbols)
Find all of the document symbols within the given file.
void getCodeActions(const URIForFile &uri, const Range &pos, const CodeActionContext &context, std::vector< CodeAction > &actions)
Get the set of code actions within the file.
llvm::LogicalResult runMlirLSPServer(MLIRServer &server, llvm::lsp::JSONTransport &transport)
Run the main loop of the LSP server using the given MLIR server and transport.
Include the generated interface declarations.
This class represents the parameters used when converting between MLIR's bytecode and textual format.
Definition Protocol.h:33
URIForFile uri
The input file containing the bytecode or textual format.
Definition Protocol.h:35
This class represents the result of converting between MLIR's bytecode and textual format.
Definition Protocol.h:48