MLIR  21.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"
14 #include "llvm/ADT/FunctionExtras.h"
15 #include "llvm/ADT/StringMap.h"
16 #include <optional>
17 
18 #define DEBUG_TYPE "mlir-lsp-server"
19 
20 using namespace mlir;
21 using namespace mlir::lsp;
22 
23 //===----------------------------------------------------------------------===//
24 // LSPServer
25 //===----------------------------------------------------------------------===//
26 
27 namespace {
28 struct LSPServer {
29  LSPServer(MLIRServer &server) : server(server) {}
30 
31  //===--------------------------------------------------------------------===//
32  // Initialization
33 
34  void onInitialize(const InitializeParams &params,
36  void onInitialized(const InitializedParams &params);
37  void onShutdown(const NoParams &params, Callback<std::nullptr_t> reply);
38 
39  //===--------------------------------------------------------------------===//
40  // Document Change
41 
42  void onDocumentDidOpen(const DidOpenTextDocumentParams &params);
43  void onDocumentDidClose(const DidCloseTextDocumentParams &params);
44  void onDocumentDidChange(const DidChangeTextDocumentParams &params);
45 
46  //===--------------------------------------------------------------------===//
47  // Definitions and References
48 
49  void onGoToDefinition(const TextDocumentPositionParams &params,
50  Callback<std::vector<Location>> reply);
51  void onReference(const ReferenceParams &params,
52  Callback<std::vector<Location>> reply);
53 
54  //===--------------------------------------------------------------------===//
55  // Hover
56 
57  void onHover(const TextDocumentPositionParams &params,
58  Callback<std::optional<Hover>> reply);
59 
60  //===--------------------------------------------------------------------===//
61  // Document Symbols
62 
63  void onDocumentSymbol(const DocumentSymbolParams &params,
64  Callback<std::vector<DocumentSymbol>> reply);
65 
66  //===--------------------------------------------------------------------===//
67  // Code Completion
68 
69  void onCompletion(const CompletionParams &params,
71 
72  //===--------------------------------------------------------------------===//
73  // Code Action
74 
75  void onCodeAction(const CodeActionParams &params,
77 
78  //===--------------------------------------------------------------------===//
79  // Bytecode
80 
81  void onConvertFromBytecode(const MLIRConvertBytecodeParams &params,
83  void onConvertToBytecode(const MLIRConvertBytecodeParams &params,
85 
86  //===--------------------------------------------------------------------===//
87  // Fields
88  //===--------------------------------------------------------------------===//
89 
90  MLIRServer &server;
91 
92  /// An outgoing notification used to send diagnostics to the client when they
93  /// are ready to be processed.
95 
96  /// Used to indicate that the 'shutdown' request was received from the
97  /// Language Server client.
98  bool shutdownRequestReceived = false;
99 };
100 } // namespace
101 
102 //===----------------------------------------------------------------------===//
103 // Initialization
104 //===----------------------------------------------------------------------===//
105 
106 void LSPServer::onInitialize(const InitializeParams &params,
108  // Send a response with the capabilities of this server.
109  llvm::json::Object serverCaps{
110  {"textDocumentSync",
111  llvm::json::Object{
112  {"openClose", true},
113  {"change", (int)TextDocumentSyncKind::Full},
114  {"save", true},
115  }},
116  {"completionProvider",
117  llvm::json::Object{
118  {"allCommitCharacters",
119  {
120  "\t",
121  ";",
122  ",",
123  ".",
124  "=",
125  }},
126  {"resolveProvider", false},
127  {"triggerCharacters",
128  {".", "%", "^", "!", "#", "(", ",", "<", ":", "[", " ", "\"", "/"}},
129  }},
130  {"definitionProvider", true},
131  {"referencesProvider", true},
132  {"hoverProvider", true},
133 
134  // For now we only support documenting symbols when the client supports
135  // hierarchical symbols.
136  {"documentSymbolProvider",
138  };
139 
140  // Per LSP, codeActionProvider can be either boolean or CodeActionOptions.
141  // CodeActionOptions is only valid if the client supports action literal
142  // via textDocument.codeAction.codeActionLiteralSupport.
143  serverCaps["codeActionProvider"] =
145  ? llvm::json::Object{{"codeActionKinds",
148  : llvm::json::Value(true);
149 
150  llvm::json::Object result{
151  {{"serverInfo",
152  llvm::json::Object{{"name", "mlir-lsp-server"}, {"version", "0.0.0"}}},
153  {"capabilities", std::move(serverCaps)}}};
154  reply(std::move(result));
155 }
156 void LSPServer::onInitialized(const InitializedParams &) {}
157 void LSPServer::onShutdown(const NoParams &, Callback<std::nullptr_t> reply) {
158  shutdownRequestReceived = true;
159  reply(nullptr);
160 }
161 
162 //===----------------------------------------------------------------------===//
163 // Document Change
164 //===----------------------------------------------------------------------===//
165 
166 void LSPServer::onDocumentDidOpen(const DidOpenTextDocumentParams &params) {
167  PublishDiagnosticsParams diagParams(params.textDocument.uri,
168  params.textDocument.version);
169  server.addOrUpdateDocument(params.textDocument.uri, params.textDocument.text,
170  params.textDocument.version,
171  diagParams.diagnostics);
172 
173  // Publish any recorded diagnostics.
174  publishDiagnostics(diagParams);
175 }
176 void LSPServer::onDocumentDidClose(const DidCloseTextDocumentParams &params) {
177  std::optional<int64_t> version =
178  server.removeDocument(params.textDocument.uri);
179  if (!version)
180  return;
181 
182  // Empty out the diagnostics shown for this document. This will clear out
183  // anything currently displayed by the client for this document (e.g. in the
184  // "Problems" pane of VSCode).
185  publishDiagnostics(
186  PublishDiagnosticsParams(params.textDocument.uri, *version));
187 }
188 void LSPServer::onDocumentDidChange(const DidChangeTextDocumentParams &params) {
189  // TODO: We currently only support full document updates, we should refactor
190  // to avoid this.
191  if (params.contentChanges.size() != 1)
192  return;
193  PublishDiagnosticsParams diagParams(params.textDocument.uri,
194  params.textDocument.version);
195  server.addOrUpdateDocument(
196  params.textDocument.uri, params.contentChanges.front().text,
197  params.textDocument.version, diagParams.diagnostics);
198 
199  // Publish any recorded diagnostics.
200  publishDiagnostics(diagParams);
201 }
202 
203 //===----------------------------------------------------------------------===//
204 // Definitions and References
205 //===----------------------------------------------------------------------===//
206 
207 void LSPServer::onGoToDefinition(const TextDocumentPositionParams &params,
208  Callback<std::vector<Location>> reply) {
209  std::vector<Location> locations;
210  server.getLocationsOf(params.textDocument.uri, params.position, locations);
211  reply(std::move(locations));
212 }
213 
214 void LSPServer::onReference(const ReferenceParams &params,
215  Callback<std::vector<Location>> reply) {
216  std::vector<Location> locations;
217  server.findReferencesOf(params.textDocument.uri, params.position, locations);
218  reply(std::move(locations));
219 }
220 
221 //===----------------------------------------------------------------------===//
222 // Hover
223 //===----------------------------------------------------------------------===//
224 
225 void LSPServer::onHover(const TextDocumentPositionParams &params,
226  Callback<std::optional<Hover>> reply) {
227  reply(server.findHover(params.textDocument.uri, params.position));
228 }
229 
230 //===----------------------------------------------------------------------===//
231 // Document Symbols
232 //===----------------------------------------------------------------------===//
233 
234 void LSPServer::onDocumentSymbol(const DocumentSymbolParams &params,
235  Callback<std::vector<DocumentSymbol>> reply) {
236  std::vector<DocumentSymbol> symbols;
237  server.findDocumentSymbols(params.textDocument.uri, symbols);
238  reply(std::move(symbols));
239 }
240 
241 //===----------------------------------------------------------------------===//
242 // Code Completion
243 //===----------------------------------------------------------------------===//
244 
245 void LSPServer::onCompletion(const CompletionParams &params,
246  Callback<CompletionList> reply) {
247  reply(server.getCodeCompletion(params.textDocument.uri, params.position));
248 }
249 
250 //===----------------------------------------------------------------------===//
251 // Code Action
252 //===----------------------------------------------------------------------===//
253 
254 void LSPServer::onCodeAction(const CodeActionParams &params,
256  URIForFile uri = params.textDocument.uri;
257 
258  // Check whether a particular CodeActionKind is included in the response.
259  auto isKindAllowed = [only(params.context.only)](StringRef kind) {
260  if (only.empty())
261  return true;
262  return llvm::any_of(only, [&](StringRef base) {
263  return kind.consume_front(base) &&
264  (kind.empty() || kind.starts_with("."));
265  });
266  };
267 
268  // We provide a code action for fixes on the specified diagnostics.
269  std::vector<CodeAction> actions;
270  if (isKindAllowed(CodeAction::kQuickFix))
271  server.getCodeActions(uri, params.range.start, params.context, actions);
272  reply(std::move(actions));
273 }
274 
275 //===----------------------------------------------------------------------===//
276 // Bytecode
277 //===----------------------------------------------------------------------===//
278 
279 void LSPServer::onConvertFromBytecode(
280  const MLIRConvertBytecodeParams &params,
282  reply(server.convertFromBytecode(params.uri));
283 }
284 
285 void LSPServer::onConvertToBytecode(const MLIRConvertBytecodeParams &params,
287  reply(server.convertToBytecode(params.uri));
288 }
289 
290 //===----------------------------------------------------------------------===//
291 // Entry point
292 //===----------------------------------------------------------------------===//
293 
294 LogicalResult lsp::runMlirLSPServer(MLIRServer &server,
295  JSONTransport &transport) {
296  LSPServer lspServer(server);
297  MessageHandler messageHandler(transport);
298 
299  // Initialization
300  messageHandler.method("initialize", &lspServer, &LSPServer::onInitialize);
301  messageHandler.notification("initialized", &lspServer,
302  &LSPServer::onInitialized);
303  messageHandler.method("shutdown", &lspServer, &LSPServer::onShutdown);
304 
305  // Document Changes
306  messageHandler.notification("textDocument/didOpen", &lspServer,
307  &LSPServer::onDocumentDidOpen);
308  messageHandler.notification("textDocument/didClose", &lspServer,
309  &LSPServer::onDocumentDidClose);
310  messageHandler.notification("textDocument/didChange", &lspServer,
311  &LSPServer::onDocumentDidChange);
312 
313  // Definitions and References
314  messageHandler.method("textDocument/definition", &lspServer,
315  &LSPServer::onGoToDefinition);
316  messageHandler.method("textDocument/references", &lspServer,
317  &LSPServer::onReference);
318 
319  // Hover
320  messageHandler.method("textDocument/hover", &lspServer, &LSPServer::onHover);
321 
322  // Document Symbols
323  messageHandler.method("textDocument/documentSymbol", &lspServer,
324  &LSPServer::onDocumentSymbol);
325 
326  // Code Completion
327  messageHandler.method("textDocument/completion", &lspServer,
328  &LSPServer::onCompletion);
329 
330  // Code Action
331  messageHandler.method("textDocument/codeAction", &lspServer,
332  &LSPServer::onCodeAction);
333 
334  // Bytecode
335  messageHandler.method("mlir/convertFromBytecode", &lspServer,
336  &LSPServer::onConvertFromBytecode);
337  messageHandler.method("mlir/convertToBytecode", &lspServer,
338  &LSPServer::onConvertToBytecode);
339 
340  // Diagnostics
341  lspServer.publishDiagnostics =
343  "textDocument/publishDiagnostics");
344 
345  // Run the main loop of the transport.
346  LogicalResult result = success();
347  if (llvm::Error error = transport.run(messageHandler)) {
348  Logger::error("Transport error: {0}", error);
349  llvm::consumeError(std::move(error));
350  result = failure();
351  } else {
352  result = success(lspServer.shutdownRequestReceived);
353  }
354  return result;
355 }
union mlir::linalg::@1196::ArityGroupAndKind::Kind kind
A transport class that performs the JSON-RPC communication with the LSP client.
Definition: Transport.h:88
llvm::Error run(MessageHandler &handler)
Start executing the JSON-RPC transport.
Definition: Transport.cpp:210
static void error(const char *fmt, Ts &&...vals)
Definition: Logging.h:42
This class implements all of the MLIR related functionality necessary for a language server.
Definition: MLIRServer.h:36
A handler used to process the incoming transport messages.
Definition: Transport.h:152
void notification(llvm::StringLiteral method, ThisT *thisPtr, void(ThisT::*handler)(const Param &))
Definition: Transport.h:194
void method(llvm::StringLiteral method, ThisT *thisPtr, void(ThisT::*handler)(const Param &, Callback< Result >))
Definition: Transport.h:181
OutgoingNotification< T > outgoingNotification(llvm::StringLiteral method)
Create an OutgoingNotification object used for the given method.
Definition: Transport.h:213
URI in "file" scheme for a file.
Definition: Protocol.h:97
llvm::unique_function< void(const T &)> OutgoingNotification
An OutgoingNotification<T> is a function used for outgoing notifications send to the client.
Definition: Transport.h:136
llvm::unique_function< void(llvm::Expected< T >)> Callback
A Callback<T> is a void function that accepts Expected<T>.
Definition: Transport.h:131
@ Full
Documents are synced by always sending the full content of the document.
llvm::LogicalResult runMlirLSPServer(MLIRServer &server, JSONTransport &transport)
Run the main loop of the LSP server using the given MLIR server and transport.
Definition: LSPServer.cpp:294
Include the generated interface declarations.
bool codeActionStructure
Client supports CodeAction return value for textDocument/codeAction.
Definition: Protocol.h:160
bool hierarchicalDocumentSymbol
Client supports hierarchical document symbols.
Definition: Protocol.h:156
std::vector< std::string > only
Requested kind of actions to return.
Definition: Protocol.h:1157
TextDocumentIdentifier textDocument
The document in which the command was invoked.
Definition: Protocol.h:1170
Range range
The range for which the command was invoked.
Definition: Protocol.h:1173
CodeActionContext context
Context carrying additional information.
Definition: Protocol.h:1176
static const llvm::StringLiteral kRefactor
Definition: Protocol.h:1217
static const llvm::StringLiteral kInfo
Definition: Protocol.h:1218
static const llvm::StringLiteral kQuickFix
Definition: Protocol.h:1216
VersionedTextDocumentIdentifier textDocument
The document that changed.
Definition: Protocol.h:503
std::vector< TextDocumentContentChangeEvent > contentChanges
The actual content changes.
Definition: Protocol.h:506
TextDocumentIdentifier textDocument
The document that was closed.
Definition: Protocol.h:469
TextDocumentItem textDocument
The document that was opened.
Definition: Protocol.h:456
TextDocumentIdentifier textDocument
Definition: Protocol.h:633
ClientCapabilities capabilities
The capabilities provided by the client (editor or tool).
Definition: Protocol.h:199
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
Position start
The range's start position.
Definition: Protocol.h:339
URIForFile uri
The text document's URI.
Definition: Protocol.h:250
int64_t version
The version number of this document.
Definition: Protocol.h:237
std::string text
The content of the opened text document.
Definition: Protocol.h:234
URIForFile uri
The text document's URI.
Definition: Protocol.h:228
TextDocumentIdentifier textDocument
The text document.
Definition: Protocol.h:419
Position position
The position inside the text document.
Definition: Protocol.h:422
int64_t version
The version number of this document.
Definition: Protocol.h:266
URIForFile uri
The text document's URI.
Definition: Protocol.h:264