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 
18 using namespace mlir;
19 using namespace mlir::lsp;
20 
21 using llvm::lsp::Callback;
22 using llvm::lsp::CodeAction;
23 using llvm::lsp::CodeActionParams;
24 using llvm::lsp::CompletionList;
25 using llvm::lsp::CompletionParams;
26 using llvm::lsp::DidChangeTextDocumentParams;
27 using llvm::lsp::DidCloseTextDocumentParams;
28 using llvm::lsp::DidOpenTextDocumentParams;
29 using llvm::lsp::DocumentSymbol;
30 using llvm::lsp::DocumentSymbolParams;
31 using llvm::lsp::Hover;
32 using llvm::lsp::InitializedParams;
33 using llvm::lsp::InitializeParams;
34 using llvm::lsp::JSONTransport;
35 using llvm::lsp::Location;
36 using llvm::lsp::Logger;
37 using llvm::lsp::MessageHandler;
40 using llvm::lsp::NoParams;
41 using llvm::lsp::OutgoingNotification;
42 using llvm::lsp::PublishDiagnosticsParams;
43 using llvm::lsp::ReferenceParams;
44 using llvm::lsp::TextDocumentPositionParams;
45 using llvm::lsp::TextDocumentSyncKind;
46 using llvm::lsp::URIForFile;
47 
48 //===----------------------------------------------------------------------===//
49 // LSPServer
50 //===----------------------------------------------------------------------===//
51 
52 namespace {
53 struct 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 
131 void 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 }
181 void LSPServer::onInitialized(const InitializedParams &) {}
182 void LSPServer::onShutdown(const NoParams &, Callback<std::nullptr_t> reply) {
183  shutdownRequestReceived = true;
184  reply(nullptr);
185 }
186 
187 //===----------------------------------------------------------------------===//
188 // Document Change
189 //===----------------------------------------------------------------------===//
190 
191 void 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 }
201 void 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 }
213 void 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 
232 void 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 
239 void 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 
250 void 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 
259 void 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 
270 void 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 
279 void 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 
304 void LSPServer::onConvertFromBytecode(
305  const MLIRConvertBytecodeParams &params,
306  Callback<MLIRConvertBytecodeResult> reply) {
307  reply(server.convertFromBytecode(params.uri));
308 }
309 
310 void LSPServer::onConvertToBytecode(const MLIRConvertBytecodeParams &params,
311  Callback<MLIRConvertBytecodeResult> reply) {
312  reply(server.convertToBytecode(params.uri));
313 }
314 
315 //===----------------------------------------------------------------------===//
316 // Entry point
317 //===----------------------------------------------------------------------===//
318 
319 LogicalResult 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 }
union mlir::linalg::@1245::ArityGroupAndKind::Kind kind
This class implements all of the MLIR related functionality necessary for a language server.
Definition: MLIRServer.h:38
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