fdeazeve created this revision.
Herald added a project: All.
fdeazeve requested review of this revision.
Herald added a project: LLDB.
Herald added a subscriber: lldb-commits.

Currently frame var --regex sometimes searches globals, sometimes it doesn't.
This happens because `StackFrame::GetVariableList` always returns the biggest
list it has, regardless of whether only globals were requested or not. In other
words, if a previous call to `GetVariableList` requested globals, all subsequent
calls will see them.

The implication here is that users of `StackFrame::GetVariableList` are expected
to filter the results of this function. This is what we do for a vanilla
`frame var` command. But it is not what we do when `--regex` is used. This
commit solves the issue by:

1. Making `--regex` imply `--globals`. This matches the behavior of `frame var

<some_name>`, which will also search the global scope.

2. Making the `--regex` search respect the command object options.

See the added test for an example of the oddities this patch addresses. Without
the patch, the test fails. However it could be made to pass by calling a plain
`frame var` before calling `frame var --regex A::`.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D155334

Files:
  lldb/include/lldb/Symbol/VariableList.h
  lldb/source/Commands/CommandObjectFrame.cpp
  lldb/test/API/commands/frame/var/TestFrameVar.py

Index: lldb/test/API/commands/frame/var/TestFrameVar.py
===================================================================
--- lldb/test/API/commands/frame/var/TestFrameVar.py
+++ lldb/test/API/commands/frame/var/TestFrameVar.py
@@ -58,6 +58,16 @@
         command_result = lldb.SBCommandReturnObject()
         interp = self.dbg.GetCommandInterpreter()
 
+        # Ensure --regex can find globals if it is the very first frame var command.
+        result = interp.HandleCommand("frame var --regex g_", command_result)
+        self.assertEqual(
+            result,
+            lldb.eReturnStatusSuccessFinishResult,
+            "frame var --regex g_ didn't succeed",
+        )
+        output = command_result.GetOutput()
+        self.assertIn("g_var", output, "g_var not found with regex g_")
+
         # Just get args:
         result = interp.HandleCommand("frame var -l", command_result)
         self.assertEqual(
Index: lldb/source/Commands/CommandObjectFrame.cpp
===================================================================
--- lldb/source/Commands/CommandObjectFrame.cpp
+++ lldb/source/Commands/CommandObjectFrame.cpp
@@ -499,6 +499,31 @@
     }
   }
 
+  /// Finds all variables in `all_variables` whose name matches `regex`,
+  /// inserting them into `matches`. Variables already contained in `matches`
+  /// are not inserted again.
+  /// Nullopt is returned in case of no matches.
+  /// A sub-range of `matches` with all newly added variables is returned. This
+  /// may be empty if all matches were already contained in `matches`.
+  std::optional<llvm::ArrayRef<VariableSP>>
+  findUniqueRegexMatches(RegularExpression &regex,
+                         VariableList &matches,
+                         const VariableList &all_variables) {
+    bool any_matches = false;
+    const size_t previous_num_vars = matches.GetSize();
+
+    for (const VariableSP &var : all_variables) {
+      if (!var->NameMatches(regex) || !ScopeRequested(var->GetScope()))
+        continue;
+      any_matches = true;
+      matches.AddVariableIfUnique(var);
+    }
+
+    if (any_matches)
+      return matches.toArrayRef().drop_front(previous_num_vars);
+    return std::nullopt;
+  }
+
   bool DoExecute(Args &command, CommandReturnObject &result) override {
     // No need to check "frame" for validity as eCommandRequiresFrame ensures
     // it is valid
@@ -506,6 +531,10 @@
 
     Stream &s = result.GetOutputStream();
 
+    // Using a regex should behave like looking for an exact name match: it
+    // also finds globals.
+    m_option_variable.show_globals |= m_option_variable.use_regex;
+
     // Be careful about the stack frame, if any summary formatter runs code, it
     // might clear the StackFrameList for the thread.  So hold onto a shared
     // pointer to the frame so it stays alive.
@@ -518,7 +547,6 @@
       result.AppendError(error.AsCString());
 
     }
-    VariableSP var_sp;
     ValueObjectSP valobj_sp;
 
     TypeSummaryImplSP summary_format_sp;
@@ -551,46 +579,38 @@
         // objects from them...
         for (auto &entry : command) {
           if (m_option_variable.use_regex) {
-            const size_t regex_start_index = regex_var_list.GetSize();
             llvm::StringRef name_str = entry.ref();
             RegularExpression regex(name_str);
             if (regex.IsValid()) {
-              size_t num_matches = 0;
-              const size_t num_new_regex_vars =
-                  variable_list->AppendVariablesIfUnique(regex, regex_var_list,
-                                                         num_matches);
-              if (num_new_regex_vars > 0) {
-                for (size_t regex_idx = regex_start_index,
-                            end_index = regex_var_list.GetSize();
-                     regex_idx < end_index; ++regex_idx) {
-                  var_sp = regex_var_list.GetVariableAtIndex(regex_idx);
-                  if (var_sp) {
-                    valobj_sp = frame->GetValueObjectForFrameVariable(
-                        var_sp, m_varobj_options.use_dynamic);
-                    if (valobj_sp) {
-                      std::string scope_string;
-                      if (m_option_variable.show_scope)
-                        scope_string = GetScopeString(var_sp).str();
-
-                      if (!scope_string.empty())
-                        s.PutCString(scope_string);
-
-                      if (m_option_variable.show_decl &&
-                          var_sp->GetDeclaration().GetFile()) {
-                        bool show_fullpaths = false;
-                        bool show_module = true;
-                        if (var_sp->DumpDeclaration(&s, show_fullpaths,
-                                                    show_module))
-                          s.PutCString(": ");
-                      }
-                      valobj_sp->Dump(result.GetOutputStream(), options);
-                    }
-                  }
-                }
-              } else if (num_matches == 0) {
+              std::optional<llvm::ArrayRef<VariableSP>> results =
+                  findUniqueRegexMatches(regex, regex_var_list, *variable_list);
+              if (!results) {
                 result.AppendErrorWithFormat(
                     "no variables matched the regular expression '%s'.",
                     entry.c_str());
+                continue;
+              }
+              for (const VariableSP &var_sp : *results) {
+                valobj_sp = frame->GetValueObjectForFrameVariable(
+                    var_sp, m_varobj_options.use_dynamic);
+                if (valobj_sp) {
+                  std::string scope_string;
+                  if (m_option_variable.show_scope)
+                    scope_string = GetScopeString(var_sp).str();
+
+                  if (!scope_string.empty())
+                    s.PutCString(scope_string);
+
+                  if (m_option_variable.show_decl &&
+                      var_sp->GetDeclaration().GetFile()) {
+                    bool show_fullpaths = false;
+                    bool show_module = true;
+                    if (var_sp->DumpDeclaration(&s, show_fullpaths,
+                                                show_module))
+                      s.PutCString(": ");
+                  }
+                  valobj_sp->Dump(result.GetOutputStream(), options);
+                }
               }
             } else {
               if (llvm::Error err = regex.GetError())
@@ -648,7 +668,7 @@
         const size_t num_variables = variable_list->GetSize();
         if (num_variables > 0) {
           for (size_t i = 0; i < num_variables; i++) {
-            var_sp = variable_list->GetVariableAtIndex(i);
+            VariableSP var_sp = variable_list->GetVariableAtIndex(i);
             if (!ScopeRequested(var_sp->GetScope()))
                 continue;
             std::string scope_string;
Index: lldb/include/lldb/Symbol/VariableList.h
===================================================================
--- lldb/include/lldb/Symbol/VariableList.h
+++ lldb/include/lldb/Symbol/VariableList.h
@@ -75,6 +75,10 @@
   const_iterator begin() const { return m_variables.begin(); }
   const_iterator end() const { return m_variables.end(); }
 
+  llvm::ArrayRef<lldb::VariableSP> toArrayRef() {
+    return llvm::makeArrayRef(m_variables);
+  }
+
 protected:
   collection m_variables;
 
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
  • [Lldb-commits]... Felipe de Azevedo Piovezan via Phabricator via lldb-commits
    • [Lldb-com... Felipe de Azevedo Piovezan via Phabricator via lldb-commits
    • [Lldb-com... Jim Ingham via Phabricator via lldb-commits
    • [Lldb-com... Felipe de Azevedo Piovezan via Phabricator via lldb-commits
    • [Lldb-com... Jim Ingham via Phabricator via lldb-commits
    • [Lldb-com... Felipe de Azevedo Piovezan via Phabricator via lldb-commits

Reply via email to