MLIR  18.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 void LSPServer::onInitialize(const InitializeParams &params,
107  // Send a response with the capabilities of this server.
108  llvm::json::Object serverCaps{
109  {"textDocumentSync",
110  llvm::json::Object{
111  {"openClose", true},
112  {"change", (int)TextDocumentSyncKind::Full},
113  {"save", true},
114  }},
115  {"completionProvider",
116  llvm::json::Object{
117  {"allCommitCharacters",
118  {
119  "\t",
120  ";",
121  ",",
122  ".",
123  "=",
124  }},
125  {"resolveProvider", false},
126  {"triggerCharacters",
127  {".", "%", "^", "!", "#", "(", ",", "<", ":", "[", " ", "\"", "/"}},
128  }},
129  {"definitionProvider", true},
130  {"referencesProvider", true},
131  {"hoverProvider", true},
132 
133  // For now we only support documenting symbols when the client supports
134  // hierarchical symbols.
135  {"documentSymbolProvider",
137  };
138 
139  // Per LSP, codeActionProvider can be either boolean or CodeActionOptions.
140  // CodeActionOptions is only valid if the client supports action literal
141  // via textDocument.codeAction.codeActionLiteralSupport.
142  serverCaps["codeActionProvider"] =
144  ? llvm::json::Object{{"codeActionKinds",
147  : llvm::json::Value(true);
148 
149  llvm::json::Object result{
150  {{"serverInfo",
151  llvm::json::Object{{"name", "mlir-lsp-server"}, {"version", "0.0.0"}}},
152  {"capabilities", std::move(serverCaps)}}};
153  reply(std::move(result));
154 }
155 void LSPServer::onInitialized(const InitializedParams &) {}
156 void LSPServer::onShutdown(const NoParams &, Callback<std::nullptr_t> reply) {
157  shutdownRequestReceived = true;
158  reply(nullptr);
159 }
160 
161 //===----------------------------------------------------------------------===//
162 // Document Change
163 
164 void LSPServer::onDocumentDidOpen(const DidOpenTextDocumentParams &params) {
165  PublishDiagnosticsParams diagParams(params.textDocument.uri,
166  params.textDocument.version);
167  server.addOrUpdateDocument(params.textDocument.uri, params.textDocument.text,
168  params.textDocument.version,
169  diagParams.diagnostics);
170 
171  // Publish any recorded diagnostics.
172  publishDiagnostics(diagParams);
173 }
174 void LSPServer::onDocumentDidClose(const DidCloseTextDocumentParams &params) {
175  std::optional<int64_t> version =
176  server.removeDocument(params.textDocument.uri);
177  if (!version)
178  return;
179 
180  // Empty out the diagnostics shown for this document. This will clear out
181  // anything currently displayed by the client for this document (e.g. in the
182  // "Problems" pane of VSCode).
183  publishDiagnostics(
184  PublishDiagnosticsParams(params.textDocument.uri, *version));
185 }
186 void LSPServer::onDocumentDidChange(const DidChangeTextDocumentParams &params) {
187  // TODO: We currently only support full document updates, we should refactor
188  // to avoid this.
189  if (params.contentChanges.size() != 1)
190  return;
191  PublishDiagnosticsParams diagParams(params.textDocument.uri,
192  params.textDocument.version);
193  server.addOrUpdateDocument(
194  params.textDocument.uri, params.contentChanges.front().text,
195  params.textDocument.version, diagParams.diagnostics);
196 
197  // Publish any recorded diagnostics.
198  publishDiagnostics(diagParams);
199 }
200 
201 //===----------------------------------------------------------------------===//
202 // Definitions and References
203 
204 void LSPServer::onGoToDefinition(const TextDocumentPositionParams &params,
205  Callback<std::vector<Location>> reply) {
206  std::vector<Location> locations;
207  server.getLocationsOf(params.textDocument.uri, params.position, locations);
208  reply(std::move(locations));
209 }
210 
211 void LSPServer::onReference(const ReferenceParams &params,
212  Callback<std::vector<Location>> reply) {
213  std::vector<Location> locations;
214  server.findReferencesOf(params.textDocument.uri, params.position, locations);
215  reply(std::move(locations));
216 }
217 
218 //===----------------------------------------------------------------------===//
219 // Hover
220 
221 void LSPServer::onHover(const TextDocumentPositionParams &params,
222  Callback<std::optional<Hover>> reply) {
223  reply(server.findHover(params.textDocument.uri, params.position));
224 }
225 
226 //===----------------------------------------------------------------------===//
227 // Document Symbols
228 
229 void LSPServer::onDocumentSymbol(const DocumentSymbolParams &params,
230  Callback<std::vector<DocumentSymbol>> reply) {
231  std::vector<DocumentSymbol> symbols;
232  server.findDocumentSymbols(params.textDocument.uri, symbols);
233  reply(std::move(symbols));
234 }
235 
236 //===----------------------------------------------------------------------===//
237 // Code Completion
238 
239 void LSPServer::onCompletion(const CompletionParams &params,
240  Callback<CompletionList> reply) {
241  reply(server.getCodeCompletion(params.textDocument.uri, params.position));
242 }
243 
244 //===----------------------------------------------------------------------===//
245 // Code Action
246 
247 void LSPServer::onCodeAction(const CodeActionParams &params,
249  URIForFile uri = params.textDocument.uri;
250 
251  // Check whether a particular CodeActionKind is included in the response.
252  auto isKindAllowed = [only(params.context.only)](StringRef kind) {
253  if (only.empty())
254  return true;
255  return llvm::any_of(only, [&](StringRef base) {
256  return kind.consume_front(base) && (kind.empty() || kind.startswith("."));
257  });
258  };
259 
260  // We provide a code action for fixes on the specified diagnostics.
261  std::vector<CodeAction> actions;
262  if (isKindAllowed(CodeAction::kQuickFix))
263  server.getCodeActions(uri, params.range.start, params.context, actions);
264  reply(std::move(actions));
265 }
266 
267 //===----------------------------------------------------------------------===//
268 // Bytecode
269 
270 void LSPServer::onConvertFromBytecode(
271  const MLIRConvertBytecodeParams &params,
273  reply(server.convertFromBytecode(params.uri));
274 }
275 
276 void LSPServer::onConvertToBytecode(const MLIRConvertBytecodeParams &params,
278  reply(server.convertToBytecode(params.uri));
279 }
280 
281 //===----------------------------------------------------------------------===//
282 // Entry point
283 //===----------------------------------------------------------------------===//
284 
286  JSONTransport &transport) {
287  LSPServer lspServer(server);
288  MessageHandler messageHandler(transport);
289 
290  // Initialization
291  messageHandler.method("initialize", &lspServer, &LSPServer::onInitialize);
292  messageHandler.notification("initialized", &lspServer,
293  &LSPServer::onInitialized);
294  messageHandler.method("shutdown", &lspServer, &LSPServer::onShutdown);
295 
296  // Document Changes
297  messageHandler.notification("textDocument/didOpen", &lspServer,
298  &LSPServer::onDocumentDidOpen);
299  messageHandler.notification("textDocument/didClose", &lspServer,
300  &LSPServer::onDocumentDidClose);
301  messageHandler.notification("textDocument/didChange", &lspServer,
302  &LSPServer::onDocumentDidChange);
303 
304  // Definitions and References
305  messageHandler.method("textDocument/definition", &lspServer,
306  &LSPServer::onGoToDefinition);
307  messageHandler.method("textDocument/references", &lspServer,
308  &LSPServer::onReference);
309 
310  // Hover
311  messageHandler.method("textDocument/hover", &lspServer, &LSPServer::onHover);
312 
313  // Document Symbols
314  messageHandler.method("textDocument/documentSymbol", &lspServer,
315  &LSPServer::onDocumentSymbol);
316 
317  // Code Completion
318  messageHandler.method("textDocument/completion", &lspServer,
319  &LSPServer::onCompletion);
320 
321  // Code Action
322  messageHandler.method("textDocument/codeAction", &lspServer,
323  &LSPServer::onCodeAction);
324 
325  // Bytecode
326  messageHandler.method("mlir/convertFromBytecode", &lspServer,
327  &LSPServer::onConvertFromBytecode);
328  messageHandler.method("mlir/convertToBytecode", &lspServer,
329  &LSPServer::onConvertToBytecode);
330 
331  // Diagnostics
332  lspServer.publishDiagnostics =
334  "textDocument/publishDiagnostics");
335 
336  // Run the main loop of the transport.
337  LogicalResult result = success();
338  if (llvm::Error error = transport.run(messageHandler)) {
339  Logger::error("Transport error: {0}", error);
340  llvm::consumeError(std::move(error));
341  result = failure();
342  } else {
343  result = success(lspServer.shutdownRequestReceived);
344  }
345  return result;
346 }
A transport class that performs the JSON-RPC communication with the LSP client.
Definition: Transport.h:48
llvm::Error run(MessageHandler &handler)
Start executing the JSON-RPC transport.
Definition: Transport.cpp:201
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:104
void notification(llvm::StringLiteral method, ThisT *thisPtr, void(ThisT::*handler)(const Param &))
Definition: Transport.h:146
void method(llvm::StringLiteral method, ThisT *thisPtr, void(ThisT::*handler)(const Param &, Callback< Result >))
Definition: Transport.h:133
OutgoingNotification< T > outgoingNotification(llvm::StringLiteral method)
Create an OutgoingNotification object used for the given method.
Definition: Transport.h:159
URI in "file" scheme for a file.
Definition: Protocol.h:100
llvm::unique_function< void(const T &)> OutgoingNotification
An OutgoingNotification<T> is a function used for outgoing notifications send to the client.
Definition: Transport.h:101
llvm::unique_function< void(llvm::Expected< T >)> Callback
A Callback<T> is a void function that accepts Expected<T>.
Definition: Transport.h:96
@ Full
Documents are synced by always sending the full content of the document.
LogicalResult runMlirLSPServer(MLIRServer &server, JSONTransport &transport)
Run the main loop of the LSP server using the given MLIR server and transport.
Definition: LSPServer.cpp:285
This header declares functions that assist transformations in the MemRef dialect.
LogicalResult failure(bool isFailure=true)
Utility function to generate a LogicalResult.
Definition: LogicalResult.h:62
LogicalResult success(bool isSuccess=true)
Utility function to generate a LogicalResult.
Definition: LogicalResult.h:56
This class represents an efficient way to signal success or failure.
Definition: LogicalResult.h:26
bool codeActionStructure
Client supports CodeAction return value for textDocument/codeAction.
Definition: Protocol.h:163
bool hierarchicalDocumentSymbol
Client supports hierarchical document symbols.
Definition: Protocol.h:159
std::vector< std::string > only
Requested kind of actions to return.
Definition: Protocol.h:1147
TextDocumentIdentifier textDocument
The document in which the command was invoked.
Definition: Protocol.h:1160
Range range
The range for which the command was invoked.
Definition: Protocol.h:1163
CodeActionContext context
Context carrying additional information.
Definition: Protocol.h:1166
static const llvm::StringLiteral kRefactor
Definition: Protocol.h:1207
static const llvm::StringLiteral kInfo
Definition: Protocol.h:1208
static const llvm::StringLiteral kQuickFix
Definition: Protocol.h:1206
VersionedTextDocumentIdentifier textDocument
The document that changed.
Definition: Protocol.h:506
std::vector< TextDocumentContentChangeEvent > contentChanges
The actual content changes.
Definition: Protocol.h:509
TextDocumentIdentifier textDocument
The document that was closed.
Definition: Protocol.h:472
TextDocumentItem textDocument
The document that was opened.
Definition: Protocol.h:459
TextDocumentIdentifier textDocument
Definition: Protocol.h:636
ClientCapabilities capabilities
The capabilities provided by the client (editor or tool).
Definition: Protocol.h:202
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:342
URIForFile uri
The text document's URI.
Definition: Protocol.h:253
int64_t version
The version number of this document.
Definition: Protocol.h:240
std::string text
The content of the opened text document.
Definition: Protocol.h:237
URIForFile uri
The text document's URI.
Definition: Protocol.h:231
TextDocumentIdentifier textDocument
The text document.
Definition: Protocol.h:422
Position position
The position inside the text document.
Definition: Protocol.h:425
int64_t version
The version number of this document.
Definition: Protocol.h:269
URIForFile uri
The text document's URI.
Definition: Protocol.h:267