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