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

>From 94caf0b58ace58ae5159e3819f776ad6b2988329 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/7] [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 dcc95c1c17e6c2a50002fe90d6420ca270efeb68 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/7] 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 40691abf97d122182c6e9ea13d38ffe96e2631bf 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/7] 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 25585ccde84122f742abe987d45be29e4f2959a5 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/7] 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 72f43cc2a728ca18aa166f222565182a53275fd7 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/7] 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

>From 4546da047b89ad5ee3b736fdc90e760dc346d9d9 Mon Sep 17 00:00:00 2001
From: Dave Lee <davelee....@gmail.com>
Date: Thu, 24 Apr 2025 14:24:28 -0700
Subject: [PATCH 6/7] Fix test for linux

---
 .../command/language/TestFrameLanguageCommands.py     | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git 
a/lldb/test/API/commands/command/language/TestFrameLanguageCommands.py 
b/lldb/test/API/commands/command/language/TestFrameLanguageCommands.py
index 3936f06abeb80..f11eb8a472939 100644
--- a/lldb/test/API/commands/command/language/TestFrameLanguageCommands.py
+++ b/lldb/test/API/commands/command/language/TestFrameLanguageCommands.py
@@ -37,9 +37,14 @@ def test(self):
 
         # Ensure `demangle` doesn't resolve from the objc frame.
         self.expect("help demangle", error=True)
+
         # Run a `language objc` command.
         self.expect(
-            "tagged-pointer info 0",
-            error=True,
-            startstr="error: could not convert '0' to a valid address",
+            "tagged-pointer",
+            substrs=[
+                "Commands for operating on Objective-C tagged pointers.",
+                "Syntax: tagged-pointer <subcommand> [<subcommand-options>]",
+                "The following subcommands are supported:",
+                "info -- Dump information on a tagged pointer.",
+            ],
         )

>From 1caa020835084356551b6c503971205199dadb56 Mon Sep 17 00:00:00 2001
From: Dave Lee <davelee....@gmail.com>
Date: Mon, 28 Apr 2025 10:55:55 -0700
Subject: [PATCH 7/7] [lldb] Make duplicate test names a conditional exception

When two or more tests have the same name, dotest will raise an exception. 
However, when
using a test name pattern (`-p`) which does not match the duplicate test names, 
there
seems to be no reason to prevent the user from running they wish to run.

This changes the exception to be raised only when a pattern matches duplicate 
tests.
---
 lldb/packages/Python/lldbsuite/test/dotest.py | 37 +++++++++----------
 1 file changed, 18 insertions(+), 19 deletions(-)

diff --git a/lldb/packages/Python/lldbsuite/test/dotest.py 
b/lldb/packages/Python/lldbsuite/test/dotest.py
index 7cc8f2985043e..e9b5985e03c11 100644
--- a/lldb/packages/Python/lldbsuite/test/dotest.py
+++ b/lldb/packages/Python/lldbsuite/test/dotest.py
@@ -619,12 +619,12 @@ def visit_file(dir, name):
     if configuration.regexp:
         if not re.search(configuration.regexp, name):
             # We didn't match the regex, we're done.
-            return
+            return False
 
     if configuration.skip_tests:
         for file_regexp in configuration.skip_tests:
             if re.search(file_regexp, name):
-                return
+                return False
 
     # We found a match for our test.  Add it to the suite.
 
@@ -659,22 +659,20 @@ def iter_filters():
                     if check(value, parts):
                         yield key + "." + filterspec
 
-    filtered = False
-    for filterspec in iter_filters():
-        filtered = True
-        print("adding filter spec %s to module %s" % (filterspec, 
repr(module)))
-        tests = unittest.defaultTestLoader.loadTestsFromName(filterspec, 
module)
-        configuration.suite.addTests(tests)
-
-    # Forgo this module if the (base, filterspec) combo is invalid
-    if configuration.filters and not filtered:
-        return
+    if configuration.filters:
+        filtered = False
+        for filterspec in iter_filters():
+            filtered = True
+            print(f"adding filter spec {filterspec} to module {module!r}")
+            tests = unittest.defaultTestLoader.loadTestsFromName(filterspec, 
module)
+            configuration.suite.addTests(tests)
+        return filtered
 
-    if not filtered:
-        # Add the entire file's worth of tests since we're not filtered.
-        # Also the fail-over case when the filterspec branch
-        # (base, filterspec) combo doesn't make sense.
-        
configuration.suite.addTests(unittest.defaultTestLoader.loadTestsFromName(base))
+    # Add the entire file's worth of tests since we're not filtered.
+    # Also the fail-over case when the filterspec branch
+    # (base, filterspec) combo doesn't make sense.
+    
configuration.suite.addTests(unittest.defaultTestLoader.loadTestsFromName(base))
+    return True
 
 
 def visit(prefix, dir, names):
@@ -699,10 +697,11 @@ def visit(prefix, dir, names):
         # to disambiguate these, so we shouldn't need this constraint.
         if name in configuration.all_tests:
             raise Exception("Found multiple tests with the name %s" % name)
-        configuration.all_tests.add(name)
 
         # Run the relevant tests in the python file.
-        visit_file(dir, name)
+        if visit_file(dir, name):
+            # Only add to all_tests if the test wasn't skipped/filtered.
+            configuration.all_tests.add(name)
 
 
 # ======================================== #

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

Reply via email to