[Mlir-commits] [mlir] [mlir-lsp] Add DiagnosticTag from LSP spec (PR #91396)

Lily Brown llvmlistbot at llvm.org
Tue May 7 13:49:51 PDT 2024


https://github.com/AmaranthineCodices created https://github.com/llvm/llvm-project/pull/91396

Adds the [DiagnosticTag][diagtag] LSP construct to the LSP support headers. I also added a unit test file to validate that the `tags` array is omitted entirely if it's empty.

The LSP spec requires that `Diagnostic::tags` be an array; in order to conform to that I used `std::vector`, as `SmallVector` doesn't have JSON decoding support (you can encode it to JSON, but not decode it from JSON).

[diagtag]: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.18/specification/#diagnosticTag

>From 362e79e443083899f16457a7547264224841ff00 Mon Sep 17 00:00:00 2001
From: Lily Brown <lbrown at modular.com>
Date: Mon, 6 May 2024 12:03:18 -0700
Subject: [PATCH] [mlir-lsp] Add DiagnosticTag from LSP spec

Adds the [DiagnosticTag][diagtag] LSP construct to the LSP support
headers. I also added a unit test file to validate that the `tags` array
is omitted entirely if it's empty.

The LSP spec requires that `Diagnostic::tags` be an array; in order to
conform to that I used `std::vector`, as `SmallVector` doesn't have JSON
decoding support (you can encode it to JSON, but not decode it from
JSON).

[diagtag]: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.18/specification/#diagnosticTag
---
 .../mlir/Tools/lsp-server-support/Protocol.h  | 12 +++++
 .../lib/Tools/lsp-server-support/Protocol.cpp | 19 ++++++-
 .../Tools/lsp-server-support/CMakeLists.txt   |  1 +
 .../Tools/lsp-server-support/Protocol.cpp     | 51 +++++++++++++++++++
 4 files changed, 82 insertions(+), 1 deletion(-)
 create mode 100644 mlir/unittests/Tools/lsp-server-support/Protocol.cpp

diff --git a/mlir/include/mlir/Tools/lsp-server-support/Protocol.h b/mlir/include/mlir/Tools/lsp-server-support/Protocol.h
index 839d82bb02b87..06205326a5a1f 100644
--- a/mlir/include/mlir/Tools/lsp-server-support/Protocol.h
+++ b/mlir/include/mlir/Tools/lsp-server-support/Protocol.h
@@ -677,6 +677,15 @@ enum class DiagnosticSeverity {
   Hint = 4
 };
 
+enum class DiagnosticTag {
+  Unnecessary = 1,
+  Deprecated = 2,
+};
+
+llvm::json::Value toJSON(DiagnosticTag tag);
+bool fromJSON(const llvm::json::Value &value, DiagnosticTag &result,
+              llvm::json::Path path);
+
 struct Diagnostic {
   /// The source range where the message applies.
   Range range;
@@ -696,6 +705,9 @@ struct Diagnostic {
   /// a scope collide all definitions can be marked via this property.
   std::optional<std::vector<DiagnosticRelatedInformation>> relatedInformation;
 
+  /// Additional metadata about the diagnostic.
+  std::vector<DiagnosticTag> tags;
+
   /// The diagnostic's category. Can be omitted.
   /// An LSP extension that's used to send the name of the category over to the
   /// client. The category typically describes the compilation stage during
diff --git a/mlir/lib/Tools/lsp-server-support/Protocol.cpp b/mlir/lib/Tools/lsp-server-support/Protocol.cpp
index e110fdd97a38f..f478dd6ec05bc 100644
--- a/mlir/lib/Tools/lsp-server-support/Protocol.cpp
+++ b/mlir/lib/Tools/lsp-server-support/Protocol.cpp
@@ -646,6 +646,20 @@ llvm::json::Value mlir::lsp::toJSON(const DiagnosticRelatedInformation &info) {
 // Diagnostic
 //===----------------------------------------------------------------------===//
 
+llvm::json::Value mlir::lsp::toJSON(DiagnosticTag tag) {
+  return static_cast<int>(tag);
+}
+
+bool mlir::lsp::fromJSON(const llvm::json::Value &value, DiagnosticTag &result,
+                         llvm::json::Path path) {
+  if (auto i = value.getAsInteger()) {
+    result = (DiagnosticTag)*i;
+    return true;
+  }
+
+  return false;
+}
+
 llvm::json::Value mlir::lsp::toJSON(const Diagnostic &diag) {
   llvm::json::Object result{
       {"range", diag.range},
@@ -658,6 +672,8 @@ llvm::json::Value mlir::lsp::toJSON(const Diagnostic &diag) {
     result["source"] = diag.source;
   if (diag.relatedInformation)
     result["relatedInformation"] = *diag.relatedInformation;
+  if (!diag.tags.empty())
+    result["tags"] = diag.tags;
   return std::move(result);
 }
 
@@ -675,7 +691,8 @@ bool mlir::lsp::fromJSON(const llvm::json::Value &value, Diagnostic &result,
          mapOptOrNull(value, "category", result.category, path) &&
          mapOptOrNull(value, "source", result.source, path) &&
          mapOptOrNull(value, "relatedInformation", result.relatedInformation,
-                      path);
+                      path) &&
+         mapOptOrNull(value, "tags", result.tags, path);
 }
 
 //===----------------------------------------------------------------------===//
diff --git a/mlir/unittests/Tools/lsp-server-support/CMakeLists.txt b/mlir/unittests/Tools/lsp-server-support/CMakeLists.txt
index 3aa8b9c4bc773..f777873ff7c65 100644
--- a/mlir/unittests/Tools/lsp-server-support/CMakeLists.txt
+++ b/mlir/unittests/Tools/lsp-server-support/CMakeLists.txt
@@ -1,4 +1,5 @@
 add_mlir_unittest(MLIRLspServerSupportTests
+  Protocol.cpp
   Transport.cpp
 )
 target_link_libraries(MLIRLspServerSupportTests
diff --git a/mlir/unittests/Tools/lsp-server-support/Protocol.cpp b/mlir/unittests/Tools/lsp-server-support/Protocol.cpp
new file mode 100644
index 0000000000000..f426fca0d62da
--- /dev/null
+++ b/mlir/unittests/Tools/lsp-server-support/Protocol.cpp
@@ -0,0 +1,51 @@
+//===- Protocol.cpp - LSP JSON protocol unit tests ------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "mlir/Tools/lsp-server-support/Protocol.h"
+
+#include "gtest/gtest.h"
+
+using namespace mlir;
+using namespace mlir::lsp;
+using namespace testing;
+
+namespace {
+
+TEST(ProtocolTest, DiagnosticTagPresent) {
+  Diagnostic diagnostic;
+  diagnostic.tags.push_back(DiagnosticTag::Unnecessary);
+
+  llvm::json::Value json = toJSON(diagnostic);
+  const llvm::json::Object *o = json.getAsObject();
+  const auto *v = o->get("tags")->getAsArray();
+  EXPECT_EQ(*v, llvm::json::Array{1});
+
+  Diagnostic parsed;
+  auto root = llvm::json::Path::Root();
+  bool success = fromJSON(json, parsed, llvm::json::Path(root));
+  EXPECT_TRUE(success);
+  ASSERT_EQ(parsed.tags.size(), 1);
+  EXPECT_EQ(parsed.tags.at(0), DiagnosticTag::Unnecessary);
+}
+
+TEST(ProtocolTest, DiagnosticTagNotPresent) {
+  Diagnostic diagnostic;
+
+  llvm::json::Value json = toJSON(diagnostic);
+  const llvm::json::Object *o = json.getAsObject();
+  const auto *v = o->get("tags");
+  EXPECT_EQ(v, nullptr);
+
+  Diagnostic parsed;
+  auto root = llvm::json::Path::Root();
+  bool success = fromJSON(json, parsed, llvm::json::Path(root));
+  EXPECT_TRUE(success);
+  EXPECT_TRUE(parsed.tags.empty());
+}
+
+} // namespace



More information about the Mlir-commits mailing list