[Lldb-commits] [lldb] 30bb0c4 - [lldb-dap] Adding a DAPError for showing users error messages. (#132255)

via lldb-commits lldb-commits at lists.llvm.org
Thu Mar 20 15:33:08 PDT 2025


Author: John Harrison
Date: 2025-03-20T15:33:05-07:00
New Revision: 30bb0c443e163b244d663c88821524b6e747747b

URL: https://github.com/llvm/llvm-project/commit/30bb0c443e163b244d663c88821524b6e747747b
DIFF: https://github.com/llvm/llvm-project/commit/30bb0c443e163b244d663c88821524b6e747747b.diff

LOG: [lldb-dap] Adding a DAPError for showing users error messages. (#132255)

The `DAPError` can be used to craft an error message that is displayed
to a user (with showUser=true).

Any request handler implementation using subclassing `RequestHandler<>`
should be able to use this.

I updated SourceRequestHandler to report DAPError's specifically.

Added: 
    lldb/tools/lldb-dap/DAPError.cpp
    lldb/tools/lldb-dap/DAPError.h

Modified: 
    lldb/tools/lldb-dap/CMakeLists.txt
    lldb/tools/lldb-dap/Handler/RequestHandler.h
    lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp
    lldb/tools/lldb-dap/Protocol/ProtocolBase.cpp
    lldb/tools/lldb-dap/Protocol/ProtocolBase.h

Removed: 
    


################################################################################
diff  --git a/lldb/tools/lldb-dap/CMakeLists.txt b/lldb/tools/lldb-dap/CMakeLists.txt
index 93c5ee4426783..e9773db7586e6 100644
--- a/lldb/tools/lldb-dap/CMakeLists.txt
+++ b/lldb/tools/lldb-dap/CMakeLists.txt
@@ -18,6 +18,7 @@ add_lldb_tool(lldb-dap
   Breakpoint.cpp
   BreakpointBase.cpp
   DAP.cpp
+  DAPError.cpp
   DAPLog.cpp
   EventHelper.cpp
   ExceptionBreakpoint.cpp

diff  --git a/lldb/tools/lldb-dap/DAPError.cpp b/lldb/tools/lldb-dap/DAPError.cpp
new file mode 100644
index 0000000000000..dcb955af0345f
--- /dev/null
+++ b/lldb/tools/lldb-dap/DAPError.cpp
@@ -0,0 +1,29 @@
+//===-- DAPError.cpp ------------------------------------------------------===//
+//
+// 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 "DAPError.h"
+#include "llvm/Support/Error.h"
+#include <system_error>
+
+namespace lldb_dap {
+
+char DAPError::ID;
+
+DAPError::DAPError(std::string message, std::error_code EC, bool show_user,
+                   std::optional<std::string> url,
+                   std::optional<std::string> url_label)
+    : m_message(message), m_ec(EC), m_show_user(show_user), m_url(url),
+      m_url_label(url_label) {}
+
+void DAPError::log(llvm::raw_ostream &OS) const { OS << m_message; }
+
+std::error_code DAPError::convertToErrorCode() const {
+  return llvm::inconvertibleErrorCode();
+}
+
+} // namespace lldb_dap

diff  --git a/lldb/tools/lldb-dap/DAPError.h b/lldb/tools/lldb-dap/DAPError.h
new file mode 100644
index 0000000000000..564651b1f587d
--- /dev/null
+++ b/lldb/tools/lldb-dap/DAPError.h
@@ -0,0 +1,43 @@
+//===-- DAPError.h --------------------------------------------------------===//
+//
+// 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 "llvm/Support/Error.h"
+#include <optional>
+#include <string>
+#include <system_error>
+
+namespace lldb_dap {
+
+/// An Error that is reported as a DAP Error Message, which may be presented to
+/// the user.
+class DAPError : public llvm::ErrorInfo<DAPError> {
+public:
+  static char ID;
+
+  DAPError(std::string message,
+           std::error_code EC = llvm::inconvertibleErrorCode(),
+           bool show_user = true, std::optional<std::string> url = std::nullopt,
+           std::optional<std::string> url_label = std::nullopt);
+
+  void log(llvm::raw_ostream &OS) const override;
+  std::error_code convertToErrorCode() const override;
+
+  const std::string &getMessage() const { return m_message; }
+  bool getShowUser() const { return m_show_user; }
+  const std::optional<std::string> &getURL() const { return m_url; }
+  const std::optional<std::string> &getURLLabel() const { return m_url; }
+
+private:
+  std::string m_message;
+  std::error_code m_ec;
+  bool m_show_user;
+  std::optional<std::string> m_url;
+  std::optional<std::string> m_url_label;
+};
+
+} // namespace lldb_dap

diff  --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h
index d327820224a30..8971b02fcb92e 100644
--- a/lldb/tools/lldb-dap/Handler/RequestHandler.h
+++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h
@@ -10,11 +10,13 @@
 #define LLDB_TOOLS_LLDB_DAP_HANDLER_HANDLER_H
 
 #include "DAP.h"
+#include "DAPError.h"
 #include "DAPLog.h"
 #include "Protocol/ProtocolBase.h"
 #include "Protocol/ProtocolRequests.h"
 #include "lldb/API/SBError.h"
 #include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Error.h"
 #include "llvm/Support/JSON.h"
 #include <optional>
 #include <type_traits>
@@ -118,20 +120,38 @@ class RequestHandler : public BaseRequestHandler {
       std::string parse_failure;
       llvm::raw_string_ostream OS(parse_failure);
       root.printErrorContext(request.arguments, OS);
+
+      protocol::ErrorMessage error_message;
+      error_message.format = parse_failure;
+
+      protocol::ErrorResponseBody body;
+      body.error = error_message;
+
       response.success = false;
-      response.message = parse_failure;
+      response.body = std::move(body);
+
       dap.Send(response);
       return;
     }
 
-    auto body = Run(arguments);
-    // FIXME: Add a dedicated DAPError for enhanced errors that are
-    // user-visibile.
+    llvm::Expected<Body> body = Run(arguments);
     if (auto Err = body.takeError()) {
+      protocol::ErrorMessage error_message;
+      error_message.sendTelemetry = false;
+      if (llvm::Error unhandled = llvm::handleErrors(
+              std::move(Err), [&](const DAPError &E) -> llvm::Error {
+                error_message.format = E.getMessage();
+                error_message.showUser = E.getShowUser();
+                error_message.id = E.convertToErrorCode().value();
+                error_message.url = E.getURL();
+                error_message.urlLabel = E.getURLLabel();
+                return llvm::Error::success();
+              }))
+        error_message.format = llvm::toString(std::move(unhandled));
+      protocol::ErrorResponseBody body;
+      body.error = error_message;
       response.success = false;
-      // FIXME: Build ErrorMessage based on error details instead of using the
-      // 'message' field.
-      response.message = llvm::toString(std::move(Err));
+      response.body = std::move(body);
     } else {
       response.success = true;
       if constexpr (!std::is_same_v<Body, std::monostate>)

diff  --git a/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp
index 57cfb09692990..1a7a13d9f267a 100644
--- a/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp
@@ -29,7 +29,7 @@ SourceRequestHandler::Run(const protocol::SourceArguments &args) const {
       args.source->sourceReference.value_or(args.sourceReference);
 
   if (!source)
-    return llvm::createStringError(
+    return llvm::make_error<DAPError>(
         "invalid arguments, expected source.sourceReference to be set");
 
   lldb::SBProcess process = dap.target.GetProcess();
@@ -39,7 +39,7 @@ SourceRequestHandler::Run(const protocol::SourceArguments &args) const {
   // Lower 32 bits is the frame index
   lldb::SBFrame frame = thread.GetFrameAtIndex(GetLLDBFrameID(source));
   if (!frame.IsValid())
-    return llvm::createStringError("source not found");
+    return llvm::make_error<DAPError>("source not found");
 
   lldb::SBInstructionList insts = frame.GetSymbol().GetInstructions(dap.target);
   lldb::SBStream stream;

diff  --git a/lldb/tools/lldb-dap/Protocol/ProtocolBase.cpp b/lldb/tools/lldb-dap/Protocol/ProtocolBase.cpp
index f30517715194f..0ef90eb7d76bd 100644
--- a/lldb/tools/lldb-dap/Protocol/ProtocolBase.cpp
+++ b/lldb/tools/lldb-dap/Protocol/ProtocolBase.cpp
@@ -286,4 +286,13 @@ json::Value toJSON(const Message &M) {
   return std::visit([](auto &M) { return toJSON(M); }, M);
 }
 
+json::Value toJSON(const ErrorResponseBody &E) {
+  json::Object result{};
+
+  if (E.error)
+    result.insert({"error", *E.error});
+
+  return result;
+}
+
 } // namespace lldb_dap::protocol

diff  --git a/lldb/tools/lldb-dap/Protocol/ProtocolBase.h b/lldb/tools/lldb-dap/Protocol/ProtocolBase.h
index e10a903b80aaa..baf5f8f165183 100644
--- a/lldb/tools/lldb-dap/Protocol/ProtocolBase.h
+++ b/lldb/tools/lldb-dap/Protocol/ProtocolBase.h
@@ -109,7 +109,7 @@ struct ErrorMessage {
   /// requirement that every user visible error message needs a corresponding
   /// error number, so that users or customer support can find information about
   /// the specific error more easily.
-  uint64_t id;
+  uint64_t id = 0;
 
   /// A format string for the message. Embedded variables have the form
   /// `{name}`. If variable name starts with an underscore character, the
@@ -122,10 +122,10 @@ struct ErrorMessage {
   std::optional<std::map<std::string, std::string>> variables;
 
   /// If true send to telemetry.
-  bool sendTelemetry;
+  bool sendTelemetry = false;
 
   /// If true show user.
-  bool showUser;
+  bool showUser = false;
 
   /// A url where additional information about this message can be found.
   std::optional<std::string> url;
@@ -141,6 +141,13 @@ using Message = std::variant<Request, Response, Event>;
 bool fromJSON(const llvm::json::Value &, Message &, llvm::json::Path);
 llvm::json::Value toJSON(const Message &);
 
+/// On error (whenever `success` is false), the body can provide more details.
+struct ErrorResponseBody {
+  /// A structured error message.
+  std::optional<ErrorMessage> error;
+};
+llvm::json::Value toJSON(const ErrorResponseBody &);
+
 /// This is just an acknowledgement, so no body field is required.
 using VoidResponse = std::monostate;
 


        


More information about the lldb-commits mailing list