[Mlir-commits] [mlir] ed344c8 - [mlir:LSP] Add a quickfix code action for inserting expected-* diagnostic checks
River Riddle
llvmlistbot at llvm.org
Wed Jul 20 15:44:18 PDT 2022
Author: River Riddle
Date: 2022-07-20T15:43:59-07:00
New Revision: ed344c88774a46aa1f1eed6b7e36f42e73031c69
URL: https://github.com/llvm/llvm-project/commit/ed344c88774a46aa1f1eed6b7e36f42e73031c69
DIFF: https://github.com/llvm/llvm-project/commit/ed344c88774a46aa1f1eed6b7e36f42e73031c69.diff
LOG: [mlir:LSP] Add a quickfix code action for inserting expected-* diagnostic checks
This allows for automatically inserting expected checks for parser and verifier
diagnostics, which simplifies the workflow when building new dialect
constructs or extending existing ones.
Differential Revision: https://reviews.llvm.org/D130152
Added:
mlir/test/mlir-lsp-server/code-action.test
Modified:
mlir/docs/Tools/MLIRLSP.md
mlir/lib/Tools/lsp-server-support/Protocol.cpp
mlir/lib/Tools/lsp-server-support/Protocol.h
mlir/lib/Tools/mlir-lsp-server/LSPServer.cpp
mlir/lib/Tools/mlir-lsp-server/MLIRServer.cpp
mlir/lib/Tools/mlir-lsp-server/MLIRServer.h
mlir/test/mlir-lsp-server/initialize-params.test
Removed:
################################################################################
diff --git a/mlir/docs/Tools/MLIRLSP.md b/mlir/docs/Tools/MLIRLSP.md
index bcea9e9bffa02..4485f0bec3285 100644
--- a/mlir/docs/Tools/MLIRLSP.md
+++ b/mlir/docs/Tools/MLIRLSP.md
@@ -58,6 +58,16 @@ any generated diagnostics in-place.
![IMG](/mlir-lsp-server/diagnostics.png)
+##### Automatically insert `expected-` diagnostic checks
+
+MLIR provides
+[infrastructure](https://mlir.llvm.org/docs/Diagnostics/#sourcemgr-diagnostic-verifier-handler)
+for checking expected diagnostics, which is heavily utilized when defining IR
+parsing and verification. The language server provides code actions for
+automatically inserting the checks for diagnostics it knows about.
+
+![IMG](/mlir-lsp-server/diagnostics_action.gif)
+
#### Code completion
The language server provides suggestions as you type, offering completions for
diff --git a/mlir/lib/Tools/lsp-server-support/Protocol.cpp b/mlir/lib/Tools/lsp-server-support/Protocol.cpp
index b8a00b9d271c1..0fe10479041f8 100644
--- a/mlir/lib/Tools/lsp-server-support/Protocol.cpp
+++ b/mlir/lib/Tools/lsp-server-support/Protocol.cpp
@@ -267,6 +267,10 @@ bool mlir::lsp::fromJSON(const llvm::json::Value &value,
documentSymbol->getBoolean("hierarchicalDocumentSymbolSupport"))
result.hierarchicalDocumentSymbol = *hierarchicalSupport;
}
+ if (auto *codeAction = textDocument->getObject("codeAction")) {
+ if (codeAction->getObject("codeActionLiteralSupport"))
+ result.codeActionStructure = true;
+ }
}
return true;
}
@@ -398,6 +402,12 @@ raw_ostream &mlir::lsp::operator<<(raw_ostream &os, const Range &value) {
// Location
//===----------------------------------------------------------------------===//
+bool mlir::lsp::fromJSON(const llvm::json::Value &value, Location &result,
+ llvm::json::Path path) {
+ llvm::json::ObjectMapper o(value, path);
+ return o && o.map("uri", result.uri) && o.map("range", result.range);
+}
+
llvm::json::Value mlir::lsp::toJSON(const Location &value) {
return llvm::json::Object{
{"uri", value.uri},
@@ -581,6 +591,14 @@ bool mlir::lsp::fromJSON(const llvm::json::Value &value,
// DiagnosticRelatedInformation
//===----------------------------------------------------------------------===//
+bool mlir::lsp::fromJSON(const llvm::json::Value &value,
+ DiagnosticRelatedInformation &result,
+ llvm::json::Path path) {
+ llvm::json::ObjectMapper o(value, path);
+ return o && o.map("location", result.location) &&
+ o.map("message", result.message);
+}
+
llvm::json::Value mlir::lsp::toJSON(const DiagnosticRelatedInformation &info) {
return llvm::json::Object{
{"location", info.location},
@@ -607,6 +625,23 @@ llvm::json::Value mlir::lsp::toJSON(const Diagnostic &diag) {
return std::move(result);
}
+bool mlir::lsp::fromJSON(const llvm::json::Value &value, Diagnostic &result,
+ llvm::json::Path path) {
+ llvm::json::ObjectMapper o(value, path);
+ if (!o)
+ return false;
+ int severity = 0;
+ if (!mapOptOrNull(value, "severity", severity, path))
+ return false;
+ result.severity = (DiagnosticSeverity)severity;
+
+ return o.map("range", result.range) && o.map("message", result.message) &&
+ mapOptOrNull(value, "category", result.category, path) &&
+ mapOptOrNull(value, "source", result.source, path) &&
+ mapOptOrNull(value, "relatedInformation", result.relatedInformation,
+ path);
+}
+
//===----------------------------------------------------------------------===//
// PublishDiagnosticsParams
//===----------------------------------------------------------------------===//
@@ -892,3 +927,65 @@ llvm::raw_ostream &mlir::lsp::operator<<(llvm::raw_ostream &os,
}
llvm_unreachable("Unknown InlayHintKind");
}
+
+//===----------------------------------------------------------------------===//
+// CodeActionContext
+//===----------------------------------------------------------------------===//
+
+bool mlir::lsp::fromJSON(const llvm::json::Value &value,
+ CodeActionContext &result, llvm::json::Path path) {
+ llvm::json::ObjectMapper o(value, path);
+ if (!o || !o.map("diagnostics", result.diagnostics))
+ return false;
+ o.map("only", result.only);
+ return true;
+}
+
+//===----------------------------------------------------------------------===//
+// CodeActionParams
+//===----------------------------------------------------------------------===//
+
+bool mlir::lsp::fromJSON(const llvm::json::Value &value,
+ CodeActionParams &result, llvm::json::Path path) {
+ llvm::json::ObjectMapper o(value, path);
+ return o && o.map("textDocument", result.textDocument) &&
+ o.map("range", result.range) && o.map("context", result.context);
+}
+
+//===----------------------------------------------------------------------===//
+// WorkspaceEdit
+//===----------------------------------------------------------------------===//
+
+bool mlir::lsp::fromJSON(const llvm::json::Value &value, WorkspaceEdit &result,
+ llvm::json::Path path) {
+ llvm::json::ObjectMapper o(value, path);
+ return o && o.map("changes", result.changes);
+}
+
+llvm::json::Value mlir::lsp::toJSON(const WorkspaceEdit &value) {
+ llvm::json::Object fileChanges;
+ for (auto &change : value.changes)
+ fileChanges[change.first] = llvm::json::Array(change.second);
+ return llvm::json::Object{{"changes", std::move(fileChanges)}};
+}
+
+//===----------------------------------------------------------------------===//
+// CodeAction
+//===----------------------------------------------------------------------===//
+
+const llvm::StringLiteral CodeAction::kQuickFix = "quickfix";
+const llvm::StringLiteral CodeAction::kRefactor = "refactor";
+const llvm::StringLiteral CodeAction::kInfo = "info";
+
+llvm::json::Value mlir::lsp::toJSON(const CodeAction &value) {
+ llvm::json::Object codeAction{{"title", value.title}};
+ if (value.kind)
+ codeAction["kind"] = *value.kind;
+ if (value.diagnostics)
+ codeAction["diagnostics"] = llvm::json::Array(*value.diagnostics);
+ if (value.isPreferred)
+ codeAction["isPreferred"] = true;
+ if (value.edit)
+ codeAction["edit"] = *value.edit;
+ return std::move(codeAction);
+}
diff --git a/mlir/lib/Tools/lsp-server-support/Protocol.h b/mlir/lib/Tools/lsp-server-support/Protocol.h
index 0fc30d5bcced2..9233f8b477503 100644
--- a/mlir/lib/Tools/lsp-server-support/Protocol.h
+++ b/mlir/lib/Tools/lsp-server-support/Protocol.h
@@ -146,6 +146,10 @@ struct ClientCapabilities {
/// Client supports hierarchical document symbols.
/// textDocument.documentSymbol.hierarchicalDocumentSymbolSupport
bool hierarchicalDocumentSymbol = false;
+
+ /// Client supports CodeAction return value for textDocument/codeAction.
+ /// textDocument.codeAction.codeActionLiteralSupport.
+ bool codeActionStructure = false;
};
/// Add support for JSON serialization.
@@ -374,6 +378,8 @@ struct Location {
};
/// Add support for JSON serialization.
+bool fromJSON(const llvm::json::Value &value, Location &result,
+ llvm::json::Path path);
llvm::json::Value toJSON(const Location &value);
raw_ostream &operator<<(raw_ostream &os, const Location &value);
@@ -612,6 +618,7 @@ bool fromJSON(const llvm::json::Value &value, DocumentSymbolParams &result,
/// This should be used to point to code locations that cause or related to a
/// diagnostics, e.g. when duplicating a symbol in a scope.
struct DiagnosticRelatedInformation {
+ DiagnosticRelatedInformation() = default;
DiagnosticRelatedInformation(Location location, std::string message)
: location(std::move(location)), message(std::move(message)) {}
@@ -622,6 +629,8 @@ struct DiagnosticRelatedInformation {
};
/// Add support for JSON serialization.
+bool fromJSON(const llvm::json::Value &value,
+ DiagnosticRelatedInformation &result, llvm::json::Path path);
llvm::json::Value toJSON(const DiagnosticRelatedInformation &info);
//===----------------------------------------------------------------------===//
@@ -666,6 +675,8 @@ struct Diagnostic {
/// Add support for JSON serialization.
llvm::json::Value toJSON(const Diagnostic &diag);
+bool fromJSON(const llvm::json::Value &value, Diagnostic &result,
+ llvm::json::Path path);
//===----------------------------------------------------------------------===//
// PublishDiagnosticsParams
@@ -1086,6 +1097,103 @@ bool operator==(const InlayHint &lhs, const InlayHint &rhs);
bool operator<(const InlayHint &lhs, const InlayHint &rhs);
llvm::raw_ostream &operator<<(llvm::raw_ostream &os, InlayHintKind value);
+//===----------------------------------------------------------------------===//
+// CodeActionContext
+//===----------------------------------------------------------------------===//
+
+struct CodeActionContext {
+ /// An array of diagnostics known on the client side overlapping the range
+ /// provided to the `textDocument/codeAction` request. They are provided so
+ /// that the server knows which errors are currently presented to the user for
+ /// the given range. There is no guarantee that these accurately reflect the
+ /// error state of the resource. The primary parameter to compute code actions
+ /// is the provided range.
+ std::vector<Diagnostic> diagnostics;
+
+ /// Requested kind of actions to return.
+ ///
+ /// Actions not of this kind are filtered out by the client before being
+ /// shown. So servers can omit computing them.
+ std::vector<std::string> only;
+};
+
+/// Add support for JSON serialization.
+bool fromJSON(const llvm::json::Value &value, CodeActionContext &result,
+ llvm::json::Path path);
+
+//===----------------------------------------------------------------------===//
+// CodeActionParams
+//===----------------------------------------------------------------------===//
+
+struct CodeActionParams {
+ /// The document in which the command was invoked.
+ TextDocumentIdentifier textDocument;
+
+ /// The range for which the command was invoked.
+ Range range;
+
+ /// Context carrying additional information.
+ CodeActionContext context;
+};
+
+/// Add support for JSON serialization.
+bool fromJSON(const llvm::json::Value &value, CodeActionParams &result,
+ llvm::json::Path path);
+
+//===----------------------------------------------------------------------===//
+// WorkspaceEdit
+//===----------------------------------------------------------------------===//
+
+struct WorkspaceEdit {
+ /// Holds changes to existing resources.
+ std::map<std::string, std::vector<TextEdit>> changes;
+
+ /// Note: "documentChanges" is not currently used because currently there is
+ /// no support for versioned edits.
+};
+
+/// Add support for JSON serialization.
+bool fromJSON(const llvm::json::Value &value, WorkspaceEdit &result,
+ llvm::json::Path path);
+llvm::json::Value toJSON(const WorkspaceEdit &value);
+
+//===----------------------------------------------------------------------===//
+// CodeAction
+//===----------------------------------------------------------------------===//
+
+/// A code action represents a change that can be performed in code, e.g. to fix
+/// a problem or to refactor code.
+///
+/// A CodeAction must set either `edit` and/or a `command`. If both are
+/// supplied, the `edit` is applied first, then the `command` is executed.
+struct CodeAction {
+ /// A short, human-readable, title for this code action.
+ std::string title;
+
+ /// The kind of the code action.
+ /// Used to filter code actions.
+ Optional<std::string> kind;
+ const static llvm::StringLiteral kQuickFix;
+ const static llvm::StringLiteral kRefactor;
+ const static llvm::StringLiteral kInfo;
+
+ /// The diagnostics that this code action resolves.
+ Optional<std::vector<Diagnostic>> diagnostics;
+
+ /// Marks this as a preferred action. Preferred actions are used by the
+ /// `auto fix` command and can be targeted by keybindings.
+ /// A quick fix should be marked preferred if it properly addresses the
+ /// underlying error. A refactoring should be marked preferred if it is the
+ /// most reasonable choice of actions to take.
+ bool isPreferred = false;
+
+ /// The workspace edit this code action performs.
+ Optional<WorkspaceEdit> edit;
+};
+
+/// Add support for JSON serialization.
+llvm::json::Value toJSON(const CodeAction &);
+
} // namespace lsp
} // namespace mlir
diff --git a/mlir/lib/Tools/mlir-lsp-server/LSPServer.cpp b/mlir/lib/Tools/mlir-lsp-server/LSPServer.cpp
index 3e9a66a428820..45fc2329e9f73 100644
--- a/mlir/lib/Tools/mlir-lsp-server/LSPServer.cpp
+++ b/mlir/lib/Tools/mlir-lsp-server/LSPServer.cpp
@@ -68,6 +68,12 @@ struct LSPServer {
void onCompletion(const CompletionParams ¶ms,
Callback<CompletionList> reply);
+ //===--------------------------------------------------------------------===//
+ // Code Action
+
+ void onCodeAction(const CodeActionParams ¶ms,
+ Callback<llvm::json::Value> reply);
+
//===--------------------------------------------------------------------===//
// Fields
//===--------------------------------------------------------------------===//
@@ -121,6 +127,16 @@ void LSPServer::onInitialize(const InitializeParams ¶ms,
params.capabilities.hierarchicalDocumentSymbol},
};
+ // Per LSP, codeActionProvider can be either boolean or CodeActionOptions.
+ // CodeActionOptions is only valid if the client supports action literal
+ // via textDocument.codeAction.codeActionLiteralSupport.
+ serverCaps["codeActionProvider"] =
+ params.capabilities.codeActionStructure
+ ? llvm::json::Object{{"codeActionKinds",
+ {CodeAction::kQuickFix, CodeAction::kRefactor,
+ CodeAction::kInfo}}}
+ : llvm::json::Value(true);
+
llvm::json::Object result{
{{"serverInfo",
llvm::json::Object{{"name", "mlir-lsp-server"}, {"version", "0.0.0"}}},
@@ -215,6 +231,29 @@ void LSPServer::onCompletion(const CompletionParams ¶ms,
reply(server.getCodeCompletion(params.textDocument.uri, params.position));
}
+//===----------------------------------------------------------------------===//
+// Code Action
+
+void LSPServer::onCodeAction(const CodeActionParams ¶ms,
+ Callback<llvm::json::Value> reply) {
+ URIForFile uri = params.textDocument.uri;
+
+ // Check whether a particular CodeActionKind is included in the response.
+ auto isKindAllowed = [only(params.context.only)](StringRef kind) {
+ if (only.empty())
+ return true;
+ return llvm::any_of(only, [&](StringRef base) {
+ return kind.consume_front(base) && (kind.empty() || kind.startswith("."));
+ });
+ };
+
+ // We provide a code action for fixes on the specified diagnostics.
+ std::vector<CodeAction> actions;
+ if (isKindAllowed(CodeAction::kQuickFix))
+ server.getCodeActions(uri, params.range.start, params.context, actions);
+ reply(std::move(actions));
+}
+
//===----------------------------------------------------------------------===//
// Entry point
//===----------------------------------------------------------------------===//
@@ -255,6 +294,10 @@ LogicalResult lsp::runMlirLSPServer(MLIRServer &server,
messageHandler.method("textDocument/completion", &lspServer,
&LSPServer::onCompletion);
+ // Code Action
+ messageHandler.method("textDocument/codeAction", &lspServer,
+ &LSPServer::onCodeAction);
+
// Diagnostics
lspServer.publishDiagnostics =
messageHandler.outgoingNotification<PublishDiagnosticsParams>(
diff --git a/mlir/lib/Tools/mlir-lsp-server/MLIRServer.cpp b/mlir/lib/Tools/mlir-lsp-server/MLIRServer.cpp
index f535667e25b8d..bd793ee344cf3 100644
--- a/mlir/lib/Tools/mlir-lsp-server/MLIRServer.cpp
+++ b/mlir/lib/Tools/mlir-lsp-server/MLIRServer.cpp
@@ -285,6 +285,15 @@ struct MLIRDocument {
const lsp::Position &completePos,
const DialectRegistry ®istry);
+ //===--------------------------------------------------------------------===//
+ // Code Action
+ //===--------------------------------------------------------------------===//
+
+ void getCodeActionForDiagnostic(const lsp::URIForFile &uri,
+ lsp::Position &pos, StringRef severity,
+ StringRef message,
+ std::vector<lsp::TextEdit> &edits);
+
//===--------------------------------------------------------------------===//
// Fields
//===--------------------------------------------------------------------===//
@@ -796,6 +805,42 @@ MLIRDocument::getCodeCompletion(const lsp::URIForFile &uri,
return completionList;
}
+//===----------------------------------------------------------------------===//
+// MLIRDocument: Code Action
+//===----------------------------------------------------------------------===//
+
+void MLIRDocument::getCodeActionForDiagnostic(
+ const lsp::URIForFile &uri, lsp::Position &pos, StringRef severity,
+ StringRef message, std::vector<lsp::TextEdit> &edits) {
+ // Ignore diagnostics that print the current operation. These are always
+ // enabled for the language server, but not generally during normal
+ // parsing/verification.
+ if (message.startswith("see current operation: "))
+ return;
+
+ // Get the start of the line containing the diagnostic.
+ const auto &buffer = sourceMgr.getBufferInfo(sourceMgr.getMainFileID());
+ const char *lineStart = buffer.getPointerForLineNumber(pos.line + 1);
+ if (!lineStart)
+ return;
+ StringRef line(lineStart, pos.character);
+
+ // Add a text edit for adding an expected-* diagnostic check for this
+ // diagnostic.
+ lsp::TextEdit edit;
+ edit.range = lsp::Range(lsp::Position(pos.line, 0));
+
+ // Use the indent of the current line for the expected-* diagnostic.
+ size_t indent = line.find_first_not_of(" ");
+ if (indent == StringRef::npos)
+ indent = line.size();
+
+ edit.newText.append(indent, ' ');
+ llvm::raw_string_ostream(edit.newText)
+ << "// expected-" << severity << " @below {{" << message << "}}\n";
+ edits.emplace_back(std::move(edit));
+}
+
//===----------------------------------------------------------------------===//
// MLIRTextFileChunk
//===----------------------------------------------------------------------===//
@@ -853,6 +898,9 @@ class MLIRTextFile {
void findDocumentSymbols(std::vector<lsp::DocumentSymbol> &symbols);
lsp::CompletionList getCodeCompletion(const lsp::URIForFile &uri,
lsp::Position completePos);
+ void getCodeActions(const lsp::URIForFile &uri, const lsp::Range &pos,
+ const lsp::CodeActionContext &context,
+ std::vector<lsp::CodeAction> &actions);
private:
/// Find the MLIR document that contains the given position, and update the
@@ -1012,6 +1060,62 @@ lsp::CompletionList MLIRTextFile::getCodeCompletion(const lsp::URIForFile &uri,
return completionList;
}
+void MLIRTextFile::getCodeActions(const lsp::URIForFile &uri,
+ const lsp::Range &pos,
+ const lsp::CodeActionContext &context,
+ std::vector<lsp::CodeAction> &actions) {
+ // Create actions for any diagnostics in this file.
+ for (auto &diag : context.diagnostics) {
+ if (diag.source != "mlir")
+ continue;
+ lsp::Position diagPos = diag.range.start;
+ MLIRTextFileChunk &chunk = getChunkFor(diagPos);
+
+ // Add a new code action that inserts a "expected" diagnostic check.
+ lsp::CodeAction action;
+ action.title = "Add expected-* diagnostic checks";
+ action.kind = lsp::CodeAction::kQuickFix.str();
+
+ StringRef severity;
+ switch (diag.severity) {
+ case lsp::DiagnosticSeverity::Error:
+ severity = "error";
+ break;
+ case lsp::DiagnosticSeverity::Warning:
+ severity = "warning";
+ break;
+ default:
+ continue;
+ }
+
+ // Get edits for the diagnostic.
+ std::vector<lsp::TextEdit> edits;
+ chunk.document.getCodeActionForDiagnostic(uri, diagPos, severity,
+ diag.message, edits);
+
+ // Walk the related diagnostics, this is how we encode notes.
+ if (diag.relatedInformation) {
+ for (auto ¬eDiag : *diag.relatedInformation) {
+ if (noteDiag.location.uri != uri)
+ continue;
+ diagPos = noteDiag.location.range.start;
+ diagPos.line -= chunk.lineOffset;
+ chunk.document.getCodeActionForDiagnostic(uri, diagPos, "note",
+ noteDiag.message, edits);
+ }
+ }
+ // Fixup the locations for any edits.
+ for (lsp::TextEdit &edit : edits)
+ chunk.adjustLocForChunkOffset(edit.range);
+
+ action.edit.emplace();
+ action.edit->changes[uri.uri().str()] = std::move(edits);
+ action.diagnostics = {diag};
+
+ actions.emplace_back(std::move(action));
+ }
+}
+
MLIRTextFileChunk &MLIRTextFile::getChunkFor(lsp::Position &pos) {
if (chunks.size() == 1)
return *chunks.front();
@@ -1106,3 +1210,11 @@ lsp::MLIRServer::getCodeCompletion(const URIForFile &uri,
return fileIt->second->getCodeCompletion(uri, completePos);
return CompletionList();
}
+
+void lsp::MLIRServer::getCodeActions(const URIForFile &uri, const Range &pos,
+ const CodeActionContext &context,
+ std::vector<CodeAction> &actions) {
+ auto fileIt = impl->files.find(uri.file());
+ if (fileIt != impl->files.end())
+ fileIt->second->getCodeActions(uri, pos, context, actions);
+}
diff --git a/mlir/lib/Tools/mlir-lsp-server/MLIRServer.h b/mlir/lib/Tools/mlir-lsp-server/MLIRServer.h
index 85ccf0a68f1b0..cee882e7d5d5a 100644
--- a/mlir/lib/Tools/mlir-lsp-server/MLIRServer.h
+++ b/mlir/lib/Tools/mlir-lsp-server/MLIRServer.h
@@ -16,12 +16,15 @@ namespace mlir {
class DialectRegistry;
namespace lsp {
+struct CodeAction;
+struct CodeActionContext;
struct CompletionList;
struct Diagnostic;
struct DocumentSymbol;
struct Hover;
struct Location;
struct Position;
+struct Range;
class URIForFile;
/// This class implements all of the MLIR related functionality necessary for a
@@ -65,6 +68,11 @@ class MLIRServer {
CompletionList getCodeCompletion(const URIForFile &uri,
const Position &completePos);
+ /// Get the set of code actions within the file.
+ void getCodeActions(const URIForFile &uri, const Range &pos,
+ const CodeActionContext &context,
+ std::vector<CodeAction> &actions);
+
private:
struct Impl;
diff --git a/mlir/test/mlir-lsp-server/code-action.test b/mlir/test/mlir-lsp-server/code-action.test
new file mode 100644
index 0000000000000..69e7773784b70
--- /dev/null
+++ b/mlir/test/mlir-lsp-server/code-action.test
@@ -0,0 +1,176 @@
+// RUN: mlir-lsp-server -lit-test < %s | FileCheck -strict-whitespace %s
+{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"mlir","capabilities":{},"trace":"off"}}
+// -----
+{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{
+ "uri":"test:///foo.mlir",
+ "languageId":"mlir",
+ "version":1,
+ "text":"#attr = 42 : f32\n// -----\nfunc.func @foo(%arg: i32) -> i64 {\nreturn %arg : i64\n}\n"
+}}}
+// -----
+{"jsonrpc":"2.0","id":1,"method":"textDocument/codeAction","params":{
+ "textDocument":{
+ "uri":"file:///foo.mlir"
+ },
+ "range":{
+ "start":{"line":0,"character":8}, "end":{"line":0,"character":10}
+ },
+ "context":{
+ "diagnostics":[{
+ "range":{"start":{"line":0,"character":8}, "end":{"line":0,"character":10}},
+ "message":"unexpected decimal integer literal for a floating point value",
+ "severity":1,
+ "relatedInformation":[{
+ "message":"add a trailing dot to make the literal a float",
+ "location":{
+ "uri":"file:///foo.mlir",
+ "range":{"start":{"line":0,"character":8}, "end":{"line":0,"character":10}}
+ }
+ }],
+ "source":"mlir"
+ }],
+ "only":["quickfix"],
+ "triggerKind":1
+ }
+}}
+// CHECK-LABEL: "id": 1
+// CHECK-NEXT: "jsonrpc": "2.0",
+// CHECK-NEXT: "result": [
+// CHECK-NEXT: {
+// CHECK-NEXT: "diagnostics": [
+// CHECK-NEXT: {
+// CHECK-NEXT: "message": "unexpected decimal integer literal for a floating point value",
+// CHECK-NEXT: "range": {
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "character": 10,
+// CHECK-NEXT: "line": 0
+// CHECK-NEXT: },
+// CHECK-NEXT: "start": {
+// CHECK-NEXT: "character": 8,
+// CHECK-NEXT: "line": 0
+// CHECK-NEXT: }
+// CHECK-NEXT: },
+// CHECK-NEXT: "relatedInformation": [
+// CHECK-NEXT: {
+// CHECK-NEXT: "location": {
+// CHECK-NEXT: "range": {
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "character": 10,
+// CHECK-NEXT: "line": 0
+// CHECK-NEXT: },
+// CHECK-NEXT: "start": {
+// CHECK-NEXT: "character": 8,
+// CHECK-NEXT: "line": 0
+// CHECK-NEXT: }
+// CHECK-NEXT: },
+// CHECK-NEXT: "uri": "file:///foo.mlir"
+// CHECK-NEXT: },
+// CHECK-NEXT: "message": "add a trailing dot to make the literal a float"
+// CHECK-NEXT: }
+// CHECK-NEXT: ],
+// CHECK-NEXT: "severity": 1,
+// CHECK-NEXT: "source": "mlir"
+// CHECK-NEXT: }
+// CHECK-NEXT: ],
+// CHECK-NEXT: "edit": {
+// CHECK-NEXT: "changes": {
+// CHECK-NEXT: "file:///foo.mlir": [
+// CHECK-NEXT: {
+// CHECK-LITERAL: "newText": "// expected-error @below {{unexpected decimal integer literal for a floating point value}}\n"
+// CHECK: "range": {
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "character": 0,
+// CHECK-NEXT: "line": 0
+// CHECK-NEXT: },
+// CHECK-NEXT: "start": {
+// CHECK-NEXT: "character": 0,
+// CHECK-NEXT: "line": 0
+// CHECK-NEXT: }
+// CHECK-NEXT: }
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT-LITERAL: "newText": "// expected-note @below {{add a trailing dot to make the literal a float}}\n",
+// CHECK: "range": {
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "character": 0,
+// CHECK-NEXT: "line": 0
+// CHECK-NEXT: },
+// CHECK-NEXT: "start": {
+// CHECK-NEXT: "character": 0,
+// CHECK-NEXT: "line": 0
+// CHECK-NEXT: }
+// CHECK-NEXT: }
+// CHECK-NEXT: }
+// CHECK-NEXT: ]
+// CHECK-NEXT: }
+// CHECK-NEXT: },
+// CHECK-NEXT: "kind": "quickfix",
+// CHECK-NEXT: "title": "Add expected-* diagnostic checks"
+// CHECK-NEXT: }
+// CHECK-NEXT: ]
+// -----
+{"jsonrpc":"2.0","id":2,"method":"textDocument/codeAction","params":{
+ "textDocument":{"uri":"file:///foo.mlir"},
+ "range":{"start":{"line":3,"character":9},"end":{"line":3,"character":13}},
+ "context":{
+ "diagnostics":[{
+ "range":{"start":{"line":3,"character":9},"end":{"line":3,"character":13}},
+ "message":"use of value '%arg' expects
diff erent type than prior uses: 'i64' vs 'i32'",
+ "severity":1,
+ "relatedInformation":[{
+ "message":"prior use here",
+ "location":{
+ "uri":"file:///foo.mlir",
+ "range":{"start":{"line":2,"character":15},"end":{"line":2,"character":19}}
+ }
+ }],
+ "source":"mlir"
+ }],
+ "only":["quickfix"],
+ "triggerKind":1
+ }
+}}
+// CHECK-LABEL: "id": 2
+// CHECK-NEXT: "jsonrpc": "2.0",
+// CHECK-NEXT: "result": [
+// CHECK-NEXT: {
+// CHECK: "edit": {
+// CHECK-NEXT: "changes": {
+// CHECK-NEXT: "file:///foo.mlir": [
+// CHECK-NEXT: {
+// CHECK-NEXT-LITERAL: "newText": "// expected-error @below {{use of value '%arg' expects
diff erent type than prior uses: 'i64' vs 'i32'}}\n",
+// CHECK: "range": {
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "character": 0,
+// CHECK-NEXT: "line": 3
+// CHECK-NEXT: },
+// CHECK-NEXT: "start": {
+// CHECK-NEXT: "character": 0,
+// CHECK-NEXT: "line": 3
+// CHECK-NEXT: }
+// CHECK-NEXT: }
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT-LITERAL: "newText": "// expected-note @below {{prior use here}}\n",
+// CHECK: "range": {
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "character": 0,
+// CHECK-NEXT: "line": 2
+// CHECK-NEXT: },
+// CHECK-NEXT: "start": {
+// CHECK-NEXT: "character": 0,
+// CHECK-NEXT: "line": 2
+// CHECK-NEXT: }
+// CHECK-NEXT: }
+// CHECK-NEXT: }
+// CHECK-NEXT: ]
+// CHECK-NEXT: }
+// CHECK-NEXT: },
+// CHECK-NEXT: "kind": "quickfix",
+// CHECK-NEXT: "title": "Add expected-* diagnostic checks"
+// CHECK-NEXT: }
+// CHECK-NEXT: ]
+// -----
+{"jsonrpc":"2.0","id":10,"method":"shutdown"}
+// -----
+{"jsonrpc":"2.0","method":"exit"}
diff --git a/mlir/test/mlir-lsp-server/initialize-params.test b/mlir/test/mlir-lsp-server/initialize-params.test
index 2fe528f8ed2f2..515a1e6908073 100644
--- a/mlir/test/mlir-lsp-server/initialize-params.test
+++ b/mlir/test/mlir-lsp-server/initialize-params.test
@@ -5,6 +5,7 @@
// CHECK-NEXT: "jsonrpc": "2.0",
// CHECK-NEXT: "result": {
// CHECK-NEXT: "capabilities": {
+// CHECK-NEXT: "codeActionProvider": true,
// CHECK-NEXT: "completionProvider": {
// CHECK-NEXT: "allCommitCharacters": [
// CHECK: ],
More information about the Mlir-commits
mailing list