[Lldb-commits] [lldb] 5e0ee1b - [lldb] Make repeat commands work for regex commands

Dave Lee via lldb-commits lldb-commits at lists.llvm.org
Wed Mar 8 16:21:54 PST 2023


Author: Dave Lee
Date: 2023-03-08T16:21:42-08:00
New Revision: 5e0ee1b395fa6fca9f23f278885c5949277de666

URL: https://github.com/llvm/llvm-project/commit/5e0ee1b395fa6fca9f23f278885c5949277de666
DIFF: https://github.com/llvm/llvm-project/commit/5e0ee1b395fa6fca9f23f278885c5949277de666.diff

LOG: [lldb] Make repeat commands work for regex commands

Fix logic for repeat commands, so that regex commands (specificially `bt`) are
given the opportunity to provide a repeat command.

rdar://104562616

Differential Revision: https://reviews.llvm.org/D143695

Added: 
    lldb/test/API/functionalities/alias/TestBtAliasRepeat.py

Modified: 
    lldb/include/lldb/Interpreter/CommandInterpreter.h
    lldb/source/Commands/CommandObjectRegexCommand.cpp
    lldb/source/Interpreter/CommandInterpreter.cpp

Removed: 
    


################################################################################
diff  --git a/lldb/include/lldb/Interpreter/CommandInterpreter.h b/lldb/include/lldb/Interpreter/CommandInterpreter.h
index 38ff061612b11..ad6427330dfd4 100644
--- a/lldb/include/lldb/Interpreter/CommandInterpreter.h
+++ b/lldb/include/lldb/Interpreter/CommandInterpreter.h
@@ -352,7 +352,8 @@ class CommandInterpreter : public Broadcaster,
                      CommandReturnObject &result);
 
   bool HandleCommand(const char *command_line, LazyBool add_to_history,
-                     CommandReturnObject &result);
+                     CommandReturnObject &result,
+                     bool force_repeat_command = false);
 
   bool WasInterrupted() const;
 

diff  --git a/lldb/source/Commands/CommandObjectRegexCommand.cpp b/lldb/source/Commands/CommandObjectRegexCommand.cpp
index 2d44ada0acc93..90b32b193e329 100644
--- a/lldb/source/Commands/CommandObjectRegexCommand.cpp
+++ b/lldb/source/Commands/CommandObjectRegexCommand.cpp
@@ -72,8 +72,9 @@ bool CommandObjectRegexCommand::DoExecute(llvm::StringRef command,
         result.GetOutputStream().Printf("%s\n", new_command->c_str());
       // We don't have to pass an override_context here, as the command that 
       // called us should have set up the context appropriately.
-      return m_interpreter.HandleCommand(new_command->c_str(),
-                                         eLazyBoolNo, result);
+      bool force_repeat_command = true;
+      return m_interpreter.HandleCommand(new_command->c_str(), eLazyBoolNo,
+                                         result, force_repeat_command);
     }
   }
   result.SetStatus(eReturnStatusFailed);

diff  --git a/lldb/source/Interpreter/CommandInterpreter.cpp b/lldb/source/Interpreter/CommandInterpreter.cpp
index c03806d94210c..f42dd6cb40794 100644
--- a/lldb/source/Interpreter/CommandInterpreter.cpp
+++ b/lldb/source/Interpreter/CommandInterpreter.cpp
@@ -1874,8 +1874,8 @@ bool CommandInterpreter::HandleCommand(const char *command_line,
 
 bool CommandInterpreter::HandleCommand(const char *command_line,
                                        LazyBool lazy_add_to_history,
-                                       CommandReturnObject &result) {
-
+                                       CommandReturnObject &result,
+                                       bool force_repeat_command) {
   std::string command_string(command_line);
   std::string original_command_string(command_line);
 
@@ -2004,17 +2004,26 @@ bool CommandInterpreter::HandleCommand(const char *command_line,
   // arguments.
 
   if (cmd_obj != nullptr) {
+    bool generate_repeat_command = add_to_history;
     // If we got here when empty_command was true, then this command is a
     // stored "repeat command" which we should give a chance to produce it's
     // repeat command, even though we don't add repeat commands to the history.
-    if (add_to_history || empty_command) {
+    generate_repeat_command |= empty_command;
+    // For `command regex`, the regex command (ex `bt`) is added to history, but
+    // the resolved command (ex `thread backtrace`) is _not_ added to history.
+    // However, the resolved command must be given the opportunity to provide a
+    // repeat command. `force_repeat_command` supports this case.
+    generate_repeat_command |= force_repeat_command;
+    if (generate_repeat_command) {
       Args command_args(command_string);
       std::optional<std::string> repeat_command =
           cmd_obj->GetRepeatCommand(command_args, 0);
-      if (repeat_command)
+      if (repeat_command) {
+        LLDB_LOGF(log, "Repeat command: %s", repeat_command->data());
         m_repeat_command.assign(*repeat_command);
-      else
+      } else {
         m_repeat_command.assign(original_command_string);
+      }
     }
 
     if (add_to_history)

diff  --git a/lldb/test/API/functionalities/alias/TestBtAliasRepeat.py b/lldb/test/API/functionalities/alias/TestBtAliasRepeat.py
new file mode 100644
index 0000000000000..42b5accddc0ba
--- /dev/null
+++ b/lldb/test/API/functionalities/alias/TestBtAliasRepeat.py
@@ -0,0 +1,19 @@
+import lldb
+from lldbsuite.test.lldbtest import TestBase
+from lldbsuite.test import lldbutil
+
+
+class TestCase(TestBase):
+    def test(self):
+        self.build()
+        lldbutil.run_to_source_breakpoint(self, "return", lldb.SBFileSpec("main.c"))
+
+        # Expect "frame #0" but not "frame #1".
+        self.expect("bt 1", inHistory=True, patterns=["frame #0", "^(?!.*frame #1)"])
+
+        # Run an empty command to run the repeat command for `bt`.
+        # The repeat command for `bt N` lists the subsequent N frames.
+        #
+        # In this case, after printing the frame 0 with `bt 1`, the repeat
+        # command will print "frame #1" (and won't print "frame #0").
+        self.expect("", patterns=["^(?!.*frame #0)", "frame #1"])


        


More information about the lldb-commits mailing list