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

>From 3db3a7184eb7d729c37f7dc02f826c77df8c65e9 Mon Sep 17 00:00:00 2001
From: John Harrison <harj...@google.com>
Date: Tue, 12 Aug 2025 16:23:18 -0700
Subject: [PATCH 1/4] [lldb-dap] Migrating 'completions' to structured types.

This migrates the CompletionHandler to structured types and adds a new 
CompletionItem and CompletionItemType to the general types.
---
 .../lldb-dap/Handler/CompletionsHandler.cpp   | 175 ++++--------------
 lldb/tools/lldb-dap/Handler/RequestHandler.h  |   9 +-
 .../lldb-dap/Protocol/ProtocolRequests.cpp    |  11 ++
 .../lldb-dap/Protocol/ProtocolRequests.h      |  29 +++
 .../tools/lldb-dap/Protocol/ProtocolTypes.cpp | 117 ++++++++++++
 lldb/tools/lldb-dap/Protocol/ProtocolTypes.h  |  78 ++++++++
 6 files changed, 272 insertions(+), 147 deletions(-)

diff --git a/lldb/tools/lldb-dap/Handler/CompletionsHandler.cpp 
b/lldb/tools/lldb-dap/Handler/CompletionsHandler.cpp
index c72fc5686cd5b..7507aa17f5421 100644
--- a/lldb/tools/lldb-dap/Handler/CompletionsHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/CompletionsHandler.cpp
@@ -8,156 +8,46 @@
 
 #include "DAP.h"
 #include "JSONUtils.h"
+#include "Protocol/ProtocolRequests.h"
+#include "Protocol/ProtocolTypes.h"
 #include "RequestHandler.h"
 #include "lldb/API/SBStringList.h"
 
-namespace lldb_dap {
+using namespace llvm;
+using namespace lldb_dap;
+using namespace lldb_dap::protocol;
 
-// "CompletionsRequest": {
-//   "allOf": [ { "$ref": "#/definitions/Request" }, {
-//     "type": "object",
-//     "description": "Returns a list of possible completions for a given caret
-//     position and text.\nThe CompletionsRequest may only be called if the
-//     'supportsCompletionsRequest' capability exists and is true.",
-//     "properties": {
-//       "command": {
-//         "type": "string",
-//         "enum": [ "completions" ]
-//       },
-//       "arguments": {
-//         "$ref": "#/definitions/CompletionsArguments"
-//       }
-//     },
-//     "required": [ "command", "arguments"  ]
-//   }]
-// },
-// "CompletionsArguments": {
-//   "type": "object",
-//   "description": "Arguments for 'completions' request.",
-//   "properties": {
-//     "frameId": {
-//       "type": "integer",
-//       "description": "Returns completions in the scope of this stack frame.
-//       If not specified, the completions are returned for the global scope."
-//     },
-//     "text": {
-//       "type": "string",
-//       "description": "One or more source lines. Typically this is the text a
-//       user has typed into the debug console before he asked for completion."
-//     },
-//     "column": {
-//       "type": "integer",
-//       "description": "The character position for which to determine the
-//       completion proposals."
-//     },
-//     "line": {
-//       "type": "integer",
-//       "description": "An optional line for which to determine the completion
-//       proposals. If missing the first line of the text is assumed."
-//     }
-//   },
-//   "required": [ "text", "column" ]
-// },
-// "CompletionsResponse": {
-//   "allOf": [ { "$ref": "#/definitions/Response" }, {
-//     "type": "object",
-//     "description": "Response to 'completions' request.",
-//     "properties": {
-//       "body": {
-//         "type": "object",
-//         "properties": {
-//           "targets": {
-//             "type": "array",
-//             "items": {
-//               "$ref": "#/definitions/CompletionItem"
-//             },
-//             "description": "The possible completions for ."
-//           }
-//         },
-//         "required": [ "targets" ]
-//       }
-//     },
-//     "required": [ "body" ]
-//   }]
-// },
-// "CompletionItem": {
-//   "type": "object",
-//   "description": "CompletionItems are the suggestions returned from the
-//   CompletionsRequest.", "properties": {
-//     "label": {
-//       "type": "string",
-//       "description": "The label of this completion item. By default this is
-//       also the text that is inserted when selecting this completion."
-//     },
-//     "text": {
-//       "type": "string",
-//       "description": "If text is not falsy then it is inserted instead of 
the
-//       label."
-//     },
-//     "sortText": {
-//       "type": "string",
-//       "description": "A string that should be used when comparing this item
-//       with other items. When `falsy` the label is used."
-//     },
-//     "type": {
-//       "$ref": "#/definitions/CompletionItemType",
-//       "description": "The item's type. Typically the client uses this
-//       information to render the item in the UI with an icon."
-//     },
-//     "start": {
-//       "type": "integer",
-//       "description": "This value determines the location (in the
-//       CompletionsRequest's 'text' attribute) where the completion text is
-//       added.\nIf missing the text is added at the location specified by the
-//       CompletionsRequest's 'column' attribute."
-//     },
-//     "length": {
-//       "type": "integer",
-//       "description": "This value determines how many characters are
-//       overwritten by the completion text.\nIf missing the value 0 is assumed
-//       which results in the completion text being inserted."
-//     }
-//   },
-//   "required": [ "label" ]
-// },
-// "CompletionItemType": {
-//   "type": "string",
-//   "description": "Some predefined types for the CompletionItem. Please note
-//   that not all clients have specific icons for all of them.", "enum": [
-//   "method", "function", "constructor", "field", "variable", "class",
-//   "interface", "module", "property", "unit", "value", "enum", "keyword",
-//   "snippet", "text", "color", "file", "reference", "customcolor" ]
-// }
-void CompletionsRequestHandler::operator()(
-    const llvm::json::Object &request) const {
-  llvm::json::Object response;
-  FillResponse(request, response);
-  llvm::json::Object body;
-  const auto *arguments = request.getObject("arguments");
+namespace lldb_dap {
 
+/// Returns a list of possible completions for a given caret position and text.
+///
+/// Clients should only call this request if the corresponding capability
+/// `supportsCompletionsRequest` is true.
+Expected<CompletionsResponseBody>
+CompletionsRequestHandler::Run(const CompletionsArguments &args) const {
   // If we have a frame, try to set the context for variable completions.
-  lldb::SBFrame frame = dap.GetLLDBFrame(*arguments);
+  lldb::SBFrame frame = dap.GetLLDBFrame(args.frameId);
   if (frame.IsValid()) {
     frame.GetThread().GetProcess().SetSelectedThread(frame.GetThread());
     frame.GetThread().SetSelectedFrame(frame.GetFrameID());
   }
 
-  std::string text = GetString(arguments, "text").value_or("").str();
-  auto original_column =
-      GetInteger<int64_t>(arguments, "column").value_or(text.size());
-  auto original_line = GetInteger<int64_t>(arguments, "line").value_or(1);
+  std::string text = args.text;
+  auto original_column = args.column;
+  auto original_line = args.line;
   auto offset = original_column - 1;
   if (original_line > 1) {
-    llvm::SmallVector<::llvm::StringRef, 2> lines;
-    llvm::StringRef(text).split(lines, '\n');
+    SmallVector<StringRef, 2> lines;
+    StringRef(text).split(lines, '\n');
     for (int i = 0; i < original_line - 1; i++) {
       offset += lines[i].size();
     }
   }
-  llvm::json::Array targets;
+
+  std::vector<CompletionItem> targets;
 
   bool had_escape_prefix =
-      llvm::StringRef(text).starts_with(dap.configuration.commandEscapePrefix);
+      StringRef(text).starts_with(dap.configuration.commandEscapePrefix);
   ReplMode completion_mode = dap.DetectReplMode(frame, text, true);
 
   // Handle the offset change introduced by stripping out the
@@ -165,10 +55,7 @@ void CompletionsRequestHandler::operator()(
   if (had_escape_prefix) {
     if (offset <
         static_cast<int64_t>(dap.configuration.commandEscapePrefix.size())) {
-      body.try_emplace("targets", std::move(targets));
-      response.try_emplace("body", std::move(body));
-      dap.SendJSON(llvm::json::Value(std::move(response)));
-      return;
+      return CompletionsResponseBody{targets};
     }
     offset -= dap.configuration.commandEscapePrefix.size();
   }
@@ -198,27 +85,27 @@ void CompletionsRequestHandler::operator()(
       std::string match = matches.GetStringAtIndex(i);
       std::string description = descriptions.GetStringAtIndex(i);
 
-      llvm::json::Object item;
-      llvm::StringRef match_ref = match;
-      for (llvm::StringRef commit_point : {".", "->"}) {
+      CompletionItem item;
+      StringRef match_ref = match;
+      for (StringRef commit_point : {".", "->"}) {
         if (match_ref.contains(commit_point)) {
           match_ref = match_ref.rsplit(commit_point).second;
         }
       }
-      EmplaceSafeString(item, "text", match_ref);
+      item.text = match_ref;
 
       if (description.empty())
-        EmplaceSafeString(item, "label", match);
+        item.label = match;
       else
-        EmplaceSafeString(item, "label", match + " -- " + description);
+        item.label = match + " -- " + description;
 
       targets.emplace_back(std::move(item));
     }
   }
 
-  body.try_emplace("targets", std::move(targets));
-  response.try_emplace("body", std::move(body));
-  dap.SendJSON(llvm::json::Value(std::move(response)));
+  CompletionsResponseBody body;
+  body.targets = std::move(targets);
+  return body;
 }
 
 } // namespace lldb_dap
diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h 
b/lldb/tools/lldb-dap/Handler/RequestHandler.h
index 16f8062f97d7b..5469cfbfa0321 100644
--- a/lldb/tools/lldb-dap/Handler/RequestHandler.h
+++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h
@@ -243,14 +243,17 @@ class BreakpointLocationsRequestHandler
                                  uint32_t end_line) const;
 };
 
-class CompletionsRequestHandler : public LegacyRequestHandler {
+class CompletionsRequestHandler
+    : public RequestHandler<protocol::CompletionsArguments,
+                            llvm::Expected<protocol::CompletionsResponseBody>> 
{
 public:
-  using LegacyRequestHandler::LegacyRequestHandler;
+  using RequestHandler::RequestHandler;
   static llvm::StringLiteral GetCommand() { return "completions"; }
   FeatureSet GetSupportedFeatures() const override {
     return {protocol::eAdapterFeatureCompletionsRequest};
   }
-  void operator()(const llvm::json::Object &request) const override;
+  llvm::Expected<protocol::CompletionsResponseBody>
+  Run(const protocol::CompletionsArguments &args) const override;
 };
 
 class ContinueRequestHandler
diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp 
b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp
index 29855ca50e9e0..40634d52a66fd 100644
--- a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp
+++ b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp
@@ -329,6 +329,17 @@ json::Value toJSON(const ContinueResponseBody &CRB) {
   return std::move(Body);
 }
 
+bool fromJSON(const json::Value &Params, CompletionsArguments &CA,
+              json::Path P) {
+  json::ObjectMapper O(Params, P);
+  return O && O.map("text", CA.text) && O.map("column", CA.column) &&
+         O.mapOptional("frameId", CA.frameId) && O.mapOptional("line", 
CA.line);
+}
+
+json::Value toJSON(const CompletionsResponseBody &CRB) {
+  return json::Object{{"targets", CRB.targets}};
+}
+
 bool fromJSON(const json::Value &Params, SetVariableArguments &SVA,
               json::Path P) {
   json::ObjectMapper O(Params, P);
diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h 
b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h
index c45ee10e77d1c..fbfa21a113b14 100644
--- a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h
+++ b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h
@@ -376,6 +376,35 @@ struct ContinueResponseBody {
 };
 llvm::json::Value toJSON(const ContinueResponseBody &);
 
+/// Arguments for `completions` request.
+struct CompletionsArguments {
+  /// Returns completions in the scope of this stack frame. If not specified,
+  /// the completions are returned for the global scope.
+  uint64_t frameId = LLDB_INVALID_FRAME_ID;
+
+  /// One or more source lines. Typically this is the text users have typed 
into
+  /// the debug console before they asked for completion.
+  std::string text;
+
+  /// The position within `text` for which to determine the completion
+  /// proposals. It is measured in UTF-16 code units and the client capability
+  /// `columnsStartAt1` determines whether it is 0- or 1-based.
+  int64_t column = 0;
+
+  /// A line for which to determine the completion proposals. If missing the
+  /// first line of the text is assumed.
+  int64_t line = 0;
+};
+bool fromJSON(const llvm::json::Value &, CompletionsArguments &,
+              llvm::json::Path);
+
+/// Response to `completions` request.
+struct CompletionsResponseBody {
+  /// The possible completions for a given caret position and text.
+  std::vector<CompletionItem> targets;
+};
+llvm::json::Value toJSON(const CompletionsResponseBody &);
+
 /// Arguments for `configurationDone` request.
 using ConfigurationDoneArguments = EmptyArguments;
 
diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp 
b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp
index 369858c3a5f4b..0708901d9ca05 100644
--- a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp
+++ b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp
@@ -200,6 +200,123 @@ bool fromJSON(const llvm::json::Value &Params, 
ChecksumAlgorithm &CA,
   return true;
 }
 
+bool fromJSON(const json::Value &Params, CompletionItemType &CIT,
+              json::Path P) {
+  auto raw_item_type = Params.getAsString();
+  if (!raw_item_type) {
+    P.report("expected a string");
+    return false;
+  }
+
+  std::optional<CompletionItemType> item_type =
+      StringSwitch<std::optional<CompletionItemType>>(*raw_item_type)
+          .Case("method", eCompletionItemTypeMethod)
+          .Case("function", eCompletionItemTypeFunction)
+          .Case("constructor", eCompletionItemTypeConstructor)
+          .Case("field", eCompletionItemTypeField)
+          .Case("variable", eCompletionItemTypeVariable)
+          .Case("class", eCompletionItemTypeClass)
+          .Case("interface", eCompletionItemTypeInterface)
+          .Case("module", eCompletionItemTypeModule)
+          .Case("property", eCompletionItemTypeProperty)
+          .Case("unit", eCompletionItemTypeUnit)
+          .Case("value", eCompletionItemTypeValue)
+          .Case("enum", eCompletionItemTypeEnum)
+          .Case("keyword", eCompletionItemTypeKeyword)
+          .Case("snippet", eCompletionItemTypeSnippet)
+          .Case("text", eCompletionItemTypeText)
+          .Case("color", eCompletionItemTypeColor)
+          .Case("file", eCompletionItemTypeFile)
+          .Case("reference", eCompletionItemTypeReference)
+          .Case("customcolor", eCompletionItemTypeCustomColor)
+          .Default(std::nullopt);
+
+  if (!item_type) {
+    P.report("unexpected value");
+    return false;
+  }
+
+  CIT = *item_type;
+  return true;
+}
+
+json::Value toJSON(const CompletionItemType &CIT) {
+  switch (CIT) {
+  case eCompletionItemTypeMethod:
+    return "method";
+  case eCompletionItemTypeFunction:
+    return "function";
+  case eCompletionItemTypeConstructor:
+    return "constructor";
+  case eCompletionItemTypeField:
+    return "field";
+  case eCompletionItemTypeVariable:
+    return "variable";
+  case eCompletionItemTypeClass:
+    return "class";
+  case eCompletionItemTypeInterface:
+    return "interface";
+  case eCompletionItemTypeModule:
+    return "module";
+  case eCompletionItemTypeProperty:
+    return "property";
+  case eCompletionItemTypeUnit:
+    return "unit";
+  case eCompletionItemTypeValue:
+    return "value";
+  case eCompletionItemTypeEnum:
+    return "enum";
+  case eCompletionItemTypeKeyword:
+    return "keyword";
+  case eCompletionItemTypeSnippet:
+    return "snippet";
+  case eCompletionItemTypeText:
+    return "text";
+  case eCompletionItemTypeColor:
+    return "color";
+  case eCompletionItemTypeFile:
+    return "file";
+  case eCompletionItemTypeReference:
+    return "reference";
+  case eCompletionItemTypeCustomColor:
+    return "customcolor";
+  }
+  llvm_unreachable("unhandled CompletionItemType.");
+}
+
+bool fromJSON(const json::Value &Params, CompletionItem &CI, json::Path P) {
+  json::ObjectMapper O(Params, P);
+  return O && O.map("label", CI.label) && O.mapOptional("text", CI.text) &&
+         O.mapOptional("sortText", CI.sortText) &&
+         O.mapOptional("detail", CI.detail) && O.mapOptional("type", CI.type) 
&&
+         O.mapOptional("start", CI.start) &&
+         O.mapOptional("length", CI.length) &&
+         O.mapOptional("selectionStart", CI.selectionStart) &&
+         O.mapOptional("selectionLength", CI.selectionLength);
+}
+json::Value toJSON(const CompletionItem &CI) {
+  json::Object result{{"label", CI.label}};
+
+  if (!CI.text.empty())
+    result.insert({"text", CI.text});
+  if (!CI.sortText.empty())
+    result.insert({"sortText", CI.sortText});
+  if (!CI.detail.empty())
+    result.insert({"detail", CI.detail});
+  if (CI.type)
+    result.insert({"type", CI.type});
+  if (CI.start)
+    result.insert({"start", CI.start});
+  if (CI.length)
+    result.insert({"length", CI.length});
+  if (CI.selectionStart)
+    result.insert({"selectionStart", CI.selectionStart});
+  if (CI.selectionLength)
+    result.insert({"selectionLength", CI.selectionLength});
+
+  return result;
+}
+
 json::Value toJSON(const BreakpointModeApplicability &BMA) {
   switch (BMA) {
   case eBreakpointModeApplicabilitySource:
diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h 
b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h
index c4be7911a662b..7a7609797c104 100644
--- a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h
+++ b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h
@@ -109,6 +109,84 @@ enum ChecksumAlgorithm : unsigned {
 bool fromJSON(const llvm::json::Value &, ChecksumAlgorithm &, 
llvm::json::Path);
 llvm::json::Value toJSON(const ChecksumAlgorithm &);
 
+/// Some predefined types for the CompletionItem. Please note that not all
+/// clients have specific icons for all of them.
+enum CompletionItemType : unsigned {
+  eCompletionItemTypeMethod,
+  eCompletionItemTypeFunction,
+  eCompletionItemTypeConstructor,
+  eCompletionItemTypeField,
+  eCompletionItemTypeVariable,
+  eCompletionItemTypeClass,
+  eCompletionItemTypeInterface,
+  eCompletionItemTypeModule,
+  eCompletionItemTypeProperty,
+  eCompletionItemTypeUnit,
+  eCompletionItemTypeValue,
+  eCompletionItemTypeEnum,
+  eCompletionItemTypeKeyword,
+  eCompletionItemTypeSnippet,
+  eCompletionItemTypeText,
+  eCompletionItemTypeColor,
+  eCompletionItemTypeFile,
+  eCompletionItemTypeReference,
+  eCompletionItemTypeCustomColor,
+};
+bool fromJSON(const llvm::json::Value &, CompletionItemType &,
+              llvm::json::Path);
+llvm::json::Value toJSON(const CompletionItemType &);
+
+/// `CompletionItems` are the suggestions returned from the `completions`
+/// request.
+struct CompletionItem {
+  /// The label of this completion item. By default this is also the text that
+  /// is inserted when selecting this completion.
+  std::string label;
+
+  /// If text is returned and not an empty string, then it is inserted instead
+  /// of the label.
+  std::string text;
+
+  /// A string that should be used when comparing this item with other items. 
If
+  /// not returned or an empty string, the `label` is used instead.
+  std::string sortText;
+
+  /// A human-readable string with additional information about this item, like
+  /// type or symbol information.
+  std::string detail;
+
+  /// The item's type. Typically the client uses this information to render the
+  /// item in the UI with an icon.
+  std::optional<CompletionItemType> type;
+
+  /// Start position (within the `text` attribute of the `completions`
+  /// request) where the completion text is added. The position is measured in
+  /// UTF-16 code units and the client capability `columnsStartAt1` determines
+  /// whether it is 0- or 1-based. If the start position is omitted the text
+  /// is added at the location specified by the `column` attribute of the
+  /// `completions` request.
+  int64_t start = 0;
+
+  /// Length determines how many characters are overwritten by the completion
+  /// text and it is measured in UTF-16 code units. If missing the value 0 is
+  /// assumed which results in the completion text being inserted.
+  int64_t length = 0;
+
+  /// Determines the start of the new selection after the text has been
+  /// inserted (or replaced). `selectionStart` is measured in UTF-16 code
+  /// units and must be in the range 0 and length of the completion text. If
+  /// omitted the selection starts at the end of the completion text.
+  int64_t selectionStart = 0;
+
+  /// Determines the length of the new selection after the text has been
+  /// inserted (or replaced) and it is measured in UTF-16 code units. The
+  /// selection can not extend beyond the bounds of the completion text. If
+  /// omitted the length is assumed to be 0.
+  int64_t selectionLength = 0;
+};
+bool fromJSON(const llvm::json::Value &, CompletionItem &, llvm::json::Path);
+llvm::json::Value toJSON(const CompletionItem &);
+
 /// Describes one or more type of breakpoint a BreakpointMode applies to. This
 /// is a non-exhaustive enumeration and may expand as future breakpoint types
 /// are added.

>From 7d118717fb2eb317145dfcf9778b1de4591aeddb Mon Sep 17 00:00:00 2001
From: John Harrison <harj...@google.com>
Date: Tue, 12 Aug 2025 16:30:43 -0700
Subject: [PATCH 2/4] Adjusting return value of CompletionsHandler::Run().

---
 lldb/tools/lldb-dap/Handler/CompletionsHandler.cpp | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/lldb/tools/lldb-dap/Handler/CompletionsHandler.cpp 
b/lldb/tools/lldb-dap/Handler/CompletionsHandler.cpp
index 7507aa17f5421..3f6e07791d4ea 100644
--- a/lldb/tools/lldb-dap/Handler/CompletionsHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/CompletionsHandler.cpp
@@ -103,9 +103,7 @@ CompletionsRequestHandler::Run(const CompletionsArguments 
&args) const {
     }
   }
 
-  CompletionsResponseBody body;
-  body.targets = std::move(targets);
-  return body;
+  return CompletionsResponseBody{targets};
 }
 
 } // namespace lldb_dap

>From 43138b7afcc2bfab03129fc8b47bfd0ac61ef081 Mon Sep 17 00:00:00 2001
From: John Harrison <harj...@google.com>
Date: Tue, 12 Aug 2025 17:00:27 -0700
Subject: [PATCH 3/4] Definining a `LLDB_DAP_INVALID_FRAME_ID` value to help
 shortcut the frame lookup if its not specified.

---
 lldb/tools/lldb-dap/DAP.cpp                            |  7 +++++--
 .../Handler/DataBreakpointInfoRequestHandler.cpp       |  2 +-
 lldb/tools/lldb-dap/Protocol/ProtocolRequests.h        | 10 ++++++----
 3 files changed, 12 insertions(+), 7 deletions(-)

diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp
index ce910b1f60b85..828a09a14c4bf 100644
--- a/lldb/tools/lldb-dap/DAP.cpp
+++ b/lldb/tools/lldb-dap/DAP.cpp
@@ -552,6 +552,9 @@ lldb::SBThread DAP::GetLLDBThread(const llvm::json::Object 
&arguments) {
 }
 
 lldb::SBFrame DAP::GetLLDBFrame(uint64_t frame_id) {
+  if (frame_id == LLDB_DAP_INVALID_FRAME_ID)
+    return lldb::SBFrame();
+
   lldb::SBProcess process = target.GetProcess();
   // Upper 32 bits is the thread index ID
   lldb::SBThread thread =
@@ -561,8 +564,8 @@ lldb::SBFrame DAP::GetLLDBFrame(uint64_t frame_id) {
 }
 
 lldb::SBFrame DAP::GetLLDBFrame(const llvm::json::Object &arguments) {
-  const auto frame_id =
-      GetInteger<uint64_t>(arguments, "frameId").value_or(UINT64_MAX);
+  const auto frame_id = GetInteger<uint64_t>(arguments, "frameId")
+                            .value_or(LLDB_DAP_INVALID_FRAME_ID);
   return GetLLDBFrame(frame_id);
 }
 
diff --git a/lldb/tools/lldb-dap/Handler/DataBreakpointInfoRequestHandler.cpp 
b/lldb/tools/lldb-dap/Handler/DataBreakpointInfoRequestHandler.cpp
index 8cb25d0603449..87b93fc999ecd 100644
--- a/lldb/tools/lldb-dap/Handler/DataBreakpointInfoRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/DataBreakpointInfoRequestHandler.cpp
@@ -23,7 +23,7 @@ llvm::Expected<protocol::DataBreakpointInfoResponseBody>
 DataBreakpointInfoRequestHandler::Run(
     const protocol::DataBreakpointInfoArguments &args) const {
   protocol::DataBreakpointInfoResponseBody response;
-  lldb::SBFrame frame = dap.GetLLDBFrame(args.frameId.value_or(UINT64_MAX));
+  lldb::SBFrame frame = dap.GetLLDBFrame(args.frameId);
   lldb::SBValue variable = dap.variables.FindVariable(
       args.variablesReference.value_or(0), args.name);
   std::string addr, size;
diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h 
b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h
index fbfa21a113b14..7c08a8887c081 100644
--- a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h
+++ b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h
@@ -310,6 +310,8 @@ bool fromJSON(const llvm::json::Value &, 
LaunchRequestArguments &,
 using LaunchResponse = VoidResponse;
 
 #define LLDB_DAP_INVALID_PORT -1
+/// An invalid 'frameId' default value.
+#define LLDB_DAP_INVALID_FRAME_ID UINT64_MAX
 
 /// lldb-dap specific attach arguments.
 struct AttachRequestArguments {
@@ -380,7 +382,7 @@ llvm::json::Value toJSON(const ContinueResponseBody &);
 struct CompletionsArguments {
   /// Returns completions in the scope of this stack frame. If not specified,
   /// the completions are returned for the global scope.
-  uint64_t frameId = LLDB_INVALID_FRAME_ID;
+  uint64_t frameId = LLDB_DAP_INVALID_FRAME_ID;
 
   /// One or more source lines. Typically this is the text users have typed 
into
   /// the debug console before they asked for completion.
@@ -484,7 +486,7 @@ struct ScopesArguments {
   /// Retrieve the scopes for the stack frame identified by `frameId`. The
   /// `frameId` must have been obtained in the current suspended state. See
   /// 'Lifetime of Object References' in the Overview section for details.
-  uint64_t frameId = LLDB_INVALID_FRAME_ID;
+  uint64_t frameId = LLDB_DAP_INVALID_FRAME_ID;
 };
 bool fromJSON(const llvm::json::Value &, ScopesArguments &, llvm::json::Path);
 
@@ -570,7 +572,7 @@ using StepInResponse = VoidResponse;
 /// Arguments for `stepInTargets` request.
 struct StepInTargetsArguments {
   /// The stack frame for which to retrieve the possible step-in targets.
-  uint64_t frameId = LLDB_INVALID_FRAME_ID;
+  uint64_t frameId = LLDB_DAP_INVALID_FRAME_ID;
 };
 bool fromJSON(const llvm::json::Value &, StepInTargetsArguments &,
               llvm::json::Path);
@@ -719,7 +721,7 @@ struct DataBreakpointInfoArguments {
   /// When `name` is an expression, evaluate it in the scope of this stack
   /// frame. If not specified, the expression is evaluated in the global scope.
   /// When `asAddress` is true, the `frameId` is ignored.
-  std::optional<uint64_t> frameId;
+  uint64_t frameId = LLDB_DAP_INVALID_FRAME_ID;
 
   /// If specified, a debug adapter should return information for the range of
   /// memory extending `bytes` number of bytes from the address or variable

>From ab3d8d46849f7b8d918c5cf71a49572ab637f169 Mon Sep 17 00:00:00 2001
From: John Harrison <harj...@google.com>
Date: Tue, 19 Aug 2025 09:23:38 -0700
Subject: [PATCH 4/4] Adding unit tests for parsing of DAP CompletionItem
 types.

---
 lldb/unittests/DAP/ProtocolTypesTest.cpp | 69 ++++++++++++++++++++++++
 1 file changed, 69 insertions(+)

diff --git a/lldb/unittests/DAP/ProtocolTypesTest.cpp 
b/lldb/unittests/DAP/ProtocolTypesTest.cpp
index 4aab2dc223134..c5d47fcb08da4 100644
--- a/lldb/unittests/DAP/ProtocolTypesTest.cpp
+++ b/lldb/unittests/DAP/ProtocolTypesTest.cpp
@@ -1004,3 +1004,72 @@ TEST(ProtocolTypesTest, VariablesResponseBody) {
   ASSERT_THAT_EXPECTED(expected, llvm::Succeeded());
   EXPECT_EQ(pp(*expected), pp(response));
 }
+
+TEST(ProtocolTypesTest, CompletionItem) {
+  CompletionItem item;
+  item.label = "label";
+  item.text = "text";
+  item.sortText = "sortText";
+  item.detail = "detail";
+  item.type = eCompletionItemTypeConstructor;
+  item.start = 1;
+  item.length = 3;
+  item.selectionStart = 4;
+  item.selectionLength = 8;
+
+  const StringRef json = R"({
+  "detail": "detail",
+  "label": "label",
+  "length": 3,
+  "selectionLength": 8,
+  "selectionStart": 4,
+  "sortText": "sortText",
+  "start": 1,
+  "text": "text",
+  "type": "constructor"
+})";
+
+  EXPECT_EQ(pp(Value(item)), json);
+  EXPECT_THAT_EXPECTED(json::parse(json), HasValue(Value(item)));
+}
+
+TEST(ProtocolTypesTest, CompletionsArguments) {
+  llvm::Expected<CompletionsArguments> expected =
+      parse<CompletionsArguments>(R"({
+    "column": 8,
+    "frameId": 7,
+    "line": 9,
+    "text": "abc"
+  })");
+  ASSERT_THAT_EXPECTED(expected, llvm::Succeeded());
+  EXPECT_EQ(expected->frameId, 7u);
+  EXPECT_EQ(expected->text, "abc");
+  EXPECT_EQ(expected->column, 8);
+  EXPECT_EQ(expected->line, 9);
+
+  // Check required keys.
+  EXPECT_THAT_EXPECTED(parse<CompletionsArguments>(R"({})"),
+                       FailedWithMessage("missing value at (root).text"));
+  EXPECT_THAT_EXPECTED(parse<CompletionsArguments>(R"({"text":"abc"})"),
+                       FailedWithMessage("missing value at (root).column"));
+}
+
+TEST(ProtocolTypesTest, CompletionsResponseBody) {
+  CompletionItem item;
+  item.label = "label";
+  item.text = "text";
+  item.detail = "detail";
+  CompletionsResponseBody response{{item}};
+
+  Expected<json::Value> expected = json::parse(R"({
+      "targets": [
+        {
+          "detail": "detail",
+          "label": "label",
+          "text": "text"
+        }
+      ]
+    })");
+  ASSERT_THAT_EXPECTED(expected, llvm::Succeeded());
+  EXPECT_EQ(pp(*expected), pp(response));
+}

_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to