================
@@ -51,155 +59,310 @@ protocol::Scope CreateScope(const ScopeKind kind, int64_t 
variablesReference,
   return scope;
 }
 
-std::optional<ScopeData>
-Variables::GetTopLevelScope(int64_t variablesReference) {
-  auto scope_kind_iter = m_scope_kinds.find(variablesReference);
-  if (scope_kind_iter == m_scope_kinds.end())
-    return std::nullopt;
+std::vector<Variable>
+ScopeStore::GetVariables(VariableReferenceStorage &storage,
+                         const Configuration &config,
+                         const VariablesArguments &args) {
+  LoadVariables();
+  if (m_kind == lldb_dap::eScopeKindRegisters)
+    SetRegistersFormat();
 
-  ScopeKind scope_kind = scope_kind_iter->second.first;
-  uint64_t dap_frame_id = scope_kind_iter->second.second;
+  const bool format_hex = args.format ? args.format->hex : false;
+  std::vector<Variable> variables;
+  if (m_kind == eScopeKindLocals)
+    AddReturnValue(storage, config, variables, format_hex);
 
-  auto frame_iter = m_frames.find(dap_frame_id);
-  if (frame_iter == m_frames.end())
-    return std::nullopt;
+  const uint64_t count = args.count;
+  const uint32_t start_idx = 0;
+  const uint32_t num_children = m_children.GetSize();
+  const uint32_t end_idx = start_idx + ((count == 0) ? num_children : count);
 
-  lldb::SBValueList *scope = frame_iter->second.GetScope(scope_kind);
-  if (scope == nullptr)
-    return std::nullopt;
+  // We first find out which variable names are duplicated.
+  std::map<llvm::StringRef, uint32_t> variable_name_counts;
+  for (auto i = start_idx; i < end_idx; ++i) {
+    lldb::SBValue variable = m_children.GetValueAtIndex(i);
+    if (!variable.IsValid())
+      break;
+    variable_name_counts[GetNonNullVariableName(variable)]++;
+  }
 
-  ScopeData scope_data;
-  scope_data.kind = scope_kind;
-  scope_data.scope = *scope;
-  return scope_data;
-}
+  // Now we construct the result with unique display variable names.
+  for (auto i = start_idx; i < end_idx; ++i) {
+    lldb::SBValue variable = m_children.GetValueAtIndex(i);
+
+    if (!variable.IsValid())
+      break;
+
+    const var_ref_t frame_var_ref =
+        storage.InsertVariable(variable, /*is_permanent=*/false);
+    if (LLVM_UNLIKELY(frame_var_ref.AsUInt32() >=
+                      var_ref_t::k_variables_reference_threshold)) {
+      DAP_LOG(storage.log,
+              "warning: scopes variablesReference threshold is reached. "
+              "current: {} threshold: {}, maximum {}\n",
+              frame_var_ref.AsUInt32(),
+              var_ref_t::k_variables_reference_threshold,
+              var_ref_t::k_max_variables_references);
+    }
 
-void Variables::Clear() {
-  m_referencedvariables.clear();
-  m_scope_kinds.clear();
-  m_frames.clear();
-  m_next_temporary_var_ref = TemporaryVariableStartIndex;
+    if (LLVM_UNLIKELY(frame_var_ref.Kind() == eReferenceKindInvalid))
+      break;
+
+    variables.emplace_back(CreateVariable(
+        variable, frame_var_ref, format_hex, 
config.enableAutoVariableSummaries,
+        config.enableSyntheticChildDebugging,
+        variable_name_counts[GetNonNullVariableName(variable)] > 1));
+  }
+  return variables;
 }
 
-int64_t Variables::GetNewVariableReference(bool is_permanent) {
-  if (is_permanent)
-    return m_next_permanent_var_ref++;
-  return m_next_temporary_var_ref++;
+lldb::SBValue ScopeStore::FindVariable(llvm::StringRef name) {
+  LoadVariables();
+
+  lldb::SBValue variable;
+  const bool is_name_duplicated = name.contains(" @");
+  // variablesReference is one of our scopes, not an actual variable it is
+  // asking for a variable in locals or globals or registers.
+  const uint32_t end_idx = m_children.GetSize();
+  // Searching backward so that we choose the variable in closest scope
+  // among variables of the same name.
+  for (const uint32_t i : llvm::reverse(llvm::seq<uint32_t>(0, end_idx))) {
+    lldb::SBValue curr_variable = m_children.GetValueAtIndex(i);
+    std::string variable_name =
+        CreateUniqueVariableNameForDisplay(curr_variable, is_name_duplicated);
+    if (variable_name == name) {
+      variable = curr_variable;
+      break;
+    }
+  }
+  return variable;
 }
 
-bool Variables::IsPermanentVariableReference(int64_t var_ref) {
-  return var_ref >= PermanentVariableStartIndex;
+void ScopeStore::LoadVariables() {
+  if (m_variables_loaded)
+    return;
+
+  m_variables_loaded = true;
+  switch (m_kind) {
+  case eScopeKindLocals:
+    m_children = m_frame.GetVariables(/*arguments=*/true,
+                                      /*locals=*/true,
+                                      /*statics=*/false,
+                                      /*in_scope_only=*/true);
+    break;
+  case eScopeKindGlobals:
+    m_children = m_frame.GetVariables(/*arguments=*/false,
+                                      /*locals=*/false,
+                                      /*statics=*/true,
+                                      /*in_scope_only=*/true);
+    break;
+  case eScopeKindRegisters:
+    m_children = m_frame.GetRegisters();
+  }
 }
 
-lldb::SBValue Variables::GetVariable(int64_t var_ref) const {
-  if (IsPermanentVariableReference(var_ref)) {
-    auto pos = m_referencedpermanent_variables.find(var_ref);
-    if (pos != m_referencedpermanent_variables.end())
-      return pos->second;
-  } else {
-    auto pos = m_referencedvariables.find(var_ref);
-    if (pos != m_referencedvariables.end())
-      return pos->second;
+void ScopeStore::SetRegistersFormat() {
+  // Change the default format of any pointer sized registers in the first
+  // register set to be the lldb::eFormatAddressInfo so we show the pointer
+  // and resolve what the pointer resolves to. Only change the format if the
+  // format was set to the default format or if it was hex as some registers
+  // have formats set for them.
+  const uint32_t addr_size =
+      m_frame.GetThread().GetProcess().GetAddressByteSize();
+  for (lldb::SBValue reg : m_children.GetValueAtIndex(0)) {
+    const lldb::Format format = reg.GetFormat();
+    if (format == lldb::eFormatDefault || format == lldb::eFormatHex) {
+      if (reg.GetByteSize() == addr_size)
+        reg.SetFormat(lldb::eFormatAddressInfo);
+    }
   }
-  return lldb::SBValue();
 }
 
-int64_t Variables::InsertVariable(lldb::SBValue variable, bool is_permanent) {
-  int64_t var_ref = GetNewVariableReference(is_permanent);
-  if (is_permanent)
-    m_referencedpermanent_variables.insert(std::make_pair(var_ref, variable));
-  else
-    m_referencedvariables.insert(std::make_pair(var_ref, variable));
-  return var_ref;
+void ScopeStore::AddReturnValue(VariableReferenceStorage &storage,
+                                const Configuration &config,
+                                std::vector<Variable> &variables,
+                                bool format_hex) {
+  assert(m_kind == eScopeKindLocals &&
+         "Return Value Should only be in local scope");
+  if (m_children.GetSize() == 0) {
+    // Check for an error in the SBValueList that might explain why we don't
+    // have locals. If we have an error display it as the sole value in the
+    // the locals.
+
+    // "error" owns the error string so we must keep it alive as long as we
+    // want to use the returns "const char *".
+    lldb::SBError error = m_children.GetError();
+    if (const char *var_err = error.GetCString()) {
+      // Create a fake variable named "error" to explain why variables were
+      // not available. This new error will help let users know when there was
+      // a problem that kept variables from being available for display and
+      // allow users to fix this issue instead of seeing no variables. The
+      // errors are only set when there is a problem that the user could
+      // fix, so no error will show up when you have no debug info, only when
+      // we do have debug info and something that is fixable can be done.
+      Variable err_var;
+      err_var.name = "<error>";
+      err_var.type = "const char *";
+      err_var.value = var_err;
+      variables.push_back(std::move(err_var));
+    }
+    return;
+  }
+
+  // Show return value if there is any ( in the local top frame )
+  lldb::SBThread selected_thread = m_frame.GetThread();
+  lldb::SBValue stop_return_value = selected_thread.GetStopReturnValue();
+
+  if (stop_return_value.IsValid() &&
+      (selected_thread.GetSelectedFrame().GetFrameID() == 0)) {
+    auto renamed_return_value = stop_return_value.Clone("(Return Value)");
+    var_ref_t return_var_ref{0};
+
+    if (stop_return_value.MightHaveChildren() ||
+        stop_return_value.IsSynthetic()) {
+      return_var_ref = storage.InsertVariable(stop_return_value,
+                                              /*is_permanent=*/false);
+    }
+    variables.emplace_back(
+        CreateVariable(renamed_return_value, return_var_ref, format_hex,
+                       config.enableAutoVariableSummaries,
+                       config.enableSyntheticChildDebugging, false));
+  }
 }
 
-lldb::SBValue Variables::FindVariable(uint64_t variablesReference,
-                                      llvm::StringRef name) {
-  lldb::SBValue variable;
-  if (std::optional<ScopeData> scope_data =
-          GetTopLevelScope(variablesReference)) {
-    bool is_duplicated_variable_name = name.contains(" @");
-    // variablesReference is one of our scopes, not an actual variable it is
-    // asking for a variable in locals or globals or registers
-    int64_t end_idx = scope_data->scope.GetSize();
-    // Searching backward so that we choose the variable in closest scope
-    // among variables of the same name.
-    for (int64_t i = end_idx - 1; i >= 0; --i) {
-      lldb::SBValue curr_variable = scope_data->scope.GetValueAtIndex(i);
-      std::string variable_name = CreateUniqueVariableNameForDisplay(
-          curr_variable, is_duplicated_variable_name);
-      if (variable_name == name) {
-        variable = curr_variable;
-        break;
-      }
+std::vector<Variable>
+ExpandableValueStore::GetVariables(VariableReferenceStorage &storage,
+                                   const Configuration &config,
+                                   const VariablesArguments &args) {
+  const var_ref_t var_ref = args.variablesReference;
+  const uint64_t count = args.count;
+  const uint64_t start = args.start;
+  const bool hex = args.format ? args.format->hex : false;
+
+  lldb::SBValue variable = storage.GetVariable(var_ref);
+  if (!variable)
+    return {};
+
+  // We are expanding a variable that has children, so we will return its
+  // children.
+  std::vector<Variable> variables;
+  const bool is_permanent = var_ref.Kind() == eReferenceKindPermanent;
+  auto addChild = [&](lldb::SBValue child,
+                      std::optional<llvm::StringRef> custom_name = {}) {
+    if (!child.IsValid())
+      return;
+
+    const var_ref_t child_var_ref = storage.InsertVariable(child, 
is_permanent);
+    if (LLVM_UNLIKELY(child_var_ref.AsUInt32() ==
+                      var_ref_t::k_variables_reference_threshold)) {
+      DAP_LOG(storage.log,
+              "warning: {} variablesReference threshold is reached. "
+              "current: {} threshold: {}, maximum {}\n",
+              (is_permanent ? "permanent" : "temporary"),
+              child_var_ref.AsUInt32(),
+              var_ref_t::k_variables_reference_threshold,
+              var_ref_t::k_max_variables_references);
     }
-  } else {
-    // This is not under the globals or locals scope, so there are no
-    // duplicated names.
-
-    // We have a named item within an actual variable so we need to find it
-    // withing the container variable by name.
-    lldb::SBValue container = GetVariable(variablesReference);
-    variable = container.GetChildMemberWithName(name.data());
-    if (!variable.IsValid()) {
-      if (name.starts_with("[")) {
-        llvm::StringRef index_str(name.drop_front(1));
-        uint64_t index = 0;
-        if (!index_str.consumeInteger(0, index)) {
-          if (index_str == "]")
-            variable = container.GetChildAtIndex(index);
-        }
+
+    if (LLVM_UNLIKELY(child_var_ref.Kind() == eReferenceKindInvalid))
+      return;
+
+    variables.emplace_back(CreateVariable(
+        child, child_var_ref, hex, config.enableAutoVariableSummaries,
+        config.enableSyntheticChildDebugging,
+        /*is_name_duplicated=*/false, custom_name));
+  };
+
+  const uint32_t num_children = variable.GetNumChildren();
+  const uint32_t end_idx = start + ((count == 0) ? num_children : count);
+  uint32_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 (config.enableSyntheticChildDebugging && variable.IsSynthetic() &&
+      i == num_children)
+    addChild(variable.GetNonSyntheticValue(), "[raw]");
+
+  return variables;
+}
+
+lldb::SBValue ExpandableValueStore::FindVariable(llvm::StringRef name) {
+  lldb::SBValue variable = m_value.GetChildMemberWithName(name.data());
+  if (!variable.IsValid()) {
+    if (name.starts_with('[') && name.ends_with(']')) {
+      llvm::StringRef index_str(name.drop_front().drop_back());
+      uint64_t index = 0;
+      if (!index_str.consumeInteger(0, index)) {
+        variable = m_value.GetChildAtIndex(index);
       }
     }
   }
+
   return variable;
----------------
DrSergei wrote:

Can we simplify this code
```
  lldb::SBValue variable = m_value.GetChildMemberWithName(name.data());
  if (variable.IsValid())
    return variable;
  if (!name.starts_with('[') || !name.ends_with(']'))
    return {};
  llvm::StringRef index_str(name.drop_front().drop_back());
  uint64_t index = 0;
  if (!index_str.consumeInteger(0, index))
    return m_value.GetChildAtIndex(index);
  return {};
```

https://github.com/llvm/llvm-project/pull/179262
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to