[Lldb-commits] [lldb] [lldb] Expose language plugin commands based based on language of current frame (PR #136766)
Dave Lee via lldb-commits
lldb-commits at lists.llvm.org
Thu May 1 16:42:20 PDT 2025
https://github.com/kastiglione updated https://github.com/llvm/llvm-project/pull/136766
>From 776dc6da5c5900adb97bb89a9ed7a60478bf05e1 Mon Sep 17 00:00:00 2001
From: Dave Lee <davelee.com at gmail.com>
Date: Tue, 22 Apr 2025 13:58:25 -0700
Subject: [PATCH 01/10] [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 ae1eb0e59e1f766b30e421b86a9dee4b42c8c59e Mon Sep 17 00:00:00 2001
From: Dave Lee <davelee.com at gmail.com>
Date: Wed, 23 Apr 2025 13:04:27 -0700
Subject: [PATCH 02/10] 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 ddd6104a9d25c2f4710c6a5f400e9a19bb5c454f Mon Sep 17 00:00:00 2001
From: Dave Lee <davelee.com at gmail.com>
Date: Wed, 23 Apr 2025 13:33:16 -0700
Subject: [PATCH 03/10] 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 6968af6618be04050667aba42eb2e7d6a5e67bf0 Mon Sep 17 00:00:00 2001
From: Dave Lee <davelee.com at gmail.com>
Date: Wed, 23 Apr 2025 16:10:35 -0700
Subject: [PATCH 04/10] 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 f79aa91e199b3757078574949a10a57ba15e2dfe Mon Sep 17 00:00:00 2001
From: Dave Lee <davelee.com at gmail.com>
Date: Thu, 24 Apr 2025 10:11:24 -0700
Subject: [PATCH 05/10] 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 6a4a80fbb273617bb7202215e94fa9f07f1307b3 Mon Sep 17 00:00:00 2001
From: Dave Lee <davelee.com at gmail.com>
Date: Thu, 24 Apr 2025 14:24:28 -0700
Subject: [PATCH 06/10] 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 8191832758a0ff7ac6f4f7565e739abdee51b683 Mon Sep 17 00:00:00 2001
From: Dave Lee <davelee.com at gmail.com>
Date: Thu, 1 May 2025 12:27:01 -0700
Subject: [PATCH 07/10] Change logic to ensure compatibility
---
.../source/Interpreter/CommandInterpreter.cpp | 100 +++++++++---------
.../language/TestFrameLanguageCommands.py | 12 ++-
.../API/commands/command/language/commands.py | 5 +
3 files changed, 66 insertions(+), 51 deletions(-)
create mode 100644 lldb/test/API/commands/command/language/commands.py
diff --git a/lldb/source/Interpreter/CommandInterpreter.cpp b/lldb/source/Interpreter/CommandInterpreter.cpp
index 2ff02ae5086b4..ed85ac25b0370 100644
--- a/lldb/source/Interpreter/CommandInterpreter.cpp
+++ b/lldb/source/Interpreter/CommandInterpreter.cpp
@@ -1019,23 +1019,25 @@ CommandInterpreter::VerifyUserMultiwordCmdPath(Args &path, bool leaf_is_command,
}
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 {};
+ auto frame_sp = GetExecutionContext().GetFrameSP();
+ if (!frame_sp)
+ return {};
+ auto frame_language =
+ Language::GetPrimaryLanguage(frame_sp->GuessLanguage().AsLanguageType());
+
+ auto it = m_command_dict.find("language");
+ if (it == m_command_dict.end())
+ return {};
+ // The root "language" command.
+ CommandObjectSP language_cmd_sp = it->second;
+
+ auto *plugin = Language::FindPlugin(frame_language);
+ if (!plugin)
+ return {};
+ // "cplusplus", "objc", etc.
+ auto lang_name = plugin->GetPluginName();
+
+ return language_cmd_sp->GetSubcommandSPExact(lang_name);
}
CommandObjectSP
@@ -1070,20 +1072,11 @@ 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, lang_match_sp;
+ real_match_sp;
StringList local_matches;
if (matches == nullptr)
@@ -1093,7 +1086,6 @@ 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
@@ -1151,28 +1143,11 @@ 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_lang_matches ==
+ num_alias_matches ==
1) {
if (num_cmd_matches)
return real_match_sp;
@@ -1180,12 +1155,37 @@ 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 if (num_user_matches)
- return user_match_sp;
else
- return lang_match_sp;
+ return user_match_sp;
+ }
+ }
+
+ // When no single match is found, attempt to resolve the command as a language
+ // plugin subcommand.
+ if (!command_sp) {
+ // The `language` subcommand ("language objc", "language cplusplus", etc).
+ CommandObjectMultiword *lang_subcmd = nullptr;
+ if (auto lang_subcmd_sp = GetFrameLanguageCommand()) {
+ lang_subcmd = lang_subcmd_sp->GetAsMultiwordCommand();
+ command_sp = lang_subcmd_sp->GetSubcommandSPExact(cmd_str);
+ }
+
+ if (!command_sp && !exact && lang_subcmd) {
+ StringList lang_matches;
+ AddNamesMatchingPartialString(lang_subcmd->GetSubcommandDictionary(),
+ cmd_str, lang_matches, descriptions);
+ if (matches)
+ matches->AppendList(lang_matches);
+ if (lang_matches.GetSize() == 1) {
+ const auto &lang_dict = lang_subcmd->GetSubcommandDictionary();
+ auto pos = lang_dict.find(lang_matches[0]);
+ if (pos != lang_dict.end())
+ return pos->second;
+ }
}
- } else if (matches && command_sp) {
+ }
+
+ if (matches && command_sp) {
matches->AppendString(cmd_str);
if (descriptions)
descriptions->AppendString(command_sp->GetHelp());
diff --git a/lldb/test/API/commands/command/language/TestFrameLanguageCommands.py b/lldb/test/API/commands/command/language/TestFrameLanguageCommands.py
index f11eb8a472939..419ccc859dbbd 100644
--- a/lldb/test/API/commands/command/language/TestFrameLanguageCommands.py
+++ b/lldb/test/API/commands/command/language/TestFrameLanguageCommands.py
@@ -3,7 +3,6 @@
from lldbsuite.test.decorators import *
import lldbsuite.test.lldbutil as lldbutil
-
class TestCase(TestBase):
def test(self):
self.build()
@@ -48,3 +47,14 @@ def test(self):
"info -- Dump information on a tagged pointer.",
],
)
+
+ # To ensure compatability with existing scripts, a language specific
+ # command must not be invoked if another command (such as a python
+ # command) has the language specific command name as its prefix.
+ #
+ # For example, this test loads a `tagged-pointer-collision` command. A
+ # script could exist that invokes this command using its prefix
+ # `tagged-pointer`, under the assumption that "tagged-pointer" uniquely
+ # identifies the python command `tagged-pointer-collision`.
+ self.runCmd("command script import commands.py")
+ self.expect("tagged-pointer", startstr="ran tagged-pointer-collision")
diff --git a/lldb/test/API/commands/command/language/commands.py b/lldb/test/API/commands/command/language/commands.py
new file mode 100644
index 0000000000000..d85e57d9c1a88
--- /dev/null
+++ b/lldb/test/API/commands/command/language/commands.py
@@ -0,0 +1,5 @@
+import lldb
+
+ at lldb.command("tagged-pointer-collision")
+def noop(dbg, cmdstr, ctx, result, _):
+ print("ran tagged-pointer-collision", file=result)
>From 6180b95279736b15098ee5aea809f1264bdb9233 Mon Sep 17 00:00:00 2001
From: Dave Lee <davelee.com at gmail.com>
Date: Thu, 1 May 2025 12:38:39 -0700
Subject: [PATCH 08/10] python formatting
---
.../API/commands/command/language/TestFrameLanguageCommands.py | 1 +
lldb/test/API/commands/command/language/commands.py | 1 +
2 files changed, 2 insertions(+)
diff --git a/lldb/test/API/commands/command/language/TestFrameLanguageCommands.py b/lldb/test/API/commands/command/language/TestFrameLanguageCommands.py
index 419ccc859dbbd..ff00c9d7cb3f6 100644
--- a/lldb/test/API/commands/command/language/TestFrameLanguageCommands.py
+++ b/lldb/test/API/commands/command/language/TestFrameLanguageCommands.py
@@ -3,6 +3,7 @@
from lldbsuite.test.decorators import *
import lldbsuite.test.lldbutil as lldbutil
+
class TestCase(TestBase):
def test(self):
self.build()
diff --git a/lldb/test/API/commands/command/language/commands.py b/lldb/test/API/commands/command/language/commands.py
index d85e57d9c1a88..e4215317f3c3e 100644
--- a/lldb/test/API/commands/command/language/commands.py
+++ b/lldb/test/API/commands/command/language/commands.py
@@ -1,5 +1,6 @@
import lldb
+
@lldb.command("tagged-pointer-collision")
def noop(dbg, cmdstr, ctx, result, _):
print("ran tagged-pointer-collision", file=result)
>From 2f91d3f4077639aa3c72871b7961ad61de8b4753 Mon Sep 17 00:00:00 2001
From: Dave Lee <davelee.com at gmail.com>
Date: Thu, 1 May 2025 16:28:37 -0700
Subject: [PATCH 09/10] Add long help for "language" command
---
lldb/source/Commands/CommandObjectLanguage.cpp | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/lldb/source/Commands/CommandObjectLanguage.cpp b/lldb/source/Commands/CommandObjectLanguage.cpp
index 925db599e4abb..e01f53369d5f2 100644
--- a/lldb/source/Commands/CommandObjectLanguage.cpp
+++ b/lldb/source/Commands/CommandObjectLanguage.cpp
@@ -21,6 +21,18 @@ CommandObjectLanguage::CommandObjectLanguage(CommandInterpreter &interpreter)
"language <language-name> <subcommand> [<subcommand-options>]") {
// Let the LanguageRuntime populates this command with subcommands
LanguageRuntime::InitializeCommands(this);
+ SetHelpLong(
+ R"(
+ Language specific subcommands may be used directly (without the `language
+ <language-name>` prefix), when stopped on a frame written in that
+ language. For example, from a C++ frame, users may run `demangle`
+ directly, instead of `language cplusplus demangle`.
+
+ Language specific subcommands are only available when the command name
+ cannot be misinterpreted. Take the `demangle` command for example, if a
+ Python command named `demangle-tree` were loaded, then the invocation
+ `demangle` would run `demangle-tree`, not `language cplusplus demangle`.
+ )");
}
CommandObjectLanguage::~CommandObjectLanguage() = default;
>From 6ff6b18b5be7c6c78acbeadcc3561420fd61ca16 Mon Sep 17 00:00:00 2001
From: Dave Lee <davelee.com at gmail.com>
Date: Thu, 1 May 2025 16:42:01 -0700
Subject: [PATCH 10/10] Remove indentation from long help
---
lldb/source/Commands/CommandObjectLanguage.cpp | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/lldb/source/Commands/CommandObjectLanguage.cpp b/lldb/source/Commands/CommandObjectLanguage.cpp
index e01f53369d5f2..7272241551058 100644
--- a/lldb/source/Commands/CommandObjectLanguage.cpp
+++ b/lldb/source/Commands/CommandObjectLanguage.cpp
@@ -23,15 +23,15 @@ CommandObjectLanguage::CommandObjectLanguage(CommandInterpreter &interpreter)
LanguageRuntime::InitializeCommands(this);
SetHelpLong(
R"(
- Language specific subcommands may be used directly (without the `language
- <language-name>` prefix), when stopped on a frame written in that
- language. For example, from a C++ frame, users may run `demangle`
- directly, instead of `language cplusplus demangle`.
-
- Language specific subcommands are only available when the command name
- cannot be misinterpreted. Take the `demangle` command for example, if a
- Python command named `demangle-tree` were loaded, then the invocation
- `demangle` would run `demangle-tree`, not `language cplusplus demangle`.
+Language specific subcommands may be used directly (without the `language
+<language-name>` prefix), when stopped on a frame written in that language. For
+example, from a C++ frame, users may run `demangle` directly, instead of
+`language cplusplus demangle`.
+
+Language specific subcommands are only available when the command name cannot be
+misinterpreted. Take the `demangle` command for example, if a Python command
+named `demangle-tree` were loaded, then the invocation `demangle` would run
+`demangle-tree`, not `language cplusplus demangle`.
)");
}
More information about the lldb-commits
mailing list