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

This adds some tests for removing lldb commands, user command and aliases. I've 
done in the SB API side for comleteness of this features. Besides that, I found 
a bug in the creation of the DummyCommand used in the test file: they were 
being allocated in the stack but they should have been allocated in the heap 
because CommandPluginInterfaceImplementation ends up owning the pointer passed 
to it, which is internally managed by a shared_ptr.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D149379

Files:
  lldb/include/lldb/API/SBCommandInterpreter.h
  lldb/source/API/SBCommandInterpreter.cpp
  lldb/unittests/API/SBCommandInterpreterTest.cpp

Index: lldb/unittests/API/SBCommandInterpreterTest.cpp
===================================================================
--- lldb/unittests/API/SBCommandInterpreterTest.cpp
+++ lldb/unittests/API/SBCommandInterpreterTest.cpp
@@ -44,15 +44,41 @@
   std::string m_message;
 };
 
+TEST_F(SBCommandInterpreterTest, RemoveCommandsAndAliases) {
+  // We first test removing non-existent commands
+  EXPECT_FALSE(m_interp.RemoveUserCommand("non-existent-user-command"));
+  EXPECT_FALSE(m_interp.RemoveCommand("non-existent-command"));
+  EXPECT_FALSE(m_interp.RemoveAlias("non-existent-alias"));
+
+  // We now test removing a built-in command
+  EXPECT_TRUE(m_interp.CommandExists("target"));
+  EXPECT_FALSE(m_interp.RemoveCommand("target"));
+  // Built-in commands need to be force removed.
+  EXPECT_TRUE(m_interp.RemoveCommand("target", /*force=*/true));
+  EXPECT_FALSE(m_interp.CommandExists("target"));
+
+  // Finally we test with a user defined command
+  m_interp.AddCommand("dummy", new DummyCommand("A dummy command"),
+                      /*help=*/nullptr);
+  EXPECT_TRUE(m_interp.UserCommandExists("dummy"));
+  EXPECT_TRUE(m_interp.RemoveUserCommand("dummy"));
+  EXPECT_FALSE(m_interp.UserCommandExists("dummy"));
+
+  // Now we remove an alias
+  EXPECT_TRUE(m_interp.AliasExists("b"));
+  EXPECT_TRUE(m_interp.RemoveAlias("b"));
+  EXPECT_FALSE(m_interp.AliasExists("b"));
+}
+
 TEST_F(SBCommandInterpreterTest, SingleWordCommand) {
   // We first test a command without autorepeat
-  DummyCommand dummy("It worked");
-  m_interp.AddCommand("dummy", &dummy, /*help=*/nullptr);
+  m_interp.AddCommand("dummy", new DummyCommand("Dummy command"),
+                      /*help=*/nullptr);
   {
     SBCommandReturnObject result;
     m_interp.HandleCommand("dummy", result, /*add_to_history=*/true);
     EXPECT_TRUE(result.Succeeded());
-    EXPECT_STREQ(result.GetOutput(), "It worked\n");
+    EXPECT_STREQ(result.GetOutput(), "Dummy command\n");
   }
   {
     SBCommandReturnObject result;
@@ -62,34 +88,36 @@
   }
 
   // Now we test a command with autorepeat
-  m_interp.AddCommand("dummy_with_autorepeat", &dummy, /*help=*/nullptr,
+  m_interp.AddCommand("dummy_with_autorepeat",
+                      new DummyCommand("Command with autorepeat"),
+                      /*help=*/nullptr,
                       /*syntax=*/nullptr, /*auto_repeat_command=*/nullptr);
   {
     SBCommandReturnObject result;
     m_interp.HandleCommand("dummy_with_autorepeat", result,
                            /*add_to_history=*/true);
     EXPECT_TRUE(result.Succeeded());
-    EXPECT_STREQ(result.GetOutput(), "It worked\n");
+    EXPECT_STREQ(result.GetOutput(), "Command with autorepeat\n");
   }
   {
     SBCommandReturnObject result;
     m_interp.HandleCommand("", result);
     EXPECT_TRUE(result.Succeeded());
-    EXPECT_STREQ(result.GetOutput(), "It worked\n");
+    EXPECT_STREQ(result.GetOutput(), "Command with autorepeat\n");
   }
 }
 
 TEST_F(SBCommandInterpreterTest, MultiWordCommand) {
   auto command = m_interp.AddMultiwordCommand("multicommand", /*help=*/nullptr);
   // We first test a subcommand without autorepeat
-  DummyCommand subcommand("It worked again");
-  command.AddCommand("subcommand", &subcommand, /*help=*/nullptr);
+  command.AddCommand("subcommand", new DummyCommand("Dummy command"),
+                     /*help=*/nullptr);
   {
     SBCommandReturnObject result;
     m_interp.HandleCommand("multicommand subcommand", result,
                            /*add_to_history=*/true);
     EXPECT_TRUE(result.Succeeded());
-    EXPECT_STREQ(result.GetOutput(), "It worked again\n");
+    EXPECT_STREQ(result.GetOutput(), "Dummy command\n");
   }
   {
     SBCommandReturnObject result;
@@ -99,7 +127,8 @@
   }
 
   // We first test a subcommand with autorepeat
-  command.AddCommand("subcommand_with_autorepeat", &subcommand,
+  command.AddCommand("subcommand_with_autorepeat",
+                     new DummyCommand("Dummy command with autorepeat"),
                      /*help=*/nullptr, /*syntax=*/nullptr,
                      /*auto_repeat_command=*/nullptr);
   {
@@ -107,19 +136,19 @@
     m_interp.HandleCommand("multicommand subcommand_with_autorepeat", result,
                            /*add_to_history=*/true);
     EXPECT_TRUE(result.Succeeded());
-    EXPECT_STREQ(result.GetOutput(), "It worked again\n");
+    EXPECT_STREQ(result.GetOutput(), "Dummy command with autorepeat\n");
   }
   {
     SBCommandReturnObject result;
     m_interp.HandleCommand("", result);
     EXPECT_TRUE(result.Succeeded());
-    EXPECT_STREQ(result.GetOutput(), "It worked again\n");
+    EXPECT_STREQ(result.GetOutput(), "Dummy command with autorepeat\n");
   }
 
-  DummyCommand subcommand2("It worked again 2");
   // We now test a subcommand with autorepeat of the command name
   command.AddCommand(
-      "subcommand_with_custom_autorepeat", &subcommand2, /*help=*/nullptr,
+      "subcommand_with_custom_autorepeat",
+      new DummyCommand("Another dummy command"), /*help=*/nullptr,
       /*syntax=*/nullptr,
       /*auto_repeat_command=*/"multicommand subcommand_with_autorepeat");
   {
@@ -127,12 +156,12 @@
     m_interp.HandleCommand("multicommand subcommand_with_custom_autorepeat",
                            result, /*add_to_history=*/true);
     EXPECT_TRUE(result.Succeeded());
-    EXPECT_STREQ(result.GetOutput(), "It worked again 2\n");
+    EXPECT_STREQ(result.GetOutput(), "Another dummy command\n");
   }
   {
     SBCommandReturnObject result;
     m_interp.HandleCommand("", result);
     EXPECT_TRUE(result.Succeeded());
-    EXPECT_STREQ(result.GetOutput(), "It worked again\n");
+    EXPECT_STREQ(result.GetOutput(), "Dummy command with autorepeat\n");
   }
 }
Index: lldb/source/API/SBCommandInterpreter.cpp
===================================================================
--- lldb/source/API/SBCommandInterpreter.cpp
+++ lldb/source/API/SBCommandInterpreter.cpp
@@ -132,6 +132,30 @@
                                           : false);
 }
 
+bool SBCommandInterpreter::RemoveCommand(const char *command, bool force) {
+  LLDB_INSTRUMENT_VA(this, command, force);
+
+  if (!IsValid())
+    return false;
+  return m_opaque_ptr->RemoveCommand(command, force);
+}
+
+bool SBCommandInterpreter::RemoveUserCommand(const char *command) {
+  LLDB_INSTRUMENT_VA(this, command);
+
+  if (!IsValid())
+    return false;
+  return m_opaque_ptr->RemoveUser(command);
+}
+
+bool SBCommandInterpreter::RemoveAlias(const char *alias) {
+  LLDB_INSTRUMENT_VA(this, alias);
+
+  if (!IsValid())
+    return false;
+  return m_opaque_ptr->RemoveAlias(alias);
+}
+
 bool SBCommandInterpreter::IsActive() {
   LLDB_INSTRUMENT_VA(this);
 
@@ -146,7 +170,7 @@
 
 bool SBCommandInterpreter::InterruptCommand() {
   LLDB_INSTRUMENT_VA(this);
-  
+
   return (IsValid() ? m_opaque_ptr->InterruptCommand() : false);
 }
 
Index: lldb/include/lldb/API/SBCommandInterpreter.h
===================================================================
--- lldb/include/lldb/API/SBCommandInterpreter.h
+++ lldb/include/lldb/API/SBCommandInterpreter.h
@@ -241,13 +241,13 @@
                                        lldb::SBStringList &matches,
                                        lldb::SBStringList &descriptions);
 
-  /// Returns whether an interrupt flag was raised either by the SBDebugger - 
+  /// Returns whether an interrupt flag was raised either by the SBDebugger -
   /// when the function is not running on the RunCommandInterpreter thread, or
   /// by SBCommandInterpreter::InterruptCommand if it is.  If your code is doing
-  /// interruptible work, check this API periodically, and interrupt if it 
+  /// interruptible work, check this API periodically, and interrupt if it
   /// returns true.
   bool WasInterrupted() const;
-  
+
   /// Interrupts the command currently executing in the RunCommandInterpreter
   /// thread.
   ///
@@ -313,6 +313,25 @@
   /// and aliases.  If successful, result->GetOutput has the full expansion.
   void ResolveCommand(const char *command_line, SBCommandReturnObject &result);
 
+  /// Remove a command if it is removable (python or regex command). If \b force
+  /// is provided, the command is removed regardless of its removable status.
+  ///
+  /// \return
+  ///   \b true if and only if the command was effectively removed.
+  bool RemoveCommand(const char *command, bool force = false);
+
+  /// Remove a user-defined command.
+  ///
+  /// \return
+  ///   \b true if and only if the command was effectively removed.
+  bool RemoveUserCommand(const char *command);
+
+  /// Remove an alias command.
+  ///
+  /// \return
+  ///   \b true if and only if the alias was effectively removed.
+  bool RemoveAlias(const char *alias);
+
 protected:
   lldb_private::CommandInterpreter &ref();
 
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to