[Lldb-commits] [lldb] [lldb-dap] Updating RequestHandler to encode/decode arguments and response. (PR #130090)

John Harrison via lldb-commits lldb-commits at lists.llvm.org
Mon Mar 17 09:22:08 PDT 2025


https://github.com/ashgti updated https://github.com/llvm/llvm-project/pull/130090

>From f26c9a79ca234bee77ec1a9694bf8be2d0e3745c Mon Sep 17 00:00:00 2001
From: John Harrison <harjohn at google.com>
Date: Thu, 6 Mar 2025 13:21:10 +0100
Subject: [PATCH 01/12] [lldb-dap] Updating RequestHandler to encode/decode
 arguments and response.

This is a work in progress refactor to add explicit types instead of
generic 'llvm::json::Value' types to the DAP protocol.

This updates RequestHandler to have take the type of the arguments and
response body for serialization for requests.

The 'source' request is updated to show how the new flow works.
---
 lldb/tools/lldb-dap/DAP.cpp                   |  57 +++--
 lldb/tools/lldb-dap/DAP.h                     |   4 +-
 lldb/tools/lldb-dap/DAPForward.h              |   2 +
 .../tools/lldb-dap/Handler/RequestHandler.cpp |  11 +-
 lldb/tools/lldb-dap/Handler/RequestHandler.h  | 214 ++++++++++++------
 .../lldb-dap/Handler/SourceRequestHandler.cpp | 104 ++-------
 lldb/tools/lldb-dap/Protocol.cpp              |  44 ++++
 lldb/tools/lldb-dap/Protocol.h                | 131 +++++++++++
 8 files changed, 381 insertions(+), 186 deletions(-)

diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp
index 4080e2c211035..9d42af2d7091f 100644
--- a/lldb/tools/lldb-dap/DAP.cpp
+++ b/lldb/tools/lldb-dap/DAP.cpp
@@ -8,10 +8,12 @@
 
 #include "DAP.h"
 #include "DAPLog.h"
+#include "Handler/RequestHandler.h"
 #include "Handler/ResponseHandler.h"
 #include "JSONUtils.h"
 #include "LLDBUtils.h"
 #include "OutputRedirector.h"
+#include "Protocol.h"
 #include "Transport.h"
 #include "lldb/API/SBBreakpoint.h"
 #include "lldb/API/SBCommandInterpreter.h"
@@ -25,6 +27,7 @@
 #include "lldb/lldb-defines.h"
 #include "lldb/lldb-enumerations.h"
 #include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/ScopeExit.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/ADT/StringRef.h"
@@ -41,6 +44,7 @@
 #include <fstream>
 #include <memory>
 #include <mutex>
+#include <string>
 #include <utility>
 
 #if defined(_WIN32)
@@ -663,31 +667,23 @@ void DAP::SetTarget(const lldb::SBTarget target) {
 }
 
 bool DAP::HandleObject(const protocol::Message &M) {
-  // FIXME: Directly handle `Message` instead of serializing to JSON.
-  llvm::json::Value v = toJSON(M);
-  llvm::json::Object object = *v.getAsObject();
-  const auto packet_type = GetString(object, "type");
-  if (packet_type == "request") {
-    const auto command = GetString(object, "command");
-
-    auto new_handler_pos = request_handlers.find(command);
+  if (const auto *req = std::get_if<protocol::Request>(&M)) {
+    auto new_handler_pos = request_handlers.find(req->command);
     if (new_handler_pos != request_handlers.end()) {
-      (*new_handler_pos->second)(object);
+      (*new_handler_pos->second)(*req);
       return true; // Success
     }
 
     DAP_LOG(log, "({0}) error: unhandled command '{1}'",
-            transport.GetClientName(), command);
+            transport.GetClientName(), req->command);
     return false; // Fail
   }
 
-  if (packet_type == "response") {
-    auto id = GetInteger<int64_t>(object, "request_seq").value_or(0);
-
+  if (const auto *resp = std::get_if<protocol::Response>(&M)) {
     std::unique_ptr<ResponseHandler> response_handler;
     {
       std::lock_guard<std::mutex> locker(call_mutex);
-      auto inflight = inflight_reverse_requests.find(id);
+      auto inflight = inflight_reverse_requests.find(resp->request_seq);
       if (inflight != inflight_reverse_requests.end()) {
         response_handler = std::move(inflight->second);
         inflight_reverse_requests.erase(inflight);
@@ -695,19 +691,31 @@ bool DAP::HandleObject(const protocol::Message &M) {
     }
 
     if (!response_handler)
-      response_handler = std::make_unique<UnknownResponseHandler>("", id);
+      response_handler =
+          std::make_unique<UnknownResponseHandler>("", resp->request_seq);
 
     // Result should be given, use null if not.
-    if (GetBoolean(object, "success").value_or(false)) {
-      llvm::json::Value Result = nullptr;
-      if (auto *B = object.get("body"))
-        Result = std::move(*B);
-      (*response_handler)(Result);
+    if (resp->success) {
+      (*response_handler)(resp->rawBody);
     } else {
-      llvm::StringRef message = GetString(object, "message");
-      if (message.empty()) {
-        message = "Unknown error, response failed";
+      std::string message = "Unknown error, response failed";
+      if (resp->message) {
+        message = std::visit(
+            llvm::makeVisitor(
+                [](const std::string &message) -> std::string {
+                  return message;
+                },
+                [](const protocol::Response::Message &message) -> std::string {
+                  switch (message) {
+                  case protocol::Response::Message::cancelled:
+                    return "cancelled";
+                  case protocol::Response::Message::notStopped:
+                    return "notStopped";
+                  }
+                }),
+            *resp->message);
       }
+
       (*response_handler)(llvm::createStringError(
           std::error_code(-1, std::generic_category()), message));
     }
@@ -715,6 +723,9 @@ bool DAP::HandleObject(const protocol::Message &M) {
     return true;
   }
 
+  if (log)
+    *log << "Unsupported protocol message" << std::endl;
+
   return false;
 }
 
diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h
index db3473b7c7027..f6b63e4a3e0bc 100644
--- a/lldb/tools/lldb-dap/DAP.h
+++ b/lldb/tools/lldb-dap/DAP.h
@@ -12,8 +12,6 @@
 #include "DAPForward.h"
 #include "ExceptionBreakpoint.h"
 #include "FunctionBreakpoint.h"
-#include "Handler/RequestHandler.h"
-#include "Handler/ResponseHandler.h"
 #include "InstructionBreakpoint.h"
 #include "OutputRedirector.h"
 #include "ProgressEvent.h"
@@ -187,7 +185,7 @@ struct DAP {
   // the old process here so we can detect this case and keep running.
   lldb::pid_t restarting_process_id;
   bool configuration_done_sent;
-  llvm::StringMap<std::unique_ptr<RequestHandler>> request_handlers;
+  llvm::StringMap<std::unique_ptr<BaseRequestHandler>> request_handlers;
   bool waiting_for_run_in_terminal;
   ProgressEventReporter progress_event_reporter;
   // Keep track of the last stop thread index IDs as threads won't go away
diff --git a/lldb/tools/lldb-dap/DAPForward.h b/lldb/tools/lldb-dap/DAPForward.h
index 0196d83dcd6a9..667aef23abd0f 100644
--- a/lldb/tools/lldb-dap/DAPForward.h
+++ b/lldb/tools/lldb-dap/DAPForward.h
@@ -19,6 +19,8 @@ struct SourceBreakpoint;
 struct Watchpoint;
 struct InstructionBreakpoint;
 struct DAP;
+class BaseRequestHandler;
+class ResponseHandler;
 } // namespace lldb_dap
 
 namespace lldb {
diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.cpp b/lldb/tools/lldb-dap/Handler/RequestHandler.cpp
index e43fa36d25e3f..13cf166e200e8 100644
--- a/lldb/tools/lldb-dap/Handler/RequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/RequestHandler.cpp
@@ -6,8 +6,9 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "RequestHandler.h"
+#include "Handler/RequestHandler.h"
 #include "DAP.h"
+#include "Handler/ResponseHandler.h"
 #include "JSONUtils.h"
 #include "LLDBUtils.h"
 #include "RunInTerminal.h"
@@ -45,7 +46,7 @@ static uint32_t SetLaunchFlag(uint32_t flags, const llvm::json::Object *obj,
 
 // Both attach and launch take either a sourcePath or a sourceMap
 // argument (or neither), from which we need to set the target.source-map.
-void RequestHandler::SetSourceMapFromArguments(
+void BaseRequestHandler::SetSourceMapFromArguments(
     const llvm::json::Object &arguments) const {
   const char *sourceMapHelp =
       "source must be be an array of two-element arrays, "
@@ -159,7 +160,7 @@ static llvm::Error RunInTerminal(DAP &dap,
 }
 
 lldb::SBError
-RequestHandler::LaunchProcess(const llvm::json::Object &request) const {
+BaseRequestHandler::LaunchProcess(const llvm::json::Object &request) const {
   lldb::SBError error;
   const auto *arguments = request.getObject("arguments");
   auto launchCommands = GetStrings(arguments, "launchCommands");
@@ -228,13 +229,13 @@ RequestHandler::LaunchProcess(const llvm::json::Object &request) const {
   return error;
 }
 
-void RequestHandler::PrintWelcomeMessage() const {
+void BaseRequestHandler::PrintWelcomeMessage() const {
 #ifdef LLDB_DAP_WELCOME_MESSAGE
   dap.SendOutput(OutputType::Console, LLDB_DAP_WELCOME_MESSAGE);
 #endif
 }
 
-bool RequestHandler::HasInstructionGranularity(
+bool BaseRequestHandler::HasInstructionGranularity(
     const llvm::json::Object &arguments) const {
   if (std::optional<llvm::StringRef> value = arguments.getString("granularity"))
     return value == "instruction";
diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h
index b44367518bcb9..da65b2de9ab99 100644
--- a/lldb/tools/lldb-dap/Handler/RequestHandler.h
+++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h
@@ -9,25 +9,36 @@
 #ifndef LLDB_TOOLS_LLDB_DAP_HANDLER_HANDLER_H
 #define LLDB_TOOLS_LLDB_DAP_HANDLER_HANDLER_H
 
+#include "DAP.h"
+#include "Protocol.h"
 #include "lldb/API/SBError.h"
+#include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/JSON.h"
 
 namespace lldb_dap {
 struct DAP;
 
-class RequestHandler {
+/// Base class for request handlers. Do not extend this directly: Extend
+/// the RequestHandler template subclass instead.
+class BaseRequestHandler {
 public:
-  RequestHandler(DAP &dap) : dap(dap) {}
+  BaseRequestHandler(DAP &dap) : dap(dap) {}
 
-  /// RequestHandler are not copyable.
+  /// BaseRequestHandler are not copyable.
   /// @{
-  RequestHandler(const RequestHandler &) = delete;
-  RequestHandler &operator=(const RequestHandler &) = delete;
+  BaseRequestHandler(const BaseRequestHandler &) = delete;
+  BaseRequestHandler &operator=(const BaseRequestHandler &) = delete;
   /// @}
 
-  virtual ~RequestHandler() = default;
+  virtual ~BaseRequestHandler() = default;
 
+  virtual void operator()(const protocol::Request &request) const {
+    auto req = toJSON(request);
+    (*this)(*req.getAsObject());
+  }
+
+  /// FIXME: Migrate callers to typed RequestHandler for improved type handling.
   virtual void operator()(const llvm::json::Object &request) const = 0;
 
 protected:
@@ -57,235 +68,288 @@ class RequestHandler {
   DAP &dap;
 };
 
-class AttachRequestHandler : public RequestHandler {
-public:
-  using RequestHandler::RequestHandler;
+/// Base class for handling DAP requests. Handlers should declare their
+/// arguments and response body types like:
+///
+/// class MyRequestHandler : public RequestHandler<Arguments, ResponseBody> {
+///   ....
+/// };
+template <typename Args, typename Body>
+class RequestHandler : public BaseRequestHandler {
+  using BaseRequestHandler::BaseRequestHandler;
+
+  void operator()(const llvm::json::Object &request) const override {
+    /* no-op, the other overload handles json coding. */
+  }
+
+  void operator()(const protocol::Request &request) const override {
+    protocol::Response response;
+    response.request_seq = request.seq;
+    response.command = request.command;
+    Args arguments;
+    llvm::json::Path::Root root;
+    if (request.rawArguments &&
+        !fromJSON(request.rawArguments, arguments, root)) {
+      std::string parseFailure;
+      llvm::raw_string_ostream OS(parseFailure);
+      root.printErrorContext(request.rawArguments, OS);
+      response.success = false;
+      response.message = parseFailure;
+      dap.SendJSON(std::move(response));
+      return;
+    }
+
+    auto ResponseBody = Run(arguments);
+    // FIXME: Add a dedicated DAPError for enhanced errors that are user
+    // visibile.
+    if (auto Err = ResponseBody.takeError()) {
+      response.success = false;
+      // FIXME: Build ErrorMessage based on error details instead of using the
+      // 'message' field.
+      response.message = llvm::toString(std::move(Err));
+    } else {
+      response.success = true;
+      response.rawBody = std::move(*ResponseBody);
+    }
+
+    dap.SendJSON(std::move(response));
+  };
+
+  virtual llvm::Expected<Body> Run(const Args &) const = 0;
+};
+
+class AttachRequestHandler : public BaseRequestHandler {
+public:
+  using BaseRequestHandler::BaseRequestHandler;
   static llvm::StringLiteral getCommand() { return "attach"; }
   void operator()(const llvm::json::Object &request) const override;
 };
 
-class BreakpointLocationsRequestHandler : public RequestHandler {
+class BreakpointLocationsRequestHandler : public BaseRequestHandler {
 public:
-  using RequestHandler::RequestHandler;
+  using BaseRequestHandler::BaseRequestHandler;
   static llvm::StringLiteral getCommand() { return "breakpointLocations"; }
   void operator()(const llvm::json::Object &request) const override;
 };
 
-class CompletionsRequestHandler : public RequestHandler {
+class CompletionsRequestHandler : public BaseRequestHandler {
 public:
-  using RequestHandler::RequestHandler;
+  using BaseRequestHandler::BaseRequestHandler;
   static llvm::StringLiteral getCommand() { return "completions"; }
   void operator()(const llvm::json::Object &request) const override;
 };
 
-class ContinueRequestHandler : public RequestHandler {
+class ContinueRequestHandler : public BaseRequestHandler {
 public:
-  using RequestHandler::RequestHandler;
+  using BaseRequestHandler::BaseRequestHandler;
   static llvm::StringLiteral getCommand() { return "continue"; }
   void operator()(const llvm::json::Object &request) const override;
 };
 
-class ConfigurationDoneRequestHandler : public RequestHandler {
+class ConfigurationDoneRequestHandler : public BaseRequestHandler {
 public:
-  using RequestHandler::RequestHandler;
+  using BaseRequestHandler::BaseRequestHandler;
   static llvm::StringLiteral getCommand() { return "configurationDone"; }
   void operator()(const llvm::json::Object &request) const override;
 };
 
-class DisconnectRequestHandler : public RequestHandler {
+class DisconnectRequestHandler : public BaseRequestHandler {
 public:
-  using RequestHandler::RequestHandler;
+  using BaseRequestHandler::BaseRequestHandler;
   static llvm::StringLiteral getCommand() { return "disconnect"; }
   void operator()(const llvm::json::Object &request) const override;
 };
 
-class EvaluateRequestHandler : public RequestHandler {
+class EvaluateRequestHandler : public BaseRequestHandler {
 public:
-  using RequestHandler::RequestHandler;
+  using BaseRequestHandler::BaseRequestHandler;
   static llvm::StringLiteral getCommand() { return "evaluate"; }
   void operator()(const llvm::json::Object &request) const override;
 };
 
-class ExceptionInfoRequestHandler : public RequestHandler {
+class ExceptionInfoRequestHandler : public BaseRequestHandler {
 public:
-  using RequestHandler::RequestHandler;
+  using BaseRequestHandler::BaseRequestHandler;
   static llvm::StringLiteral getCommand() { return "exceptionInfo"; }
   void operator()(const llvm::json::Object &request) const override;
 };
 
-class InitializeRequestHandler : public RequestHandler {
+class InitializeRequestHandler : public BaseRequestHandler {
 public:
-  using RequestHandler::RequestHandler;
+  using BaseRequestHandler::BaseRequestHandler;
   static llvm::StringLiteral getCommand() { return "initialize"; }
   void operator()(const llvm::json::Object &request) const override;
 };
 
-class LaunchRequestHandler : public RequestHandler {
+class LaunchRequestHandler : public BaseRequestHandler {
 public:
-  using RequestHandler::RequestHandler;
+  using BaseRequestHandler::BaseRequestHandler;
   static llvm::StringLiteral getCommand() { return "launch"; }
   void operator()(const llvm::json::Object &request) const override;
 };
 
-class RestartRequestHandler : public RequestHandler {
+class RestartRequestHandler : public BaseRequestHandler {
 public:
-  using RequestHandler::RequestHandler;
+  using BaseRequestHandler::BaseRequestHandler;
   static llvm::StringLiteral getCommand() { return "restart"; }
   void operator()(const llvm::json::Object &request) const override;
 };
 
-class NextRequestHandler : public RequestHandler {
+class NextRequestHandler : public BaseRequestHandler {
 public:
-  using RequestHandler::RequestHandler;
+  using BaseRequestHandler::BaseRequestHandler;
   static llvm::StringLiteral getCommand() { return "next"; }
   void operator()(const llvm::json::Object &request) const override;
 };
 
-class StepInRequestHandler : public RequestHandler {
+class StepInRequestHandler : public BaseRequestHandler {
 public:
-  using RequestHandler::RequestHandler;
+  using BaseRequestHandler::BaseRequestHandler;
   static llvm::StringLiteral getCommand() { return "stepIn"; }
   void operator()(const llvm::json::Object &request) const override;
 };
 
-class StepInTargetsRequestHandler : public RequestHandler {
+class StepInTargetsRequestHandler : public BaseRequestHandler {
 public:
-  using RequestHandler::RequestHandler;
+  using BaseRequestHandler::BaseRequestHandler;
   static llvm::StringLiteral getCommand() { return "stepInTargets"; }
   void operator()(const llvm::json::Object &request) const override;
 };
 
-class StepOutRequestHandler : public RequestHandler {
+class StepOutRequestHandler : public BaseRequestHandler {
 public:
-  using RequestHandler::RequestHandler;
+  using BaseRequestHandler::BaseRequestHandler;
   static llvm::StringLiteral getCommand() { return "stepOut"; }
   void operator()(const llvm::json::Object &request) const override;
 };
 
-class SetBreakpointsRequestHandler : public RequestHandler {
+class SetBreakpointsRequestHandler : public BaseRequestHandler {
 public:
-  using RequestHandler::RequestHandler;
+  using BaseRequestHandler::BaseRequestHandler;
   static llvm::StringLiteral getCommand() { return "setBreakpoints"; }
   void operator()(const llvm::json::Object &request) const override;
 };
 
-class SetExceptionBreakpointsRequestHandler : public RequestHandler {
+class SetExceptionBreakpointsRequestHandler : public BaseRequestHandler {
 public:
-  using RequestHandler::RequestHandler;
+  using BaseRequestHandler::BaseRequestHandler;
   static llvm::StringLiteral getCommand() { return "setExceptionBreakpoints"; }
   void operator()(const llvm::json::Object &request) const override;
 };
 
-class SetFunctionBreakpointsRequestHandler : public RequestHandler {
+class SetFunctionBreakpointsRequestHandler : public BaseRequestHandler {
 public:
-  using RequestHandler::RequestHandler;
+  using BaseRequestHandler::BaseRequestHandler;
   static llvm::StringLiteral getCommand() { return "setFunctionBreakpoints"; }
   void operator()(const llvm::json::Object &request) const override;
 };
 
-class DataBreakpointInfoRequestHandler : public RequestHandler {
+class DataBreakpointInfoRequestHandler : public BaseRequestHandler {
 public:
-  using RequestHandler::RequestHandler;
+  using BaseRequestHandler::BaseRequestHandler;
   static llvm::StringLiteral getCommand() { return "dataBreakpointInfo"; }
   void operator()(const llvm::json::Object &request) const override;
 };
 
-class SetDataBreakpointsRequestHandler : public RequestHandler {
+class SetDataBreakpointsRequestHandler : public BaseRequestHandler {
 public:
-  using RequestHandler::RequestHandler;
+  using BaseRequestHandler::BaseRequestHandler;
   static llvm::StringLiteral getCommand() { return "setDataBreakpoints"; }
   void operator()(const llvm::json::Object &request) const override;
 };
 
-class SetInstructionBreakpointsRequestHandler : public RequestHandler {
+class SetInstructionBreakpointsRequestHandler : public BaseRequestHandler {
 public:
-  using RequestHandler::RequestHandler;
+  using BaseRequestHandler::BaseRequestHandler;
   static llvm::StringLiteral getCommand() {
     return "setInstructionBreakpoints";
   }
   void operator()(const llvm::json::Object &request) const override;
 };
 
-class CompileUnitsRequestHandler : public RequestHandler {
+class CompileUnitsRequestHandler : public BaseRequestHandler {
 public:
-  using RequestHandler::RequestHandler;
+  using BaseRequestHandler::BaseRequestHandler;
   static llvm::StringLiteral getCommand() { return "compileUnits"; }
   void operator()(const llvm::json::Object &request) const override;
 };
 
-class ModulesRequestHandler : public RequestHandler {
+class ModulesRequestHandler : public BaseRequestHandler {
 public:
-  using RequestHandler::RequestHandler;
+  using BaseRequestHandler::BaseRequestHandler;
   static llvm::StringLiteral getCommand() { return "modules"; }
   void operator()(const llvm::json::Object &request) const override;
 };
 
-class PauseRequestHandler : public RequestHandler {
+class PauseRequestHandler : public BaseRequestHandler {
 public:
-  using RequestHandler::RequestHandler;
+  using BaseRequestHandler::BaseRequestHandler;
   static llvm::StringLiteral getCommand() { return "pause"; }
   void operator()(const llvm::json::Object &request) const override;
 };
 
-class ScopesRequestHandler : public RequestHandler {
+class ScopesRequestHandler : public BaseRequestHandler {
 public:
-  using RequestHandler::RequestHandler;
+  using BaseRequestHandler::BaseRequestHandler;
   static llvm::StringLiteral getCommand() { return "scopes"; }
   void operator()(const llvm::json::Object &request) const override;
 };
 
-class SetVariableRequestHandler : public RequestHandler {
+class SetVariableRequestHandler : public BaseRequestHandler {
 public:
-  using RequestHandler::RequestHandler;
+  using BaseRequestHandler::BaseRequestHandler;
   static llvm::StringLiteral getCommand() { return "setVariable"; }
   void operator()(const llvm::json::Object &request) const override;
 };
 
-class SourceRequestHandler : public RequestHandler {
+class SourceRequestHandler
+    : public RequestHandler<protocol::SourceArguments,
+                            protocol::SourceResponseBody> {
 public:
   using RequestHandler::RequestHandler;
   static llvm::StringLiteral getCommand() { return "source"; }
-  void operator()(const llvm::json::Object &request) const override;
+  llvm::Expected<protocol::SourceResponseBody>
+  Run(const protocol::SourceArguments &args) const override;
 };
 
-class StackTraceRequestHandler : public RequestHandler {
+class StackTraceRequestHandler : public BaseRequestHandler {
 public:
-  using RequestHandler::RequestHandler;
+  using BaseRequestHandler::BaseRequestHandler;
   static llvm::StringLiteral getCommand() { return "stackTrace"; }
   void operator()(const llvm::json::Object &request) const override;
 };
 
-class ThreadsRequestHandler : public RequestHandler {
+class ThreadsRequestHandler : public BaseRequestHandler {
 public:
-  using RequestHandler::RequestHandler;
+  using BaseRequestHandler::BaseRequestHandler;
   static llvm::StringLiteral getCommand() { return "threads"; }
   void operator()(const llvm::json::Object &request) const override;
 };
 
-class VariablesRequestHandler : public RequestHandler {
+class VariablesRequestHandler : public BaseRequestHandler {
 public:
-  using RequestHandler::RequestHandler;
+  using BaseRequestHandler::BaseRequestHandler;
   static llvm::StringLiteral getCommand() { return "variables"; }
   void operator()(const llvm::json::Object &request) const override;
 };
 
-class LocationsRequestHandler : public RequestHandler {
+class LocationsRequestHandler : public BaseRequestHandler {
 public:
-  using RequestHandler::RequestHandler;
+  using BaseRequestHandler::BaseRequestHandler;
   static llvm::StringLiteral getCommand() { return "locations"; }
   void operator()(const llvm::json::Object &request) const override;
 };
 
-class DisassembleRequestHandler : public RequestHandler {
+class DisassembleRequestHandler : public BaseRequestHandler {
 public:
-  using RequestHandler::RequestHandler;
+  using BaseRequestHandler::BaseRequestHandler;
   static llvm::StringLiteral getCommand() { return "disassemble"; }
   void operator()(const llvm::json::Object &request) const override;
 };
 
-class ReadMemoryRequestHandler : public RequestHandler {
+class ReadMemoryRequestHandler : public BaseRequestHandler {
 public:
-  using RequestHandler::RequestHandler;
+  using BaseRequestHandler::BaseRequestHandler;
   static llvm::StringLiteral getCommand() { return "readMemory"; }
   void operator()(const llvm::json::Object &request) const override;
 };
@@ -294,9 +358,9 @@ class ReadMemoryRequestHandler : public RequestHandler {
 /// currently set in the target. This helps us to test "setBreakpoints" and
 /// "setFunctionBreakpoints" requests to verify we have the correct set of
 /// breakpoints currently set in LLDB.
-class TestGetTargetBreakpointsRequestHandler : public RequestHandler {
+class TestGetTargetBreakpointsRequestHandler : public BaseRequestHandler {
 public:
-  using RequestHandler::RequestHandler;
+  using BaseRequestHandler::BaseRequestHandler;
   static llvm::StringLiteral getCommand() {
     return "_testGetTargetBreakpoints";
   }
diff --git a/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp
index 493543b395fd1..101f18ef5220a 100644
--- a/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp
@@ -7,17 +7,15 @@
 //===----------------------------------------------------------------------===//
 
 #include "DAP.h"
-#include "EventHelper.h"
-#include "JSONUtils.h"
+#include "Handler/RequestHandler.h"
 #include "LLDBUtils.h"
-#include "RequestHandler.h"
 #include "lldb/API/SBFrame.h"
 #include "lldb/API/SBInstructionList.h"
 #include "lldb/API/SBProcess.h"
 #include "lldb/API/SBStream.h"
 #include "lldb/API/SBTarget.h"
 #include "lldb/API/SBThread.h"
-#include "llvm/Support/JSON.h"
+#include "llvm/Support/Error.h"
 
 namespace lldb_dap {
 
@@ -38,84 +36,30 @@ namespace lldb_dap {
 //     "required": [ "command", "arguments"  ]
 //   }]
 // },
-// "SourceArguments": {
-//   "type": "object",
-//   "description": "Arguments for 'source' request.",
-//   "properties": {
-//     "source": {
-//       "$ref": "#/definitions/Source",
-//       "description": "Specifies the source content to load. Either
-//       source.path or source.sourceReference must be specified."
-//     },
-//     "sourceReference": {
-//       "type": "integer",
-//       "description": "The reference to the source. This is the same as
-//       source.sourceReference. This is provided for backward compatibility
-//       since old backends do not understand the 'source' attribute."
-//     }
-//   },
-//   "required": [ "sourceReference" ]
-// },
-// "SourceResponse": {
-//   "allOf": [ { "$ref": "#/definitions/Response" }, {
-//     "type": "object",
-//     "description": "Response to 'source' request.",
-//     "properties": {
-//       "body": {
-//         "type": "object",
-//         "properties": {
-//           "content": {
-//             "type": "string",
-//             "description": "Content of the source reference."
-//           },
-//           "mimeType": {
-//             "type": "string",
-//             "description": "Optional content type (mime type) of the source."
-//           }
-//         },
-//         "required": [ "content" ]
-//       }
-//     },
-//     "required": [ "body" ]
-//   }]
-// }
-void SourceRequestHandler::operator()(const llvm::json::Object &request) const {
-  llvm::json::Object response;
-  FillResponse(request, response);
-  const auto *arguments = request.getObject("arguments");
-  const auto *source = arguments->getObject("source");
-  llvm::json::Object body;
-  const auto source_ref =
-      GetInteger<uint64_t>(source, "sourceReference")
-          .value_or(
-              GetInteger<uint64_t>(arguments, "sourceReference").value_or(0));
+llvm::Expected<protocol::SourceResponseBody>
+SourceRequestHandler::Run(const protocol::SourceArguments &args) const {
+  const auto source =
+      args.source->sourceReference.value_or(args.sourceReference);
+
+  if (!source)
+    return llvm::createStringError(
+        "invalid arguments, expected source.sourceReference to be set");
+
+  lldb::SBProcess process = dap.target.GetProcess();
+  // Upper 32 bits is the thread index ID
+  lldb::SBThread thread =
+      process.GetThreadByIndexID(GetLLDBThreadIndexID(source));
+  // Lower 32 bits is the frame index
+  lldb::SBFrame frame = thread.GetFrameAtIndex(GetLLDBFrameID(source));
+  if (!frame.IsValid())
+    return llvm::createStringError("source not found");
 
-  if (source_ref) {
-    lldb::SBProcess process = dap.target.GetProcess();
-    // Upper 32 bits is the thread index ID
-    lldb::SBThread thread =
-        process.GetThreadByIndexID(GetLLDBThreadIndexID(source_ref));
-    // Lower 32 bits is the frame index
-    lldb::SBFrame frame = thread.GetFrameAtIndex(GetLLDBFrameID(source_ref));
-    if (!frame.IsValid()) {
-      response["success"] = false;
-      response["message"] = "source not found";
-    } else {
-      lldb::SBInstructionList insts =
-          frame.GetSymbol().GetInstructions(dap.target);
-      lldb::SBStream stream;
-      insts.GetDescription(stream);
-      body["content"] = stream.GetData();
-      body["mimeType"] = "text/x-lldb.disassembly";
-      response.try_emplace("body", std::move(body));
-    }
-  } else {
-    response["success"] = false;
-    response["message"] =
-        "invalid arguments, expected source.sourceReference to be set";
-  }
+  lldb::SBInstructionList insts = frame.GetSymbol().GetInstructions(dap.target);
+  lldb::SBStream stream;
+  insts.GetDescription(stream);
 
-  dap.SendJSON(llvm::json::Value(std::move(response)));
+  return protocol::SourceResponseBody{/*content=*/stream.GetData(),
+                                      /*mimeType=*/"text/x-lldb.disassembly"};
 }
 
 } // namespace lldb_dap
diff --git a/lldb/tools/lldb-dap/Protocol.cpp b/lldb/tools/lldb-dap/Protocol.cpp
index b516c0cb19ebf..68cfa40580b31 100644
--- a/lldb/tools/lldb-dap/Protocol.cpp
+++ b/lldb/tools/lldb-dap/Protocol.cpp
@@ -287,5 +287,49 @@ json::Value toJSON(const Message &M) {
   return std::visit([](auto &M) { return toJSON(M); }, M);
 }
 
+bool fromJSON(const llvm::json::Value &Params, Source::PresentationHint &PH,
+              llvm::json::Path P) {
+  auto rawHint = Params.getAsString();
+  if (!rawHint) {
+    P.report("expected a string");
+    return false;
+  }
+  std::optional<Source::PresentationHint> hint =
+      llvm::StringSwitch<std::optional<Source::PresentationHint>>(*rawHint)
+          .Case("normal", Source::PresentationHint::normal)
+          .Case("emphasize", Source::PresentationHint::emphasize)
+          .Case("deemphasize", Source::PresentationHint::deemphasize)
+          .Default(std::nullopt);
+  if (!hint) {
+    P.report("unexpected value");
+    return false;
+  }
+  PH = *hint;
+  return true;
+}
+
+bool fromJSON(const llvm::json::Value &Params, Source &S, llvm::json::Path P) {
+  llvm::json::ObjectMapper O(Params, P);
+  return O && O.mapOptional("name", S.name) && O.mapOptional("path", S.path) &&
+         O.mapOptional("presentationHint", S.presentationHint) &&
+         O.mapOptional("sourceReference", S.sourceReference);
+}
+
+bool fromJSON(const llvm::json::Value &Params, SourceArguments &SA,
+              llvm::json::Path P) {
+  llvm::json::ObjectMapper O(Params, P);
+  return O && O.mapOptional("source", SA.source) &&
+         O.map("sourceReference", SA.sourceReference);
+}
+
+llvm::json::Value toJSON(const SourceResponseBody &SA) {
+  llvm::json::Object Result{{"content", SA.content}};
+
+  if (SA.mimeType)
+    Result.insert({"mimeType", SA.mimeType});
+
+  return std::move(Result);
+}
+
 } // namespace protocol
 } // namespace lldb_dap
diff --git a/lldb/tools/lldb-dap/Protocol.h b/lldb/tools/lldb-dap/Protocol.h
index a9a5532fa6bfa..a1219400fdea5 100644
--- a/lldb/tools/lldb-dap/Protocol.h
+++ b/lldb/tools/lldb-dap/Protocol.h
@@ -240,6 +240,137 @@ using Message = std::variant<Request, Response, Event>;
 bool fromJSON(const llvm::json::Value &, Message &, llvm::json::Path);
 llvm::json::Value toJSON(const Message &);
 
+// MARK: Types
+
+// "Source": {
+//   "type": "object",
+//   "description": "A `Source` is a descriptor for source code.\nIt is returned
+//   from the debug adapter as part of a `StackFrame` and it is used by clients
+//   when specifying breakpoints.", "properties": {
+//     "name": {
+//       "type": "string",
+//       "description": "The short name of the source. Every source returned
+//       from the debug adapter has a name.\nWhen sending a source to the debug
+//       adapter this name is optional."
+//     },
+//     "path": {
+//       "type": "string",
+//       "description": "The path of the source to be shown in the UI.\nIt is
+//       only used to locate and load the content of the source if no
+//       `sourceReference` is specified (or its value is 0)."
+//     },
+//     "sourceReference": {
+//       "type": "integer",
+//       "description": "If the value > 0 the contents of the source must be
+//       retrieved through the `source` request (even if a path is
+//       specified).\nSince a `sourceReference` is only valid for a session, it
+//       can not be used to persist a source.\nThe value should be less than or
+//       equal to 2147483647 (2^31-1)."
+//     },
+//     "presentationHint": {
+//       "type": "string",
+//       "description": "A hint for how to present the source in the UI.\nA
+//       value of `deemphasize` can be used to indicate that the source is not
+//       available or that it is skipped on stepping.", "enum": [ "normal",
+//       "emphasize", "deemphasize" ]
+//     },
+//     "origin": {
+//       "type": "string",
+//       "description": "The origin of this source. For example, 'internal
+//       module', 'inlined content from source map', etc."
+//     },
+//     "sources": {
+//       "type": "array",
+//       "items": {
+//         "$ref": "#/definitions/Source"
+//       },
+//       "description": "A list of sources that are related to this source.
+//       These may be the source that generated this source."
+//     },
+//     "adapterData": {
+//       "type": [ "array", "boolean", "integer", "null", "number", "object",
+//       "string" ], "description": "Additional data that a debug adapter might
+//       want to loop through the client.\nThe client should leave the data
+//       intact and persist it across sessions. The client should not interpret
+//       the data."
+//     },
+//     "checksums": {
+//       "type": "array",
+//       "items": {
+//         "$ref": "#/definitions/Checksum"
+//       },
+//       "description": "The checksums associated with this file."
+//     }
+//   }
+// },
+struct Source {
+  enum class PresentationHint { normal, emphasize, deemphasize };
+
+  std::optional<std::string> name;
+  std::optional<std::string> path;
+  std::optional<int64_t> sourceReference;
+  std::optional<PresentationHint> presentationHint;
+
+  // unsupproted keys origin, sources, adapterData, checksums
+};
+bool fromJSON(const llvm::json::Value &, Source &, llvm::json::Path);
+llvm::json::Value toJSON(const Source &);
+
+// MARK: Requests
+
+// "SourceArguments": {
+//   "type": "object",
+//   "description": "Arguments for `source` request.",
+//   "properties": {
+//     "source": {
+//       "$ref": "#/definitions/Source",
+//       "description": "Specifies the source content to load. Either
+//       `source.path` or `source.sourceReference` must be specified."
+//     },
+//     "sourceReference": {
+//       "type": "integer",
+//       "description": "The reference to the source. This is the same as
+//       `source.sourceReference`.\nThis is provided for backward compatibility
+//       since old clients do not understand the `source` attribute."
+//     }
+//   },
+//   "required": [ "sourceReference" ]
+// },
+struct SourceArguments {
+  std::optional<Source> source;
+  int64_t sourceReference;
+};
+bool fromJSON(const llvm::json::Value &, SourceArguments &, llvm::json::Path);
+
+// "SourceResponse": {
+//   "allOf": [ { "$ref": "#/definitions/Response" }, {
+//     "type": "object",
+//     "description": "Response to `source` request.",
+//     "properties": {
+//       "body": {
+//         "type": "object",
+//         "properties": {
+//           "content": {
+//             "type": "string",
+//             "description": "Content of the source reference."
+//           },
+//           "mimeType": {
+//             "type": "string",
+//             "description": "Content type (MIME type) of the source."
+//           }
+//         },
+//         "required": [ "content" ]
+//       }
+//     },
+//     "required": [ "body" ]
+//   }]
+// },
+struct SourceResponseBody {
+  std::string content;
+  std::optional<std::string> mimeType;
+};
+llvm::json::Value toJSON(const SourceResponseBody &);
+
 } // namespace lldb_dap::protocol
 
 #endif

>From 9908931bb162606eef779072481f6e0081290623 Mon Sep 17 00:00:00 2001
From: John Harrison <harjohn at google.com>
Date: Wed, 12 Mar 2025 13:28:49 -0700
Subject: [PATCH 02/12] Adjusting comments to not be a copy-paste of the DAP
 json spec but instead extracting the comments to their c++ repr.

---
 .../lldb-dap/Handler/SourceRequestHandler.cpp |  19 +-
 lldb/tools/lldb-dap/Protocol.h                | 355 +++++-------------
 2 files changed, 91 insertions(+), 283 deletions(-)

diff --git a/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp
index 101f18ef5220a..b8e0c39cb2e08 100644
--- a/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp
@@ -19,23 +19,8 @@
 
 namespace lldb_dap {
 
-// "SourceRequest": {
-//   "allOf": [ { "$ref": "#/definitions/Request" }, {
-//     "type": "object",
-//     "description": "Source request; value of command field is 'source'. The
-//     request retrieves the source code for a given source reference.",
-//     "properties": {
-//       "command": {
-//         "type": "string",
-//         "enum": [ "source" ]
-//       },
-//       "arguments": {
-//         "$ref": "#/definitions/SourceArguments"
-//       }
-//     },
-//     "required": [ "command", "arguments"  ]
-//   }]
-// },
+/// Source request; value of command field is 'source'. The request retrieves
+/// the source code for a given source reference.
 llvm::Expected<protocol::SourceResponseBody>
 SourceRequestHandler::Run(const protocol::SourceArguments &args) const {
   const auto source =
diff --git a/lldb/tools/lldb-dap/Protocol.h b/lldb/tools/lldb-dap/Protocol.h
index a1219400fdea5..03c65a19d4451 100644
--- a/lldb/tools/lldb-dap/Protocol.h
+++ b/lldb/tools/lldb-dap/Protocol.h
@@ -30,343 +30,166 @@ namespace lldb_dap::protocol {
 
 // MARK: Base Protocol
 
-// "Request": {
-//   "allOf": [ { "$ref": "#/definitions/ProtocolMessage" }, {
-//     "type": "object",
-//     "description": "A client or debug adapter initiated request.",
-//     "properties": {
-//       "type": {
-//         "type": "string",
-//         "enum": [ "request" ]
-//       },
-//       "command": {
-//         "type": "string",
-//         "description": "The command to execute."
-//       },
-//       "arguments": {
-//         "type": [ "array", "boolean", "integer", "null", "number" , "object",
-//         "string" ], "description": "Object containing arguments for the
-//         command."
-//       }
-//     },
-//     "required": [ "type", "command" ]
-//   }]
-// },
+/// A client or debug adapter initiated request.
 struct Request {
+  /// Sequence number of the message (also known as message ID). The `seq` for
+  /// the first message sent by a client or debug adapter is 1, and for each
+  /// subsequent message is 1 greater than the previous message sent by that
+  /// actor. `seq` can be used to order requests, responses, and events, and to
+  /// associate requests with their corresponding responses. For protocol
+  /// messages of type `request` the sequence number can be used to cancel the
+  /// request.
   int64_t seq;
+
+  /// The command to execute.
   std::string command;
+
+  /// Object containing arguments for the command.
   std::optional<llvm::json::Value> rawArguments;
 };
 llvm::json::Value toJSON(const Request &);
 bool fromJSON(const llvm::json::Value &, Request &, llvm::json::Path);
 
-// "Event": {
-//   "allOf": [ { "$ref": "#/definitions/ProtocolMessage" }, {
-//     "type": "object",
-//     "description": "A debug adapter initiated event.",
-//     "properties": {
-//       "type": {
-//         "type": "string",
-//         "enum": [ "event" ]
-//       },
-//       "event": {
-//         "type": "string",
-//         "description": "Type of event."
-//       },
-//       "body": {
-//         "type": [ "array", "boolean", "integer", "null", "number" , "object",
-//         "string" ], "description": "Event-specific information."
-//       }
-//     },
-//     "required": [ "type", "event" ]
-//   }]
-// },
+/// A debug adapter initiated event.
 struct Event {
+  /// Type of event.
   std::string event;
+
+  /// Event-specific information.
   std::optional<llvm::json::Value> rawBody;
 };
 llvm::json::Value toJSON(const Event &);
 bool fromJSON(const llvm::json::Value &, Event &, llvm::json::Path);
 
-// "Response" : {
-//   "allOf" : [
-//     {"$ref" : "#/definitions/ProtocolMessage"}, {
-//       "type" : "object",
-//       "description" : "Response for a request.",
-//       "properties" : {
-//         "type" : {"type" : "string", "enum" : ["response"]},
-//         "request_seq" : {
-//           "type" : "integer",
-//           "description" : "Sequence number of the corresponding request."
-//         },
-//         "success" : {
-//           "type" : "boolean",
-//           "description" :
-//               "Outcome of the request.\nIf true, the request was successful "
-//               "and the `body` attribute may contain the result of the "
-//               "request.\nIf the value is false, the attribute `message` "
-//               "contains the error in short form and the `body` may contain "
-//               "additional information (see `ErrorResponse.body.error`)."
-//         },
-//         "command" :
-//             {"type" : "string", "description" : "The command requested."},
-//         "message" : {
-//           "type" : "string",
-//           "description" :
-//               "Contains the raw error in short form if `success` is "
-//               "false.\nThis raw error might be interpreted by the client and
-//               " "is not shown in the UI.\nSome predefined values exist.",
-//           "_enum" : [ "cancelled", "notStopped" ],
-//           "enumDescriptions" : [
-//             "the request was cancelled.",
-//             "the request may be retried once the adapter is in a 'stopped'"
-//             "state."
-//           ]
-//         },
-//         "body" : {
-//           "type" : [
-//             "array", "boolean", "integer", "null", "number", "object",
-//             "string"
-//           ],
-//           "description" : "Contains request result if success is true and "
-//                           "error details if success is false."
-//         }
-//       },
-//       "required" : [ "type", "request_seq", "success", "command" ]
-//     }
-//   ]
-// }
+/// Response for a request.
 struct Response {
   enum class Message {
+    /// the request was cancelled
     cancelled,
+    /// the request may be retried once the adapter is in a 'stopped' state
     notStopped,
   };
 
+  /// Sequence number of the corresponding request.
   int64_t request_seq;
+
+  /// The command requested.
   std::string command;
+
+  /// Outcome of the request. If true, the request was successful and the `body`
+  /// attribute may contain the result of the request. If the value is false,
+  /// the attribute `message` contains the error in short form and the `body`
+  /// may contain additional information (see `ErrorMessage`).
   bool success;
+
   // FIXME: Migrate usage of fallback string to ErrorMessage
+
+  /// Contains the raw error in short form if `success` is false. This raw error
+  /// might be interpreted by the client and is not shown in the UI. Some
+  /// predefined values exist.
   std::optional<std::variant<Message, std::string>> message;
+
+  /// Contains request result if success is true and error details if success is
+  /// false.
   std::optional<llvm::json::Value> rawBody;
 };
 bool fromJSON(const llvm::json::Value &, Response &, llvm::json::Path);
 llvm::json::Value toJSON(const Response &);
 
-// "Message": {
-//   "type": "object",
-//   "description": "A structured message object. Used to return errors from
-//   requests.", "properties": {
-//     "id": {
-//       "type": "integer",
-//       "description": "Unique (within a debug adapter implementation)
-//       identifier for the message. The purpose of these error IDs is to help
-//       extension authors that have the 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."
-//     },
-//     "format": {
-//       "type": "string",
-//       "description": "A format string for the message. Embedded variables
-//       have the form `{name}`.\nIf variable name starts with an underscore
-//       character, the variable does not contain user data (PII) and can be
-//       safely used for telemetry purposes."
-//     },
-//     "variables": {
-//       "type": "object",
-//       "description": "An object used as a dictionary for looking up the
-//       variables in the format string.", "additionalProperties": {
-//         "type": "string",
-//         "description": "All dictionary values must be strings."
-//       }
-//     },
-//     "sendTelemetry": {
-//       "type": "boolean",
-//       "description": "If true send to telemetry."
-//     },
-//     "showUser": {
-//       "type": "boolean",
-//       "description": "If true show user."
-//     },
-//     "url": {
-//       "type": "string",
-//       "description": "A url where additional information about this message
-//       can be found."
-//     },
-//     "urlLabel": {
-//       "type": "string",
-//       "description": "A label that is presented to the user as the UI for
-//       opening the url."
-//     }
-//   },
-//   "required": [ "id", "format" ]
-// },
+/// A structured message object. Used to return errors from requests.
 struct ErrorMessage {
+  /// Unique (within a debug adapter implementation) identifier for the message.
+  /// The purpose of these error IDs is to help extension authors that have the
+  /// 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;
+
+  /// A format string for the message. Embedded variables have the form
+  /// `{name}`. If variable name starts with an underscore character, the
+  /// variable does not contain user data (PII) and can be safely used for
+  /// telemetry purposes.
   std::string format;
+
+  /// An object used as a dictionary for looking up the variables in the format
+  /// string.
   std::optional<std::map<std::string, std::string>> variables;
+
+  /// If true send to telemetry.
   bool sendTelemetry;
+
+  /// If true show user.
   bool showUser;
+
+  /// A url where additional information about this message can be found.
   std::optional<std::string> url;
+
+  /// A label that is presented to the user as the UI for opening the url.
   std::optional<std::string> urlLabel;
 };
 bool fromJSON(const llvm::json::Value &, ErrorMessage &, llvm::json::Path);
 llvm::json::Value toJSON(const ErrorMessage &);
 
-// "ProtocolMessage": {
-//   "type": "object",
-//   "title": "Base Protocol",
-//   "description": "Base class of requests, responses, and events.",
-//   "properties": {
-//     "seq": {
-//       "type": "integer",
-//       "description": "Sequence number of the message (also known as
-//       message ID). The `seq` for the first message sent by a client or
-//       debug adapter is 1, and for each subsequent message is 1 greater
-//       than the previous message sent by that actor. `seq` can be used to
-//       order requests, responses, and events, and to associate requests
-//       with their corresponding responses. For protocol messages of type
-//       `request` the sequence number can be used to cancel the request."
-//     },
-//     "type": {
-//       "type": "string",
-//       "description": "Message type.",
-//       "_enum": [ "request", "response", "event" ]
-//     }
-//   },
-//   "required": [ "seq", "type" ]
-// },
+/// An individual protocol message of requests, responses, and events.
 using Message = std::variant<Request, Response, Event>;
 bool fromJSON(const llvm::json::Value &, Message &, llvm::json::Path);
 llvm::json::Value toJSON(const Message &);
 
 // MARK: Types
 
-// "Source": {
-//   "type": "object",
-//   "description": "A `Source` is a descriptor for source code.\nIt is returned
-//   from the debug adapter as part of a `StackFrame` and it is used by clients
-//   when specifying breakpoints.", "properties": {
-//     "name": {
-//       "type": "string",
-//       "description": "The short name of the source. Every source returned
-//       from the debug adapter has a name.\nWhen sending a source to the debug
-//       adapter this name is optional."
-//     },
-//     "path": {
-//       "type": "string",
-//       "description": "The path of the source to be shown in the UI.\nIt is
-//       only used to locate and load the content of the source if no
-//       `sourceReference` is specified (or its value is 0)."
-//     },
-//     "sourceReference": {
-//       "type": "integer",
-//       "description": "If the value > 0 the contents of the source must be
-//       retrieved through the `source` request (even if a path is
-//       specified).\nSince a `sourceReference` is only valid for a session, it
-//       can not be used to persist a source.\nThe value should be less than or
-//       equal to 2147483647 (2^31-1)."
-//     },
-//     "presentationHint": {
-//       "type": "string",
-//       "description": "A hint for how to present the source in the UI.\nA
-//       value of `deemphasize` can be used to indicate that the source is not
-//       available or that it is skipped on stepping.", "enum": [ "normal",
-//       "emphasize", "deemphasize" ]
-//     },
-//     "origin": {
-//       "type": "string",
-//       "description": "The origin of this source. For example, 'internal
-//       module', 'inlined content from source map', etc."
-//     },
-//     "sources": {
-//       "type": "array",
-//       "items": {
-//         "$ref": "#/definitions/Source"
-//       },
-//       "description": "A list of sources that are related to this source.
-//       These may be the source that generated this source."
-//     },
-//     "adapterData": {
-//       "type": [ "array", "boolean", "integer", "null", "number", "object",
-//       "string" ], "description": "Additional data that a debug adapter might
-//       want to loop through the client.\nThe client should leave the data
-//       intact and persist it across sessions. The client should not interpret
-//       the data."
-//     },
-//     "checksums": {
-//       "type": "array",
-//       "items": {
-//         "$ref": "#/definitions/Checksum"
-//       },
-//       "description": "The checksums associated with this file."
-//     }
-//   }
-// },
+/// A `Source` is a descriptor for source code. It is returned from the debug
+/// adapter as part of a `StackFrame` and it is used by clients when specifying
+/// breakpoints.
 struct Source {
   enum class PresentationHint { normal, emphasize, deemphasize };
 
+  /// The short name of the source. Every source returned from the debug adapter
+  /// has a name. When sending a source to the debug adapter this name is
+  /// optional.
   std::optional<std::string> name;
+
+  /// The path of the source to be shown in the UI. It is only used to locate
+  /// and load the content of the source if no `sourceReference` is specified
+  /// (or its value is 0).
   std::optional<std::string> path;
+
+  /// If the value > 0 the contents of the source must be retrieved through the
+  /// `source` request (even if a path is specified). Since a `sourceReference`
+  /// is only valid for a session, it can not be used to persist a source. The
+  /// value should be less than or equal to 2147483647 (2^31-1).
   std::optional<int64_t> sourceReference;
+
+  /// A hint for how to present the source in the UI. A value of `deemphasize`
+  /// can be used to indicate that the source is not available or that it is
+  /// skipped on stepping.
   std::optional<PresentationHint> presentationHint;
 
-  // unsupproted keys origin, sources, adapterData, checksums
+  // unsupported keys origin, sources, adapterData, checksums
 };
 bool fromJSON(const llvm::json::Value &, Source &, llvm::json::Path);
 llvm::json::Value toJSON(const Source &);
 
 // MARK: Requests
 
-// "SourceArguments": {
-//   "type": "object",
-//   "description": "Arguments for `source` request.",
-//   "properties": {
-//     "source": {
-//       "$ref": "#/definitions/Source",
-//       "description": "Specifies the source content to load. Either
-//       `source.path` or `source.sourceReference` must be specified."
-//     },
-//     "sourceReference": {
-//       "type": "integer",
-//       "description": "The reference to the source. This is the same as
-//       `source.sourceReference`.\nThis is provided for backward compatibility
-//       since old clients do not understand the `source` attribute."
-//     }
-//   },
-//   "required": [ "sourceReference" ]
-// },
+/// Arguments for `source` request.
 struct SourceArguments {
+  /// Specifies the source content to load. Either `source.path` or
+  /// `source.sourceReference` must be specified.
   std::optional<Source> source;
+
+  /// The reference to the source. This is the same as `source.sourceReference`.
+  /// This is provided for backward compatibility since old clients do not
+  /// understand the `source` attribute.
   int64_t sourceReference;
 };
 bool fromJSON(const llvm::json::Value &, SourceArguments &, llvm::json::Path);
 
-// "SourceResponse": {
-//   "allOf": [ { "$ref": "#/definitions/Response" }, {
-//     "type": "object",
-//     "description": "Response to `source` request.",
-//     "properties": {
-//       "body": {
-//         "type": "object",
-//         "properties": {
-//           "content": {
-//             "type": "string",
-//             "description": "Content of the source reference."
-//           },
-//           "mimeType": {
-//             "type": "string",
-//             "description": "Content type (MIME type) of the source."
-//           }
-//         },
-//         "required": [ "content" ]
-//       }
-//     },
-//     "required": [ "body" ]
-//   }]
-// },
+/// Response to `source` request.
 struct SourceResponseBody {
+  /// Content of the source reference.
   std::string content;
+
+  /// Content type (MIME type) of the source.
   std::optional<std::string> mimeType;
 };
 llvm::json::Value toJSON(const SourceResponseBody &);

>From 798a57393e483aa5b514ca9aed52be0f30ec91a2 Mon Sep 17 00:00:00 2001
From: John Harrison <harjohn at google.com>
Date: Wed, 12 Mar 2025 13:33:53 -0700
Subject: [PATCH 03/12] Updating fixme comment

---
 lldb/tools/lldb-dap/Handler/RequestHandler.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h
index da65b2de9ab99..44a1aa4cefcde 100644
--- a/lldb/tools/lldb-dap/Handler/RequestHandler.h
+++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h
@@ -100,8 +100,8 @@ class RequestHandler : public BaseRequestHandler {
     }
 
     auto ResponseBody = Run(arguments);
-    // FIXME: Add a dedicated DAPError for enhanced errors that are user
-    // visibile.
+    // FIXME: Add a dedicated DAPError for enhanced errors that are
+    // user-visibile.
     if (auto Err = ResponseBody.takeError()) {
       response.success = false;
       // FIXME: Build ErrorMessage based on error details instead of using the

>From f4f88ddb5f15646e3e794dfa21e7a87f863cd5f0 Mon Sep 17 00:00:00 2001
From: John Harrison <ash at greaterthaninfinity.com>
Date: Thu, 13 Mar 2025 08:24:09 -0700
Subject: [PATCH 04/12] Apply suggestions from code review

Co-authored-by: Adrian Vogelsgesang <adrian.vogelsgesang at tum.de>
---
 lldb/tools/lldb-dap/Protocol.h | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/lldb/tools/lldb-dap/Protocol.h b/lldb/tools/lldb-dap/Protocol.h
index 03c65a19d4451..57f8c976be444 100644
--- a/lldb/tools/lldb-dap/Protocol.h
+++ b/lldb/tools/lldb-dap/Protocol.h
@@ -64,9 +64,9 @@ bool fromJSON(const llvm::json::Value &, Event &, llvm::json::Path);
 /// Response for a request.
 struct Response {
   enum class Message {
-    /// the request was cancelled
+    /// The request was cancelled
     cancelled,
-    /// the request may be retried once the adapter is in a 'stopped' state
+    /// The request may be retried once the adapter is in a 'stopped' state
     notStopped,
   };
 
@@ -167,7 +167,6 @@ struct Source {
   // unsupported keys origin, sources, adapterData, checksums
 };
 bool fromJSON(const llvm::json::Value &, Source &, llvm::json::Path);
-llvm::json::Value toJSON(const Source &);
 
 // MARK: Requests
 

>From 13e3f0d493bb148c7deeef4bd4bc629af2da4f55 Mon Sep 17 00:00:00 2001
From: John Harrison <harjohn at google.com>
Date: Thu, 13 Mar 2025 09:36:58 -0700
Subject: [PATCH 05/12] Adding checks for missing arguments and added a
 `VoidResponse` for messages without a response body.

To validate both of these changes I also migrated the 'disconnect' request to have new types, since it has an `optional<DisconnectArguments>` and a `VoidResponse` body.
---
 lldb/tools/lldb-dap/DAP.cpp                   |  4 +
 lldb/tools/lldb-dap/DAP.h                     |  1 +
 .../Handler/DisconnectRequestHandler.cpp      | 82 ++++++-------------
 lldb/tools/lldb-dap/Handler/RequestHandler.h  | 41 ++++++++--
 lldb/tools/lldb-dap/Protocol.cpp              | 27 +++---
 lldb/tools/lldb-dap/Protocol.h                | 28 +++++++
 6 files changed, 108 insertions(+), 75 deletions(-)

diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp
index 9d42af2d7091f..133be7dbdf94e 100644
--- a/lldb/tools/lldb-dap/DAP.cpp
+++ b/lldb/tools/lldb-dap/DAP.cpp
@@ -237,6 +237,10 @@ void DAP::SendJSON(const llvm::json::Value &json) {
                   transport.GetClientName());
     return;
   }
+  Send(message);
+}
+
+void DAP::Send(const protocol::Message &message) {
   if (llvm::Error err = transport.Write(message))
     DAP_LOG_ERROR(log, std::move(err), "({1}) write failed: {0}",
                   transport.GetClientName());
diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h
index f6b63e4a3e0bc..a1158b1706abd 100644
--- a/lldb/tools/lldb-dap/DAP.h
+++ b/lldb/tools/lldb-dap/DAP.h
@@ -246,6 +246,7 @@ struct DAP {
   // Serialize the JSON value into a string and send the JSON packet to
   // the "out" stream.
   void SendJSON(const llvm::json::Value &json);
+  void Send(const protocol::Message &message);
 
   void SendOutput(OutputType o, const llvm::StringRef output);
 
diff --git a/lldb/tools/lldb-dap/Handler/DisconnectRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/DisconnectRequestHandler.cpp
index b8f3404874e91..f90475e44d022 100644
--- a/lldb/tools/lldb-dap/Handler/DisconnectRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/DisconnectRequestHandler.cpp
@@ -7,70 +7,36 @@
 //===----------------------------------------------------------------------===//
 
 #include "DAP.h"
-#include "EventHelper.h"
-#include "JSONUtils.h"
+#include "Protocol.h"
 #include "RequestHandler.h"
+#include "lldb/API/SBError.h"
+#include "llvm/Support/Error.h"
+#include <optional>
+#include <system_error>
+#include <variant>
+
+llvm::Error takeError(lldb::SBError error) {
+  if (error.Success())
+    return llvm::Error::success();
+
+  return llvm::createStringError(
+      std::error_code(error.GetError(), std::generic_category()),
+      error.GetCString());
+}
 
 namespace lldb_dap {
 
-// "DisconnectRequest": {
-//   "allOf": [ { "$ref": "#/definitions/Request" }, {
-//     "type": "object",
-//     "description": "Disconnect request; value of command field is
-//                     'disconnect'.",
-//     "properties": {
-//       "command": {
-//         "type": "string",
-//         "enum": [ "disconnect" ]
-//       },
-//       "arguments": {
-//         "$ref": "#/definitions/DisconnectArguments"
-//       }
-//     },
-//     "required": [ "command" ]
-//   }]
-// },
-// "DisconnectArguments": {
-//   "type": "object",
-//   "description": "Arguments for 'disconnect' request.",
-//   "properties": {
-//     "terminateDebuggee": {
-//       "type": "boolean",
-//       "description": "Indicates whether the debuggee should be terminated
-//                       when the debugger is disconnected. If unspecified,
-//                       the debug adapter is free to do whatever it thinks
-//                       is best. A client can only rely on this attribute
-//                       being properly honored if a debug adapter returns
-//                       true for the 'supportTerminateDebuggee' capability."
-//     },
-//     "restart": {
-//       "type": "boolean",
-//       "description": "Indicates whether the debuggee should be restart
-//                       the process."
-//     }
-//   }
-// },
-// "DisconnectResponse": {
-//   "allOf": [ { "$ref": "#/definitions/Response" }, {
-//     "type": "object",
-//     "description": "Response to 'disconnect' request. This is just an
-//                     acknowledgement, so no body field is required."
-//   }]
-// }
-void DisconnectRequestHandler::operator()(
-    const llvm::json::Object &request) const {
-  llvm::json::Object response;
-  FillResponse(request, response);
-  const auto *arguments = request.getObject("arguments");
+/// Disconnect request; value of command field is 'disconnect'.
+llvm::Expected<protocol::DisconnectResponse> DisconnectRequestHandler::Run(
+    const std::optional<protocol::DisconnectArguments> &arguments) const {
+  bool terminateDebuggee = dap.is_attach ? false : true;
 
-  bool defaultTerminateDebuggee = dap.is_attach ? false : true;
-  bool terminateDebuggee = GetBoolean(arguments, "terminateDebuggee")
-                               .value_or(defaultTerminateDebuggee);
+  if (arguments && arguments->terminateDebuggee)
+    terminateDebuggee = *arguments->terminateDebuggee;
 
   lldb::SBError error = dap.Disconnect(terminateDebuggee);
-  if (error.Fail())
-    EmplaceSafeString(response, "error", error.GetCString());
-
-  dap.SendJSON(llvm::json::Value(std::move(response)));
+  if (llvm::Error wrappedError = takeError(error))
+    return wrappedError;
+  return std::monostate{};
 }
 } // namespace lldb_dap
diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h
index 44a1aa4cefcde..033c24712cb38 100644
--- a/lldb/tools/lldb-dap/Handler/RequestHandler.h
+++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h
@@ -10,11 +10,20 @@
 #define LLDB_TOOLS_LLDB_DAP_HANDLER_HANDLER_H
 
 #include "DAP.h"
+#include "DAPLog.h"
 #include "Protocol.h"
 #include "lldb/API/SBError.h"
-#include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/JSON.h"
+#include <optional>
+#include <type_traits>
+
+template <typename T> struct is_optional : std::false_type {};
+
+template <typename T> struct is_optional<std::optional<T>> : std::true_type {};
+
+template <typename T>
+inline constexpr bool is_optional_v = is_optional<T>::value;
 
 namespace lldb_dap {
 struct DAP;
@@ -86,6 +95,20 @@ class RequestHandler : public BaseRequestHandler {
     protocol::Response response;
     response.request_seq = request.seq;
     response.command = request.command;
+
+    if (!is_optional_v<Args> && !request.rawArguments) {
+      DAP_LOG(dap.log,
+              "({0}) malformed request {1}, expected arguments but got none",
+              dap.transport.GetClientName(), request.command);
+      response.success = false;
+      response.message = llvm::formatv("arguments required for command '{0}' "
+                                       "but none received",
+                                       request.command)
+                             .str();
+      dap.Send(response);
+      return;
+    }
+
     Args arguments;
     llvm::json::Path::Root root;
     if (request.rawArguments &&
@@ -95,7 +118,7 @@ class RequestHandler : public BaseRequestHandler {
       root.printErrorContext(request.rawArguments, OS);
       response.success = false;
       response.message = parseFailure;
-      dap.SendJSON(std::move(response));
+      dap.Send(response);
       return;
     }
 
@@ -109,10 +132,11 @@ class RequestHandler : public BaseRequestHandler {
       response.message = llvm::toString(std::move(Err));
     } else {
       response.success = true;
-      response.rawBody = std::move(*ResponseBody);
+      if constexpr (!std::is_same_v<Body, std::monostate>)
+        response.rawBody = std::move(*ResponseBody);
     }
 
-    dap.SendJSON(std::move(response));
+    dap.Send(response);
   };
 
   virtual llvm::Expected<Body> Run(const Args &) const = 0;
@@ -153,11 +177,14 @@ class ConfigurationDoneRequestHandler : public BaseRequestHandler {
   void operator()(const llvm::json::Object &request) const override;
 };
 
-class DisconnectRequestHandler : public BaseRequestHandler {
+class DisconnectRequestHandler
+    : public RequestHandler<std::optional<protocol::DisconnectArguments>,
+                            protocol::DisconnectResponse> {
 public:
-  using BaseRequestHandler::BaseRequestHandler;
+  using RequestHandler::RequestHandler;
   static llvm::StringLiteral getCommand() { return "disconnect"; }
-  void operator()(const llvm::json::Object &request) const override;
+  llvm::Expected<protocol::DisconnectResponse>
+  Run(const std::optional<protocol::DisconnectArguments> &args) const override;
 };
 
 class EvaluateRequestHandler : public BaseRequestHandler {
diff --git a/lldb/tools/lldb-dap/Protocol.cpp b/lldb/tools/lldb-dap/Protocol.cpp
index 68cfa40580b31..cba899649b69d 100644
--- a/lldb/tools/lldb-dap/Protocol.cpp
+++ b/lldb/tools/lldb-dap/Protocol.cpp
@@ -287,15 +287,15 @@ json::Value toJSON(const Message &M) {
   return std::visit([](auto &M) { return toJSON(M); }, M);
 }
 
-bool fromJSON(const llvm::json::Value &Params, Source::PresentationHint &PH,
-              llvm::json::Path P) {
+bool fromJSON(const json::Value &Params, Source::PresentationHint &PH,
+              json::Path P) {
   auto rawHint = Params.getAsString();
   if (!rawHint) {
     P.report("expected a string");
     return false;
   }
   std::optional<Source::PresentationHint> hint =
-      llvm::StringSwitch<std::optional<Source::PresentationHint>>(*rawHint)
+      StringSwitch<std::optional<Source::PresentationHint>>(*rawHint)
           .Case("normal", Source::PresentationHint::normal)
           .Case("emphasize", Source::PresentationHint::emphasize)
           .Case("deemphasize", Source::PresentationHint::deemphasize)
@@ -308,22 +308,29 @@ bool fromJSON(const llvm::json::Value &Params, Source::PresentationHint &PH,
   return true;
 }
 
-bool fromJSON(const llvm::json::Value &Params, Source &S, llvm::json::Path P) {
-  llvm::json::ObjectMapper O(Params, P);
+bool fromJSON(const json::Value &Params, Source &S, json::Path P) {
+  json::ObjectMapper O(Params, P);
   return O && O.mapOptional("name", S.name) && O.mapOptional("path", S.path) &&
          O.mapOptional("presentationHint", S.presentationHint) &&
          O.mapOptional("sourceReference", S.sourceReference);
 }
 
-bool fromJSON(const llvm::json::Value &Params, SourceArguments &SA,
-              llvm::json::Path P) {
-  llvm::json::ObjectMapper O(Params, P);
+bool fromJSON(const json::Value &Params, DisconnectArguments &DA,
+              json::Path P) {
+  json::ObjectMapper O(Params, P);
+  return O && O.mapOptional("restart", DA.restart) &&
+         O.mapOptional("terminateDebuggee", DA.terminateDebuggee) &&
+         O.mapOptional("suspendDebuggee", DA.suspendDebuggee);
+}
+
+bool fromJSON(const json::Value &Params, SourceArguments &SA, json::Path P) {
+  json::ObjectMapper O(Params, P);
   return O && O.mapOptional("source", SA.source) &&
          O.map("sourceReference", SA.sourceReference);
 }
 
-llvm::json::Value toJSON(const SourceResponseBody &SA) {
-  llvm::json::Object Result{{"content", SA.content}};
+json::Value toJSON(const SourceResponseBody &SA) {
+  json::Object Result{{"content", SA.content}};
 
   if (SA.mimeType)
     Result.insert({"mimeType", SA.mimeType});
diff --git a/lldb/tools/lldb-dap/Protocol.h b/lldb/tools/lldb-dap/Protocol.h
index 57f8c976be444..3bdc250449564 100644
--- a/lldb/tools/lldb-dap/Protocol.h
+++ b/lldb/tools/lldb-dap/Protocol.h
@@ -170,6 +170,34 @@ bool fromJSON(const llvm::json::Value &, Source &, llvm::json::Path);
 
 // MARK: Requests
 
+/// This is just an acknowledgement, so no body field is required.
+using VoidResponse = std::monostate;
+
+/// Arguments for `disconnect` request.
+struct DisconnectArguments {
+  /// A value of true indicates that this `disconnect` request is part of a
+  /// restart sequence.
+  std::optional<bool> restart;
+
+  /// Indicates whether the debuggee should be terminated when the debugger is
+  /// disconnected. If unspecified, the debug adapter is free to do whatever it
+  /// thinks is best. The attribute is only honored by a debug adapter if the
+  /// corresponding capability `supportTerminateDebuggee` is true.
+  std::optional<bool> terminateDebuggee;
+
+  /// Indicates whether the debuggee should stay suspended when the debugger is
+  /// disconnected. If unspecified, the debuggee should resume execution. The
+  /// attribute is only honored by a debug adapter if the corresponding
+  /// capability `supportSuspendDebuggee` is true.
+  std::optional<bool> suspendDebuggee;
+};
+bool fromJSON(const llvm::json::Value &, DisconnectArguments &,
+              llvm::json::Path);
+
+/// Response to `disconnect` request. This is just an acknowledgement, so no
+/// body field is required.
+using DisconnectResponse = VoidResponse;
+
 /// Arguments for `source` request.
 struct SourceArguments {
   /// Specifies the source content to load. Either `source.path` or

>From b9e3f25cfd11e396b80a4624bff6953e73a53334 Mon Sep 17 00:00:00 2001
From: John Harrison <harjohn at google.com>
Date: Thu, 13 Mar 2025 09:59:40 -0700
Subject: [PATCH 06/12] Moving the lldb::SBError > llvm::Error into LLDBUtils
 and making the `DAP::Disconnect` method a little more ergnomic.

---
 lldb/tools/lldb-dap/DAP.cpp                   |  6 ++---
 lldb/tools/lldb-dap/DAP.h                     |  4 +--
 .../Handler/DisconnectRequestHandler.cpp      | 25 ++++++-------------
 lldb/tools/lldb-dap/LLDBUtils.cpp             |  9 +++++++
 lldb/tools/lldb-dap/LLDBUtils.h               |  5 ++++
 lldb/tools/lldb-dap/lldb-dap.cpp              |  6 ++---
 6 files changed, 30 insertions(+), 25 deletions(-)

diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp
index 133be7dbdf94e..ebbd3cb0deca8 100644
--- a/lldb/tools/lldb-dap/DAP.cpp
+++ b/lldb/tools/lldb-dap/DAP.cpp
@@ -743,9 +743,9 @@ void DAP::SendTerminatedEvent() {
   });
 }
 
-lldb::SBError DAP::Disconnect() { return Disconnect(is_attach); }
+llvm::Error DAP::Disconnect() { return Disconnect(is_attach); }
 
-lldb::SBError DAP::Disconnect(bool terminateDebuggee) {
+llvm::Error DAP::Disconnect(bool terminateDebuggee) {
   lldb::SBError error;
   lldb::SBProcess process = target.GetProcess();
   auto state = process.GetState();
@@ -773,7 +773,7 @@ lldb::SBError DAP::Disconnect(bool terminateDebuggee) {
 
   disconnecting = true;
 
-  return error;
+  return takeError(error);
 }
 
 llvm::Error DAP::Loop() {
diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h
index a1158b1706abd..42e7ee0dbfb07 100644
--- a/lldb/tools/lldb-dap/DAP.h
+++ b/lldb/tools/lldb-dap/DAP.h
@@ -323,10 +323,10 @@ struct DAP {
   bool HandleObject(const protocol::Message &M);
 
   /// Disconnect the DAP session.
-  lldb::SBError Disconnect();
+  llvm::Error Disconnect();
 
   /// Disconnect the DAP session and optionally terminate the debuggee.
-  lldb::SBError Disconnect(bool terminateDebuggee);
+  llvm::Error Disconnect(bool terminateDebuggee);
 
   /// Send a "terminated" event to indicate the process is done being debugged.
   void SendTerminatedEvent();
diff --git a/lldb/tools/lldb-dap/Handler/DisconnectRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/DisconnectRequestHandler.cpp
index f90475e44d022..3b89dbf570115 100644
--- a/lldb/tools/lldb-dap/Handler/DisconnectRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/DisconnectRequestHandler.cpp
@@ -9,34 +9,25 @@
 #include "DAP.h"
 #include "Protocol.h"
 #include "RequestHandler.h"
-#include "lldb/API/SBError.h"
 #include "llvm/Support/Error.h"
 #include <optional>
-#include <system_error>
-#include <variant>
 
-llvm::Error takeError(lldb::SBError error) {
-  if (error.Success())
-    return llvm::Error::success();
-
-  return llvm::createStringError(
-      std::error_code(error.GetError(), std::generic_category()),
-      error.GetCString());
-}
+using namespace llvm;
+using namespace lldb_dap::protocol;
 
 namespace lldb_dap {
 
 /// Disconnect request; value of command field is 'disconnect'.
-llvm::Expected<protocol::DisconnectResponse> DisconnectRequestHandler::Run(
-    const std::optional<protocol::DisconnectArguments> &arguments) const {
+Expected<DisconnectResponse> DisconnectRequestHandler::Run(
+    const std::optional<DisconnectArguments> &arguments) const {
   bool terminateDebuggee = dap.is_attach ? false : true;
 
   if (arguments && arguments->terminateDebuggee)
     terminateDebuggee = *arguments->terminateDebuggee;
 
-  lldb::SBError error = dap.Disconnect(terminateDebuggee);
-  if (llvm::Error wrappedError = takeError(error))
-    return wrappedError;
-  return std::monostate{};
+  if (Error error = dap.Disconnect(terminateDebuggee))
+    return error;
+
+  return DisconnectResponse();
 }
 } // namespace lldb_dap
diff --git a/lldb/tools/lldb-dap/LLDBUtils.cpp b/lldb/tools/lldb-dap/LLDBUtils.cpp
index 48b63b59e0e3f..63fa38ba1e8fa 100644
--- a/lldb/tools/lldb-dap/LLDBUtils.cpp
+++ b/lldb/tools/lldb-dap/LLDBUtils.cpp
@@ -162,4 +162,13 @@ GetEnvironmentFromArguments(const llvm::json::Object &arguments) {
   return envs;
 }
 
+llvm::Error takeError(const lldb::SBError &error) {
+  if (error.Success())
+    return llvm::Error::success();
+
+  return llvm::createStringError(
+      std::error_code(error.GetError(), std::generic_category()),
+      error.GetCString());
+}
+
 } // namespace lldb_dap
diff --git a/lldb/tools/lldb-dap/LLDBUtils.h b/lldb/tools/lldb-dap/LLDBUtils.h
index a9e13bb3678da..b514aa30957e2 100644
--- a/lldb/tools/lldb-dap/LLDBUtils.h
+++ b/lldb/tools/lldb-dap/LLDBUtils.h
@@ -10,10 +10,12 @@
 #define LLDB_TOOLS_LLDB_DAP_LLDBUTILS_H
 
 #include "DAPForward.h"
+#include "lldb/API/SBError.h"
 #include "lldb/API/SBDebugger.h"
 #include "lldb/API/SBEnvironment.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Error.h"
 #include "llvm/Support/JSON.h"
 #include "llvm/Support/raw_ostream.h"
 #include <string>
@@ -154,6 +156,9 @@ uint32_t GetLLDBFrameID(uint64_t dap_frame_id);
 lldb::SBEnvironment
 GetEnvironmentFromArguments(const llvm::json::Object &arguments);
 
+/// Take ownership of the stored error.
+llvm::Error takeError(const lldb::SBError &error);
+
 } // namespace lldb_dap
 
 #endif
diff --git a/lldb/tools/lldb-dap/lldb-dap.cpp b/lldb/tools/lldb-dap/lldb-dap.cpp
index ca8b548632ff7..59e31cf8e2cc8 100644
--- a/lldb/tools/lldb-dap/lldb-dap.cpp
+++ b/lldb/tools/lldb-dap/lldb-dap.cpp
@@ -374,11 +374,11 @@ serveConnection(const Socket::SocketProtocol &protocol, const std::string &name,
   {
     std::scoped_lock<std::mutex> lock(dap_sessions_mutex);
     for (auto [sock, dap] : dap_sessions) {
-      auto error = dap->Disconnect();
-      if (error.Fail()) {
+      if (llvm::Error error = dap->Disconnect()) {
         client_failed = true;
         llvm::errs() << "DAP client " << dap->transport.GetClientName()
-                     << " disconnected failed: " << error.GetCString() << "\n";
+                     << " disconnected failed: "
+                     << llvm::toString(std::move(error)) << "\n";
       }
       // Close the socket to ensure the DAP::Loop read finishes.
       sock->Close();

>From 380b75e400a43097516b71088903040295e502fe Mon Sep 17 00:00:00 2001
From: John Harrison <harjohn at google.com>
Date: Thu, 13 Mar 2025 10:04:50 -0700
Subject: [PATCH 07/12] Applying clang-format.

---
 lldb/tools/lldb-dap/LLDBUtils.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lldb/tools/lldb-dap/LLDBUtils.h b/lldb/tools/lldb-dap/LLDBUtils.h
index b514aa30957e2..aef21c2895151 100644
--- a/lldb/tools/lldb-dap/LLDBUtils.h
+++ b/lldb/tools/lldb-dap/LLDBUtils.h
@@ -10,9 +10,9 @@
 #define LLDB_TOOLS_LLDB_DAP_LLDBUTILS_H
 
 #include "DAPForward.h"
-#include "lldb/API/SBError.h"
 #include "lldb/API/SBDebugger.h"
 #include "lldb/API/SBEnvironment.h"
+#include "lldb/API/SBError.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/Error.h"

>From 02bfcf442c3a335c914638a6a026c9330dbb25e6 Mon Sep 17 00:00:00 2001
From: John Harrison <harjohn at google.com>
Date: Fri, 14 Mar 2025 09:17:34 -0700
Subject: [PATCH 08/12] Adding a LegacyRequestHandler to simplify the
 BaseRequestHandler.

---
 lldb/tools/lldb-dap/DAP.cpp                  |   9 +-
 lldb/tools/lldb-dap/DAP.h                    |   5 +-
 lldb/tools/lldb-dap/Handler/RequestHandler.h | 150 +++++++++----------
 lldb/tools/lldb-dap/Protocol.h               |   2 +-
 4 files changed, 83 insertions(+), 83 deletions(-)

diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp
index ebbd3cb0deca8..e4d1ea7aa9488 100644
--- a/lldb/tools/lldb-dap/DAP.cpp
+++ b/lldb/tools/lldb-dap/DAP.cpp
@@ -672,9 +672,9 @@ void DAP::SetTarget(const lldb::SBTarget target) {
 
 bool DAP::HandleObject(const protocol::Message &M) {
   if (const auto *req = std::get_if<protocol::Request>(&M)) {
-    auto new_handler_pos = request_handlers.find(req->command);
-    if (new_handler_pos != request_handlers.end()) {
-      (*new_handler_pos->second)(*req);
+    auto handler_pos = request_handlers.find(req->command);
+    if (handler_pos != request_handlers.end()) {
+      (*handler_pos->second)(*req);
       return true; // Success
     }
 
@@ -727,8 +727,7 @@ bool DAP::HandleObject(const protocol::Message &M) {
     return true;
   }
 
-  if (log)
-    *log << "Unsupported protocol message" << std::endl;
+  DAP_LOG(log, "Unsupported protocol message");
 
   return false;
 }
diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h
index 42e7ee0dbfb07..09789ae964492 100644
--- a/lldb/tools/lldb-dap/DAP.h
+++ b/lldb/tools/lldb-dap/DAP.h
@@ -243,9 +243,10 @@ struct DAP {
   /// Stop event handler threads.
   void StopEventHandlers();
 
-  // Serialize the JSON value into a string and send the JSON packet to
-  // the "out" stream.
+  /// Serialize the JSON value into a string and send the JSON packet to the
+  /// "out" stream.
   void SendJSON(const llvm::json::Value &json);
+  /// Send the given message to the client
   void Send(const protocol::Message &message);
 
   void SendOutput(OutputType o, const llvm::StringRef output);
diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h
index 033c24712cb38..11800cd66fcad 100644
--- a/lldb/tools/lldb-dap/Handler/RequestHandler.h
+++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h
@@ -42,13 +42,7 @@ class BaseRequestHandler {
 
   virtual ~BaseRequestHandler() = default;
 
-  virtual void operator()(const protocol::Request &request) const {
-    auto req = toJSON(request);
-    (*this)(*req.getAsObject());
-  }
-
-  /// FIXME: Migrate callers to typed RequestHandler for improved type handling.
-  virtual void operator()(const llvm::json::Object &request) const = 0;
+  virtual void operator()(const protocol::Request &request) const = 0;
 
 protected:
   /// Helpers used by multiple request handlers.
@@ -77,6 +71,16 @@ class BaseRequestHandler {
   DAP &dap;
 };
 
+/// FIXME: Migrate callers to typed RequestHandler for improved type handling.
+class LegacyRequestHandler : public BaseRequestHandler {
+  using BaseRequestHandler::BaseRequestHandler;
+  virtual void operator()(const llvm::json::Object &request) const = 0;
+  void operator()(const protocol::Request &request) const override {
+    auto req = toJSON(request);
+    (*this)(*req.getAsObject());
+  }
+};
+
 /// Base class for handling DAP requests. Handlers should declare their
 /// arguments and response body types like:
 ///
@@ -87,10 +91,6 @@ template <typename Args, typename Body>
 class RequestHandler : public BaseRequestHandler {
   using BaseRequestHandler::BaseRequestHandler;
 
-  void operator()(const llvm::json::Object &request) const override {
-    /* no-op, the other overload handles json coding. */
-  }
-
   void operator()(const protocol::Request &request) const override {
     protocol::Response response;
     response.request_seq = request.seq;
@@ -142,37 +142,37 @@ class RequestHandler : public BaseRequestHandler {
   virtual llvm::Expected<Body> Run(const Args &) const = 0;
 };
 
-class AttachRequestHandler : public BaseRequestHandler {
+class AttachRequestHandler : public LegacyRequestHandler {
 public:
-  using BaseRequestHandler::BaseRequestHandler;
+  using LegacyRequestHandler::LegacyRequestHandler;
   static llvm::StringLiteral getCommand() { return "attach"; }
   void operator()(const llvm::json::Object &request) const override;
 };
 
-class BreakpointLocationsRequestHandler : public BaseRequestHandler {
+class BreakpointLocationsRequestHandler : public LegacyRequestHandler {
 public:
-  using BaseRequestHandler::BaseRequestHandler;
+  using LegacyRequestHandler::LegacyRequestHandler;
   static llvm::StringLiteral getCommand() { return "breakpointLocations"; }
   void operator()(const llvm::json::Object &request) const override;
 };
 
-class CompletionsRequestHandler : public BaseRequestHandler {
+class CompletionsRequestHandler : public LegacyRequestHandler {
 public:
-  using BaseRequestHandler::BaseRequestHandler;
+  using LegacyRequestHandler::LegacyRequestHandler;
   static llvm::StringLiteral getCommand() { return "completions"; }
   void operator()(const llvm::json::Object &request) const override;
 };
 
-class ContinueRequestHandler : public BaseRequestHandler {
+class ContinueRequestHandler : public LegacyRequestHandler {
 public:
-  using BaseRequestHandler::BaseRequestHandler;
+  using LegacyRequestHandler::LegacyRequestHandler;
   static llvm::StringLiteral getCommand() { return "continue"; }
   void operator()(const llvm::json::Object &request) const override;
 };
 
-class ConfigurationDoneRequestHandler : public BaseRequestHandler {
+class ConfigurationDoneRequestHandler : public LegacyRequestHandler {
 public:
-  using BaseRequestHandler::BaseRequestHandler;
+  using LegacyRequestHandler::LegacyRequestHandler;
   static llvm::StringLiteral getCommand() { return "configurationDone"; }
   void operator()(const llvm::json::Object &request) const override;
 };
@@ -187,144 +187,144 @@ class DisconnectRequestHandler
   Run(const std::optional<protocol::DisconnectArguments> &args) const override;
 };
 
-class EvaluateRequestHandler : public BaseRequestHandler {
+class EvaluateRequestHandler : public LegacyRequestHandler {
 public:
-  using BaseRequestHandler::BaseRequestHandler;
+  using LegacyRequestHandler::LegacyRequestHandler;
   static llvm::StringLiteral getCommand() { return "evaluate"; }
   void operator()(const llvm::json::Object &request) const override;
 };
 
-class ExceptionInfoRequestHandler : public BaseRequestHandler {
+class ExceptionInfoRequestHandler : public LegacyRequestHandler {
 public:
-  using BaseRequestHandler::BaseRequestHandler;
+  using LegacyRequestHandler::LegacyRequestHandler;
   static llvm::StringLiteral getCommand() { return "exceptionInfo"; }
   void operator()(const llvm::json::Object &request) const override;
 };
 
-class InitializeRequestHandler : public BaseRequestHandler {
+class InitializeRequestHandler : public LegacyRequestHandler {
 public:
-  using BaseRequestHandler::BaseRequestHandler;
+  using LegacyRequestHandler::LegacyRequestHandler;
   static llvm::StringLiteral getCommand() { return "initialize"; }
   void operator()(const llvm::json::Object &request) const override;
 };
 
-class LaunchRequestHandler : public BaseRequestHandler {
+class LaunchRequestHandler : public LegacyRequestHandler {
 public:
-  using BaseRequestHandler::BaseRequestHandler;
+  using LegacyRequestHandler::LegacyRequestHandler;
   static llvm::StringLiteral getCommand() { return "launch"; }
   void operator()(const llvm::json::Object &request) const override;
 };
 
-class RestartRequestHandler : public BaseRequestHandler {
+class RestartRequestHandler : public LegacyRequestHandler {
 public:
-  using BaseRequestHandler::BaseRequestHandler;
+  using LegacyRequestHandler::LegacyRequestHandler;
   static llvm::StringLiteral getCommand() { return "restart"; }
   void operator()(const llvm::json::Object &request) const override;
 };
 
-class NextRequestHandler : public BaseRequestHandler {
+class NextRequestHandler : public LegacyRequestHandler {
 public:
-  using BaseRequestHandler::BaseRequestHandler;
+  using LegacyRequestHandler::LegacyRequestHandler;
   static llvm::StringLiteral getCommand() { return "next"; }
   void operator()(const llvm::json::Object &request) const override;
 };
 
-class StepInRequestHandler : public BaseRequestHandler {
+class StepInRequestHandler : public LegacyRequestHandler {
 public:
-  using BaseRequestHandler::BaseRequestHandler;
+  using LegacyRequestHandler::LegacyRequestHandler;
   static llvm::StringLiteral getCommand() { return "stepIn"; }
   void operator()(const llvm::json::Object &request) const override;
 };
 
-class StepInTargetsRequestHandler : public BaseRequestHandler {
+class StepInTargetsRequestHandler : public LegacyRequestHandler {
 public:
-  using BaseRequestHandler::BaseRequestHandler;
+  using LegacyRequestHandler::LegacyRequestHandler;
   static llvm::StringLiteral getCommand() { return "stepInTargets"; }
   void operator()(const llvm::json::Object &request) const override;
 };
 
-class StepOutRequestHandler : public BaseRequestHandler {
+class StepOutRequestHandler : public LegacyRequestHandler {
 public:
-  using BaseRequestHandler::BaseRequestHandler;
+  using LegacyRequestHandler::LegacyRequestHandler;
   static llvm::StringLiteral getCommand() { return "stepOut"; }
   void operator()(const llvm::json::Object &request) const override;
 };
 
-class SetBreakpointsRequestHandler : public BaseRequestHandler {
+class SetBreakpointsRequestHandler : public LegacyRequestHandler {
 public:
-  using BaseRequestHandler::BaseRequestHandler;
+  using LegacyRequestHandler::LegacyRequestHandler;
   static llvm::StringLiteral getCommand() { return "setBreakpoints"; }
   void operator()(const llvm::json::Object &request) const override;
 };
 
-class SetExceptionBreakpointsRequestHandler : public BaseRequestHandler {
+class SetExceptionBreakpointsRequestHandler : public LegacyRequestHandler {
 public:
-  using BaseRequestHandler::BaseRequestHandler;
+  using LegacyRequestHandler::LegacyRequestHandler;
   static llvm::StringLiteral getCommand() { return "setExceptionBreakpoints"; }
   void operator()(const llvm::json::Object &request) const override;
 };
 
-class SetFunctionBreakpointsRequestHandler : public BaseRequestHandler {
+class SetFunctionBreakpointsRequestHandler : public LegacyRequestHandler {
 public:
-  using BaseRequestHandler::BaseRequestHandler;
+  using LegacyRequestHandler::LegacyRequestHandler;
   static llvm::StringLiteral getCommand() { return "setFunctionBreakpoints"; }
   void operator()(const llvm::json::Object &request) const override;
 };
 
-class DataBreakpointInfoRequestHandler : public BaseRequestHandler {
+class DataBreakpointInfoRequestHandler : public LegacyRequestHandler {
 public:
-  using BaseRequestHandler::BaseRequestHandler;
+  using LegacyRequestHandler::LegacyRequestHandler;
   static llvm::StringLiteral getCommand() { return "dataBreakpointInfo"; }
   void operator()(const llvm::json::Object &request) const override;
 };
 
-class SetDataBreakpointsRequestHandler : public BaseRequestHandler {
+class SetDataBreakpointsRequestHandler : public LegacyRequestHandler {
 public:
-  using BaseRequestHandler::BaseRequestHandler;
+  using LegacyRequestHandler::LegacyRequestHandler;
   static llvm::StringLiteral getCommand() { return "setDataBreakpoints"; }
   void operator()(const llvm::json::Object &request) const override;
 };
 
-class SetInstructionBreakpointsRequestHandler : public BaseRequestHandler {
+class SetInstructionBreakpointsRequestHandler : public LegacyRequestHandler {
 public:
-  using BaseRequestHandler::BaseRequestHandler;
+  using LegacyRequestHandler::LegacyRequestHandler;
   static llvm::StringLiteral getCommand() {
     return "setInstructionBreakpoints";
   }
   void operator()(const llvm::json::Object &request) const override;
 };
 
-class CompileUnitsRequestHandler : public BaseRequestHandler {
+class CompileUnitsRequestHandler : public LegacyRequestHandler {
 public:
-  using BaseRequestHandler::BaseRequestHandler;
+  using LegacyRequestHandler::LegacyRequestHandler;
   static llvm::StringLiteral getCommand() { return "compileUnits"; }
   void operator()(const llvm::json::Object &request) const override;
 };
 
-class ModulesRequestHandler : public BaseRequestHandler {
+class ModulesRequestHandler : public LegacyRequestHandler {
 public:
-  using BaseRequestHandler::BaseRequestHandler;
+  using LegacyRequestHandler::LegacyRequestHandler;
   static llvm::StringLiteral getCommand() { return "modules"; }
   void operator()(const llvm::json::Object &request) const override;
 };
 
-class PauseRequestHandler : public BaseRequestHandler {
+class PauseRequestHandler : public LegacyRequestHandler {
 public:
-  using BaseRequestHandler::BaseRequestHandler;
+  using LegacyRequestHandler::LegacyRequestHandler;
   static llvm::StringLiteral getCommand() { return "pause"; }
   void operator()(const llvm::json::Object &request) const override;
 };
 
-class ScopesRequestHandler : public BaseRequestHandler {
+class ScopesRequestHandler : public LegacyRequestHandler {
 public:
-  using BaseRequestHandler::BaseRequestHandler;
+  using LegacyRequestHandler::LegacyRequestHandler;
   static llvm::StringLiteral getCommand() { return "scopes"; }
   void operator()(const llvm::json::Object &request) const override;
 };
 
-class SetVariableRequestHandler : public BaseRequestHandler {
+class SetVariableRequestHandler : public LegacyRequestHandler {
 public:
-  using BaseRequestHandler::BaseRequestHandler;
+  using LegacyRequestHandler::LegacyRequestHandler;
   static llvm::StringLiteral getCommand() { return "setVariable"; }
   void operator()(const llvm::json::Object &request) const override;
 };
@@ -339,44 +339,44 @@ class SourceRequestHandler
   Run(const protocol::SourceArguments &args) const override;
 };
 
-class StackTraceRequestHandler : public BaseRequestHandler {
+class StackTraceRequestHandler : public LegacyRequestHandler {
 public:
-  using BaseRequestHandler::BaseRequestHandler;
+  using LegacyRequestHandler::LegacyRequestHandler;
   static llvm::StringLiteral getCommand() { return "stackTrace"; }
   void operator()(const llvm::json::Object &request) const override;
 };
 
-class ThreadsRequestHandler : public BaseRequestHandler {
+class ThreadsRequestHandler : public LegacyRequestHandler {
 public:
-  using BaseRequestHandler::BaseRequestHandler;
+  using LegacyRequestHandler::LegacyRequestHandler;
   static llvm::StringLiteral getCommand() { return "threads"; }
   void operator()(const llvm::json::Object &request) const override;
 };
 
-class VariablesRequestHandler : public BaseRequestHandler {
+class VariablesRequestHandler : public LegacyRequestHandler {
 public:
-  using BaseRequestHandler::BaseRequestHandler;
+  using LegacyRequestHandler::LegacyRequestHandler;
   static llvm::StringLiteral getCommand() { return "variables"; }
   void operator()(const llvm::json::Object &request) const override;
 };
 
-class LocationsRequestHandler : public BaseRequestHandler {
+class LocationsRequestHandler : public LegacyRequestHandler {
 public:
-  using BaseRequestHandler::BaseRequestHandler;
+  using LegacyRequestHandler::LegacyRequestHandler;
   static llvm::StringLiteral getCommand() { return "locations"; }
   void operator()(const llvm::json::Object &request) const override;
 };
 
-class DisassembleRequestHandler : public BaseRequestHandler {
+class DisassembleRequestHandler : public LegacyRequestHandler {
 public:
-  using BaseRequestHandler::BaseRequestHandler;
+  using LegacyRequestHandler::LegacyRequestHandler;
   static llvm::StringLiteral getCommand() { return "disassemble"; }
   void operator()(const llvm::json::Object &request) const override;
 };
 
-class ReadMemoryRequestHandler : public BaseRequestHandler {
+class ReadMemoryRequestHandler : public LegacyRequestHandler {
 public:
-  using BaseRequestHandler::BaseRequestHandler;
+  using LegacyRequestHandler::LegacyRequestHandler;
   static llvm::StringLiteral getCommand() { return "readMemory"; }
   void operator()(const llvm::json::Object &request) const override;
 };
@@ -385,9 +385,9 @@ class ReadMemoryRequestHandler : public BaseRequestHandler {
 /// currently set in the target. This helps us to test "setBreakpoints" and
 /// "setFunctionBreakpoints" requests to verify we have the correct set of
 /// breakpoints currently set in LLDB.
-class TestGetTargetBreakpointsRequestHandler : public BaseRequestHandler {
+class TestGetTargetBreakpointsRequestHandler : public LegacyRequestHandler {
 public:
-  using BaseRequestHandler::BaseRequestHandler;
+  using LegacyRequestHandler::LegacyRequestHandler;
   static llvm::StringLiteral getCommand() {
     return "_testGetTargetBreakpoints";
   }
diff --git a/lldb/tools/lldb-dap/Protocol.h b/lldb/tools/lldb-dap/Protocol.h
index 3bdc250449564..745c96a1a2d4b 100644
--- a/lldb/tools/lldb-dap/Protocol.h
+++ b/lldb/tools/lldb-dap/Protocol.h
@@ -164,7 +164,7 @@ struct Source {
   /// skipped on stepping.
   std::optional<PresentationHint> presentationHint;
 
-  // unsupported keys origin, sources, adapterData, checksums
+  // unsupported keys: origin, sources, adapterData, checksums
 };
 bool fromJSON(const llvm::json::Value &, Source &, llvm::json::Path);
 

>From 348b4273a10b6d5b2c481967029dd73b7ddc5e80 Mon Sep 17 00:00:00 2001
From: John Harrison <harjohn at google.com>
Date: Fri, 14 Mar 2025 17:14:11 -0700
Subject: [PATCH 09/12] Adjusting the names of the "arguments" and "body" to
 remove the raw prefix. The types should be enough to tell that theyre not
 specific values and this helps with the naming consistency.

---
 lldb/tools/lldb-dap/DAP.cpp                  |  2 +-
 lldb/tools/lldb-dap/Handler/RequestHandler.h | 19 +++++++++----------
 lldb/tools/lldb-dap/Protocol.cpp             | 18 +++++++++---------
 lldb/tools/lldb-dap/Protocol.h               | 12 +++++++++---
 4 files changed, 28 insertions(+), 23 deletions(-)

diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp
index e4d1ea7aa9488..5266bc8a1c105 100644
--- a/lldb/tools/lldb-dap/DAP.cpp
+++ b/lldb/tools/lldb-dap/DAP.cpp
@@ -700,7 +700,7 @@ bool DAP::HandleObject(const protocol::Message &M) {
 
     // Result should be given, use null if not.
     if (resp->success) {
-      (*response_handler)(resp->rawBody);
+      (*response_handler)(resp->body);
     } else {
       std::string message = "Unknown error, response failed";
       if (resp->message) {
diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h
index 11800cd66fcad..8e1eb51a97320 100644
--- a/lldb/tools/lldb-dap/Handler/RequestHandler.h
+++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h
@@ -96,7 +96,7 @@ class RequestHandler : public BaseRequestHandler {
     response.request_seq = request.seq;
     response.command = request.command;
 
-    if (!is_optional_v<Args> && !request.rawArguments) {
+    if (!is_optional_v<Args> && !request.arguments) {
       DAP_LOG(dap.log,
               "({0}) malformed request {1}, expected arguments but got none",
               dap.transport.GetClientName(), request.command);
@@ -111,21 +111,20 @@ class RequestHandler : public BaseRequestHandler {
 
     Args arguments;
     llvm::json::Path::Root root;
-    if (request.rawArguments &&
-        !fromJSON(request.rawArguments, arguments, root)) {
-      std::string parseFailure;
-      llvm::raw_string_ostream OS(parseFailure);
-      root.printErrorContext(request.rawArguments, OS);
+    if (request.arguments && !fromJSON(request.arguments, arguments, root)) {
+      std::string parse_failure;
+      llvm::raw_string_ostream OS(parse_failure);
+      root.printErrorContext(request.arguments, OS);
       response.success = false;
-      response.message = parseFailure;
+      response.message = parse_failure;
       dap.Send(response);
       return;
     }
 
-    auto ResponseBody = Run(arguments);
+    auto body = Run(arguments);
     // FIXME: Add a dedicated DAPError for enhanced errors that are
     // user-visibile.
-    if (auto Err = ResponseBody.takeError()) {
+    if (auto Err = body.takeError()) {
       response.success = false;
       // FIXME: Build ErrorMessage based on error details instead of using the
       // 'message' field.
@@ -133,7 +132,7 @@ class RequestHandler : public BaseRequestHandler {
     } else {
       response.success = true;
       if constexpr (!std::is_same_v<Body, std::monostate>)
-        response.rawBody = std::move(*ResponseBody);
+        response.body = std::move(*body);
     }
 
     dap.Send(response);
diff --git a/lldb/tools/lldb-dap/Protocol.cpp b/lldb/tools/lldb-dap/Protocol.cpp
index cba899649b69d..049ed310432ab 100644
--- a/lldb/tools/lldb-dap/Protocol.cpp
+++ b/lldb/tools/lldb-dap/Protocol.cpp
@@ -61,8 +61,8 @@ json::Value toJSON(const Request &R) {
       {"command", R.command},
   };
 
-  if (R.rawArguments)
-    Result.insert({"arguments", R.rawArguments});
+  if (R.arguments)
+    Result.insert({"arguments", R.arguments});
 
   return std::move(Result);
 }
@@ -92,7 +92,7 @@ bool fromJSON(json::Value const &Params, Request &R, json::Path P) {
     return false;
   }
 
-  return mapRaw(Params, "arguments", R.rawArguments, P);
+  return mapRaw(Params, "arguments", R.arguments, P);
 }
 
 json::Value toJSON(const Response &R) {
@@ -119,8 +119,8 @@ json::Value toJSON(const Response &R) {
     }
   }
 
-  if (R.rawBody)
-    Result.insert({"body", R.rawBody});
+  if (R.body)
+    Result.insert({"body", R.body});
 
   return std::move(Result);
 }
@@ -176,7 +176,7 @@ bool fromJSON(json::Value const &Params, Response &R, json::Path P) {
   }
 
   return O.map("success", R.success) && O.mapOptional("message", R.message) &&
-         mapRaw(Params, "body", R.rawBody, P);
+         mapRaw(Params, "body", R.body, P);
 }
 
 json::Value toJSON(const ErrorMessage &EM) {
@@ -216,8 +216,8 @@ json::Value toJSON(const Event &E) {
       {"event", E.event},
   };
 
-  if (E.rawBody)
-    Result.insert({"body", E.rawBody});
+  if (E.body)
+    Result.insert({"body", E.body});
 
   return std::move(Result);
 }
@@ -247,7 +247,7 @@ bool fromJSON(json::Value const &Params, Event &E, json::Path P) {
     return false;
   }
 
-  return mapRaw(Params, "body", E.rawBody, P);
+  return mapRaw(Params, "body", E.body, P);
 }
 
 bool fromJSON(const json::Value &Params, Message &PM, json::Path P) {
diff --git a/lldb/tools/lldb-dap/Protocol.h b/lldb/tools/lldb-dap/Protocol.h
index 745c96a1a2d4b..769796d005378 100644
--- a/lldb/tools/lldb-dap/Protocol.h
+++ b/lldb/tools/lldb-dap/Protocol.h
@@ -45,7 +45,10 @@ struct Request {
   std::string command;
 
   /// Object containing arguments for the command.
-  std::optional<llvm::json::Value> rawArguments;
+  ///
+  /// Request handlers are expected to validate the arguments, which is handled
+  /// by `RequestHandler`.
+  std::optional<llvm::json::Value> arguments;
 };
 llvm::json::Value toJSON(const Request &);
 bool fromJSON(const llvm::json::Value &, Request &, llvm::json::Path);
@@ -56,7 +59,7 @@ struct Event {
   std::string event;
 
   /// Event-specific information.
-  std::optional<llvm::json::Value> rawBody;
+  std::optional<llvm::json::Value> body;
 };
 llvm::json::Value toJSON(const Event &);
 bool fromJSON(const llvm::json::Value &, Event &, llvm::json::Path);
@@ -91,7 +94,10 @@ struct Response {
 
   /// Contains request result if success is true and error details if success is
   /// false.
-  std::optional<llvm::json::Value> rawBody;
+  ///
+  /// Request handlers are expected to build an appropriate body, see
+  /// `RequestHandler`.
+  std::optional<llvm::json::Value> body;
 };
 bool fromJSON(const llvm::json::Value &, Response &, llvm::json::Path);
 llvm::json::Value toJSON(const Response &);

>From 66843c65aa1ba55386e09b065111ba4a596479df Mon Sep 17 00:00:00 2001
From: John Harrison <harjohn at google.com>
Date: Sat, 15 Mar 2025 15:12:50 -0700
Subject: [PATCH 10/12] Splitting Protocol.{h,cpp} into
 Protocol/Protocol{Base,Types,Requests}.{h,cpp}.

---
 lldb/tools/lldb-dap/CMakeLists.txt            |  5 +-
 lldb/tools/lldb-dap/DAP.cpp                   |  2 +-
 lldb/tools/lldb-dap/DAP.h                     |  2 +-
 .../Handler/DisconnectRequestHandler.cpp      |  2 +-
 lldb/tools/lldb-dap/Handler/RequestHandler.h  |  3 +-
 .../lldb-dap/Handler/SourceRequestHandler.cpp |  2 +
 .../ProtocolBase.cpp}                         | 62 +-------------
 .../{Protocol.h => Protocol/ProtocolBase.h}   | 85 +------------------
 .../lldb-dap/Protocol/ProtocolRequests.cpp    | 41 +++++++++
 .../lldb-dap/Protocol/ProtocolRequests.h      | 82 ++++++++++++++++++
 .../tools/lldb-dap/Protocol/ProtocolTypes.cpp | 47 ++++++++++
 lldb/tools/lldb-dap/Protocol/ProtocolTypes.h  | 63 ++++++++++++++
 lldb/tools/lldb-dap/Transport.cpp             |  2 +-
 lldb/tools/lldb-dap/Transport.h               |  2 +-
 14 files changed, 251 insertions(+), 149 deletions(-)
 rename lldb/tools/lldb-dap/{Protocol.cpp => Protocol/ProtocolBase.cpp} (79%)
 rename lldb/tools/lldb-dap/{Protocol.h => Protocol/ProtocolBase.h} (60%)
 create mode 100644 lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp
 create mode 100644 lldb/tools/lldb-dap/Protocol/ProtocolRequests.h
 create mode 100644 lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp
 create mode 100644 lldb/tools/lldb-dap/Protocol/ProtocolTypes.h

diff --git a/lldb/tools/lldb-dap/CMakeLists.txt b/lldb/tools/lldb-dap/CMakeLists.txt
index 8a76cb58dbcab..adad75a79fa7a 100644
--- a/lldb/tools/lldb-dap/CMakeLists.txt
+++ b/lldb/tools/lldb-dap/CMakeLists.txt
@@ -32,7 +32,6 @@ add_lldb_tool(lldb-dap
   LLDBUtils.cpp
   OutputRedirector.cpp
   ProgressEvent.cpp
-  Protocol.cpp
   RunInTerminal.cpp
   SourceBreakpoint.cpp
   Transport.cpp
@@ -74,6 +73,10 @@ add_lldb_tool(lldb-dap
   Handler/TestGetTargetBreakpointsRequestHandler.cpp
   Handler/ThreadsRequestHandler.cpp
   Handler/VariablesRequestHandler.cpp
+  
+  Protocol/ProtocolBase.cpp
+  Protocol/ProtocolTypes.cpp
+  Protocol/ProtocolRequests.cpp
 
   LINK_LIBS
     liblldb
diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp
index 5266bc8a1c105..5e3af9e2eaada 100644
--- a/lldb/tools/lldb-dap/DAP.cpp
+++ b/lldb/tools/lldb-dap/DAP.cpp
@@ -13,7 +13,7 @@
 #include "JSONUtils.h"
 #include "LLDBUtils.h"
 #include "OutputRedirector.h"
-#include "Protocol.h"
+#include "Protocol/ProtocolBase.h"
 #include "Transport.h"
 #include "lldb/API/SBBreakpoint.h"
 #include "lldb/API/SBCommandInterpreter.h"
diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h
index 09789ae964492..4c57f9fef3d89 100644
--- a/lldb/tools/lldb-dap/DAP.h
+++ b/lldb/tools/lldb-dap/DAP.h
@@ -15,7 +15,7 @@
 #include "InstructionBreakpoint.h"
 #include "OutputRedirector.h"
 #include "ProgressEvent.h"
-#include "Protocol.h"
+#include "Protocol/ProtocolBase.h"
 #include "SourceBreakpoint.h"
 #include "Transport.h"
 #include "lldb/API/SBBroadcaster.h"
diff --git a/lldb/tools/lldb-dap/Handler/DisconnectRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/DisconnectRequestHandler.cpp
index 3b89dbf570115..f12fecfb2ff65 100644
--- a/lldb/tools/lldb-dap/Handler/DisconnectRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/DisconnectRequestHandler.cpp
@@ -7,7 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "DAP.h"
-#include "Protocol.h"
+#include "Protocol/ProtocolRequests.h"
 #include "RequestHandler.h"
 #include "llvm/Support/Error.h"
 #include <optional>
diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h
index 8e1eb51a97320..c9bcf15933c33 100644
--- a/lldb/tools/lldb-dap/Handler/RequestHandler.h
+++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h
@@ -11,7 +11,8 @@
 
 #include "DAP.h"
 #include "DAPLog.h"
-#include "Protocol.h"
+#include "Protocol/ProtocolBase.h"
+#include "Protocol/ProtocolRequests.h"
 #include "lldb/API/SBError.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/JSON.h"
diff --git a/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp
index b8e0c39cb2e08..57cfb09692990 100644
--- a/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp
@@ -9,6 +9,8 @@
 #include "DAP.h"
 #include "Handler/RequestHandler.h"
 #include "LLDBUtils.h"
+#include "Protocol/ProtocolRequests.h"
+#include "Protocol/ProtocolTypes.h"
 #include "lldb/API/SBFrame.h"
 #include "lldb/API/SBInstructionList.h"
 #include "lldb/API/SBProcess.h"
diff --git a/lldb/tools/lldb-dap/Protocol.cpp b/lldb/tools/lldb-dap/Protocol/ProtocolBase.cpp
similarity index 79%
rename from lldb/tools/lldb-dap/Protocol.cpp
rename to lldb/tools/lldb-dap/Protocol/ProtocolBase.cpp
index 049ed310432ab..467dfb2cefe45 100644
--- a/lldb/tools/lldb-dap/Protocol.cpp
+++ b/lldb/tools/lldb-dap/Protocol/ProtocolBase.cpp
@@ -1,4 +1,4 @@
-//===-- Protocol.cpp ------------------------------------------------------===//
+//===-- ProtocolBase.cpp --------------------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -6,7 +6,7 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "Protocol.h"
+#include "Protocol/ProtocolBase.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/ADT/StringSwitch.h"
 #include "llvm/Support/ErrorHandling.h"
@@ -29,8 +29,7 @@ static bool mapRaw(const json::Value &Params, StringLiteral Prop,
   return true;
 }
 
-namespace lldb_dap {
-namespace protocol {
+namespace lldb_dap::protocol {
 
 enum class MessageType { request, response, event };
 
@@ -286,57 +285,4 @@ bool fromJSON(const json::Value &Params, Message &PM, json::Path P) {
 json::Value toJSON(const Message &M) {
   return std::visit([](auto &M) { return toJSON(M); }, M);
 }
-
-bool fromJSON(const json::Value &Params, Source::PresentationHint &PH,
-              json::Path P) {
-  auto rawHint = Params.getAsString();
-  if (!rawHint) {
-    P.report("expected a string");
-    return false;
-  }
-  std::optional<Source::PresentationHint> hint =
-      StringSwitch<std::optional<Source::PresentationHint>>(*rawHint)
-          .Case("normal", Source::PresentationHint::normal)
-          .Case("emphasize", Source::PresentationHint::emphasize)
-          .Case("deemphasize", Source::PresentationHint::deemphasize)
-          .Default(std::nullopt);
-  if (!hint) {
-    P.report("unexpected value");
-    return false;
-  }
-  PH = *hint;
-  return true;
-}
-
-bool fromJSON(const json::Value &Params, Source &S, json::Path P) {
-  json::ObjectMapper O(Params, P);
-  return O && O.mapOptional("name", S.name) && O.mapOptional("path", S.path) &&
-         O.mapOptional("presentationHint", S.presentationHint) &&
-         O.mapOptional("sourceReference", S.sourceReference);
-}
-
-bool fromJSON(const json::Value &Params, DisconnectArguments &DA,
-              json::Path P) {
-  json::ObjectMapper O(Params, P);
-  return O && O.mapOptional("restart", DA.restart) &&
-         O.mapOptional("terminateDebuggee", DA.terminateDebuggee) &&
-         O.mapOptional("suspendDebuggee", DA.suspendDebuggee);
-}
-
-bool fromJSON(const json::Value &Params, SourceArguments &SA, json::Path P) {
-  json::ObjectMapper O(Params, P);
-  return O && O.mapOptional("source", SA.source) &&
-         O.map("sourceReference", SA.sourceReference);
-}
-
-json::Value toJSON(const SourceResponseBody &SA) {
-  json::Object Result{{"content", SA.content}};
-
-  if (SA.mimeType)
-    Result.insert({"mimeType", SA.mimeType});
-
-  return std::move(Result);
-}
-
-} // namespace protocol
-} // namespace lldb_dap
+} // namespace lldb_dap::protocol
diff --git a/lldb/tools/lldb-dap/Protocol.h b/lldb/tools/lldb-dap/Protocol/ProtocolBase.h
similarity index 60%
rename from lldb/tools/lldb-dap/Protocol.h
rename to lldb/tools/lldb-dap/Protocol/ProtocolBase.h
index 769796d005378..e10a903b80aaa 100644
--- a/lldb/tools/lldb-dap/Protocol.h
+++ b/lldb/tools/lldb-dap/Protocol/ProtocolBase.h
@@ -1,4 +1,4 @@
-//===-- Protocol.h --------------------------------------------------------===//
+//===-- ProtocolBase.h ----------------------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -141,92 +141,9 @@ using Message = std::variant<Request, Response, Event>;
 bool fromJSON(const llvm::json::Value &, Message &, llvm::json::Path);
 llvm::json::Value toJSON(const Message &);
 
-// MARK: Types
-
-/// A `Source` is a descriptor for source code. It is returned from the debug
-/// adapter as part of a `StackFrame` and it is used by clients when specifying
-/// breakpoints.
-struct Source {
-  enum class PresentationHint { normal, emphasize, deemphasize };
-
-  /// The short name of the source. Every source returned from the debug adapter
-  /// has a name. When sending a source to the debug adapter this name is
-  /// optional.
-  std::optional<std::string> name;
-
-  /// The path of the source to be shown in the UI. It is only used to locate
-  /// and load the content of the source if no `sourceReference` is specified
-  /// (or its value is 0).
-  std::optional<std::string> path;
-
-  /// If the value > 0 the contents of the source must be retrieved through the
-  /// `source` request (even if a path is specified). Since a `sourceReference`
-  /// is only valid for a session, it can not be used to persist a source. The
-  /// value should be less than or equal to 2147483647 (2^31-1).
-  std::optional<int64_t> sourceReference;
-
-  /// A hint for how to present the source in the UI. A value of `deemphasize`
-  /// can be used to indicate that the source is not available or that it is
-  /// skipped on stepping.
-  std::optional<PresentationHint> presentationHint;
-
-  // unsupported keys: origin, sources, adapterData, checksums
-};
-bool fromJSON(const llvm::json::Value &, Source &, llvm::json::Path);
-
-// MARK: Requests
-
 /// This is just an acknowledgement, so no body field is required.
 using VoidResponse = std::monostate;
 
-/// Arguments for `disconnect` request.
-struct DisconnectArguments {
-  /// A value of true indicates that this `disconnect` request is part of a
-  /// restart sequence.
-  std::optional<bool> restart;
-
-  /// Indicates whether the debuggee should be terminated when the debugger is
-  /// disconnected. If unspecified, the debug adapter is free to do whatever it
-  /// thinks is best. The attribute is only honored by a debug adapter if the
-  /// corresponding capability `supportTerminateDebuggee` is true.
-  std::optional<bool> terminateDebuggee;
-
-  /// Indicates whether the debuggee should stay suspended when the debugger is
-  /// disconnected. If unspecified, the debuggee should resume execution. The
-  /// attribute is only honored by a debug adapter if the corresponding
-  /// capability `supportSuspendDebuggee` is true.
-  std::optional<bool> suspendDebuggee;
-};
-bool fromJSON(const llvm::json::Value &, DisconnectArguments &,
-              llvm::json::Path);
-
-/// Response to `disconnect` request. This is just an acknowledgement, so no
-/// body field is required.
-using DisconnectResponse = VoidResponse;
-
-/// Arguments for `source` request.
-struct SourceArguments {
-  /// Specifies the source content to load. Either `source.path` or
-  /// `source.sourceReference` must be specified.
-  std::optional<Source> source;
-
-  /// The reference to the source. This is the same as `source.sourceReference`.
-  /// This is provided for backward compatibility since old clients do not
-  /// understand the `source` attribute.
-  int64_t sourceReference;
-};
-bool fromJSON(const llvm::json::Value &, SourceArguments &, llvm::json::Path);
-
-/// Response to `source` request.
-struct SourceResponseBody {
-  /// Content of the source reference.
-  std::string content;
-
-  /// Content type (MIME type) of the source.
-  std::optional<std::string> mimeType;
-};
-llvm::json::Value toJSON(const SourceResponseBody &);
-
 } // namespace lldb_dap::protocol
 
 #endif
diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp
new file mode 100644
index 0000000000000..5cc5429227439
--- /dev/null
+++ b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp
@@ -0,0 +1,41 @@
+//===-- ProtocolRequests.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 "Protocol/ProtocolRequests.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/JSON.h"
+#include <utility>
+
+using namespace llvm;
+
+namespace lldb_dap::protocol {
+
+bool fromJSON(const json::Value &Params, DisconnectArguments &DA,
+              json::Path P) {
+  json::ObjectMapper O(Params, P);
+  return O && O.mapOptional("restart", DA.restart) &&
+         O.mapOptional("terminateDebuggee", DA.terminateDebuggee) &&
+         O.mapOptional("suspendDebuggee", DA.suspendDebuggee);
+}
+
+bool fromJSON(const json::Value &Params, SourceArguments &SA, json::Path P) {
+  json::ObjectMapper O(Params, P);
+  return O && O.mapOptional("source", SA.source) &&
+         O.map("sourceReference", SA.sourceReference);
+}
+
+json::Value toJSON(const SourceResponseBody &SA) {
+  json::Object Result{{"content", SA.content}};
+
+  if (SA.mimeType)
+    Result.insert({"mimeType", SA.mimeType});
+
+  return std::move(Result);
+}
+
+} // namespace lldb_dap::protocol
diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h
new file mode 100644
index 0000000000000..07ed67e61495d
--- /dev/null
+++ b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h
@@ -0,0 +1,82 @@
+//===-- ProtocolTypes.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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains POD structs based on the DAP specification at
+// https://microsoft.github.io/debug-adapter-protocol/specification
+//
+// This is not meant to be a complete implementation, new interfaces are added
+// when they're needed.
+//
+// Each struct has a toJSON and fromJSON function, that converts between
+// the struct and a JSON representation. (See JSON.h)
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_TOOLS_LLDB_DAP_PROTOCOL_PROTOCOL_REQUESTS_H
+#define LLDB_TOOLS_LLDB_DAP_PROTOCOL_PROTOCOL_REQUESTS_H
+
+#include "Protocol/ProtocolBase.h"
+#include "Protocol/ProtocolTypes.h"
+#include "llvm/Support/JSON.h"
+#include <cstdint>
+#include <optional>
+#include <string>
+
+namespace lldb_dap::protocol {
+
+/// Arguments for `disconnect` request.
+struct DisconnectArguments {
+  /// A value of true indicates that this `disconnect` request is part of a
+  /// restart sequence.
+  std::optional<bool> restart;
+
+  /// Indicates whether the debuggee should be terminated when the debugger is
+  /// disconnected. If unspecified, the debug adapter is free to do whatever it
+  /// thinks is best. The attribute is only honored by a debug adapter if the
+  /// corresponding capability `supportTerminateDebuggee` is true.
+  std::optional<bool> terminateDebuggee;
+
+  /// Indicates whether the debuggee should stay suspended when the debugger is
+  /// disconnected. If unspecified, the debuggee should resume execution. The
+  /// attribute is only honored by a debug adapter if the corresponding
+  /// capability `supportSuspendDebuggee` is true.
+  std::optional<bool> suspendDebuggee;
+};
+bool fromJSON(const llvm::json::Value &, DisconnectArguments &,
+              llvm::json::Path);
+
+/// Response to `disconnect` request. This is just an acknowledgement, so no
+/// body field is required.
+using DisconnectResponse = VoidResponse;
+
+/// Arguments for `source` request.
+struct SourceArguments {
+  /// Specifies the source content to load. Either `source.path` or
+  /// `source.sourceReference` must be specified.
+  std::optional<Source> source;
+
+  /// The reference to the source. This is the same as `source.sourceReference`.
+  /// This is provided for backward compatibility since old clients do not
+  /// understand the `source` attribute.
+  int64_t sourceReference;
+};
+bool fromJSON(const llvm::json::Value &, SourceArguments &, llvm::json::Path);
+
+/// Response to `source` request.
+struct SourceResponseBody {
+  /// Content of the source reference.
+  std::string content;
+
+  /// Content type (MIME type) of the source.
+  std::optional<std::string> mimeType;
+};
+llvm::json::Value toJSON(const SourceResponseBody &);
+
+} // namespace lldb_dap::protocol
+
+#endif
\ No newline at end of file
diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp
new file mode 100644
index 0000000000000..efb5c3abe32bf
--- /dev/null
+++ b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp
@@ -0,0 +1,47 @@
+//===-- ProtocolTypes.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 "Protocol/ProtocolTypes.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/JSON.h"
+#include <optional>
+
+using namespace llvm;
+
+namespace lldb_dap::protocol {
+
+bool fromJSON(const json::Value &Params, Source::PresentationHint &PH,
+              json::Path P) {
+  auto rawHint = Params.getAsString();
+  if (!rawHint) {
+    P.report("expected a string");
+    return false;
+  }
+  std::optional<Source::PresentationHint> hint =
+      StringSwitch<std::optional<Source::PresentationHint>>(*rawHint)
+          .Case("normal", Source::PresentationHint::normal)
+          .Case("emphasize", Source::PresentationHint::emphasize)
+          .Case("deemphasize", Source::PresentationHint::deemphasize)
+          .Default(std::nullopt);
+  if (!hint) {
+    P.report("unexpected value");
+    return false;
+  }
+  PH = *hint;
+  return true;
+}
+
+bool fromJSON(const json::Value &Params, Source &S, json::Path P) {
+  json::ObjectMapper O(Params, P);
+  return O && O.mapOptional("name", S.name) && O.mapOptional("path", S.path) &&
+         O.mapOptional("presentationHint", S.presentationHint) &&
+         O.mapOptional("sourceReference", S.sourceReference);
+}
+
+} // namespace lldb_dap::protocol
diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h
new file mode 100644
index 0000000000000..b54d76cb29a77
--- /dev/null
+++ b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h
@@ -0,0 +1,63 @@
+//===-- ProtocolTypes.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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains POD structs based on the DAP specification at
+// https://microsoft.github.io/debug-adapter-protocol/specification
+//
+// This is not meant to be a complete implementation, new interfaces are added
+// when they're needed.
+//
+// Each struct has a toJSON and fromJSON function, that converts between
+// the struct and a JSON representation. (See JSON.h)
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_TOOLS_LLDB_DAP_PROTOCOL_PROTOCOL_TYPES_H
+#define LLDB_TOOLS_LLDB_DAP_PROTOCOL_PROTOCOL_TYPES_H
+
+#include "llvm/Support/JSON.h"
+#include <cstdint>
+#include <optional>
+#include <string>
+
+namespace lldb_dap::protocol {
+
+/// A `Source` is a descriptor for source code. It is returned from the debug
+/// adapter as part of a `StackFrame` and it is used by clients when specifying
+/// breakpoints.
+struct Source {
+  enum class PresentationHint { normal, emphasize, deemphasize };
+
+  /// The short name of the source. Every source returned from the debug adapter
+  /// has a name. When sending a source to the debug adapter this name is
+  /// optional.
+  std::optional<std::string> name;
+
+  /// The path of the source to be shown in the UI. It is only used to locate
+  /// and load the content of the source if no `sourceReference` is specified
+  /// (or its value is 0).
+  std::optional<std::string> path;
+
+  /// If the value > 0 the contents of the source must be retrieved through the
+  /// `source` request (even if a path is specified). Since a `sourceReference`
+  /// is only valid for a session, it can not be used to persist a source. The
+  /// value should be less than or equal to 2147483647 (2^31-1).
+  std::optional<int64_t> sourceReference;
+
+  /// A hint for how to present the source in the UI. A value of `deemphasize`
+  /// can be used to indicate that the source is not available or that it is
+  /// skipped on stepping.
+  std::optional<PresentationHint> presentationHint;
+
+  // unsupported keys: origin, sources, adapterData, checksums
+};
+bool fromJSON(const llvm::json::Value &, Source &, llvm::json::Path);
+
+} // namespace lldb_dap::protocol
+
+#endif
diff --git a/lldb/tools/lldb-dap/Transport.cpp b/lldb/tools/lldb-dap/Transport.cpp
index db2d7228d3fb7..981ade12d2b85 100644
--- a/lldb/tools/lldb-dap/Transport.cpp
+++ b/lldb/tools/lldb-dap/Transport.cpp
@@ -8,7 +8,7 @@
 
 #include "Transport.h"
 #include "DAPLog.h"
-#include "Protocol.h"
+#include "Protocol/ProtocolBase.h"
 #include "lldb/Utility/IOObject.h"
 #include "lldb/Utility/Status.h"
 #include "lldb/lldb-forward.h"
diff --git a/lldb/tools/lldb-dap/Transport.h b/lldb/tools/lldb-dap/Transport.h
index 013a6c98af1ce..e77bb5dd05e65 100644
--- a/lldb/tools/lldb-dap/Transport.h
+++ b/lldb/tools/lldb-dap/Transport.h
@@ -14,7 +14,7 @@
 #ifndef LLDB_TOOLS_LLDB_DAP_TRANSPORT_H
 #define LLDB_TOOLS_LLDB_DAP_TRANSPORT_H
 
-#include "Protocol.h"
+#include "Protocol/ProtocolBase.h"
 #include "lldb/lldb-forward.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/Error.h"

>From 639afb58a893e2a3e32c8ee1c2498468de967577 Mon Sep 17 00:00:00 2001
From: John Harrison <harjohn at google.com>
Date: Sat, 15 Mar 2025 15:25:39 -0700
Subject: [PATCH 11/12] Adding a newline to ProtocolRequests.h and adjusting
 whitespace in ProtocolBase.cpp.

---
 lldb/tools/lldb-dap/Protocol/ProtocolBase.cpp   | 1 +
 lldb/tools/lldb-dap/Protocol/ProtocolRequests.h | 2 +-
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolBase.cpp b/lldb/tools/lldb-dap/Protocol/ProtocolBase.cpp
index 467dfb2cefe45..f30517715194f 100644
--- a/lldb/tools/lldb-dap/Protocol/ProtocolBase.cpp
+++ b/lldb/tools/lldb-dap/Protocol/ProtocolBase.cpp
@@ -285,4 +285,5 @@ bool fromJSON(const json::Value &Params, Message &PM, json::Path P) {
 json::Value toJSON(const Message &M) {
   return std::visit([](auto &M) { return toJSON(M); }, M);
 }
+
 } // namespace lldb_dap::protocol
diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h
index 07ed67e61495d..5dc4a589178d2 100644
--- a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h
+++ b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h
@@ -79,4 +79,4 @@ llvm::json::Value toJSON(const SourceResponseBody &);
 
 } // namespace lldb_dap::protocol
 
-#endif
\ No newline at end of file
+#endif

>From f4f3349e2394f1f1759e2565656f84d558e56693 Mon Sep 17 00:00:00 2001
From: John Harrison <harjohn at google.com>
Date: Mon, 17 Mar 2025 09:21:30 -0700
Subject: [PATCH 12/12] Applying reviewer suggestions.

---
 lldb/tools/lldb-dap/DAP.cpp       | 33 ++++++++++++++++---------------
 lldb/tools/lldb-dap/LLDBUtils.cpp |  2 +-
 lldb/tools/lldb-dap/LLDBUtils.h   |  2 +-
 3 files changed, 19 insertions(+), 18 deletions(-)

diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp
index 5e3af9e2eaada..f670fb77db0dd 100644
--- a/lldb/tools/lldb-dap/DAP.cpp
+++ b/lldb/tools/lldb-dap/DAP.cpp
@@ -702,22 +702,23 @@ bool DAP::HandleObject(const protocol::Message &M) {
     if (resp->success) {
       (*response_handler)(resp->body);
     } else {
-      std::string message = "Unknown error, response failed";
+      llvm::StringRef message = "Unknown error, response failed";
       if (resp->message) {
-        message = std::visit(
-            llvm::makeVisitor(
-                [](const std::string &message) -> std::string {
-                  return message;
-                },
-                [](const protocol::Response::Message &message) -> std::string {
-                  switch (message) {
-                  case protocol::Response::Message::cancelled:
-                    return "cancelled";
-                  case protocol::Response::Message::notStopped:
-                    return "notStopped";
-                  }
-                }),
-            *resp->message);
+        message =
+            std::visit(llvm::makeVisitor(
+                           [](const std::string &message) -> llvm::StringRef {
+                             return message;
+                           },
+                           [](const protocol::Response::Message &message)
+                               -> llvm::StringRef {
+                             switch (message) {
+                             case protocol::Response::Message::cancelled:
+                               return "cancelled";
+                             case protocol::Response::Message::notStopped:
+                               return "notStopped";
+                             }
+                           }),
+                       *resp->message);
       }
 
       (*response_handler)(llvm::createStringError(
@@ -772,7 +773,7 @@ llvm::Error DAP::Disconnect(bool terminateDebuggee) {
 
   disconnecting = true;
 
-  return takeError(error);
+  return ToError(error);
 }
 
 llvm::Error DAP::Loop() {
diff --git a/lldb/tools/lldb-dap/LLDBUtils.cpp b/lldb/tools/lldb-dap/LLDBUtils.cpp
index 63fa38ba1e8fa..dc87ebf18f0a5 100644
--- a/lldb/tools/lldb-dap/LLDBUtils.cpp
+++ b/lldb/tools/lldb-dap/LLDBUtils.cpp
@@ -162,7 +162,7 @@ GetEnvironmentFromArguments(const llvm::json::Object &arguments) {
   return envs;
 }
 
-llvm::Error takeError(const lldb::SBError &error) {
+llvm::Error ToError(const lldb::SBError &error) {
   if (error.Success())
     return llvm::Error::success();
 
diff --git a/lldb/tools/lldb-dap/LLDBUtils.h b/lldb/tools/lldb-dap/LLDBUtils.h
index aef21c2895151..2c57847303cb3 100644
--- a/lldb/tools/lldb-dap/LLDBUtils.h
+++ b/lldb/tools/lldb-dap/LLDBUtils.h
@@ -157,7 +157,7 @@ lldb::SBEnvironment
 GetEnvironmentFromArguments(const llvm::json::Object &arguments);
 
 /// Take ownership of the stored error.
-llvm::Error takeError(const lldb::SBError &error);
+llvm::Error ToError(const lldb::SBError &error);
 
 } // namespace lldb_dap
 



More information about the lldb-commits mailing list