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