[Lldb-commits] [lldb] [lldb-dap] Improve support for variables with anonymous fields and types (PR #186482)

John Harrison via lldb-commits lldb-commits at lists.llvm.org
Mon Mar 16 12:58:30 PDT 2026


================
@@ -47,73 +45,167 @@ template <typename T> StringMap<uint32_t> DistinctNames(T &container) {
   return variable_name_counts;
 }
 
-template <typename T>
-std::vector<Variable> MakeVariables(
-    VariableReferenceStorage &storage, const Configuration &config,
-    const VariablesArguments &args, T &container, bool is_permanent,
-    const std::map<lldb::user_id_t, std::string> &name_overrides = {}) {
-  std::vector<Variable> variables;
+protocol::Scope CreateScope(ScopeKind kind, var_ref_t variablesReference,
+                            bool expensive) {
+  protocol::Scope scope;
+  scope.variablesReference = variablesReference;
+  scope.expensive = expensive;
 
-  // We first find out which variable names are duplicated.
-  StringMap<uint32_t> variable_name_counts = DistinctNames(container);
+  switch (kind) {
+  case eScopeKindLocals:
+    scope.presentationHint = protocol::Scope::eScopePresentationHintLocals;
+    scope.name = "Locals";
+    break;
+  case eScopeKindGlobals:
+    scope.name = "Globals";
+    break;
+  case eScopeKindRegisters:
+    scope.presentationHint = protocol::Scope::eScopePresentationHintRegisters;
+    scope.name = "Registers";
+    break;
+  }
 
-  const bool format_hex = args.format ? args.format->hex : false;
-  auto start_it = begin(container) + args.start;
-  auto end_it = args.count == 0 ? end(container) : start_it + args.count;
+  return scope;
+}
 
-  // Now we construct the result with unique display variable names.
-  for (; start_it != end_it; start_it++) {
-    lldb::SBValue variable = *start_it;
-    if (!variable.IsValid())
-      break;
+class VariableStoreImpl : public VariableStore {
+public:
+  using VariableStore::VariableStore;
+  Variable CreateVariable(lldb::SBValue v, bool format_hex,
+                          bool is_name_duplicated,
+                          std::optional<llvm::StringRef> custom_name) {
+    VariableDescription desc(v, m_storage.config.enableAutoVariableSummaries,
+                             format_hex, is_name_duplicated, custom_name);
+    Variable var;
+    var.name = desc.name;
+    var.value = desc.display_value;
+    var.type = desc.display_type_name;
+
+    if (!desc.evaluate_name.empty())
+      var.evaluateName = desc.evaluate_name;
+
+    // If we have a type with many children, we would like to be able to
+    // give a hint to the IDE that the type has indexed children so that the
+    // request can be broken up in grabbing only a few children at a time. We
+    // want to be careful and only call "v.GetNumChildren()" if we have an array
+    // type or if we have a synthetic child provider producing indexed children.
+    // We don't want to call "v.GetNumChildren()" on all objects as class,
+    // struct and union types don't need to be completed if they are never
+    // expanded. So we want to avoid calling this to only cases where we it
+    // makes sense to keep performance high during normal debugging.
+
+    // If we have an array type, say that it is indexed and provide the number
+    // of children in case we have a huge array. If we don't do this, then we
+    // might take a while to produce all children at onces which can delay your
+    // debug session.
+    if (desc.type_obj.IsArrayType()) {
+      var.indexedVariables = v.GetNumChildren();
+    } else if (v.IsSynthetic()) {
+      // For a type with a synthetic child provider, the SBType of "v" won't
+      // tell us anything about what might be displayed. Instead, we check if
+      // the first child's name is "[0]" and then say it is indexed. We call
+      // GetNumChildren() only if the child name matches to avoid a potentially
+      // expensive operation.
+      if (lldb::SBValue first_child = v.GetChildAtIndex(0)) {
+        llvm::StringRef first_child_name = first_child.GetName();
+        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.
+          if (m_storage.config.enableSyntheticChildDebugging)
+            ++num_children;
+          var.indexedVariables = num_children;
+        }
+      }
+    }
+
+    const bool is_internal = var.name == "[raw]" || m_is_internal;
 
     const var_ref_t var_ref =
-        HasInnerVarref(variable)
-            ? storage.Insert(variable, /*is_permanent=*/is_permanent)
+        HasInnerVarref(v)
+            ? m_storage.Insert(v, /*is_permanent=*/m_is_permanent, is_internal)
             : var_ref_t(var_ref_t::k_no_child);
-    if (LLVM_UNLIKELY(var_ref.AsUInt32() >=
-                      var_ref_t::k_variables_reference_threshold)) {
-      DAP_LOG(storage.log,
-              "warning: variablesReference threshold reached. "
-              "current: {} threshold: {}, maximum {}.",
-              var_ref.AsUInt32(), var_ref_t::k_variables_reference_threshold,
-              var_ref_t::k_max_variables_references);
-      break;
-    }
 
-    if (LLVM_UNLIKELY(var_ref.Kind() == eReferenceKindInvalid))
-      break;
+    if (var.indexedVariables || v.MightHaveChildren())
+      var.variablesReference = var_ref;
+
+    if (v.GetDeclaration().IsValid())
+      var.declarationLocationReference =
+          PackLocation(var_ref.AsUInt32(), false);
 
-    std::optional<std::string> custom_name;
-    auto name_it = name_overrides.find(variable.GetID());
-    if (name_it != name_overrides.end())
-      custom_name = name_it->second;
+    if (ValuePointsToCode(v))
+      var.valueLocationReference = PackLocation(var_ref.AsUInt32(), true);
 
-    variables.emplace_back(CreateVariable(
-        variable, var_ref, format_hex, config.enableAutoVariableSummaries,
-        config.enableSyntheticChildDebugging,
-        variable_name_counts[GetNonNullVariableName(variable)] > 1,
-        custom_name));
+    if (lldb::addr_t addr = v.GetLoadAddress(); addr != LLDB_INVALID_ADDRESS)
+      var.memoryReference = addr;
+
+    bool is_readonly = is_internal || v.GetType().IsAggregateType() ||
+                       v.GetValueType() == lldb::eValueTypeRegisterSet;
+    if (is_readonly) {
+      if (!var.presentationHint)
+        var.presentationHint = {VariablePresentationHint()};
+      var.presentationHint->attributes.push_back("readOnly");
+    }
+
+    if (is_internal) {
+      if (!var.presentationHint)
+        var.presentationHint = {VariablePresentationHint()};
+      var.presentationHint->visibility = "internal";
+    }
----------------
ashgti wrote:

Done.

https://github.com/llvm/llvm-project/pull/186482


More information about the lldb-commits mailing list