Skip to content

[lldb-vscode] Show a fake child with the raw value of synthetic types #65552

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down
17 changes: 12 additions & 5 deletions lldb/tools/lldb-vscode/JSONUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);
Expand Down
7 changes: 6 additions & 1 deletion lldb/tools/lldb-vscode/JSONUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
33 changes: 23 additions & 10 deletions lldb/tools/lldb-vscode/lldb-vscode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand All @@ -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;
Expand Down