[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
Wed Mar 12 13:34:09 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 1/3] [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 2/3] 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 3/3] 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



More information about the lldb-commits mailing list