[Lldb-commits] [lldb] [lldb-vscode] Show a fake child with the raw value of synthetic types (PR #65552)
Walter Erquinigo via lldb-commits
lldb-commits at lists.llvm.org
Wed Sep 6 17:04:48 PDT 2023
https://github.com/walter-erquinigo created https://github.com/llvm/llvm-project/pull/65552:
Currently, if the user wants to inspect the raw version of a synthetic variable, they have to go to the debug console and type `frame var <variable>, which is not a great experience. Taking inspiration from CodeLLDB, this adds a `[raw]` child to every synthetic variable so that this kind of inspection can be done visually.
>From 5a5f3031e381ef3b2bf5bf76923548c56bc17b2b Mon Sep 17 00:00:00 2001
From: walter erquinigo <walter at modular.com>
Date: Wed, 6 Sep 2023 20:01:37 -0400
Subject: [PATCH] [lldb-vscode] Show a fake child with the raw value of
synthetic types
Currently, if the user wants to inspect the raw version of a synthetic variable, they have to go to the debug console and type `frame var <variable>, which is not a great experience. Taking inspiration from CodeLLDB, this adds a `[raw]` child to every synthetic variable so that this kind of inspection can be done visually.
---
.../variables/TestVSCode_variables.py | 14 ++++++++
lldb/tools/lldb-vscode/JSONUtils.cpp | 17 +++++++---
lldb/tools/lldb-vscode/JSONUtils.h | 7 +++-
lldb/tools/lldb-vscode/lldb-vscode.cpp | 33 +++++++++++++------
4 files changed, 55 insertions(+), 16 deletions(-)
diff --git a/lldb/test/API/tools/lldb-vscode/variables/TestVSCode_variables.py b/lldb/test/API/tools/lldb-vscode/variables/TestVSCode_variables.py
index 6eb8e87190d0074..953f330e14a0f97 100644
--- a/lldb/test/API/tools/lldb-vscode/variables/TestVSCode_variables.py
+++ b/lldb/test/API/tools/lldb-vscode/variables/TestVSCode_variables.py
@@ -517,6 +517,20 @@ def test_indexedVariables(self):
}
self.verify_variables(verify_locals, locals)
+ # We also verify that we produce a "[raw]" fake child with the real
+ # SBValue for the synthetic type.
+ verify_children = {
+ "[0]": {"equals": {"type": "int", "value": "0"}},
+ "[1]": {"equals": {"type": "int", "value": "0"}},
+ "[2]": {"equals": {"type": "int", "value": "0"}},
+ "[3]": {"equals": {"type": "int", "value": "0"}},
+ "[4]": {"equals": {"type": "int", "value": "0"}},
+ "[raw]": {"contains": {"type": ["vector"]}},
+ }
+ children = self.vscode.request_variables(locals[2]["variablesReference"])["body"]["variables"]
+ self.verify_variables(verify_children, children)
+
+
@skipIfWindows
@skipIfRemote
def test_registers(self):
diff --git a/lldb/tools/lldb-vscode/JSONUtils.cpp b/lldb/tools/lldb-vscode/JSONUtils.cpp
index 9a6fd26d2bd5864..e34448c9b7f2f85 100644
--- a/lldb/tools/lldb-vscode/JSONUtils.cpp
+++ b/lldb/tools/lldb-vscode/JSONUtils.cpp
@@ -1103,10 +1103,13 @@ std::string CreateUniqueVariableNameForDisplay(lldb::SBValue v,
// }
llvm::json::Value CreateVariable(lldb::SBValue v, int64_t variablesReference,
int64_t varID, bool format_hex,
- bool is_name_duplicated) {
+ bool is_name_duplicated,
+ std::optional<std::string> custom_name) {
llvm::json::Object object;
- EmplaceSafeString(object, "name",
- CreateUniqueVariableNameForDisplay(v, is_name_duplicated));
+ EmplaceSafeString(
+ object, "name",
+ custom_name ? *custom_name
+ : CreateUniqueVariableNameForDisplay(v, is_name_duplicated));
if (format_hex)
v.SetFormat(lldb::eFormatHex);
@@ -1131,15 +1134,19 @@ llvm::json::Value CreateVariable(lldb::SBValue v, int64_t variablesReference,
const bool is_synthetic = v.IsSynthetic();
if (is_array || is_synthetic) {
const auto num_children = v.GetNumChildren();
+ // We create a "[raw]" fake child for each synthetic type, so we have to
+ // account for it when returning indexed variables. We don't need to do this
+ // for non-indexed ones.
+ int actual_num_children = num_children + (is_synthetic ? 1 : 0);
if (is_array) {
- object.try_emplace("indexedVariables", num_children);
+ object.try_emplace("indexedVariables", actual_num_children);
} else if (num_children > 0) {
// If a type has a synthetic child provider, then the SBType of "v" won't
// tell us anything about what might be displayed. So we can check if the
// first child's name is "[0]" and then we can say it is indexed.
const char *first_child_name = v.GetChildAtIndex(0).GetName();
if (first_child_name && strcmp(first_child_name, "[0]") == 0)
- object.try_emplace("indexedVariables", num_children);
+ object.try_emplace("indexedVariables", actual_num_children);
}
}
EmplaceSafeString(object, "type", type_cstr ? type_cstr : NO_TYPENAME);
diff --git a/lldb/tools/lldb-vscode/JSONUtils.h b/lldb/tools/lldb-vscode/JSONUtils.h
index 516bc462eae1b16..2013147f5d3532a 100644
--- a/lldb/tools/lldb-vscode/JSONUtils.h
+++ b/lldb/tools/lldb-vscode/JSONUtils.h
@@ -440,12 +440,17 @@ std::string CreateUniqueVariableNameForDisplay(lldb::SBValue v,
/// As VSCode doesn't render two of more variables with the same name, we
/// apply a suffix to distinguish duplicated variables.
///
+/// \param[in] custom_name
+/// A provided custom name that is used instead of the SBValue's when
+/// creating the JSON representation.
+///
/// \return
/// A "Variable" JSON object with that follows the formal JSON
/// definition outlined by Microsoft.
llvm::json::Value CreateVariable(lldb::SBValue v, int64_t variablesReference,
int64_t varID, bool format_hex,
- bool is_name_duplicated = false);
+ bool is_name_duplicated = false,
+ std::optional<std::string> custom_name = {});
llvm::json::Value CreateCompileUnit(lldb::SBCompileUnit unit);
diff --git a/lldb/tools/lldb-vscode/lldb-vscode.cpp b/lldb/tools/lldb-vscode/lldb-vscode.cpp
index 294783c4f505d37..5480edd74f24f47 100644
--- a/lldb/tools/lldb-vscode/lldb-vscode.cpp
+++ b/lldb/tools/lldb-vscode/lldb-vscode.cpp
@@ -3251,7 +3251,7 @@ void request_variables(const llvm::json::Object &request) {
break;
int64_t var_ref = 0;
- if (variable.MightHaveChildren()) {
+ if (variable.MightHaveChildren() || variable.IsSynthetic()) {
var_ref = g_vsc.variables.InsertExpandableVariable(
variable, /*is_permanent=*/false);
}
@@ -3264,23 +3264,36 @@ void request_variables(const llvm::json::Object &request) {
// children.
lldb::SBValue variable = g_vsc.variables.GetVariable(variablesReference);
if (variable.IsValid()) {
- const auto num_children = variable.GetNumChildren();
- const int64_t end_idx = start + ((count == 0) ? num_children : count);
- for (auto i = start; i < end_idx; ++i) {
- lldb::SBValue child = variable.GetChildAtIndex(i);
+ auto addChild = [&](lldb::SBValue child,
+ std::optional<std::string> custom_name = {}) {
if (!child.IsValid())
- break;
+ return;
if (child.MightHaveChildren()) {
auto is_permanent =
g_vsc.variables.IsPermanentVariableReference(variablesReference);
auto childVariablesReferences =
g_vsc.variables.InsertExpandableVariable(child, is_permanent);
- variables.emplace_back(CreateVariable(child, childVariablesReferences,
- childVariablesReferences, hex));
+ variables.emplace_back(CreateVariable(
+ child, childVariablesReferences, childVariablesReferences, hex,
+ /*is_name_duplicated=*/false, custom_name));
} else {
- variables.emplace_back(CreateVariable(child, 0, INT64_MAX, hex));
+ variables.emplace_back(CreateVariable(child, 0, INT64_MAX, hex,
+ /*is_name_duplicated=*/false,
+ custom_name));
}
- }
+ };
+ const int64_t num_children = variable.GetNumChildren();
+ int64_t end_idx = start + ((count == 0) ? num_children : count);
+ int64_t i = start;
+ for (; i < end_idx && i < num_children; ++i)
+ addChild(variable.GetChildAtIndex(i));
+
+ // If we haven't filled the count quota from the request, we insert a new
+ // "[raw]" child that can be used to inspect the raw version of a
+ // synthetic member. That eliminates the need for the user to go to the
+ // debug console and type `frame var <variable> to get these values.
+ if (variable.IsSynthetic() && i == num_children)
+ addChild(variable.GetNonSyntheticValue(), "[raw]");
}
}
llvm::json::Object body;
More information about the lldb-commits
mailing list