1 //===- LSPServer.cpp - MLIR Language Server -------------------------------===//
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
7 //===----------------------------------------------------------------------===//
10 #include "MLIRServer.h"
12 #include "mlir/Tools/lsp-server-support/Logging.h"
13 #include "mlir/Tools/lsp-server-support/Transport.h"
14 #include "llvm/ADT/FunctionExtras.h"
15 #include "llvm/ADT/StringMap.h"
18 #define DEBUG_TYPE "mlir-lsp-server"
21 using namespace mlir::lsp
;
23 //===----------------------------------------------------------------------===//
25 //===----------------------------------------------------------------------===//
29 LSPServer(MLIRServer
&server
) : server(server
) {}
31 //===--------------------------------------------------------------------===//
34 void onInitialize(const InitializeParams
¶ms
,
35 Callback
<llvm::json::Value
> reply
);
36 void onInitialized(const InitializedParams
¶ms
);
37 void onShutdown(const NoParams
¶ms
, Callback
<std::nullptr_t
> reply
);
39 //===--------------------------------------------------------------------===//
42 void onDocumentDidOpen(const DidOpenTextDocumentParams
¶ms
);
43 void onDocumentDidClose(const DidCloseTextDocumentParams
¶ms
);
44 void onDocumentDidChange(const DidChangeTextDocumentParams
¶ms
);
46 //===--------------------------------------------------------------------===//
47 // Definitions and References
49 void onGoToDefinition(const TextDocumentPositionParams
¶ms
,
50 Callback
<std::vector
<Location
>> reply
);
51 void onReference(const ReferenceParams
¶ms
,
52 Callback
<std::vector
<Location
>> reply
);
54 //===--------------------------------------------------------------------===//
57 void onHover(const TextDocumentPositionParams
¶ms
,
58 Callback
<std::optional
<Hover
>> reply
);
60 //===--------------------------------------------------------------------===//
63 void onDocumentSymbol(const DocumentSymbolParams
¶ms
,
64 Callback
<std::vector
<DocumentSymbol
>> reply
);
66 //===--------------------------------------------------------------------===//
69 void onCompletion(const CompletionParams
¶ms
,
70 Callback
<CompletionList
> reply
);
72 //===--------------------------------------------------------------------===//
75 void onCodeAction(const CodeActionParams
¶ms
,
76 Callback
<llvm::json::Value
> reply
);
78 //===--------------------------------------------------------------------===//
81 void onConvertFromBytecode(const MLIRConvertBytecodeParams
¶ms
,
82 Callback
<MLIRConvertBytecodeResult
> reply
);
83 void onConvertToBytecode(const MLIRConvertBytecodeParams
¶ms
,
84 Callback
<MLIRConvertBytecodeResult
> reply
);
86 //===--------------------------------------------------------------------===//
88 //===--------------------------------------------------------------------===//
92 /// An outgoing notification used to send diagnostics to the client when they
93 /// are ready to be processed.
94 OutgoingNotification
<PublishDiagnosticsParams
> publishDiagnostics
;
96 /// Used to indicate that the 'shutdown' request was received from the
97 /// Language Server client.
98 bool shutdownRequestReceived
= false;
102 //===----------------------------------------------------------------------===//
105 void LSPServer::onInitialize(const InitializeParams
¶ms
,
106 Callback
<llvm::json::Value
> reply
) {
107 // Send a response with the capabilities of this server.
108 llvm::json::Object serverCaps
{
112 {"change", (int)TextDocumentSyncKind::Full
},
115 {"completionProvider",
117 {"allCommitCharacters",
125 {"resolveProvider", false},
126 {"triggerCharacters",
127 {".", "%", "^", "!", "#", "(", ",", "<", ":", "[", " ", "\"", "/"}},
129 {"definitionProvider", true},
130 {"referencesProvider", true},
131 {"hoverProvider", true},
133 // For now we only support documenting symbols when the client supports
134 // hierarchical symbols.
135 {"documentSymbolProvider",
136 params
.capabilities
.hierarchicalDocumentSymbol
},
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"] =
143 params
.capabilities
.codeActionStructure
144 ? llvm::json::Object
{{"codeActionKinds",
145 {CodeAction::kQuickFix
, CodeAction::kRefactor
,
147 : llvm::json::Value(true);
149 llvm::json::Object result
{
151 llvm::json::Object
{{"name", "mlir-lsp-server"}, {"version", "0.0.0"}}},
152 {"capabilities", std::move(serverCaps
)}}};
153 reply(std::move(result
));
155 void LSPServer::onInitialized(const InitializedParams
&) {}
156 void LSPServer::onShutdown(const NoParams
&, Callback
<std::nullptr_t
> reply
) {
157 shutdownRequestReceived
= true;
161 //===----------------------------------------------------------------------===//
164 void LSPServer::onDocumentDidOpen(const DidOpenTextDocumentParams
¶ms
) {
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
);
171 // Publish any recorded diagnostics.
172 publishDiagnostics(diagParams
);
174 void LSPServer::onDocumentDidClose(const DidCloseTextDocumentParams
¶ms
) {
175 std::optional
<int64_t> version
=
176 server
.removeDocument(params
.textDocument
.uri
);
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).
184 PublishDiagnosticsParams(params
.textDocument
.uri
, *version
));
186 void LSPServer::onDocumentDidChange(const DidChangeTextDocumentParams
¶ms
) {
187 // TODO: We currently only support full document updates, we should refactor
189 if (params
.contentChanges
.size() != 1)
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
);
197 // Publish any recorded diagnostics.
198 publishDiagnostics(diagParams
);
201 //===----------------------------------------------------------------------===//
202 // Definitions and References
204 void LSPServer::onGoToDefinition(const TextDocumentPositionParams
¶ms
,
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
));
211 void LSPServer::onReference(const ReferenceParams
¶ms
,
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
));
218 //===----------------------------------------------------------------------===//
221 void LSPServer::onHover(const TextDocumentPositionParams
¶ms
,
222 Callback
<std::optional
<Hover
>> reply
) {
223 reply(server
.findHover(params
.textDocument
.uri
, params
.position
));
226 //===----------------------------------------------------------------------===//
229 void LSPServer::onDocumentSymbol(const DocumentSymbolParams
¶ms
,
230 Callback
<std::vector
<DocumentSymbol
>> reply
) {
231 std::vector
<DocumentSymbol
> symbols
;
232 server
.findDocumentSymbols(params
.textDocument
.uri
, symbols
);
233 reply(std::move(symbols
));
236 //===----------------------------------------------------------------------===//
239 void LSPServer::onCompletion(const CompletionParams
¶ms
,
240 Callback
<CompletionList
> reply
) {
241 reply(server
.getCodeCompletion(params
.textDocument
.uri
, params
.position
));
244 //===----------------------------------------------------------------------===//
247 void LSPServer::onCodeAction(const CodeActionParams
¶ms
,
248 Callback
<llvm::json::Value
> reply
) {
249 URIForFile uri
= params
.textDocument
.uri
;
251 // Check whether a particular CodeActionKind is included in the response.
252 auto isKindAllowed
= [only(params
.context
.only
)](StringRef kind
) {
255 return llvm::any_of(only
, [&](StringRef base
) {
256 return kind
.consume_front(base
) &&
257 (kind
.empty() || kind
.starts_with("."));
261 // We provide a code action for fixes on the specified diagnostics.
262 std::vector
<CodeAction
> actions
;
263 if (isKindAllowed(CodeAction::kQuickFix
))
264 server
.getCodeActions(uri
, params
.range
.start
, params
.context
, actions
);
265 reply(std::move(actions
));
268 //===----------------------------------------------------------------------===//
271 void LSPServer::onConvertFromBytecode(
272 const MLIRConvertBytecodeParams
¶ms
,
273 Callback
<MLIRConvertBytecodeResult
> reply
) {
274 reply(server
.convertFromBytecode(params
.uri
));
277 void LSPServer::onConvertToBytecode(const MLIRConvertBytecodeParams
¶ms
,
278 Callback
<MLIRConvertBytecodeResult
> reply
) {
279 reply(server
.convertToBytecode(params
.uri
));
282 //===----------------------------------------------------------------------===//
284 //===----------------------------------------------------------------------===//
286 LogicalResult
lsp::runMlirLSPServer(MLIRServer
&server
,
287 JSONTransport
&transport
) {
288 LSPServer
lspServer(server
);
289 MessageHandler
messageHandler(transport
);
292 messageHandler
.method("initialize", &lspServer
, &LSPServer::onInitialize
);
293 messageHandler
.notification("initialized", &lspServer
,
294 &LSPServer::onInitialized
);
295 messageHandler
.method("shutdown", &lspServer
, &LSPServer::onShutdown
);
298 messageHandler
.notification("textDocument/didOpen", &lspServer
,
299 &LSPServer::onDocumentDidOpen
);
300 messageHandler
.notification("textDocument/didClose", &lspServer
,
301 &LSPServer::onDocumentDidClose
);
302 messageHandler
.notification("textDocument/didChange", &lspServer
,
303 &LSPServer::onDocumentDidChange
);
305 // Definitions and References
306 messageHandler
.method("textDocument/definition", &lspServer
,
307 &LSPServer::onGoToDefinition
);
308 messageHandler
.method("textDocument/references", &lspServer
,
309 &LSPServer::onReference
);
312 messageHandler
.method("textDocument/hover", &lspServer
, &LSPServer::onHover
);
315 messageHandler
.method("textDocument/documentSymbol", &lspServer
,
316 &LSPServer::onDocumentSymbol
);
319 messageHandler
.method("textDocument/completion", &lspServer
,
320 &LSPServer::onCompletion
);
323 messageHandler
.method("textDocument/codeAction", &lspServer
,
324 &LSPServer::onCodeAction
);
327 messageHandler
.method("mlir/convertFromBytecode", &lspServer
,
328 &LSPServer::onConvertFromBytecode
);
329 messageHandler
.method("mlir/convertToBytecode", &lspServer
,
330 &LSPServer::onConvertToBytecode
);
333 lspServer
.publishDiagnostics
=
334 messageHandler
.outgoingNotification
<PublishDiagnosticsParams
>(
335 "textDocument/publishDiagnostics");
337 // Run the main loop of the transport.
338 LogicalResult result
= success();
339 if (llvm::Error error
= transport
.run(messageHandler
)) {
340 Logger::error("Transport error: {0}", error
);
341 llvm::consumeError(std::move(error
));
344 result
= success(lspServer
.shutdownRequestReceived
);