https://github.com/kastiglione updated 
https://github.com/llvm/llvm-project/pull/136766

>From daf394bf76b5fd627f77aee6e451e7d706d26916 Mon Sep 17 00:00:00 2001
From: Dave Lee <davelee....@gmail.com>
Date: Tue, 22 Apr 2025 13:58:25 -0700
Subject: [PATCH 1/5] [lldb] Expose language plugin commands based based on
 language of current frame

---
 .../lldb/Interpreter/CommandInterpreter.h     |  6 ++
 .../source/Interpreter/CommandInterpreter.cpp | 55 ++++++++++++++++++-
 2 files changed, 58 insertions(+), 3 deletions(-)

diff --git a/lldb/include/lldb/Interpreter/CommandInterpreter.h 
b/lldb/include/lldb/Interpreter/CommandInterpreter.h
index 724d88d65f6ac..26e0767951e7f 100644
--- a/lldb/include/lldb/Interpreter/CommandInterpreter.h
+++ b/lldb/include/lldb/Interpreter/CommandInterpreter.h
@@ -730,6 +730,12 @@ class CommandInterpreter : public Broadcaster,
   bool EchoCommandNonInteractive(llvm::StringRef line,
                                  const Flags &io_handler_flags) const;
 
+  /// Return the language specific command object for the current frame.
+  ///
+  /// For example, when stopped on a C++ frame, this returns the command object
+  /// for "language cplusplus" (`CommandObjectMultiwordItaniumABI`).
+  lldb::CommandObjectSP GetFrameLanguageCommand() const;
+
   // A very simple state machine which models the command handling transitions
   enum class CommandHandlingState {
     eIdle,
diff --git a/lldb/source/Interpreter/CommandInterpreter.cpp 
b/lldb/source/Interpreter/CommandInterpreter.cpp
index eb4741feb0aa5..2ff02ae5086b4 100644
--- a/lldb/source/Interpreter/CommandInterpreter.cpp
+++ b/lldb/source/Interpreter/CommandInterpreter.cpp
@@ -1018,6 +1018,26 @@ CommandInterpreter::VerifyUserMultiwordCmdPath(Args 
&path, bool leaf_is_command,
   return cur_as_multi;
 }
 
+CommandObjectSP CommandInterpreter::GetFrameLanguageCommand() const {
+  if (auto frame_sp = GetExecutionContext().GetFrameSP()) {
+    auto frame_language = Language::GetPrimaryLanguage(
+        frame_sp->GuessLanguage().AsLanguageType());
+
+    auto it = m_command_dict.find("language");
+    if (it != m_command_dict.end()) {
+      // The root "language" command.
+      CommandObjectSP language_cmd_sp = it->second;
+
+      if (auto *plugin = Language::FindPlugin(frame_language)) {
+        // "cplusplus", "objc", etc.
+        auto lang_name = plugin->GetPluginName();
+        return language_cmd_sp->GetSubcommandSPExact(lang_name);
+      }
+    }
+  }
+  return {};
+}
+
 CommandObjectSP
 CommandInterpreter::GetCommandSP(llvm::StringRef cmd_str, bool include_aliases,
                                  bool exact, StringList *matches,
@@ -1050,11 +1070,20 @@ CommandInterpreter::GetCommandSP(llvm::StringRef 
cmd_str, bool include_aliases,
       command_sp = pos->second;
   }
 
+  // The `language` subcommand ("language objc", "language cplusplus", etc).
+  CommandObjectMultiword *lang_subcmd = nullptr;
+  if (!command_sp) {
+    if (auto subcmd_sp = GetFrameLanguageCommand()) {
+      lang_subcmd = subcmd_sp->GetAsMultiwordCommand();
+      command_sp = subcmd_sp->GetSubcommandSPExact(cmd_str);
+    }
+  }
+
   if (!exact && !command_sp) {
     // We will only get into here if we didn't find any exact matches.
 
     CommandObjectSP user_match_sp, user_mw_match_sp, alias_match_sp,
-        real_match_sp;
+        real_match_sp, lang_match_sp;
 
     StringList local_matches;
     if (matches == nullptr)
@@ -1064,6 +1093,7 @@ CommandInterpreter::GetCommandSP(llvm::StringRef cmd_str, 
bool include_aliases,
     unsigned int num_alias_matches = 0;
     unsigned int num_user_matches = 0;
     unsigned int num_user_mw_matches = 0;
+    unsigned int num_lang_matches = 0;
 
     // Look through the command dictionaries one by one, and if we get only one
     // match from any of them in toto, then return that, otherwise return an
@@ -1121,11 +1151,28 @@ CommandInterpreter::GetCommandSP(llvm::StringRef 
cmd_str, bool include_aliases,
         user_mw_match_sp = pos->second;
     }
 
+    if (lang_subcmd) {
+      num_lang_matches =
+          AddNamesMatchingPartialString(lang_subcmd->GetSubcommandDictionary(),
+                                        cmd_str, *matches, descriptions);
+    }
+
+    if (num_lang_matches == 1) {
+      cmd.assign(matches->GetStringAtIndex(num_cmd_matches + num_alias_matches 
+
+                                           num_user_matches +
+                                           num_user_mw_matches));
+
+      auto &lang_dict = lang_subcmd->GetSubcommandDictionary();
+      auto pos = lang_dict.find(cmd);
+      if (pos != lang_dict.end())
+        lang_match_sp = pos->second;
+    }
+
     // If we got exactly one match, return that, otherwise return the match
     // list.
 
     if (num_user_matches + num_user_mw_matches + num_cmd_matches +
-            num_alias_matches ==
+            num_alias_matches + num_lang_matches ==
         1) {
       if (num_cmd_matches)
         return real_match_sp;
@@ -1133,8 +1180,10 @@ CommandInterpreter::GetCommandSP(llvm::StringRef 
cmd_str, bool include_aliases,
         return alias_match_sp;
       else if (num_user_mw_matches)
         return user_mw_match_sp;
-      else
+      else if (num_user_matches)
         return user_match_sp;
+      else
+        return lang_match_sp;
     }
   } else if (matches && command_sp) {
     matches->AppendString(cmd_str);

>From 1bbfd1276f9617f6df451700e0ed601c2bd0f341 Mon Sep 17 00:00:00 2001
From: Dave Lee <davelee....@gmail.com>
Date: Wed, 23 Apr 2025 13:04:27 -0700
Subject: [PATCH 2/5] Add test

---
 .../API/commands/command/language/Makefile    |  3 ++
 .../language/TestFrameLanguageCommands.py     | 43 +++++++++++++++++++
 .../API/commands/command/language/lib.cpp     |  3 ++
 .../API/commands/command/language/main.mm     |  6 +++
 4 files changed, 55 insertions(+)
 create mode 100644 lldb/test/API/commands/command/language/Makefile
 create mode 100644 
lldb/test/API/commands/command/language/TestFrameLanguageCommands.py
 create mode 100644 lldb/test/API/commands/command/language/lib.cpp
 create mode 100644 lldb/test/API/commands/command/language/main.mm

diff --git a/lldb/test/API/commands/command/language/Makefile 
b/lldb/test/API/commands/command/language/Makefile
new file mode 100644
index 0000000000000..ce845d59ac035
--- /dev/null
+++ b/lldb/test/API/commands/command/language/Makefile
@@ -0,0 +1,3 @@
+OBJCXX_SOURCES := main.mm
+CXX_SOURCES := lib.cpp
+include Makefile.rules
diff --git 
a/lldb/test/API/commands/command/language/TestFrameLanguageCommands.py 
b/lldb/test/API/commands/command/language/TestFrameLanguageCommands.py
new file mode 100644
index 0000000000000..89439856470a7
--- /dev/null
+++ b/lldb/test/API/commands/command/language/TestFrameLanguageCommands.py
@@ -0,0 +1,43 @@
+import lldb
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test.decorators import *
+import lldbsuite.test.lldbutil as lldbutil
+
+
+class TestCase(TestBase):
+    def test(self):
+        self.build()
+        _, _, thread, _ = lldbutil.run_to_source_breakpoint(
+            self, "break here", lldb.SBFileSpec("lib.cpp")
+        )
+
+        frame = thread.selected_frame
+        self.assertEqual(frame.GuessLanguage(), 
lldb.eLanguageTypeC_plus_plus_11)
+        self.assertEqual(frame.name, "f()")
+        self.expect(
+            "help demangle",
+            substrs=[
+                "Demangle a C++ mangled name.",
+                "Syntax: language cplusplus demangle [<mangled-name> ...]",
+            ],
+        )
+        self.expect("demangle _Z1fv", startstr="_Z1fv ---> f()")
+
+        # Switch the objc caller.
+        self.runCmd("up")
+        frame = thread.selected_frame
+        self.assertEqual(frame.GuessLanguage(), 
lldb.eLanguageTypeObjC_plus_plus)
+        self.assertEqual(frame.name, "main")
+        self.expect("help demangle", error=True)
+        self.expect(
+            "help tagged-pointer",
+            substrs=[
+                "Commands for operating on Objective-C tagged pointers.",
+                "Syntax: class-table <subcommand> [<subcommand-options>]",
+            ],
+        )
+        self.expect(
+            "tagged-pointer info 0",
+            error=True,
+            startstr="error: could not convert '0' to a valid address",
+        )
diff --git a/lldb/test/API/commands/command/language/lib.cpp 
b/lldb/test/API/commands/command/language/lib.cpp
new file mode 100644
index 0000000000000..225d2992d36d2
--- /dev/null
+++ b/lldb/test/API/commands/command/language/lib.cpp
@@ -0,0 +1,3 @@
+#include <stdio.h>
+extern void f();
+void f() { puts("break here"); }
diff --git a/lldb/test/API/commands/command/language/main.mm 
b/lldb/test/API/commands/command/language/main.mm
new file mode 100644
index 0000000000000..93b87eb4d3176
--- /dev/null
+++ b/lldb/test/API/commands/command/language/main.mm
@@ -0,0 +1,6 @@
+extern void f();
+
+int main() {
+  f();
+  return 0;
+}

>From 57173b13cacd2dc0c593420748731b47ebee30eb Mon Sep 17 00:00:00 2001
From: Dave Lee <davelee....@gmail.com>
Date: Wed, 23 Apr 2025 13:33:16 -0700
Subject: [PATCH 3/5] Check prefix matching in the test

---
 .../language/TestFrameLanguageCommands.py     | 20 ++++++++++---------
 1 file changed, 11 insertions(+), 9 deletions(-)

diff --git 
a/lldb/test/API/commands/command/language/TestFrameLanguageCommands.py 
b/lldb/test/API/commands/command/language/TestFrameLanguageCommands.py
index 89439856470a7..5a4c62c5721bb 100644
--- a/lldb/test/API/commands/command/language/TestFrameLanguageCommands.py
+++ b/lldb/test/API/commands/command/language/TestFrameLanguageCommands.py
@@ -14,6 +14,8 @@ def test(self):
         frame = thread.selected_frame
         self.assertEqual(frame.GuessLanguage(), 
lldb.eLanguageTypeC_plus_plus_11)
         self.assertEqual(frame.name, "f()")
+
+        # Test `help`.
         self.expect(
             "help demangle",
             substrs=[
@@ -21,21 +23,21 @@ def test(self):
                 "Syntax: language cplusplus demangle [<mangled-name> ...]",
             ],
         )
-        self.expect("demangle _Z1fv", startstr="_Z1fv ---> f()")
 
-        # Switch the objc caller.
+        # Run a `language cplusplus` command.
+        self.expect(f"demangle _Z1fv", startstr="_Z1fv ---> f()")
+        # Test prefix matching.
+        self.expect("dem _Z1fv", startstr="_Z1fv ---> f()")
+
+        # Select the objc caller.
         self.runCmd("up")
         frame = thread.selected_frame
         self.assertEqual(frame.GuessLanguage(), 
lldb.eLanguageTypeObjC_plus_plus)
         self.assertEqual(frame.name, "main")
+
+        # Ensure `demangle` doesn't resolve from the objc frame.
         self.expect("help demangle", error=True)
-        self.expect(
-            "help tagged-pointer",
-            substrs=[
-                "Commands for operating on Objective-C tagged pointers.",
-                "Syntax: class-table <subcommand> [<subcommand-options>]",
-            ],
-        )
+        # Run a `language objc` command.
         self.expect(
             "tagged-pointer info 0",
             error=True,

>From e49a373d678d697b532fb3fbb76dda912e53ad46 Mon Sep 17 00:00:00 2001
From: Dave Lee <davelee....@gmail.com>
Date: Wed, 23 Apr 2025 16:10:35 -0700
Subject: [PATCH 4/5] Change Makefile to (hopefully) load the objc runtime

---
 lldb/test/API/commands/command/language/Makefile                | 2 ++
 .../API/commands/command/language/TestFrameLanguageCommands.py  | 2 +-
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/lldb/test/API/commands/command/language/Makefile 
b/lldb/test/API/commands/command/language/Makefile
index ce845d59ac035..48d511771b0a6 100644
--- a/lldb/test/API/commands/command/language/Makefile
+++ b/lldb/test/API/commands/command/language/Makefile
@@ -1,3 +1,5 @@
 OBJCXX_SOURCES := main.mm
+CFLAGS_EXTRAS := -fobjc-arc
 CXX_SOURCES := lib.cpp
+LD_EXTRAS := -lobjc
 include Makefile.rules
diff --git 
a/lldb/test/API/commands/command/language/TestFrameLanguageCommands.py 
b/lldb/test/API/commands/command/language/TestFrameLanguageCommands.py
index 5a4c62c5721bb..3936f06abeb80 100644
--- a/lldb/test/API/commands/command/language/TestFrameLanguageCommands.py
+++ b/lldb/test/API/commands/command/language/TestFrameLanguageCommands.py
@@ -25,7 +25,7 @@ def test(self):
         )
 
         # Run a `language cplusplus` command.
-        self.expect(f"demangle _Z1fv", startstr="_Z1fv ---> f()")
+        self.expect("demangle _Z1fv", startstr="_Z1fv ---> f()")
         # Test prefix matching.
         self.expect("dem _Z1fv", startstr="_Z1fv ---> f()")
 

>From 0d267ec6eae56a5745d52338e0febbc33f32be9b Mon Sep 17 00:00:00 2001
From: Dave Lee <davelee....@gmail.com>
Date: Thu, 24 Apr 2025 10:11:24 -0700
Subject: [PATCH 5/5] Remove -fobjc-arc (not supported on linux)

---
 lldb/test/API/commands/command/language/Makefile | 1 -
 1 file changed, 1 deletion(-)

diff --git a/lldb/test/API/commands/command/language/Makefile 
b/lldb/test/API/commands/command/language/Makefile
index 48d511771b0a6..2d5049417ee70 100644
--- a/lldb/test/API/commands/command/language/Makefile
+++ b/lldb/test/API/commands/command/language/Makefile
@@ -1,5 +1,4 @@
 OBJCXX_SOURCES := main.mm
-CFLAGS_EXTRAS := -fobjc-arc
 CXX_SOURCES := lib.cpp
 LD_EXTRAS := -lobjc
 include Makefile.rules

_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to