[Lldb-commits] [lldb] [lldb-dap] Validate utf8 protocol messages. (PR #181261)
John Harrison via lldb-commits
lldb-commits at lists.llvm.org
Fri Feb 13 10:23:30 PST 2026
https://github.com/ashgti updated https://github.com/llvm/llvm-project/pull/181261
>From 3ef369da5dba9ef0c509459b7c4bc00f0d2c857f Mon Sep 17 00:00:00 2001
From: John Harrison <harjohn at google.com>
Date: Thu, 12 Feb 2026 14:51:04 -0800
Subject: [PATCH 1/4] [lldb-dap] Validate utf8 protocol messages.
I ran into this while debugging a different issue, but when we calcualte the 'value' field of a variable we were not ensuring the contents were valid utf8. If assertions are enabled then llvm::json::Value will assert that the string contains invalid utf8.
To address this I added a wrapper type (`lldb_dap::protocol::SanitizedString`) that can be used as a thin wrapper around `std::string` to ensure a field contains valid utf8.
I've used it in a handful of places that I believe could contain invalid utf8 output, but we can add it to other places as well in the protocol types.
---
.../lldb-dap/variables/TestDAP_variables.py | 46 +++++++++++++------
.../API/tools/lldb-dap/variables/main.cpp | 4 ++
lldb/tools/lldb-dap/DAP.cpp | 7 +--
lldb/tools/lldb-dap/Protocol/ProtocolBase.cpp | 17 +++++++
lldb/tools/lldb-dap/Protocol/ProtocolBase.h | 19 ++++++++
.../lldb-dap/Protocol/ProtocolRequests.h | 2 +-
lldb/tools/lldb-dap/Protocol/ProtocolTypes.h | 3 +-
7 files changed, 80 insertions(+), 18 deletions(-)
diff --git a/lldb/test/API/tools/lldb-dap/variables/TestDAP_variables.py b/lldb/test/API/tools/lldb-dap/variables/TestDAP_variables.py
index 1dbb0143e7a55..f737d41eaecec 100644
--- a/lldb/test/API/tools/lldb-dap/variables/TestDAP_variables.py
+++ b/lldb/test/API/tools/lldb-dap/variables/TestDAP_variables.py
@@ -188,6 +188,8 @@ def do_test_scopes_variables_setVariable_evaluate(
},
"readOnly": True,
},
+ "valid_str": {},
+ "malformed_str": {},
"x": {"equals": {"type": "int"}},
}
@@ -340,9 +342,9 @@ def do_test_scopes_variables_setVariable_evaluate(
verify_locals["argc"]["equals"]["value"] = "123"
verify_locals["pt"]["children"]["x"]["equals"]["value"] = "111"
- verify_locals["x @ main.cpp:19"] = {"equals": {"type": "int", "value": "89"}}
- verify_locals["x @ main.cpp:21"] = {"equals": {"type": "int", "value": "42"}}
- verify_locals["x @ main.cpp:23"] = {"equals": {"type": "int", "value": "72"}}
+ verify_locals["x @ main.cpp:23"] = {"equals": {"type": "int", "value": "89"}}
+ verify_locals["x @ main.cpp:25"] = {"equals": {"type": "int", "value": "42"}}
+ verify_locals["x @ main.cpp:27"] = {"equals": {"type": "int", "value": "72"}}
self.verify_variables(verify_locals, self.dap_server.get_local_variables())
@@ -350,22 +352,22 @@ def do_test_scopes_variables_setVariable_evaluate(
self.assertFalse(self.set_local("x2", 9)["success"])
self.assertFalse(self.set_local("x @ main.cpp:0", 9)["success"])
- self.assertTrue(self.set_local("x @ main.cpp:19", 19)["success"])
- self.assertTrue(self.set_local("x @ main.cpp:21", 21)["success"])
- self.assertTrue(self.set_local("x @ main.cpp:23", 23)["success"])
+ self.assertTrue(self.set_local("x @ main.cpp:23", 19)["success"])
+ self.assertTrue(self.set_local("x @ main.cpp:25", 21)["success"])
+ self.assertTrue(self.set_local("x @ main.cpp:27", 23)["success"])
# The following should have no effect
- self.assertFalse(self.set_local("x @ main.cpp:23", "invalid")["success"])
+ self.assertFalse(self.set_local("x @ main.cpp:27", "invalid")["success"])
- verify_locals["x @ main.cpp:19"]["equals"]["value"] = "19"
- verify_locals["x @ main.cpp:21"]["equals"]["value"] = "21"
- verify_locals["x @ main.cpp:23"]["equals"]["value"] = "23"
+ verify_locals["x @ main.cpp:23"]["equals"]["value"] = "19"
+ verify_locals["x @ main.cpp:25"]["equals"]["value"] = "21"
+ verify_locals["x @ main.cpp:27"]["equals"]["value"] = "23"
self.verify_variables(verify_locals, self.dap_server.get_local_variables())
# The plain x variable shold refer to the innermost x
self.assertTrue(self.set_local("x", 22)["success"])
- verify_locals["x @ main.cpp:23"]["equals"]["value"] = "22"
+ verify_locals["x @ main.cpp:27"]["equals"]["value"] = "22"
self.verify_variables(verify_locals, self.dap_server.get_local_variables())
@@ -382,9 +384,9 @@ def do_test_scopes_variables_setVariable_evaluate(
names = [var["name"] for var in locals]
# The first shadowed x shouldn't have a suffix anymore
verify_locals["x"] = {"equals": {"type": "int", "value": "19"}}
- self.assertNotIn("x @ main.cpp:19", names)
- self.assertNotIn("x @ main.cpp:21", names)
self.assertNotIn("x @ main.cpp:23", names)
+ self.assertNotIn("x @ main.cpp:25", names)
+ self.assertNotIn("x @ main.cpp:27", names)
self.verify_variables(verify_locals, locals)
@@ -455,6 +457,22 @@ def do_test_scopes_and_evaluate_expansion(self, enableAutoVariableSummaries: boo
},
"readOnly": True,
},
+ "valid_str": {
+ "equals": {
+ "type": "const char *",
+ },
+ "matches": {
+ "value": re.compile(r'0x\w+ "πΆπ°LπΎπ CππΌπ΄π"'),
+ },
+ },
+ "malformed_str": {
+ "equals": {
+ "type": "const char *",
+ },
+ "matches": {
+ "value": re.compile(r'0x\w+ "lone trailing \\x81\\x82 bytes"'),
+ },
+ },
"x": {
"equals": {"type": "int"},
"missing": ["indexedVariables"],
@@ -678,6 +696,8 @@ def test_return_variables(self):
"argc": {},
"argv": {},
"pt": {"readOnly": True},
+ "valid_str": {},
+ "malformed_str": {},
"x": {},
"return_result": {"equals": {"type": "int"}},
}
diff --git a/lldb/test/API/tools/lldb-dap/variables/main.cpp b/lldb/test/API/tools/lldb-dap/variables/main.cpp
index 0e363001f2f42..04fc62f02c22f 100644
--- a/lldb/test/API/tools/lldb-dap/variables/main.cpp
+++ b/lldb/test/API/tools/lldb-dap/variables/main.cpp
@@ -5,6 +5,7 @@ struct PointType {
int y;
int buffer[BUFFER_SIZE];
};
+#include <cstdio>
#include <vector>
int g_global = 123;
static int s_global = 234;
@@ -16,6 +17,9 @@ int main(int argc, char const *argv[]) {
PointType pt = {11, 22, {0}};
for (int i = 0; i < BUFFER_SIZE; ++i)
pt.buffer[i] = i;
+ const char *valid_str = "πΆπ°LπΎπ CππΌπ΄π";
+ const char *malformed_str = "lone trailing \x81\x82 bytes";
+ printf("print malformed utf8 %s %s\n", valid_str, malformed_str);
int x = s_global - g_global - pt.y; // breakpoint 1
{
int x = 42;
diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp
index b76b05c5d1459..a629453dd5347 100644
--- a/lldb/tools/lldb-dap/DAP.cpp
+++ b/lldb/tools/lldb-dap/DAP.cpp
@@ -411,9 +411,10 @@ void DAP::SendOutput(OutputType o, const llvm::StringRef output) {
if (end == llvm::StringRef::npos)
end = output.size() - 1;
llvm::json::Object event(CreateEventObject("output"));
- llvm::json::Object body;
- body.try_emplace("category", category);
- EmplaceSafeString(body, "output", output.slice(idx, end + 1).str());
+ llvm::json::Object body{
+ {"category", category},
+ {"output", protocol::SanitizedString(output.slice(idx, end + 1).str())},
+ };
event.try_emplace("body", std::move(body));
SendJSON(llvm::json::Value(std::move(event)));
idx = end + 1;
diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolBase.cpp b/lldb/tools/lldb-dap/Protocol/ProtocolBase.cpp
index 72359214c8537..a9a929f9b88d2 100644
--- a/lldb/tools/lldb-dap/Protocol/ProtocolBase.cpp
+++ b/lldb/tools/lldb-dap/Protocol/ProtocolBase.cpp
@@ -57,6 +57,23 @@ bool fromJSON(const json::Value &Params, MessageType &M, json::Path P) {
return true;
}
+json::Value toJSON(const SanitizedString &S) {
+ if (LLVM_LIKELY(llvm::json::isUTF8(std::string(S))))
+ return std::string(S);
+ llvm::errs() << "Here!\n";
+ return llvm::json::fixUTF8(std::string(S));
+}
+
+bool fromJSON(const llvm::json::Value &Param, SanitizedString &Str,
+ llvm::json::Path Path) {
+ if (auto s = Param.getAsString()) {
+ Str = *s;
+ return true;
+ }
+ Path.report("expected string");
+ return false;
+}
+
json::Value toJSON(const Request &R) {
assert(R.seq != kCalculateSeq && "invalid seq");
diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolBase.h b/lldb/tools/lldb-dap/Protocol/ProtocolBase.h
index 09ce6802b17c0..3053312c4660f 100644
--- a/lldb/tools/lldb-dap/Protocol/ProtocolBase.h
+++ b/lldb/tools/lldb-dap/Protocol/ProtocolBase.h
@@ -20,6 +20,7 @@
#ifndef LLDB_TOOLS_LLDB_DAP_PROTOCOL_PROTOCOL_BASE_H
#define LLDB_TOOLS_LLDB_DAP_PROTOCOL_PROTOCOL_BASE_H
+#include "llvm/ADT/StringRef.h"
#include "llvm/Support/JSON.h"
#include <cstdint>
#include <optional>
@@ -37,6 +38,24 @@ using Id = uint64_t;
/// the current session.
static constexpr Id kCalculateSeq = UINT64_MAX;
+/// A wrapper around a string to ensure the contents are sanitized as utf8
+/// during serialization. This value should be used for any strings that may
+/// contain raw data like variable values.
+class SanitizedString {
+public:
+ SanitizedString(std::string str) : m_str(str) {}
+ SanitizedString(llvm::StringRef str) : m_str(str.str()) {}
+ SanitizedString(const char *str) : m_str(str) {}
+ SanitizedString() = default;
+
+ operator std::string() const { return m_str; }
+
+private:
+ std::string m_str;
+};
+llvm::json::Value toJSON(const SanitizedString &s);
+bool fromJSON(const llvm::json::Value &, SanitizedString &, llvm::json::Path);
+
/// A client or debug adapter initiated request.
struct Request {
/// The command to execute.
diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h
index 28c9f48200e0c..af50e77ce6ab2 100644
--- a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h
+++ b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h
@@ -452,7 +452,7 @@ bool fromJSON(const llvm::json::Value &, SetVariableArguments &,
/// Response to `setVariable` request.
struct SetVariableResponseBody {
/// The new value of the variable.
- std::string value;
+ SanitizedString value;
/// The type of the new value. Typically shown in the UI when hovering over
/// the value.
diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h
index 71046d24c9787..e627b02e37bd1 100644
--- a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h
+++ b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h
@@ -21,6 +21,7 @@
#define LLDB_TOOLS_LLDB_DAP_PROTOCOL_PROTOCOL_TYPES_H
#include "Protocol/DAPTypes.h"
+#include "Protocol/ProtocolBase.h"
#include "lldb/lldb-defines.h"
#include "lldb/lldb-types.h"
#include "llvm/ADT/DenseSet.h"
@@ -942,7 +943,7 @@ struct Variable {
/// its children are not yet visible.
///
/// An empty string can be used if no value should be shown in the UI.
- std::string value;
+ SanitizedString value;
/// The type of the variable's value. Typically shown in the UI when hovering
/// over the value.
>From 6f7a944c287106d05389e5d833fde762ade42049 Mon Sep 17 00:00:00 2001
From: John Harrison <harjohn at google.com>
Date: Thu, 12 Feb 2026 15:11:38 -0800
Subject: [PATCH 2/4] Adding unit tests and removing debug logging.
---
lldb/tools/lldb-dap/Protocol/ProtocolBase.cpp | 1 -
lldb/unittests/DAP/CMakeLists.txt | 1 +
lldb/unittests/DAP/ProtocolBaseTest.cpp | 29 +++++++++++++++++++
3 files changed, 30 insertions(+), 1 deletion(-)
create mode 100644 lldb/unittests/DAP/ProtocolBaseTest.cpp
diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolBase.cpp b/lldb/tools/lldb-dap/Protocol/ProtocolBase.cpp
index a9a929f9b88d2..de0f815d443bc 100644
--- a/lldb/tools/lldb-dap/Protocol/ProtocolBase.cpp
+++ b/lldb/tools/lldb-dap/Protocol/ProtocolBase.cpp
@@ -60,7 +60,6 @@ bool fromJSON(const json::Value &Params, MessageType &M, json::Path P) {
json::Value toJSON(const SanitizedString &S) {
if (LLVM_LIKELY(llvm::json::isUTF8(std::string(S))))
return std::string(S);
- llvm::errs() << "Here!\n";
return llvm::json::fixUTF8(std::string(S));
}
diff --git a/lldb/unittests/DAP/CMakeLists.txt b/lldb/unittests/DAP/CMakeLists.txt
index 97f9cad7477ed..53e0fde5687ec 100644
--- a/lldb/unittests/DAP/CMakeLists.txt
+++ b/lldb/unittests/DAP/CMakeLists.txt
@@ -10,6 +10,7 @@ add_lldb_unittest(DAPTests
Handler/ContinueTest.cpp
JSONUtilsTest.cpp
LLDBUtilsTest.cpp
+ ProtocolBaseTest.cpp
ProtocolEventsTest.cpp
ProtocolRequestsTest.cpp
ProtocolTypesTest.cpp
diff --git a/lldb/unittests/DAP/ProtocolBaseTest.cpp b/lldb/unittests/DAP/ProtocolBaseTest.cpp
new file mode 100644
index 0000000000000..3eb5551f7f41c
--- /dev/null
+++ b/lldb/unittests/DAP/ProtocolBaseTest.cpp
@@ -0,0 +1,29 @@
+//===----------------------------------------------------------------------===//
+//
+// 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/ProtocolBase.h"
+#include "TestingSupport/TestUtilities.h"
+#include "llvm/Testing/Support/Error.h"
+#include <gtest/gtest.h>
+
+using namespace llvm;
+using namespace lldb_dap::protocol;
+using lldb_private::PrettyPrint;
+using llvm::json::parse;
+using llvm::json::Value;
+
+TEST(ProtocolBaseTest, SanitizedString) {
+ for (auto [input, json] : std::vector<std::pair<const char *, const char *>>{
+ {"valid str", R"("valid str")"},
+ {"lone trailing \x81\x82 bytes", R"("lone trailing οΏ½οΏ½ bytes")"}}) {
+ SanitizedString str = input;
+ Expected<Value> expected_str = parse(json);
+ ASSERT_THAT_EXPECTED(expected_str, llvm::Succeeded());
+ EXPECT_EQ(PrettyPrint(*expected_str), PrettyPrint(str));
+ }
+}
>From 48dc1eb5f1538ae23b099a8cfd824687edccc4a3 Mon Sep 17 00:00:00 2001
From: John Harrison <harjohn at google.com>
Date: Thu, 12 Feb 2026 17:18:27 -0800
Subject: [PATCH 3/4] Converting all std::string in protocol to String.
---
lldb/tools/lldb-dap/DAP.cpp | 41 +++---
lldb/tools/lldb-dap/DAP.h | 10 +-
.../DataBreakpointInfoRequestHandler.cpp | 9 +-
.../Handler/DisassembleRequestHandler.cpp | 2 +-
.../Handler/ExceptionInfoRequestHandler.cpp | 4 +-
.../tools/lldb-dap/Handler/RequestHandler.cpp | 16 +--
lldb/tools/lldb-dap/Handler/RequestHandler.h | 2 +-
.../SetExceptionBreakpointsRequestHandler.cpp | 8 +-
.../Handler/StackTraceRequestHandler.cpp | 7 +-
lldb/tools/lldb-dap/JSONUtils.cpp | 10 +-
lldb/tools/lldb-dap/JSONUtils.h | 6 +-
lldb/tools/lldb-dap/LLDBUtils.cpp | 4 +-
lldb/tools/lldb-dap/LLDBUtils.h | 5 +-
lldb/tools/lldb-dap/Protocol/DAPTypes.cpp | 6 +-
lldb/tools/lldb-dap/Protocol/DAPTypes.h | 8 +-
lldb/tools/lldb-dap/Protocol/ProtocolBase.cpp | 43 ++++--
lldb/tools/lldb-dap/Protocol/ProtocolBase.h | 66 ++++++---
.../lldb-dap/Protocol/ProtocolRequests.cpp | 10 +-
.../lldb-dap/Protocol/ProtocolRequests.h | 100 ++++++-------
lldb/tools/lldb-dap/Protocol/ProtocolTypes.h | 133 +++++++++---------
lldb/tools/lldb-dap/ProtocolUtils.cpp | 12 +-
lldb/tools/lldb-dap/tool/lldb-dap.cpp | 4 +-
lldb/unittests/DAP/ProtocolBaseTest.cpp | 2 +-
lldb/unittests/DAP/ProtocolTypesTest.cpp | 2 +-
lldb/unittests/DAP/TestBase.cpp | 2 +-
25 files changed, 279 insertions(+), 233 deletions(-)
diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp
index a629453dd5347..43038fcff43ef 100644
--- a/lldb/tools/lldb-dap/DAP.cpp
+++ b/lldb/tools/lldb-dap/DAP.cpp
@@ -123,14 +123,14 @@ static std::string capitalize(llvm::StringRef str) {
llvm::StringRef DAP::debug_adapter_path = "";
DAP::DAP(Log &log, const ReplMode default_repl_mode,
- std::vector<std::string> pre_init_commands, bool no_lldbinit,
+ std::vector<String> pre_init_commands, bool no_lldbinit,
llvm::StringRef client_name, DAPTransport &transport, MainLoop &loop)
: log(log), transport(transport), broadcaster("lldb-dap"),
progress_event_reporter(
[&](const ProgressEvent &event) { SendJSON(event.ToJSON()); }),
repl_mode(default_repl_mode), no_lldbinit(no_lldbinit),
m_client_name(client_name), m_loop(loop) {
- configuration.preInitCommands = std::move(pre_init_commands);
+ configuration.preInitCommands = pre_init_commands;
RegisterRequests();
}
@@ -413,7 +413,7 @@ void DAP::SendOutput(OutputType o, const llvm::StringRef output) {
llvm::json::Object event(CreateEventObject("output"));
llvm::json::Object body{
{"category", category},
- {"output", protocol::SanitizedString(output.slice(idx, end + 1).str())},
+ {"output", protocol::String(output.slice(idx, end + 1).str())},
};
event.try_emplace("body", std::move(body));
SendJSON(llvm::json::Value(std::move(event)));
@@ -604,7 +604,7 @@ ReplMode DAP::DetectReplMode(lldb::SBFrame &frame, std::string &expression,
bool partial_expression) {
// Check for the escape hatch prefix.
if (llvm::StringRef expr_ref = expression;
- expr_ref.consume_front(configuration.commandEscapePrefix)) {
+ expr_ref.consume_front(configuration.commandEscapePrefix.str())) {
expression = expr_ref;
return ReplMode::Command;
}
@@ -722,7 +722,7 @@ DAP::ResolveAssemblySource(lldb::SBAddress address) {
}
bool DAP::RunLLDBCommands(llvm::StringRef prefix,
- llvm::ArrayRef<std::string> commands) {
+ llvm::ArrayRef<String> commands) {
bool required_command_failed = false;
std::string output = ::RunLLDBCommands(
debugger, prefix, commands, required_command_failed,
@@ -741,15 +741,13 @@ static llvm::Error createRunLLDBCommandsErrorMessage(llvm::StringRef category) {
.c_str());
}
-llvm::Error
-DAP::RunAttachCommands(llvm::ArrayRef<std::string> attach_commands) {
+llvm::Error DAP::RunAttachCommands(llvm::ArrayRef<String> attach_commands) {
if (!RunLLDBCommands("Running attachCommands:", attach_commands))
return createRunLLDBCommandsErrorMessage("attach");
return llvm::Error::success();
}
-llvm::Error
-DAP::RunLaunchCommands(llvm::ArrayRef<std::string> launch_commands) {
+llvm::Error DAP::RunLaunchCommands(llvm::ArrayRef<String> launch_commands) {
if (!RunLLDBCommands("Running launchCommands:", launch_commands))
return createRunLLDBCommandsErrorMessage("launch");
return llvm::Error::success();
@@ -801,9 +799,9 @@ lldb::SBTarget DAP::CreateTarget(lldb::SBError &error) {
// omitted at all), so it is good to leave the user an opportunity to specify
// those. Any of those three can be left empty.
auto target = this->debugger.CreateTarget(
- /*filename=*/configuration.program.data(),
- /*target_triple=*/configuration.targetTriple.data(),
- /*platform_name=*/configuration.platformName.data(),
+ /*filename=*/configuration.program.str().data(),
+ /*target_triple=*/configuration.targetTriple.str().data(),
+ /*platform_name=*/configuration.platformName.str().data(),
/*add_dependent_modules=*/true, // Add dependent modules.
error);
@@ -855,8 +853,8 @@ bool DAP::HandleObject(const Message &M) {
return true; // Success
}
- dispatcher.Set("error",
- llvm::Twine("unhandled-command:" + req->command).str());
+ dispatcher.Set(
+ "error", llvm::Twine("unhandled-command:" + req->command.str()).str());
DAP_LOG(log, "error: unhandled command '{0}'", req->command);
return false; // Fail
}
@@ -886,7 +884,7 @@ bool DAP::HandleObject(const Message &M) {
if (resp->message) {
message =
std::visit(llvm::makeVisitor(
- [](const std::string &message) -> llvm::StringRef {
+ [](const String &message) -> llvm::StringRef {
return message;
},
[](const protocol::ResponseMessage &message)
@@ -987,7 +985,7 @@ void DAP::Received(const protocol::Event &event) {
}
void DAP::Received(const protocol::Request &request) {
- if (request.command == "disconnect")
+ if (request.command.str() == "disconnect")
m_disconnecting = true;
const std::optional<CancelArguments> cancel_args =
@@ -1161,7 +1159,8 @@ lldb::SBError DAP::WaitForProcessToStop(std::chrono::seconds seconds) {
}
void DAP::ConfigureSourceMaps() {
- if (configuration.sourceMap.empty() && configuration.sourcePath.empty())
+ llvm::StringRef srcPath = configuration.sourcePath;
+ if (configuration.sourceMap.empty() && srcPath.empty())
return;
std::string sourceMapCommand;
@@ -1170,10 +1169,10 @@ void DAP::ConfigureSourceMaps() {
if (!configuration.sourceMap.empty()) {
for (const auto &kv : configuration.sourceMap) {
- strm << "\"" << kv.first << "\" \"" << kv.second << "\" ";
+ strm << "\"" << kv.first.str() << "\" \"" << kv.second.str() << "\" ";
}
- } else if (!configuration.sourcePath.empty()) {
- strm << "\".\" \"" << configuration.sourcePath << "\"";
+ } else if (!srcPath.empty()) {
+ strm << "\".\" \"" << srcPath << "\"";
}
RunLLDBCommands("Setting source map:", {sourceMapCommand});
@@ -1268,7 +1267,7 @@ protocol::Capabilities DAP::GetCapabilities() {
capabilities.exceptionBreakpointFilters = std::move(filters);
// FIXME: This should be registered based on the supported languages?
- std::vector<std::string> completion_characters;
+ std::vector<String> completion_characters;
completion_characters.emplace_back(".");
// FIXME: I wonder if we should remove this key... its very aggressive
// triggering and accepting completions.
diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h
index 34d6a29b3c110..0b0aa5924d931 100644
--- a/lldb/tools/lldb-dap/DAP.h
+++ b/lldb/tools/lldb-dap/DAP.h
@@ -194,7 +194,7 @@ struct DAP final : public DAPTransport::MessageHandler {
/// \param[in] loop
/// Main loop associated with this instance.
DAP(Log &log, const ReplMode default_repl_mode,
- std::vector<std::string> pre_init_commands, bool no_lldbinit,
+ std::vector<protocol::String> pre_init_commands, bool no_lldbinit,
llvm::StringRef client_name, DAPTransport &transport,
lldb_private::MainLoop &loop);
@@ -314,10 +314,12 @@ struct DAP final : public DAPTransport::MessageHandler {
/// \b false if a fatal error was found while executing these commands,
/// according to the rules of \a LLDBUtils::RunLLDBCommands.
bool RunLLDBCommands(llvm::StringRef prefix,
- llvm::ArrayRef<std::string> commands);
+ llvm::ArrayRef<protocol::String> commands);
- llvm::Error RunAttachCommands(llvm::ArrayRef<std::string> attach_commands);
- llvm::Error RunLaunchCommands(llvm::ArrayRef<std::string> launch_commands);
+ llvm::Error
+ RunAttachCommands(llvm::ArrayRef<protocol::String> attach_commands);
+ llvm::Error
+ RunLaunchCommands(llvm::ArrayRef<protocol::String> launch_commands);
llvm::Error RunPreInitCommands();
llvm::Error RunInitCommands();
llvm::Error RunPreRunCommands();
diff --git a/lldb/tools/lldb-dap/Handler/DataBreakpointInfoRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/DataBreakpointInfoRequestHandler.cpp
index 245d92c18e59e..662fb67839f60 100644
--- a/lldb/tools/lldb-dap/Handler/DataBreakpointInfoRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/DataBreakpointInfoRequestHandler.cpp
@@ -84,14 +84,15 @@ DataBreakpointInfoRequestHandler::Run(
} else {
is_data_ok = false;
response.description =
- "unable to get byte size for expression: " + args.name;
+ "unable to get byte size for expression: " + args.name.str();
}
}
} else if (args.asAddress) {
size = llvm::utostr(args.bytes.value_or(dap.target.GetAddressByteSize()));
lldb::addr_t load_addr = LLDB_INVALID_ADDRESS;
if (llvm::StringRef(args.name).getAsInteger<lldb::addr_t>(0, load_addr))
- return llvm::make_error<DAPError>(args.name + " is not a valid address",
+ return llvm::make_error<DAPError>(args.name.str() +
+ " is not a valid address",
llvm::inconvertibleErrorCode(), false);
addr = llvm::utohexstr(load_addr);
if (!IsRW(dap, load_addr))
@@ -100,7 +101,7 @@ DataBreakpointInfoRequestHandler::Run(
llvm::inconvertibleErrorCode(), false);
} else {
is_data_ok = false;
- response.description = "variable not found: " + args.name;
+ response.description = "variable not found: " + args.name.str();
}
if (is_data_ok) {
@@ -111,7 +112,7 @@ DataBreakpointInfoRequestHandler::Run(
if (args.asAddress)
response.description = size + " bytes at " + addr;
else
- response.description = size + " bytes at " + addr + " " + args.name;
+ response.description = size + " bytes at " + addr + " " + args.name.str();
}
return response;
diff --git a/lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp
index 8387f9ab5c387..762f8fb6b7ebf 100644
--- a/lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp
@@ -120,7 +120,7 @@ static DisassembledInstruction ConvertSBInstructionToDisassembledInstruction(
bytes.pop_back();
disassembled_inst.instructionBytes = std::move(bytes);
- llvm::raw_string_ostream si(disassembled_inst.instruction);
+ llvm::raw_string_ostream si(disassembled_inst.instruction.str());
si << llvm::formatv("{0,-7} {1,-25}", m, o);
// Only add the symbol on the first line of the function.
diff --git a/lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp
index 74ab9a2837034..e19b5d4267f72 100644
--- a/lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp
@@ -268,7 +268,7 @@ static std::optional<ExceptionDetails> FormatException(lldb::SBThread &thread) {
return {};
ExceptionDetails details;
- raw_string_ostream OS(details.message);
+ raw_string_ostream OS(details.message.str());
if (const char *name = exception.GetName())
details.evaluateName = name;
@@ -317,7 +317,7 @@ ExceptionInfoRequestHandler::Run(const ExceptionInfoArguments &args) const {
body.exceptionId = FormatExceptionId(dap, thread);
body.details = FormatException(thread);
- raw_string_ostream OS(body.description);
+ raw_string_ostream OS(body.description.str());
OS << FormatStopDescription(thread);
if (std::string stop_info = FormatExtendedStopInfo(thread);
diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.cpp b/lldb/tools/lldb-dap/Handler/RequestHandler.cpp
index 47ae9a7195a7d..a84e00d124de7 100644
--- a/lldb/tools/lldb-dap/Handler/RequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/RequestHandler.cpp
@@ -37,8 +37,7 @@ using namespace lldb_dap::protocol;
namespace lldb_dap {
-static std::vector<const char *>
-MakeArgv(const llvm::ArrayRef<std::string> &strs) {
+static std::vector<const char *> MakeArgv(const llvm::ArrayRef<String> &strs) {
// Create and return an array of "const char *", one for each C string in
// "strs" and terminate the list with a NULL. This can be used for argument
// vectors (argv) or environment vectors (envp) like those passed to the
@@ -60,9 +59,8 @@ static uint32_t SetLaunchFlag(uint32_t flags, bool flag,
return flags;
}
-static void
-SetupIORedirection(const std::vector<std::optional<std::string>> &stdio,
- lldb::SBLaunchInfo &launch_info) {
+static void SetupIORedirection(const std::vector<std::optional<String>> &stdio,
+ lldb::SBLaunchInfo &launch_info) {
for (const auto &[idx, value_opt] : llvm::enumerate(stdio)) {
if (!value_opt)
continue;
@@ -191,7 +189,7 @@ void BaseRequestHandler::Run(const Request &request) {
llvm::Error BaseRequestHandler::LaunchProcess(
const protocol::LaunchRequestArguments &arguments) const {
- const std::vector<std::string> &launchCommands = arguments.launchCommands;
+ const std::vector<String> &launchCommands = arguments.launchCommands;
// Instantiate a launch info instance for the target.
auto launch_info = dap.target.GetLaunchInfo();
@@ -287,7 +285,7 @@ void BaseRequestHandler::PrintWelcomeMessage() const {
OS << "\"<lldb-cmd>\" or \"help [<lldb-cmd>]\".\r\n";
break;
case ReplMode::Variable:
- OS << "\"<variable>\" or \"" << dap.configuration.commandEscapePrefix
+ OS << "\"<variable>\" or \"" << dap.configuration.commandEscapePrefix.str()
<< "help [<lldb-cmd>]\".\r\n";
break;
}
@@ -340,8 +338,8 @@ void BaseRequestHandler::BuildErrorResponse(
error_message.format = err.getMessage();
error_message.showUser = err.getShowUser();
error_message.id = err.convertToErrorCode().value();
- error_message.url = err.getURL();
- error_message.urlLabel = err.getURLLabel();
+ error_message.url = err.getURL().value_or("");
+ error_message.urlLabel = err.getURLLabel().value_or("");
protocol::ErrorResponseBody body;
body.error = error_message;
diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h
index 9feb636fd5c28..08f826ebc0599 100644
--- a/lldb/tools/lldb-dap/Handler/RequestHandler.h
+++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h
@@ -112,7 +112,7 @@ llvm::Expected<Args> parseArgs(const protocol::Request &request) {
if (request.arguments && !fromJSON(*request.arguments, arguments, root)) {
std::string parse_failure;
llvm::raw_string_ostream OS(parse_failure);
- OS << "invalid arguments for request '" << request.command
+ OS << "invalid arguments for request '" << llvm::StringRef(request.command)
<< "': " << llvm::toString(root.getError()) << "\n";
root.printErrorContext(*request.arguments, OS);
return llvm::make_error<DAPError>(parse_failure);
diff --git a/lldb/tools/lldb-dap/Handler/SetExceptionBreakpointsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SetExceptionBreakpointsRequestHandler.cpp
index 6a271fb825137..9592437287850 100644
--- a/lldb/tools/lldb-dap/Handler/SetExceptionBreakpointsRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/SetExceptionBreakpointsRequestHandler.cpp
@@ -37,20 +37,20 @@ SetExceptionBreakpointsRequestHandler::Run(
SetExceptionBreakpointsResponseBody body;
for (const auto &filter : arguments.filters) {
- auto *exc_bp = dap.GetExceptionBreakpoint(filter);
+ auto *exc_bp = dap.GetExceptionBreakpoint(filter.str());
if (!exc_bp)
continue;
body.breakpoints.push_back(exc_bp->SetBreakpoint());
- unset_filters.erase(filter);
+ unset_filters.erase(filter.str());
}
for (const auto &filterOptions : arguments.filterOptions) {
- auto *exc_bp = dap.GetExceptionBreakpoint(filterOptions.filterId);
+ auto *exc_bp = dap.GetExceptionBreakpoint(filterOptions.filterId.str());
if (!exc_bp)
continue;
body.breakpoints.push_back(exc_bp->SetBreakpoint(filterOptions.condition));
- unset_filters.erase(filterOptions.filterId);
+ unset_filters.erase(filterOptions.filterId.str());
}
// Clear any unset filters.
diff --git a/lldb/tools/lldb-dap/Handler/StackTraceRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/StackTraceRequestHandler.cpp
index 6e6f9b0e5b285..f0a990a8b59de 100644
--- a/lldb/tools/lldb-dap/Handler/StackTraceRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/StackTraceRequestHandler.cpp
@@ -47,7 +47,7 @@ static StackFrame CreateStackFrame(DAP &dap, lldb::SBFrame &frame,
// We only include `[opt]` if a custom frame format is not specified.
if (!format && frame.GetFunction().GetIsOptimized())
- stack_frame.name += " [opt]";
+ stack_frame.name.str() += " [opt]";
std::optional<protocol::Source> source = dap.ResolveSource(frame);
if (source && !IsAssemblySource(*source)) {
@@ -97,9 +97,10 @@ static StackFrame CreateExtendedStackFrameLabel(lldb::SBThread &thread,
if (llvm::StringRef queue_name = thread.GetQueueName();
!queue_name.empty()) {
stack_frame.name = llvm::formatv("Enqueued from {0} (Thread {1})",
- queue_name, thread_idx);
+ queue_name, thread_idx)
+ .str();
} else {
- stack_frame.name = llvm::formatv("Thread {0}", thread_idx);
+ stack_frame.name = llvm::formatv("Thread {0}", thread_idx).str();
}
}
diff --git a/lldb/tools/lldb-dap/JSONUtils.cpp b/lldb/tools/lldb-dap/JSONUtils.cpp
index 5bcc2f9c71c2d..460d2a46049c6 100644
--- a/lldb/tools/lldb-dap/JSONUtils.cpp
+++ b/lldb/tools/lldb-dap/JSONUtils.cpp
@@ -462,10 +462,10 @@ std::pair<int64_t, bool> UnpackLocation(int64_t location_id) {
/// See
/// https://microsoft.github.io/debug-adapter-protocol/specification#Reverse_Requests_RunInTerminal
llvm::json::Object CreateRunInTerminalReverseRequest(
- llvm::StringRef program, const std::vector<std::string> &args,
- const llvm::StringMap<std::string> &env, llvm::StringRef cwd,
+ llvm::StringRef program, const std::vector<protocol::String> &args,
+ const llvm::StringMap<protocol::String> &env, llvm::StringRef cwd,
llvm::StringRef comm_file, lldb::pid_t debugger_pid,
- const std::vector<std::optional<std::string>> &stdio, bool external) {
+ const std::vector<std::optional<protocol::String>> &stdio, bool external) {
llvm::json::Object run_in_terminal_args;
if (external) {
// This indicates the IDE to open an external terminal window.
@@ -488,10 +488,10 @@ llvm::json::Object CreateRunInTerminalReverseRequest(
std::stringstream ss;
std::string_view delimiter;
- for (const std::optional<std::string> &file : stdio) {
+ for (const std::optional<protocol::String> &file : stdio) {
ss << std::exchange(delimiter, ":");
if (file)
- ss << *file;
+ ss << file->str();
}
req_args.push_back(ss.str());
}
diff --git a/lldb/tools/lldb-dap/JSONUtils.h b/lldb/tools/lldb-dap/JSONUtils.h
index 232b1810a3cf4..e12fb5b937bac 100644
--- a/lldb/tools/lldb-dap/JSONUtils.h
+++ b/lldb/tools/lldb-dap/JSONUtils.h
@@ -322,10 +322,10 @@ std::pair<int64_t, bool> UnpackLocation(int64_t location_id);
/// A "runInTerminal" JSON object that follows the specification outlined by
/// Microsoft.
llvm::json::Object CreateRunInTerminalReverseRequest(
- llvm::StringRef program, const std::vector<std::string> &args,
- const llvm::StringMap<std::string> &env, llvm::StringRef cwd,
+ llvm::StringRef program, const std::vector<protocol::String> &args,
+ const llvm::StringMap<protocol::String> &env, llvm::StringRef cwd,
llvm::StringRef comm_file, lldb::pid_t debugger_pid,
- const std::vector<std::optional<std::string>> &stdio, bool external);
+ const std::vector<std::optional<protocol::String>> &stdio, bool external);
/// Create a "Terminated" JSON object that contains statistics
///
diff --git a/lldb/tools/lldb-dap/LLDBUtils.cpp b/lldb/tools/lldb-dap/LLDBUtils.cpp
index e7407e9da9efb..7e69813477b29 100644
--- a/lldb/tools/lldb-dap/LLDBUtils.cpp
+++ b/lldb/tools/lldb-dap/LLDBUtils.cpp
@@ -32,7 +32,7 @@
namespace lldb_dap {
bool RunLLDBCommands(lldb::SBDebugger &debugger, llvm::StringRef prefix,
- const llvm::ArrayRef<std::string> &commands,
+ const llvm::ArrayRef<protocol::String> &commands,
llvm::raw_ostream &strm, bool parse_command_directives,
bool echo_commands) {
if (commands.empty())
@@ -115,7 +115,7 @@ bool RunLLDBCommands(lldb::SBDebugger &debugger, llvm::StringRef prefix,
}
std::string RunLLDBCommands(lldb::SBDebugger &debugger, llvm::StringRef prefix,
- const llvm::ArrayRef<std::string> &commands,
+ const llvm::ArrayRef<protocol::String> &commands,
bool &required_command_failed,
bool parse_command_directives, bool echo_commands) {
required_command_failed = false;
diff --git a/lldb/tools/lldb-dap/LLDBUtils.h b/lldb/tools/lldb-dap/LLDBUtils.h
index 19174ba59654d..37757ada7ab4d 100644
--- a/lldb/tools/lldb-dap/LLDBUtils.h
+++ b/lldb/tools/lldb-dap/LLDBUtils.h
@@ -10,6 +10,7 @@
#define LLDB_TOOLS_LLDB_DAP_LLDBUTILS_H
#include "DAPForward.h"
+#include "Protocol/ProtocolBase.h"
#include "lldb/API/SBDebugger.h"
#include "lldb/API/SBEnvironment.h"
#include "lldb/API/SBError.h"
@@ -63,7 +64,7 @@ namespace lldb_dap {
/// \b true, unless a command prefixed with \b ! fails and parsing of
/// command directives is enabled.
bool RunLLDBCommands(lldb::SBDebugger &debugger, llvm::StringRef prefix,
- const llvm::ArrayRef<std::string> &commands,
+ const llvm::ArrayRef<protocol::String> &commands,
llvm::raw_ostream &strm, bool parse_command_directives,
bool echo_commands);
@@ -97,7 +98,7 @@ bool RunLLDBCommands(lldb::SBDebugger &debugger, llvm::StringRef prefix,
/// A std::string that contains the prefix and all commands and
/// command output.
std::string RunLLDBCommands(lldb::SBDebugger &debugger, llvm::StringRef prefix,
- const llvm::ArrayRef<std::string> &commands,
+ const llvm::ArrayRef<protocol::String> &commands,
bool &required_command_failed,
bool parse_command_directives = true,
bool echo_commands = false);
diff --git a/lldb/tools/lldb-dap/Protocol/DAPTypes.cpp b/lldb/tools/lldb-dap/Protocol/DAPTypes.cpp
index a14ed9e521f48..bd4cbc29e76bc 100644
--- a/lldb/tools/lldb-dap/Protocol/DAPTypes.cpp
+++ b/lldb/tools/lldb-dap/Protocol/DAPTypes.cpp
@@ -15,11 +15,11 @@ bool fromJSON(const llvm::json::Value &Params, PersistenceData &PD,
llvm::json::Value toJSON(const PersistenceData &PD) {
json::Object result{
- {"module_path", PD.module_path},
- {"symbol_name", PD.symbol_name},
+ {"module_path", std::move(PD.module_path)},
+ {"symbol_name", std::move(PD.symbol_name)},
};
- return result;
+ return std::move(result);
}
bool fromJSON(const llvm::json::Value &Params, SourceLLDBData &SLD,
diff --git a/lldb/tools/lldb-dap/Protocol/DAPTypes.h b/lldb/tools/lldb-dap/Protocol/DAPTypes.h
index 23ba93946bdee..d07ff046d367d 100644
--- a/lldb/tools/lldb-dap/Protocol/DAPTypes.h
+++ b/lldb/tools/lldb-dap/Protocol/DAPTypes.h
@@ -16,11 +16,11 @@
#ifndef LLDB_TOOLS_LLDB_DAP_PROTOCOL_DAP_TYPES_H
#define LLDB_TOOLS_LLDB_DAP_PROTOCOL_DAP_TYPES_H
+#include "Protocol/ProtocolBase.h"
#include "lldb/lldb-defines.h"
#include "lldb/lldb-types.h"
#include "llvm/Support/JSON.h"
#include <optional>
-#include <string>
namespace lldb_dap::protocol {
@@ -30,10 +30,10 @@ namespace lldb_dap::protocol {
/// breakpoints the path and line are the same For each session.
struct PersistenceData {
/// The source module path.
- std::string module_path;
+ String module_path;
/// The symbol name of the Source.
- std::string symbol_name;
+ String symbol_name;
};
bool fromJSON(const llvm::json::Value &, PersistenceData &, llvm::json::Path);
llvm::json::Value toJSON(const PersistenceData &);
@@ -76,7 +76,7 @@ struct Symbol {
lldb::addr_t size = 0;
/// The symbol name.
- std::string name;
+ String name;
};
bool fromJSON(const llvm::json::Value &, Symbol &, llvm::json::Path);
llvm::json::Value toJSON(const Symbol &);
diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolBase.cpp b/lldb/tools/lldb-dap/Protocol/ProtocolBase.cpp
index de0f815d443bc..170742c7615d7 100644
--- a/lldb/tools/lldb-dap/Protocol/ProtocolBase.cpp
+++ b/lldb/tools/lldb-dap/Protocol/ProtocolBase.cpp
@@ -57,13 +57,13 @@ bool fromJSON(const json::Value &Params, MessageType &M, json::Path P) {
return true;
}
-json::Value toJSON(const SanitizedString &S) {
+json::Value toJSON(const String &S) {
if (LLVM_LIKELY(llvm::json::isUTF8(std::string(S))))
return std::string(S);
return llvm::json::fixUTF8(std::string(S));
}
-bool fromJSON(const llvm::json::Value &Param, SanitizedString &Str,
+bool fromJSON(const llvm::json::Value &Param, String &Str,
llvm::json::Path Path) {
if (auto s = Param.getAsString()) {
Str = *s;
@@ -140,8 +140,7 @@ json::Value toJSON(const Response &R) {
Result.insert({"message", "notStopped"});
break;
}
- } else if (const auto *messageString =
- std::get_if<std::string>(&*R.message)) {
+ } else if (const auto *messageString = std::get_if<String>(&*R.message)) {
Result.insert({"message", *messageString});
}
}
@@ -153,8 +152,7 @@ json::Value toJSON(const Response &R) {
}
static bool fromJSON(json::Value const &Params,
- std::variant<ResponseMessage, std::string> &M,
- json::Path P) {
+ std::variant<ResponseMessage, String> &M, json::Path P) {
auto rawMessage = Params.getAsString();
if (!rawMessage) {
P.report("expected a string");
@@ -204,31 +202,46 @@ bool operator==(const Response &a, const Response &b) {
json::Value toJSON(const ErrorMessage &EM) {
json::Object Result{{"id", EM.id}, {"format", EM.format}};
- if (EM.variables) {
+ if (!EM.variables.empty()) {
json::Object variables;
- for (auto &var : *EM.variables)
- variables[var.first] = var.second;
+ for (auto &var : EM.variables)
+ variables[var.first.str()] = var.second;
Result.insert({"variables", std::move(variables)});
}
if (EM.sendTelemetry)
Result.insert({"sendTelemetry", EM.sendTelemetry});
if (EM.showUser)
Result.insert({"showUser", EM.showUser});
- if (EM.url)
+ if (!EM.url.empty())
Result.insert({"url", EM.url});
- if (EM.urlLabel)
+ if (!EM.urlLabel.empty())
Result.insert({"urlLabel", EM.urlLabel});
return std::move(Result);
}
+bool fromJSON(json::Value const &Params, std::map<String, String> &M,
+ json::Path P) {
+ const auto *const O = Params.getAsObject();
+ if (!O) {
+ P.report("expected object");
+ return false;
+ }
+ for (auto [k, v] : *O) {
+ auto str = v.getAsString();
+ if (str)
+ M[k.str()] = *str;
+ }
+ return true;
+}
+
bool fromJSON(json::Value const &Params, ErrorMessage &EM, json::Path P) {
json::ObjectMapper O(Params, P);
return O && O.map("id", EM.id) && O.map("format", EM.format) &&
- O.map("variables", EM.variables) &&
- O.map("sendTelemetry", EM.sendTelemetry) &&
- O.map("showUser", EM.showUser) && O.map("url", EM.url) &&
- O.map("urlLabel", EM.urlLabel);
+ O.mapOptional("variables", EM.variables) &&
+ O.mapOptional("sendTelemetry", EM.sendTelemetry) &&
+ O.mapOptional("showUser", EM.showUser) &&
+ O.mapOptional("url", EM.url) && O.mapOptional("urlLabel", EM.urlLabel);
}
json::Value toJSON(const Event &E) {
diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolBase.h b/lldb/tools/lldb-dap/Protocol/ProtocolBase.h
index 3053312c4660f..c37c56c0751fa 100644
--- a/lldb/tools/lldb-dap/Protocol/ProtocolBase.h
+++ b/lldb/tools/lldb-dap/Protocol/ProtocolBase.h
@@ -21,7 +21,9 @@
#define LLDB_TOOLS_LLDB_DAP_PROTOCOL_PROTOCOL_BASE_H
#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Error.h"
#include "llvm/Support/JSON.h"
+#include "llvm/Support/raw_ostream.h"
#include <cstdint>
#include <optional>
#include <string>
@@ -38,28 +40,55 @@ using Id = uint64_t;
/// the current session.
static constexpr Id kCalculateSeq = UINT64_MAX;
-/// A wrapper around a string to ensure the contents are sanitized as utf8
-/// during serialization. This value should be used for any strings that may
-/// contain raw data like variable values.
-class SanitizedString {
+/// A wrapper around a 'std::string' to ensure the contents are valid utf8
+/// during serialization.
+class String {
public:
- SanitizedString(std::string str) : m_str(str) {}
- SanitizedString(llvm::StringRef str) : m_str(str.str()) {}
- SanitizedString(const char *str) : m_str(str) {}
- SanitizedString() = default;
+ String(std::string str) : m_str(str) {}
+ String(llvm::StringRef str) : m_str(str.str()) {}
+ String(const char *str) : m_str(str) {}
+ String() = default;
+ operator llvm::Twine() { return m_str; }
+ operator std::string &() { return m_str; }
operator std::string() const { return m_str; }
+ operator llvm::StringRef() const { return llvm::StringRef(m_str); }
+
+ void clear() { m_str.clear(); }
+ bool empty() const { return m_str.empty(); }
+ const char *c_str() const { return m_str.c_str(); }
+ const char *data() const { return m_str.data(); }
+ std::string str() const { return m_str; }
+ std::string &str() { return m_str; }
private:
std::string m_str;
};
-llvm::json::Value toJSON(const SanitizedString &s);
-bool fromJSON(const llvm::json::Value &, SanitizedString &, llvm::json::Path);
+llvm::json::Value toJSON(const String &s);
+bool fromJSON(const llvm::json::Value &, String &, llvm::json::Path);
+inline bool operator==(const String &a, const String &b) {
+ return a.str() == b.str();
+}
+inline bool operator==(const String &a, const char *b) { return a.str() == b; }
+inline bool operator==(const char *a, const String &b) { return a == b.str(); }
+inline bool operator==(llvm::StringRef a, const String &b) {
+ return a.str() == b.str();
+}
+inline bool operator==(const String &a, llvm::StringRef b) {
+ return a.str() == b.str();
+}
+inline bool operator<(const String &a, const String &b) {
+ return a.str() < b.str();
+}
+inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const String &S) {
+ OS << S.str();
+ return OS;
+}
/// A client or debug adapter initiated request.
struct Request {
/// The command to execute.
- std::string command;
+ String command;
/// Object containing arguments for the command.
///
@@ -83,7 +112,7 @@ bool operator==(const Request &, const Request &);
/// A debug adapter initiated event.
struct Event {
/// Type of event.
- std::string event;
+ String event;
/// Event-specific information.
std::optional<llvm::json::Value> body = std::nullopt;
@@ -114,7 +143,7 @@ struct Response {
Id request_seq = 0;
/// The command requested.
- std::string command;
+ 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,
@@ -127,8 +156,7 @@ struct Response {
/// 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<ResponseMessage, std::string>> message =
- std::nullopt;
+ std::optional<std::variant<ResponseMessage, String>> message = std::nullopt;
/// Contains request result if success is true and error details if success is
/// false.
@@ -163,11 +191,11 @@ struct ErrorMessage {
/// `{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;
+ 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;
+ std::map<String, String> variables;
/// If true send to telemetry.
bool sendTelemetry = false;
@@ -176,10 +204,10 @@ struct ErrorMessage {
bool showUser = false;
/// A url where additional information about this message can be found.
- std::optional<std::string> url;
+ String url;
/// A label that is presented to the user as the UI for opening the url.
- std::optional<std::string> urlLabel;
+ String urlLabel;
};
bool fromJSON(const llvm::json::Value &, ErrorMessage &, llvm::json::Path);
llvm::json::Value toJSON(const ErrorMessage &);
diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp
index a72802a33fc9c..eeb1a901396b1 100644
--- a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp
+++ b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp
@@ -8,6 +8,7 @@
#include "Protocol/ProtocolRequests.h"
#include "JSONUtils.h"
+#include "Protocol/ProtocolBase.h"
#include "Protocol/ProtocolTypes.h"
#include "lldb/lldb-defines.h"
#include "llvm/ADT/DenseMap.h"
@@ -21,8 +22,8 @@ using namespace llvm;
// The 'env' field is either an object as a map of strings or as an array of
// strings formatted like 'key=value'.
-static bool parseEnv(const json::Value &Params, StringMap<std::string> &env,
- json::Path P) {
+static bool parseEnv(const json::Value &Params,
+ StringMap<lldb_dap::protocol::String> &env, json::Path P) {
const json::Object *O = Params.getAsObject();
if (!O) {
P.report("expected object");
@@ -87,7 +88,8 @@ static bool parseTimeout(const json::Value &Params, std::chrono::seconds &S,
static bool
parseSourceMap(const json::Value &Params,
- std::vector<std::pair<std::string, std::string>> &sourceMap,
+ std::vector<std::pair<lldb_dap::protocol::String,
+ lldb_dap::protocol::String>> &sourceMap,
json::Path P) {
const json::Object *O = Params.getAsObject();
if (!O) {
@@ -311,7 +313,7 @@ bool fromJSON(const json::Value &Params, LaunchRequestArguments &LRA,
if (!success)
return false;
- for (std::optional<std::string> &io_path : LRA.stdio) {
+ for (std::optional<String> &io_path : LRA.stdio) {
// set empty paths to null.
if (io_path && llvm::StringRef(*io_path).trim().empty())
io_path.reset();
diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h
index af50e77ce6ab2..6825c07ce21fc 100644
--- a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h
+++ b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h
@@ -106,16 +106,16 @@ enum PathFormat : unsigned { ePatFormatPath, ePathFormatURI };
/// Arguments for `initialize` request.
struct InitializeRequestArguments {
/// The ID of the debug adapter.
- std::string adapterID;
+ String adapterID;
/// The ID of the client using this adapter.
- std::string clientID;
+ String clientID;
/// The human-readable name of the client using this adapter.
- std::string clientName;
+ String clientName;
/// The ISO-639 locale of the client using this adapter, e.g. en-US or de-CH.
- std::string locale;
+ String locale;
/// Determines in what format paths are specified. The default is `path`,
/// which is the native format.
@@ -153,7 +153,7 @@ struct Configuration {
/// information in your executable contains relative paths, this option can be
/// used so that `lldb-dap` can find source files and object files that have
/// relative paths.
- std::string debuggerRoot;
+ String debuggerRoot;
/// Enable auto generated summaries for variables when no summaries exist for
/// a given type. This feature can cause performance delays in large projects
@@ -180,7 +180,7 @@ struct Configuration {
/// Console, instead of printing variables. Defaults to a backtick. If it's an
/// empty string, then all expression in the Debug Console are treated as
/// regular LLDB commands.
- std::string commandEscapePrefix = "`";
+ String commandEscapePrefix = "`";
/// If non-empty, stack frames will have descriptions generated based on the
/// provided format. See https://lldb.llvm.org/use/formatting.html for an
@@ -189,58 +189,58 @@ struct Configuration {
/// default frame names will be used. This might come with a performance cost
/// because debug information might need to be processed to generate the
/// description.
- std::optional<std::string> customFrameFormat;
+ std::optional<String> customFrameFormat;
/// Same as `customFrameFormat`, but for threads instead of stack frames.
- std::optional<std::string> customThreadFormat;
+ std::optional<String> customThreadFormat;
/// Specify a source path to remap "./" to allow full paths to be used when
/// setting breakpoints in binaries that have relative source paths.
- std::string sourcePath;
+ String sourcePath;
/// Specify an array of path re-mappings. Each element in the array must be a
/// two element array containing a source and destination pathname. Overrides
/// sourcePath.
- std::vector<std::pair<std::string, std::string>> sourceMap;
+ std::vector<std::pair<String, String>> sourceMap;
/// LLDB commands executed upon debugger startup prior to creating the LLDB
/// target.
- std::vector<std::string> preInitCommands;
+ std::vector<String> preInitCommands;
/// LLDB commands executed upon debugger startup prior to creating the LLDB
/// target.
- std::vector<std::string> initCommands;
+ std::vector<String> initCommands;
/// LLDB commands executed just before launching/attaching, after the LLDB
/// target has been created.
- std::vector<std::string> preRunCommands;
+ std::vector<String> preRunCommands;
/// LLDB commands executed just after launching/attaching, after the LLDB
/// target has been created.
- std::vector<std::string> postRunCommands;
+ std::vector<String> postRunCommands;
/// LLDB commands executed just after each stop.
- std::vector<std::string> stopCommands;
+ std::vector<String> stopCommands;
/// LLDB commands executed when the program exits.
- std::vector<std::string> exitCommands;
+ std::vector<String> exitCommands;
/// LLDB commands executed when the debugging session ends.
- std::vector<std::string> terminateCommands;
+ std::vector<String> terminateCommands;
/// Path to the executable.
///
/// *NOTE:* When launching, either `launchCommands` or `program` must be
/// configured. If both are configured then `launchCommands` takes priority.
- std::string program;
+ String program;
/// Target triple for the program (arch-vendor-os). If not set, inferred from
/// the binary.
- std::string targetTriple;
+ String targetTriple;
/// Specify name of the platform to use for this target, creating the platform
/// if necessary.
- std::string platformName;
+ String platformName;
};
enum Console : unsigned {
@@ -269,19 +269,19 @@ struct LaunchRequestArguments {
/// *NOTE:* Either launchCommands or program must be configured.
///
/// If set, takes priority over the 'program' when launching the target.
- std::vector<std::string> launchCommands;
+ std::vector<String> launchCommands;
/// The program working directory.
- std::string cwd;
+ String cwd;
/// An array of command line argument strings to be passed to the program
/// being launched.
- std::vector<std::string> args;
+ std::vector<String> args;
/// Environment variables to set when launching the program. The format of
/// each environment variable string is "VAR=VALUE" for environment variables
/// with values or just "VAR" for environment variables with no values.
- llvm::StringMap<std::string> env;
+ llvm::StringMap<String> env;
/// If set, then the client stub should detach rather than killing the
/// debuggee if it loses connection with lldb.
@@ -302,7 +302,7 @@ struct LaunchRequestArguments {
Console console = eConsoleInternal;
/// An array of file paths for redirecting the program's standard IO streams.
- std::vector<std::optional<std::string>> stdio;
+ std::vector<std::optional<String>> stdio;
/// @}
};
@@ -341,7 +341,7 @@ struct AttachRequestArguments {
/// to a process by name. These commands may optionally create a new target
/// and must perform an attach. A valid process must exist after these
/// commands complete or the `"attach"` will fail.
- std::vector<std::string> attachCommands;
+ std::vector<String> attachCommands;
/// System process ID to attach to.
lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
@@ -355,10 +355,10 @@ struct AttachRequestArguments {
/// The hostname to connect to a remote system. The default hostname being
/// used `localhost`.
- std::string gdbRemoteHostname = "localhost";
+ String gdbRemoteHostname = "localhost";
/// Path to the core file to debug.
- std::string coreFile;
+ String coreFile;
/// An existing session that consist of a target and debugger.
std::optional<DAPSession> session;
@@ -402,7 +402,7 @@ struct CompletionsArguments {
/// 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;
+ 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
@@ -438,10 +438,10 @@ struct SetVariableArguments {
uint64_t variablesReference = UINT64_MAX;
/// The name of the variable in the container.
- std::string name;
+ String name;
/// The value of the variable.
- std::string value;
+ String value;
/// Specifies details on how to format the response value.
ValueFormat format;
@@ -452,11 +452,11 @@ bool fromJSON(const llvm::json::Value &, SetVariableArguments &,
/// Response to `setVariable` request.
struct SetVariableResponseBody {
/// The new value of the variable.
- SanitizedString value;
+ String value;
/// The type of the new value. Typically shown in the UI when hovering over
/// the value.
- std::string type;
+ String type;
/// If `variablesReference` is > 0, the new value is structured and its
/// children can be retrieved by passing `variablesReference` to the
@@ -527,10 +527,10 @@ bool fromJSON(const llvm::json::Value &, SourceArguments &, llvm::json::Path);
/// Response to `source` request.
struct SourceResponseBody {
/// Content of the source reference.
- std::string content;
+ String content;
/// Content type (MIME type) of the source.
- std::optional<std::string> mimeType;
+ std::optional<String> mimeType;
};
llvm::json::Value toJSON(const SourceResponseBody &);
@@ -732,7 +732,7 @@ struct DataBreakpointInfoArguments {
/// The name of the variable's child to obtain data breakpoint information
/// for. If `variablesReference` isn't specified, this can be an expression,
/// or an address if `asAddress` is also true.
- std::string name;
+ String name;
/// 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.
@@ -755,7 +755,7 @@ struct DataBreakpointInfoArguments {
/// The mode of the desired breakpoint. If defined, this must be one of the
/// `breakpointModes` the debug adapter advertised in its `Capabilities`.
- std::optional<std::string> mode;
+ std::optional<String> mode;
};
bool fromJSON(const llvm::json::Value &, DataBreakpointInfoArguments &,
llvm::json::Path);
@@ -770,11 +770,11 @@ struct DataBreakpointInfoResponseBody {
/// for details. Breakpoints set using the `dataId` in the
/// `setDataBreakpoints` request may outlive the lifetime of the associated
/// `dataId`.
- std::optional<std::string> dataId;
+ std::optional<String> dataId;
/// UI string that describes on what data the breakpoint is set on or why a
/// data breakpoint is not available.
- std::string description;
+ String description;
/// Attribute lists the available access types for a potential data
/// breakpoint. A UI client could surface this information.
@@ -808,7 +808,7 @@ struct SetExceptionBreakpointsArguments {
/// Set of exception filters specified by their ID. The set of all possible
/// exception filters is defined by the `exceptionBreakpointFilters`
/// capability. The `filter` and `filterOptions` sets are additive.
- std::vector<std::string> filters;
+ std::vector<String> filters;
/// Set of exception filters and their options. The set of all possible
/// exception filters is defined by the `exceptionBreakpointFilters`
@@ -1015,7 +1015,7 @@ struct WriteMemoryArguments {
bool allowPartial = false;
/// Bytes to write, encoded using base64.
- std::string data;
+ String data;
};
bool fromJSON(const llvm::json::Value &, WriteMemoryArguments &,
llvm::json::Path);
@@ -1030,10 +1030,10 @@ llvm::json::Value toJSON(const WriteMemoryResponseBody &);
struct ModuleSymbolsArguments {
/// The module UUID for which to retrieve symbols.
- std::string moduleId;
+ String moduleId;
/// The module path.
- std::string moduleName;
+ String moduleName;
/// The index of the first symbol to return; if omitted, start at the
/// beginning.
@@ -1061,10 +1061,10 @@ bool fromJSON(const llvm::json::Value &, ExceptionInfoArguments &,
struct ExceptionInfoResponseBody {
/// ID of the exception that was thrown.
- std::string exceptionId;
+ String exceptionId;
/// Descriptive text for the exception.
- std::string description;
+ String description;
/// Mode that caused the exception notification to be raised.
ExceptionBreakMode breakMode = eExceptionBreakModeNever;
@@ -1097,7 +1097,7 @@ enum EvaluateContext : unsigned {
/// Arguments for `evaluate` request.
struct EvaluateArguments {
/// The expression to evaluate.
- std::string expression;
+ String expression;
/// Evaluate the expression in the scope of this stack frame. If not
/// specified, the expression is evaluated in the global scope.
@@ -1143,12 +1143,12 @@ bool fromJSON(const llvm::json::Value &, EvaluateArguments &, llvm::json::Path);
/// Response to 'evaluate' request.
struct EvaluateResponseBody {
/// The result of the evaluate request.
- std::string result;
+ String result;
/// The type of the evaluate result.
/// This attribute should only be returned by a debug adapter if the
/// corresponding capability `supportsVariableType` is true.
- std::string type;
+ String type;
/// Properties of an evaluate result that can be used to determine how to
/// render the result in the UI.
@@ -1177,7 +1177,7 @@ struct EvaluateResponseBody {
/// memory address contained in the pointer.
/// This attribute may be returned by a debug adapter if corresponding
/// capability `supportsMemoryReferences` is true.
- std::string memoryReference;
+ String memoryReference;
/// A reference that allows the client to request the location where the
/// returned value is declared. For example, if a function pointer is
@@ -1240,7 +1240,7 @@ llvm::json::Value toJSON(const LocationsResponseBody &);
/// Arguments for `compileUnits` request.
struct CompileUnitsArguments {
/// The ID of the module.
- std::string moduleId;
+ String moduleId;
};
bool fromJSON(const llvm::json::Value &, CompileUnitsArguments &,
llvm::json::Path);
diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h
index e627b02e37bd1..fbb5dbc39d75c 100644
--- a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h
+++ b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h
@@ -28,7 +28,6 @@
#include "llvm/Support/JSON.h"
#include <cstdint>
#include <optional>
-#include <string>
#define LLDB_DAP_INVALID_VAR_REF INT64_MAX
#define LLDB_DAP_INVALID_SRC_REF 0
@@ -42,14 +41,14 @@ namespace lldb_dap::protocol {
struct ExceptionBreakpointsFilter {
/// The internal ID of the filter option. This value is passed to the
/// `setExceptionBreakpoints` request.
- std::string filter;
+ String filter;
/// The name of the filter option. This is shown in the UI.
- std::string label;
+ String label;
/// A help text providing additional information about the exception filter.
/// This string is typically shown as a hover and can be translated.
- std::string description;
+ String description;
/// Initial value of the filter option. If not specified a value false is
/// assumed.
@@ -61,7 +60,7 @@ struct ExceptionBreakpointsFilter {
/// A help text providing information about the condition. This string is
/// shown as the placeholder text for a text box and can be translated.
- std::string conditionDescription;
+ String conditionDescription;
};
bool fromJSON(const llvm::json::Value &, ExceptionBreakpointsFilter &,
llvm::json::Path);
@@ -83,14 +82,14 @@ llvm::json::Value toJSON(const ColumnType &);
/// customization.
struct ColumnDescriptor {
/// Name of the attribute rendered in this column.
- std::string attributeName;
+ String attributeName;
/// Header UI label of column.
- std::string label;
+ String label;
/// Format to use for the rendered values in this column. TBD how the format
/// strings looks like.
- std::optional<std::string> format;
+ std::optional<String> format;
/// Datatype of values in this column. Defaults to `string` if not specified.
/// Values: 'string', 'number', 'boolean', 'unixTimestampUTC'.
@@ -145,19 +144,19 @@ llvm::json::Value toJSON(const CompletionItemType &);
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;
+ String label;
/// If text is returned and not an empty string, then it is inserted instead
/// of the label.
- std::string text;
+ 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;
+ String sortText;
/// A human-readable string with additional information about this item, like
/// type or symbol information.
- std::string detail;
+ String detail;
/// The item's type. Typically the client uses this information to render the
/// item in the UI with an icon.
@@ -213,14 +212,14 @@ llvm::json::Value toJSON(const BreakpointModeApplicability &);
struct BreakpointMode {
/// The internal ID of the mode. This value is passed to the `setBreakpoints`
/// request.
- std::string mode;
+ String mode;
/// The name of the breakpoint mode. This is shown in the UI.
- std::string label;
+ String label;
/// A help text providing additional information about the breakpoint mode.
/// This string is typically shown as a hover and can be translated.
- std::optional<std::string> description;
+ std::optional<String> description;
/// Describes one or more type of breakpoint this mode applies to.
std::vector<BreakpointModeApplicability> appliesTo;
@@ -344,7 +343,7 @@ struct Capabilities {
/// The set of characters that should trigger completion in a REPL. If not
/// specified, the UI should assume the `.` character.
- std::vector<std::string> completionTriggerCharacters;
+ std::vector<String> completionTriggerCharacters;
/// The set of additional module information exposed by the debug adapter.
std::vector<ColumnDescriptor> additionalModuleColumns;
@@ -364,7 +363,7 @@ struct Capabilities {
/// @{
/// The version of the adapter.
- std::string lldbExtVersion;
+ String lldbExtVersion;
/// @}
};
@@ -376,16 +375,16 @@ llvm::json::Value toJSON(const Capabilities &);
struct ExceptionFilterOptions {
/// ID of an exception filter returned by the `exceptionBreakpointFilters`
/// capability.
- std::string filterId;
+ String filterId;
/// An expression for conditional exceptions.
/// The exception breaks into the debugger if the result of the condition is
/// true.
- std::string condition;
+ String condition;
/// The mode of this exception breakpoint. If defined, this must be one of the
/// `breakpointModes` the debug adapter advertised in its `Capabilities`.
- std::string mode;
+ String mode;
};
bool fromJSON(const llvm::json::Value &, ExceptionFilterOptions &,
llvm::json::Path);
@@ -404,12 +403,12 @@ struct Source {
/// 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;
+ std::optional<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;
+ std::optional<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`
@@ -447,7 +446,7 @@ struct Scope {
/// Name of the scope such as 'Arguments', 'Locals', or 'Registers'. This
/// string is shown in the UI as is and can be translated.
////
- std::string name;
+ String name;
/// A hint for how to present this scope in the UI. If this attribute is
/// missing, the scope is shown with a generic UI.
@@ -532,7 +531,7 @@ struct StepInTarget {
lldb::addr_t id = LLDB_INVALID_ADDRESS;
/// The name of the step-in target (shown in the UI).
- std::string label;
+ String label;
/// The line of the step-in target.
uint32_t line = LLDB_INVALID_LINE_NUMBER;
@@ -558,7 +557,7 @@ struct Thread {
/// Unique identifier for the thread.
lldb::tid_t id = LLDB_INVALID_THREAD_ID;
/// The name of the thread.
- std::string name;
+ String name;
};
bool fromJSON(const llvm::json::Value &, Thread &, llvm::json::Path);
llvm::json::Value toJSON(const Thread &);
@@ -618,7 +617,7 @@ struct Breakpoint {
/// A message about the state of the breakpoint.
/// This is shown to the user and can be used to explain why a breakpoint
/// could not be verified.
- std::optional<std::string> message;
+ std::optional<String> message;
/// The source where the breakpoint is located.
std::optional<Source> source;
@@ -641,7 +640,7 @@ struct Breakpoint {
std::optional<uint32_t> endColumn;
/// A memory reference to where the breakpoint is set.
- std::optional<std::string> instructionReference;
+ std::optional<String> instructionReference;
/// The offset from the instruction reference.
/// This can be negative.
@@ -669,7 +668,7 @@ struct SourceBreakpoint {
/// The expression for conditional breakpoints.
/// It is only honored by a debug adapter if the corresponding capability
/// `supportsConditionalBreakpoints` is true.
- std::optional<std::string> condition;
+ std::optional<String> condition;
/// The expression that controls how many hits of the breakpoint are ignored.
/// The debug adapter is expected to interpret the expression as needed.
@@ -678,7 +677,7 @@ struct SourceBreakpoint {
/// If both this property and `condition` are specified, `hitCondition` should
/// be evaluated only if the `condition` is met, and the debug adapter should
/// stop only if both conditions are met.
- std::optional<std::string> hitCondition;
+ std::optional<String> hitCondition;
/// If this attribute exists and is non-empty, the debug adapter must not
/// 'break' (stop)
@@ -687,11 +686,11 @@ struct SourceBreakpoint {
/// capability `supportsLogPoints` is true.
/// If either `hitCondition` or `condition` is specified, then the message
/// should only be logged if those conditions are met.
- std::optional<std::string> logMessage;
+ std::optional<String> logMessage;
/// The mode of this breakpoint. If defined, this must be one of the
/// `breakpointModes` the debug adapter advertised in its `Capabilities`.
- std::optional<std::string> mode;
+ std::optional<String> mode;
};
bool fromJSON(const llvm::json::Value &, SourceBreakpoint &, llvm::json::Path);
llvm::json::Value toJSON(const SourceBreakpoint &);
@@ -699,18 +698,18 @@ llvm::json::Value toJSON(const SourceBreakpoint &);
/// Properties of a breakpoint passed to the `setFunctionBreakpoints` request.
struct FunctionBreakpoint {
/// The name of the function.
- std::string name;
+ String name;
/// An expression for conditional breakpoints.
/// It is only honored by a debug adapter if the corresponding capability
/// `supportsConditionalBreakpoints` is true.
- std::optional<std::string> condition;
+ std::optional<String> condition;
/// An expression that controls how many hits of the breakpoint are ignored.
/// The debug adapter is expected to interpret the expression as needed.
/// The attribute is only honored by a debug adapter if the corresponding
/// capability `supportsHitConditionalBreakpoints` is true.
- std::optional<std::string> hitCondition;
+ std::optional<String> hitCondition;
};
bool fromJSON(const llvm::json::Value &, FunctionBreakpoint &,
llvm::json::Path);
@@ -731,17 +730,17 @@ llvm::json::Value toJSON(const DataBreakpointAccessType &);
struct DataBreakpoint {
/// An id representing the data. This id is returned from the
/// `dataBreakpointInfo` request.
- std::string dataId;
+ String dataId;
/// The access type of the data.
std::optional<DataBreakpointAccessType> accessType;
/// An expression for conditional breakpoints.
- std::optional<std::string> condition;
+ std::optional<String> condition;
/// An expression that controls how many hits of the breakpoint are ignored.
/// The debug adapter is expected to interpret the expression as needed.
- std::optional<std::string> hitCondition;
+ std::optional<String> hitCondition;
};
bool fromJSON(const llvm::json::Value &, DataBreakpoint &, llvm::json::Path);
llvm::json::Value toJSON(const DataBreakpoint &);
@@ -752,7 +751,7 @@ struct InstructionBreakpoint {
/// This should be a memory or instruction pointer reference from an
/// `EvaluateResponse`, `Variable`, `StackFrame`, `GotoTarget`, or
/// `Breakpoint`.
- std::string instructionReference;
+ String instructionReference;
/// The offset from the instruction reference in bytes.
/// This can be negative.
@@ -761,17 +760,17 @@ struct InstructionBreakpoint {
/// An expression for conditional breakpoints.
/// It is only honored by a debug adapter if the corresponding capability
/// `supportsConditionalBreakpoints` is true.
- std::optional<std::string> condition;
+ std::optional<String> condition;
/// An expression that controls how many hits of the breakpoint are ignored.
/// The debug adapter is expected to interpret the expression as needed.
/// The attribute is only honored by a debug adapter if the corresponding
/// capability `supportsHitConditionalBreakpoints` is true.
- std::optional<std::string> hitCondition;
+ std::optional<String> hitCondition;
/// The mode of this breakpoint. If defined, this must be one of the
/// `breakpointModes` the debug adapter advertised in its `Capabilities`.
- std::optional<std::string> mode;
+ std::optional<String> mode;
};
bool fromJSON(const llvm::json::Value &, InstructionBreakpoint &,
llvm::json::Path);
@@ -790,15 +789,15 @@ struct DisassembledInstruction {
/// Raw bytes representing the instruction and its operands, in an
/// implementation-defined format.
- std::optional<std::string> instructionBytes;
+ std::optional<String> instructionBytes;
/// Text representing the instruction and its operands, in an
/// implementation-defined format.
- std::string instruction;
+ String instruction;
/// Name of the symbol that corresponds with the location of this instruction,
/// if any.
- std::optional<std::string> symbol;
+ std::optional<String> symbol;
/// Source location that corresponds to this instruction, if any.
/// Should always be set (if available) on the first instruction returned,
@@ -836,15 +835,15 @@ llvm::json::Value toJSON(const DisassembledInstruction &);
struct Module {
/// Unique identifier for the module.
- std::string id;
+ String id;
/// A name of the module.
- std::string name;
+ String name;
/// Logical full path to the module. The exact definition is implementation
/// defined, but usually this would be a full path to the on-disk file for the
/// module.
- std::string path;
+ String path;
/// True if the module is optimized.
bool isOptimized = false;
@@ -854,21 +853,21 @@ struct Module {
bool isUserCode = false;
/// Version of Module.
- std::string version;
+ String version;
/// User-understandable description of if symbols were found for the module
/// (ex: 'Symbols Loaded', 'Symbols not found', etc.)
- std::string symbolStatus;
+ String symbolStatus;
/// Logical full path to the symbol file. The exact definition is
/// implementation defined.
- std::string symbolFilePath;
+ String symbolFilePath;
/// Module created or modified, encoded as an RFC 3339 timestamp.
- std::string dateTimeStamp;
+ String dateTimeStamp;
/// Address range covered by this module.
- std::string addressRange;
+ String addressRange;
/// Custom fields
/// @{
@@ -885,15 +884,15 @@ llvm::json::Value toJSON(const Module &);
struct VariablePresentationHint {
/// The kind of variable. Before introducing additional values, try to use the
/// listed values.
- std::string kind;
+ String kind;
/// Set of attributes represented as an array of strings. Before introducing
/// additional values, try to use the listed values.
- std::vector<std::string> attributes;
+ std::vector<String> attributes;
/// Visibility of variable. Before introducing additional values, try to use
/// the listed values.
- std::string visibility;
+ String visibility;
/// If true, clients can present the variable with a UI that supports a
/// specific gesture to trigger its evaluation.
@@ -931,7 +930,7 @@ bool fromJSON(const llvm::json::Value &, VariablePresentationHint &,
/// and fetch them in chunks.
struct Variable {
/// The variable's name.
- std::string name;
+ String name;
/// The variable's value.
///
@@ -943,14 +942,14 @@ struct Variable {
/// its children are not yet visible.
///
/// An empty string can be used if no value should be shown in the UI.
- SanitizedString value;
+ String value;
/// The type of the variable's value. Typically shown in the UI when hovering
/// over the value.
///
/// This attribute should only be returned by a debug adapter if the
/// corresponding capability `supportsVariableType` is true.
- std::string type;
+ String type;
/// Properties of a variable that can be used to determine how to render the
/// variable in the UI.
@@ -958,7 +957,7 @@ struct Variable {
/// The evaluatable name of this variable which can be passed to the
/// `evaluate` request to fetch the variable's value.
- std::string evaluateName;
+ String evaluateName;
/// If `variablesReference` is > 0, the variable is structured and its
/// children can be retrieved by passing `variablesReference` to the
@@ -1021,20 +1020,20 @@ llvm::json::Value toJSON(ExceptionBreakMode);
struct ExceptionDetails {
/// Message contained in the exception.
- std::string message;
+ String message;
/// Short type name of the exception object.
- std::string typeName;
+ String typeName;
/// Fully-qualified type name of the exception object.
- std::string fullTypeName;
+ String fullTypeName;
/// An expression that can be evaluated in the current scope to obtain the
/// exception object.
- std::string evaluateName;
+ String evaluateName;
/// Stack trace at the time the exception was thrown.
- std::string stackTrace;
+ String stackTrace;
/// Details of the exception contained by this exception, if any.
std::vector<ExceptionDetails> innerException;
@@ -1043,7 +1042,7 @@ llvm::json::Value toJSON(const ExceptionDetails &);
struct CompileUnit {
/// Path of compile unit.
- std::string compileUnitPath;
+ String compileUnitPath;
};
llvm::json::Value toJSON(const CompileUnit &);
@@ -1088,7 +1087,7 @@ struct StackFrame {
lldb::tid_t id = LLDB_DAP_INVALID_STACK_FRAME_ID;
/// The name of the stack frame, typically a method name.
- std::string name;
+ String name;
/// The source of the frame.
std::optional<Source> source;
@@ -1122,7 +1121,7 @@ struct StackFrame {
lldb::addr_t instructionPointerReference = LLDB_INVALID_ADDRESS;
/// The module associated with this frame, if any.
- std::optional<std::string> moduleId;
+ std::optional<String> moduleId;
/// A hint for how to present this frame in the UI. A value of `label` can be
/// used to indicate that the frame is an artificial frame that is used as a
diff --git a/lldb/tools/lldb-dap/ProtocolUtils.cpp b/lldb/tools/lldb-dap/ProtocolUtils.cpp
index af583fdef52fb..c2c8d7e6b6f88 100644
--- a/lldb/tools/lldb-dap/ProtocolUtils.cpp
+++ b/lldb/tools/lldb-dap/ProtocolUtils.cpp
@@ -136,15 +136,17 @@ std::optional<protocol::Module> CreateModule(const lldb::SBTarget &target,
const auto load_address = module.GetObjectFileHeaderAddress();
if (const lldb::addr_t raw_address = load_address.GetLoadAddress(target);
raw_address != LLDB_INVALID_ADDRESS)
- p_module.addressRange = llvm::formatv("{0:x}", raw_address);
+ p_module.addressRange = llvm::formatv("{0:x}", raw_address).str();
std::array<uint32_t, 3> version_nums{};
const uint32_t num_versions =
module.GetVersion(version_nums.data(), version_nums.size());
if (num_versions > 0) {
- p_module.version = llvm::formatv(
- "{:$[.]}", llvm::make_range(version_nums.begin(),
- version_nums.begin() + num_versions));
+ p_module.version =
+ llvm::formatv("{:$[.]}",
+ llvm::make_range(version_nums.begin(),
+ version_nums.begin() + num_versions))
+ .str();
}
return p_module;
@@ -277,7 +279,7 @@ Variable CreateVariable(lldb::SBValue v, int64_t var_ref, bool format_hex,
// expensive operation.
if (lldb::SBValue first_child = v.GetChildAtIndex(0)) {
llvm::StringRef first_child_name = first_child.GetName();
- if (first_child_name == "[0]") {
+ if (first_child_name.str() == "[0]") {
size_t num_children = v.GetNumChildren();
// If we are creating a "[raw]" fake child for each synthetic type, we
// have to account for it when returning indexed variables.
diff --git a/lldb/tools/lldb-dap/tool/lldb-dap.cpp b/lldb/tools/lldb-dap/tool/lldb-dap.cpp
index af5c743a5edf1..afbc2c7f4c28c 100644
--- a/lldb/tools/lldb-dap/tool/lldb-dap.cpp
+++ b/lldb/tools/lldb-dap/tool/lldb-dap.cpp
@@ -411,7 +411,7 @@ validateConnection(llvm::StringRef conn) {
static llvm::Error serveConnection(
const Socket::SocketProtocol &protocol, llvm::StringRef name, Log &log,
const ReplMode default_repl_mode,
- const std::vector<std::string> &pre_init_commands, bool no_lldbinit,
+ const std::vector<protocol::String> &pre_init_commands, bool no_lldbinit,
std::optional<std::chrono::seconds> connection_timeout_seconds) {
Status status;
static std::unique_ptr<Socket> listener = Socket::Create(protocol, status);
@@ -705,7 +705,7 @@ int main(int argc, char *argv[]) {
lldb::SBDebugger::Terminate();
});
- std::vector<std::string> pre_init_commands;
+ std::vector<protocol::String> pre_init_commands;
for (const std::string &arg :
input_args.getAllArgValues(OPT_pre_init_command)) {
pre_init_commands.push_back(arg);
diff --git a/lldb/unittests/DAP/ProtocolBaseTest.cpp b/lldb/unittests/DAP/ProtocolBaseTest.cpp
index 3eb5551f7f41c..b22ef916bc00a 100644
--- a/lldb/unittests/DAP/ProtocolBaseTest.cpp
+++ b/lldb/unittests/DAP/ProtocolBaseTest.cpp
@@ -21,7 +21,7 @@ TEST(ProtocolBaseTest, SanitizedString) {
for (auto [input, json] : std::vector<std::pair<const char *, const char *>>{
{"valid str", R"("valid str")"},
{"lone trailing \x81\x82 bytes", R"("lone trailing οΏ½οΏ½ bytes")"}}) {
- SanitizedString str = input;
+ String str = input;
Expected<Value> expected_str = parse(json);
ASSERT_THAT_EXPECTED(expected_str, llvm::Succeeded());
EXPECT_EQ(PrettyPrint(*expected_str), PrettyPrint(str));
diff --git a/lldb/unittests/DAP/ProtocolTypesTest.cpp b/lldb/unittests/DAP/ProtocolTypesTest.cpp
index 88af97248febc..c529a5c49eddb 100644
--- a/lldb/unittests/DAP/ProtocolTypesTest.cpp
+++ b/lldb/unittests/DAP/ProtocolTypesTest.cpp
@@ -706,7 +706,7 @@ TEST(ProtocolTypesTest, SetExceptionBreakpointsArguments) {
/*filterOptions=*/testing::IsEmpty())));
EXPECT_THAT_EXPECTED(
parse<SetExceptionBreakpointsArguments>(R"({"filters":["abc"]})"),
- HasValue(testing::FieldsAre(/*filters=*/std::vector<std::string>{"abc"},
+ HasValue(testing::FieldsAre(/*filters=*/std::vector<String>{"abc"},
/*filterOptions=*/testing::IsEmpty())));
EXPECT_THAT_EXPECTED(
parse<SetExceptionBreakpointsArguments>(
diff --git a/lldb/unittests/DAP/TestBase.cpp b/lldb/unittests/DAP/TestBase.cpp
index 1afac18833a03..39634593779ad 100644
--- a/lldb/unittests/DAP/TestBase.cpp
+++ b/lldb/unittests/DAP/TestBase.cpp
@@ -41,7 +41,7 @@ void TransportBase::SetUp() {
dap = std::make_unique<DAP>(
/*log=*/*log,
/*default_repl_mode=*/ReplMode::Auto,
- /*pre_init_commands=*/std::vector<std::string>(),
+ /*pre_init_commands=*/std::vector<String>(),
/*no_lldbinit=*/false,
/*client_name=*/"test_client",
/*transport=*/*to_client, /*loop=*/loop);
>From b6d3ca3effcbb9c4278cbc2b632d220941651d3a Mon Sep 17 00:00:00 2001
From: John Harrison <harjohn at google.com>
Date: Fri, 13 Feb 2026 10:22:26 -0800
Subject: [PATCH 4/4] Adjusting the protocol::String implementation to have
additional overloads for common operations.
---
lldb/tools/lldb-dap/DAP.cpp | 34 +++++------
lldb/tools/lldb-dap/DAP.h | 2 +-
.../Handler/CompileUnitsRequestHandler.cpp | 2 +-
.../DataBreakpointInfoRequestHandler.cpp | 9 ++-
.../Handler/DisassembleRequestHandler.cpp | 2 +-
.../Handler/ExceptionInfoRequestHandler.cpp | 4 +-
.../tools/lldb-dap/Handler/RequestHandler.cpp | 2 +-
lldb/tools/lldb-dap/Handler/RequestHandler.h | 2 +-
.../SetExceptionBreakpointsRequestHandler.cpp | 8 +--
.../Handler/StackTraceRequestHandler.cpp | 7 +--
lldb/tools/lldb-dap/Protocol/DAPTypes.cpp | 6 +-
lldb/tools/lldb-dap/Protocol/ProtocolBase.cpp | 4 +-
lldb/tools/lldb-dap/Protocol/ProtocolBase.h | 60 ++++++++++++++-----
lldb/tools/lldb-dap/ProtocolUtils.cpp | 17 +++---
lldb/unittests/DAP/VariablesTest.cpp | 3 +-
15 files changed, 93 insertions(+), 69 deletions(-)
diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp
index 43038fcff43ef..20241bd585a26 100644
--- a/lldb/tools/lldb-dap/DAP.cpp
+++ b/lldb/tools/lldb-dap/DAP.cpp
@@ -123,7 +123,7 @@ static std::string capitalize(llvm::StringRef str) {
llvm::StringRef DAP::debug_adapter_path = "";
DAP::DAP(Log &log, const ReplMode default_repl_mode,
- std::vector<String> pre_init_commands, bool no_lldbinit,
+ const std::vector<String> &pre_init_commands, bool no_lldbinit,
llvm::StringRef client_name, DAPTransport &transport, MainLoop &loop)
: log(log), transport(transport), broadcaster("lldb-dap"),
progress_event_reporter(
@@ -413,7 +413,7 @@ void DAP::SendOutput(OutputType o, const llvm::StringRef output) {
llvm::json::Object event(CreateEventObject("output"));
llvm::json::Object body{
{"category", category},
- {"output", protocol::String(output.slice(idx, end + 1).str())},
+ {"output", protocol::String(output.slice(idx, end + 1))},
};
event.try_emplace("body", std::move(body));
SendJSON(llvm::json::Value(std::move(event)));
@@ -604,7 +604,7 @@ ReplMode DAP::DetectReplMode(lldb::SBFrame &frame, std::string &expression,
bool partial_expression) {
// Check for the escape hatch prefix.
if (llvm::StringRef expr_ref = expression;
- expr_ref.consume_front(configuration.commandEscapePrefix.str())) {
+ expr_ref.consume_front(configuration.commandEscapePrefix)) {
expression = expr_ref;
return ReplMode::Command;
}
@@ -799,9 +799,9 @@ lldb::SBTarget DAP::CreateTarget(lldb::SBError &error) {
// omitted at all), so it is good to leave the user an opportunity to specify
// those. Any of those three can be left empty.
auto target = this->debugger.CreateTarget(
- /*filename=*/configuration.program.str().data(),
- /*target_triple=*/configuration.targetTriple.str().data(),
- /*platform_name=*/configuration.platformName.str().data(),
+ /*filename=*/configuration.program.c_str(),
+ /*target_triple=*/configuration.targetTriple.c_str(),
+ /*platform_name=*/configuration.platformName.c_str(),
/*add_dependent_modules=*/true, // Add dependent modules.
error);
@@ -846,15 +846,13 @@ bool DAP::HandleObject(const Message &M) {
});
auto handler_pos = request_handlers.find(req->command);
- dispatcher.Set("client_data",
- llvm::Twine("request_command:", req->command).str());
+ dispatcher.Set("client_data", "request_command:" + req->command);
if (handler_pos != request_handlers.end()) {
handler_pos->second->Run(*req);
return true; // Success
}
- dispatcher.Set(
- "error", llvm::Twine("unhandled-command:" + req->command.str()).str());
+ dispatcher.Set("error", "unhandled-command:" + req->command);
DAP_LOG(log, "error: unhandled command '{0}'", req->command);
return false; // Fail
}
@@ -877,8 +875,7 @@ bool DAP::HandleObject(const Message &M) {
// Result should be given, use null if not.
if (resp->success) {
(*response_handler)(resp->body);
- dispatcher.Set("client_data",
- llvm::Twine("response_command:", resp->command).str());
+ dispatcher.Set("client_data", "response_command:" + resp->command);
} else {
llvm::StringRef message = "Unknown error, response failed";
if (resp->message) {
@@ -968,7 +965,7 @@ void DAP::ClearCancelRequest(const CancelArguments &args) {
template <typename T>
static std::optional<T> getArgumentsIfRequest(const Request &req,
- llvm::StringLiteral command) {
+ const protocol::String &command) {
if (req.command != command)
return std::nullopt;
@@ -985,7 +982,7 @@ void DAP::Received(const protocol::Event &event) {
}
void DAP::Received(const protocol::Request &request) {
- if (request.command.str() == "disconnect")
+ if (request.command == "disconnect")
m_disconnecting = true;
const std::optional<CancelArguments> cancel_args =
@@ -1159,8 +1156,7 @@ lldb::SBError DAP::WaitForProcessToStop(std::chrono::seconds seconds) {
}
void DAP::ConfigureSourceMaps() {
- llvm::StringRef srcPath = configuration.sourcePath;
- if (configuration.sourceMap.empty() && srcPath.empty())
+ if (configuration.sourceMap.empty() && configuration.sourcePath.empty())
return;
std::string sourceMapCommand;
@@ -1169,10 +1165,10 @@ void DAP::ConfigureSourceMaps() {
if (!configuration.sourceMap.empty()) {
for (const auto &kv : configuration.sourceMap) {
- strm << "\"" << kv.first.str() << "\" \"" << kv.second.str() << "\" ";
+ strm << "\"" << kv.first << "\" \"" << kv.second << "\" ";
}
- } else if (!srcPath.empty()) {
- strm << "\".\" \"" << srcPath << "\"";
+ } else if (!configuration.sourcePath.empty()) {
+ strm << "\".\" \"" << configuration.sourcePath << "\"";
}
RunLLDBCommands("Setting source map:", {sourceMapCommand});
diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h
index 0b0aa5924d931..3f14dbf723f9e 100644
--- a/lldb/tools/lldb-dap/DAP.h
+++ b/lldb/tools/lldb-dap/DAP.h
@@ -194,7 +194,7 @@ struct DAP final : public DAPTransport::MessageHandler {
/// \param[in] loop
/// Main loop associated with this instance.
DAP(Log &log, const ReplMode default_repl_mode,
- std::vector<protocol::String> pre_init_commands, bool no_lldbinit,
+ const std::vector<protocol::String> &pre_init_commands, bool no_lldbinit,
llvm::StringRef client_name, DAPTransport &transport,
lldb_private::MainLoop &loop);
diff --git a/lldb/tools/lldb-dap/Handler/CompileUnitsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/CompileUnitsRequestHandler.cpp
index e1a3b15b4697b..d24072c8cc05d 100644
--- a/lldb/tools/lldb-dap/Handler/CompileUnitsRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/CompileUnitsRequestHandler.cpp
@@ -30,7 +30,7 @@ llvm::Expected<CompileUnitsResponseBody> CompileUnitsRequestHandler::Run(
int num_modules = dap.target.GetNumModules();
for (int i = 0; i < num_modules; i++) {
auto curr_module = dap.target.GetModuleAtIndex(i);
- if (args->moduleId == llvm::StringRef(curr_module.GetUUIDString())) {
+ if (args->moduleId == curr_module.GetUUIDString()) {
int num_units = curr_module.GetNumCompileUnits();
for (int j = 0; j < num_units; j++) {
auto curr_unit = curr_module.GetCompileUnitAtIndex(j);
diff --git a/lldb/tools/lldb-dap/Handler/DataBreakpointInfoRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/DataBreakpointInfoRequestHandler.cpp
index 662fb67839f60..245d92c18e59e 100644
--- a/lldb/tools/lldb-dap/Handler/DataBreakpointInfoRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/DataBreakpointInfoRequestHandler.cpp
@@ -84,15 +84,14 @@ DataBreakpointInfoRequestHandler::Run(
} else {
is_data_ok = false;
response.description =
- "unable to get byte size for expression: " + args.name.str();
+ "unable to get byte size for expression: " + args.name;
}
}
} else if (args.asAddress) {
size = llvm::utostr(args.bytes.value_or(dap.target.GetAddressByteSize()));
lldb::addr_t load_addr = LLDB_INVALID_ADDRESS;
if (llvm::StringRef(args.name).getAsInteger<lldb::addr_t>(0, load_addr))
- return llvm::make_error<DAPError>(args.name.str() +
- " is not a valid address",
+ return llvm::make_error<DAPError>(args.name + " is not a valid address",
llvm::inconvertibleErrorCode(), false);
addr = llvm::utohexstr(load_addr);
if (!IsRW(dap, load_addr))
@@ -101,7 +100,7 @@ DataBreakpointInfoRequestHandler::Run(
llvm::inconvertibleErrorCode(), false);
} else {
is_data_ok = false;
- response.description = "variable not found: " + args.name.str();
+ response.description = "variable not found: " + args.name;
}
if (is_data_ok) {
@@ -112,7 +111,7 @@ DataBreakpointInfoRequestHandler::Run(
if (args.asAddress)
response.description = size + " bytes at " + addr;
else
- response.description = size + " bytes at " + addr + " " + args.name.str();
+ response.description = size + " bytes at " + addr + " " + args.name;
}
return response;
diff --git a/lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp
index 762f8fb6b7ebf..8387f9ab5c387 100644
--- a/lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp
@@ -120,7 +120,7 @@ static DisassembledInstruction ConvertSBInstructionToDisassembledInstruction(
bytes.pop_back();
disassembled_inst.instructionBytes = std::move(bytes);
- llvm::raw_string_ostream si(disassembled_inst.instruction.str());
+ llvm::raw_string_ostream si(disassembled_inst.instruction);
si << llvm::formatv("{0,-7} {1,-25}", m, o);
// Only add the symbol on the first line of the function.
diff --git a/lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp
index e19b5d4267f72..74ab9a2837034 100644
--- a/lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp
@@ -268,7 +268,7 @@ static std::optional<ExceptionDetails> FormatException(lldb::SBThread &thread) {
return {};
ExceptionDetails details;
- raw_string_ostream OS(details.message.str());
+ raw_string_ostream OS(details.message);
if (const char *name = exception.GetName())
details.evaluateName = name;
@@ -317,7 +317,7 @@ ExceptionInfoRequestHandler::Run(const ExceptionInfoArguments &args) const {
body.exceptionId = FormatExceptionId(dap, thread);
body.details = FormatException(thread);
- raw_string_ostream OS(body.description.str());
+ raw_string_ostream OS(body.description);
OS << FormatStopDescription(thread);
if (std::string stop_info = FormatExtendedStopInfo(thread);
diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.cpp b/lldb/tools/lldb-dap/Handler/RequestHandler.cpp
index a84e00d124de7..5e8c2163c838f 100644
--- a/lldb/tools/lldb-dap/Handler/RequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/RequestHandler.cpp
@@ -285,7 +285,7 @@ void BaseRequestHandler::PrintWelcomeMessage() const {
OS << "\"<lldb-cmd>\" or \"help [<lldb-cmd>]\".\r\n";
break;
case ReplMode::Variable:
- OS << "\"<variable>\" or \"" << dap.configuration.commandEscapePrefix.str()
+ OS << "\"<variable>\" or \"" << dap.configuration.commandEscapePrefix
<< "help [<lldb-cmd>]\".\r\n";
break;
}
diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h
index 08f826ebc0599..9feb636fd5c28 100644
--- a/lldb/tools/lldb-dap/Handler/RequestHandler.h
+++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h
@@ -112,7 +112,7 @@ llvm::Expected<Args> parseArgs(const protocol::Request &request) {
if (request.arguments && !fromJSON(*request.arguments, arguments, root)) {
std::string parse_failure;
llvm::raw_string_ostream OS(parse_failure);
- OS << "invalid arguments for request '" << llvm::StringRef(request.command)
+ OS << "invalid arguments for request '" << request.command
<< "': " << llvm::toString(root.getError()) << "\n";
root.printErrorContext(*request.arguments, OS);
return llvm::make_error<DAPError>(parse_failure);
diff --git a/lldb/tools/lldb-dap/Handler/SetExceptionBreakpointsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SetExceptionBreakpointsRequestHandler.cpp
index 9592437287850..6a271fb825137 100644
--- a/lldb/tools/lldb-dap/Handler/SetExceptionBreakpointsRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/SetExceptionBreakpointsRequestHandler.cpp
@@ -37,20 +37,20 @@ SetExceptionBreakpointsRequestHandler::Run(
SetExceptionBreakpointsResponseBody body;
for (const auto &filter : arguments.filters) {
- auto *exc_bp = dap.GetExceptionBreakpoint(filter.str());
+ auto *exc_bp = dap.GetExceptionBreakpoint(filter);
if (!exc_bp)
continue;
body.breakpoints.push_back(exc_bp->SetBreakpoint());
- unset_filters.erase(filter.str());
+ unset_filters.erase(filter);
}
for (const auto &filterOptions : arguments.filterOptions) {
- auto *exc_bp = dap.GetExceptionBreakpoint(filterOptions.filterId.str());
+ auto *exc_bp = dap.GetExceptionBreakpoint(filterOptions.filterId);
if (!exc_bp)
continue;
body.breakpoints.push_back(exc_bp->SetBreakpoint(filterOptions.condition));
- unset_filters.erase(filterOptions.filterId.str());
+ unset_filters.erase(filterOptions.filterId);
}
// Clear any unset filters.
diff --git a/lldb/tools/lldb-dap/Handler/StackTraceRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/StackTraceRequestHandler.cpp
index f0a990a8b59de..6e6f9b0e5b285 100644
--- a/lldb/tools/lldb-dap/Handler/StackTraceRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/StackTraceRequestHandler.cpp
@@ -47,7 +47,7 @@ static StackFrame CreateStackFrame(DAP &dap, lldb::SBFrame &frame,
// We only include `[opt]` if a custom frame format is not specified.
if (!format && frame.GetFunction().GetIsOptimized())
- stack_frame.name.str() += " [opt]";
+ stack_frame.name += " [opt]";
std::optional<protocol::Source> source = dap.ResolveSource(frame);
if (source && !IsAssemblySource(*source)) {
@@ -97,10 +97,9 @@ static StackFrame CreateExtendedStackFrameLabel(lldb::SBThread &thread,
if (llvm::StringRef queue_name = thread.GetQueueName();
!queue_name.empty()) {
stack_frame.name = llvm::formatv("Enqueued from {0} (Thread {1})",
- queue_name, thread_idx)
- .str();
+ queue_name, thread_idx);
} else {
- stack_frame.name = llvm::formatv("Thread {0}", thread_idx).str();
+ stack_frame.name = llvm::formatv("Thread {0}", thread_idx);
}
}
diff --git a/lldb/tools/lldb-dap/Protocol/DAPTypes.cpp b/lldb/tools/lldb-dap/Protocol/DAPTypes.cpp
index bd4cbc29e76bc..a14ed9e521f48 100644
--- a/lldb/tools/lldb-dap/Protocol/DAPTypes.cpp
+++ b/lldb/tools/lldb-dap/Protocol/DAPTypes.cpp
@@ -15,11 +15,11 @@ bool fromJSON(const llvm::json::Value &Params, PersistenceData &PD,
llvm::json::Value toJSON(const PersistenceData &PD) {
json::Object result{
- {"module_path", std::move(PD.module_path)},
- {"symbol_name", std::move(PD.symbol_name)},
+ {"module_path", PD.module_path},
+ {"symbol_name", PD.symbol_name},
};
- return std::move(result);
+ return result;
}
bool fromJSON(const llvm::json::Value &Params, SourceLLDBData &SLD,
diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolBase.cpp b/lldb/tools/lldb-dap/Protocol/ProtocolBase.cpp
index 170742c7615d7..9008719ba543d 100644
--- a/lldb/tools/lldb-dap/Protocol/ProtocolBase.cpp
+++ b/lldb/tools/lldb-dap/Protocol/ProtocolBase.cpp
@@ -66,7 +66,7 @@ json::Value toJSON(const String &S) {
bool fromJSON(const llvm::json::Value &Param, String &Str,
llvm::json::Path Path) {
if (auto s = Param.getAsString()) {
- Str = *s;
+ Str = *std::move(s);
return true;
}
Path.report("expected string");
@@ -230,7 +230,7 @@ bool fromJSON(json::Value const &Params, std::map<String, String> &M,
for (auto [k, v] : *O) {
auto str = v.getAsString();
if (str)
- M[k.str()] = *str;
+ M[k.str()] = *std::move(str);
}
return true;
}
diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolBase.h b/lldb/tools/lldb-dap/Protocol/ProtocolBase.h
index c37c56c0751fa..8579317bad09a 100644
--- a/lldb/tools/lldb-dap/Protocol/ProtocolBase.h
+++ b/lldb/tools/lldb-dap/Protocol/ProtocolBase.h
@@ -44,42 +44,74 @@ static constexpr Id kCalculateSeq = UINT64_MAX;
/// during serialization.
class String {
public:
- String(std::string str) : m_str(str) {}
+ String() = default;
+ String(const std::string &str) : m_str(str) {}
String(llvm::StringRef str) : m_str(str.str()) {}
String(const char *str) : m_str(str) {}
- String() = default;
+ String(const llvm::formatv_object_base &payload) : m_str(payload.str()) {}
- operator llvm::Twine() { return m_str; }
+ /// Conversion Operators
+ /// @{
operator std::string &() { return m_str; }
+ operator llvm::Twine() const { return m_str; }
operator std::string() const { return m_str; }
operator llvm::StringRef() const { return llvm::StringRef(m_str); }
+ /// @}
void clear() { m_str.clear(); }
bool empty() const { return m_str.empty(); }
const char *c_str() const { return m_str.c_str(); }
const char *data() const { return m_str.data(); }
std::string str() const { return m_str; }
- std::string &str() { return m_str; }
+
+ inline String &operator+=(const String &RHS) {
+ m_str += RHS.m_str;
+ return *this;
+ }
private:
std::string m_str;
};
llvm::json::Value toJSON(const String &s);
bool fromJSON(const llvm::json::Value &, String &, llvm::json::Path);
-inline bool operator==(const String &a, const String &b) {
- return a.str() == b.str();
+
+/// @name String Comparision Operators
+/// @{
+
+inline bool operator==(const String &LHS, const String &RHS) {
+ return llvm::StringRef(LHS) == llvm::StringRef(RHS);
+}
+
+inline bool operator!=(const String &LHS, const String &RHS) {
+ return !(LHS == RHS);
+}
+
+inline bool operator<(const String &LHS, const String &RHS) {
+ return llvm::StringRef(LHS) < llvm::StringRef(RHS);
}
-inline bool operator==(const String &a, const char *b) { return a.str() == b; }
-inline bool operator==(const char *a, const String &b) { return a == b.str(); }
-inline bool operator==(llvm::StringRef a, const String &b) {
- return a.str() == b.str();
+
+inline bool operator<=(const String &LHS, const String &RHS) {
+ return llvm::StringRef(LHS) <= llvm::StringRef(RHS);
}
-inline bool operator==(const String &a, llvm::StringRef b) {
- return a.str() == b.str();
+
+inline bool operator>(const String &LHS, const String &RHS) {
+ return llvm::StringRef(LHS) > llvm::StringRef(RHS);
}
-inline bool operator<(const String &a, const String &b) {
- return a.str() < b.str();
+
+inline bool operator>=(const String &LHS, const String &RHS) {
+ return llvm::StringRef(LHS) >= llvm::StringRef(RHS);
}
+
+/// @}
+
+inline String operator+(const char *LHS, const String &RHS) {
+ return std::string(LHS).append(RHS.str().data(), RHS.str().size());
+}
+
+inline String operator+(const std::string &LHS, const String &RHS) {
+ return std::string(LHS).append(RHS.str().data(), RHS.str().size());
+}
+
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const String &S) {
OS << S.str();
return OS;
diff --git a/lldb/tools/lldb-dap/ProtocolUtils.cpp b/lldb/tools/lldb-dap/ProtocolUtils.cpp
index c2c8d7e6b6f88..32aaf62831848 100644
--- a/lldb/tools/lldb-dap/ProtocolUtils.cpp
+++ b/lldb/tools/lldb-dap/ProtocolUtils.cpp
@@ -136,17 +136,15 @@ std::optional<protocol::Module> CreateModule(const lldb::SBTarget &target,
const auto load_address = module.GetObjectFileHeaderAddress();
if (const lldb::addr_t raw_address = load_address.GetLoadAddress(target);
raw_address != LLDB_INVALID_ADDRESS)
- p_module.addressRange = llvm::formatv("{0:x}", raw_address).str();
+ p_module.addressRange = llvm::formatv("{0:x}", raw_address);
std::array<uint32_t, 3> version_nums{};
const uint32_t num_versions =
module.GetVersion(version_nums.data(), version_nums.size());
if (num_versions > 0) {
- p_module.version =
- llvm::formatv("{:$[.]}",
- llvm::make_range(version_nums.begin(),
- version_nums.begin() + num_versions))
- .str();
+ p_module.version = llvm::formatv(
+ "{:$[.]}", llvm::make_range(version_nums.begin(),
+ version_nums.begin() + num_versions));
}
return p_module;
@@ -205,10 +203,9 @@ protocol::Thread CreateThread(lldb::SBThread &thread, lldb::SBFormat &format) {
queue_kind_label = " (concurrent)";
name = llvm::formatv("Thread {0} Queue: {1}{2}", thread.GetIndexID(),
- queue_name, queue_kind_label)
- .str();
+ queue_name, queue_kind_label);
} else {
- name = llvm::formatv("Thread {0}", thread.GetIndexID()).str();
+ name = llvm::formatv("Thread {0}", thread.GetIndexID());
}
}
return protocol::Thread{thread.GetThreadID(), name};
@@ -279,7 +276,7 @@ Variable CreateVariable(lldb::SBValue v, int64_t var_ref, bool format_hex,
// expensive operation.
if (lldb::SBValue first_child = v.GetChildAtIndex(0)) {
llvm::StringRef first_child_name = first_child.GetName();
- if (first_child_name.str() == "[0]") {
+ if (first_child_name == "[0]") {
size_t num_children = v.GetNumChildren();
// If we are creating a "[raw]" fake child for each synthetic type, we
// have to account for it when returning indexed variables.
diff --git a/lldb/unittests/DAP/VariablesTest.cpp b/lldb/unittests/DAP/VariablesTest.cpp
index c7ffe42202090..dcc956d3e5801 100644
--- a/lldb/unittests/DAP/VariablesTest.cpp
+++ b/lldb/unittests/DAP/VariablesTest.cpp
@@ -21,7 +21,8 @@ class VariablesTest : public ::testing::Test {
Variables vars;
static const protocol::Scope *
- FindScope(const std::vector<protocol::Scope> &scopes, llvm::StringRef name) {
+ FindScope(const std::vector<protocol::Scope> &scopes,
+ const protocol::String &name) {
for (const auto &scope : scopes) {
if (scope.name == name)
return &scope;
More information about the lldb-commits
mailing list