[Lldb-commits] [lldb] [lldb][api-test] Add API test for SBCommandInterpreter::CommandOverrideCallback (PR #94518)
Chelsea Cassanova via lldb-commits
lldb-commits at lists.llvm.org
Fri Jun 7 13:36:15 PDT 2024
https://github.com/chelcassanova updated https://github.com/llvm/llvm-project/pull/94518
>From 44e8cab5d45a87eb1ea2076c498abe5be423eb1c Mon Sep 17 00:00:00 2001
From: Chelsea Cassanova <chelsea_cassanova at apple.com>
Date: Wed, 5 Jun 2024 11:24:01 -0700
Subject: [PATCH] [lldb][api-test] Add API test for
SBCommandInterpreter::CommandOverrideCallback
`SBCommandInterpreter::CommandOverrideCallback` was not being exposed to
the Python API has no coverage in the
API test suite, so this commits exposes and adds a test for it. Doing
this involves also adding a typemap for the callback used for this
function so that it matches the functionality of other callback
functions that are exposed to Python.
---
lldb/bindings/python/python-typemaps.swig | 18 ++++++++++++-
lldb/bindings/python/python-wrapper.swig | 22 +++++++++++++++
lldb/include/lldb/API/SBCommandInterpreter.h | 2 --
.../TestCommandOverrideCallback.py | 27 +++++++++++++++++++
4 files changed, 66 insertions(+), 3 deletions(-)
create mode 100644 lldb/test/API/python_api/interpreter/TestCommandOverrideCallback.py
diff --git a/lldb/bindings/python/python-typemaps.swig b/lldb/bindings/python/python-typemaps.swig
index 8d4b740e5f35c..ff698907568c8 100644
--- a/lldb/bindings/python/python-typemaps.swig
+++ b/lldb/bindings/python/python-typemaps.swig
@@ -427,7 +427,6 @@ template <> bool SetNumberFromPyObject<double>(double &number, PyObject *obj) {
free($1);
}
-
// For Log::LogOutputCallback
%typemap(in) (lldb::LogOutputCallback log_callback, void *baton) {
if (!($input == Py_None ||
@@ -476,6 +475,23 @@ template <> bool SetNumberFromPyObject<double>(double &number, PyObject *obj) {
$1 = $1 || PyCallable_Check(reinterpret_cast<PyObject *>($input));
}
+%typemap(in) (lldb::CommandOverrideCallback callback, void *baton) {
+ if (!($input == Py_None ||
+ PyCallable_Check(reinterpret_cast<PyObject *>($input)))) {
+ PyErr_SetString(PyExc_TypeError, "Need a callable object or None!");
+ SWIG_fail;
+ }
+
+ // Don't lose the callback reference
+ Py_INCREF($input);
+ $1 = LLDBSwigPythonCallPythonSBCommandInterpreterSetCommandOverrideCallback;
+ $2 = $input;
+}
+%typemap(typecheck) (lldb::CommandOverrideCallback callback, void *baton) {
+ $1 = $input == Py_None;
+ $1 = $1 || PyCallable_Check(reinterpret_cast<PyObject *>($input));
+}
+
%typemap(in) lldb::FileSP {
PythonFile py_file(PyRefType::Borrowed, $input);
if (!py_file) {
diff --git a/lldb/bindings/python/python-wrapper.swig b/lldb/bindings/python/python-wrapper.swig
index 1370afc885d43..bd3de8ce5d46c 100644
--- a/lldb/bindings/python/python-wrapper.swig
+++ b/lldb/bindings/python/python-wrapper.swig
@@ -1099,6 +1099,28 @@ static void LLDBSwigPythonCallPythonSBDebuggerTerminateCallback(lldb::user_id_t
}
}
+static bool LLDBSwigPythonCallPythonSBCommandInterpreterSetCommandOverrideCallback(void *baton, const char **argv) {
+ bool ret_val = false;
+ if (baton != Py_None) {
+ SWIG_PYTHON_THREAD_BEGIN_BLOCK;
+ // Create a PyList of items since we're going to pass it to the callback as a tuple
+ // of arguments.
+ PyObject *py_argv = PyList_New(0);
+ for (const char **arg = argv; arg && *arg; arg++) {
+ std::string arg_string = *arg;
+ PyObject *py_string = PyUnicode_FromStringAndSize(arg_string.c_str(), arg_string.size());
+ PyList_Append(py_argv, py_string);
+ }
+
+ PyObject *result = PyObject_CallObject(
+ reinterpret_cast<PyObject *>(baton), PyList_AsTuple(py_argv));
+ ret_val = result ? PyObject_IsTrue(result) : false;
+ Py_XDECREF(result);
+ SWIG_PYTHON_THREAD_END_BLOCK;
+ }
+ return ret_val;
+}
+
static SBError LLDBSwigPythonCallLocateModuleCallback(
void *callback_baton, const SBModuleSpec &module_spec_sb,
SBFileSpec &module_file_spec_sb, SBFileSpec &symbol_file_spec_sb) {
diff --git a/lldb/include/lldb/API/SBCommandInterpreter.h b/lldb/include/lldb/API/SBCommandInterpreter.h
index 8ac36344b3a79..084b6d9adb703 100644
--- a/lldb/include/lldb/API/SBCommandInterpreter.h
+++ b/lldb/include/lldb/API/SBCommandInterpreter.h
@@ -265,11 +265,9 @@ class SBCommandInterpreter {
// Catch commands before they execute by registering a callback that will get
// called when the command gets executed. This allows GUI or command line
// interfaces to intercept a command and stop it from happening
-#ifndef SWIG
bool SetCommandOverrideCallback(const char *command_name,
lldb::CommandOverrideCallback callback,
void *baton);
-#endif
/// Return true if the command interpreter is the active IO handler.
///
diff --git a/lldb/test/API/python_api/interpreter/TestCommandOverrideCallback.py b/lldb/test/API/python_api/interpreter/TestCommandOverrideCallback.py
new file mode 100644
index 0000000000000..e8d374987fc90
--- /dev/null
+++ b/lldb/test/API/python_api/interpreter/TestCommandOverrideCallback.py
@@ -0,0 +1,27 @@
+from typing_extensions import override
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class CommandOverrideCallback(TestBase):
+ def setUp(self):
+ TestBase.setUp(self)
+ self.line = line_number("main.c", "Hello world.")
+
+ def test_command_override_callback(self):
+ self.build()
+ exe = self.getBuildArtifact("a.out")
+
+ target = self.dbg.CreateTarget(exe)
+ self.assertTrue(target, VALID_TARGET)
+
+ ci = self.dbg.GetCommandInterpreter()
+ self.assertTrue(ci, VALID_COMMAND_INTERPRETER)
+
+ def foo(*command_args):
+ pass
+
+ self.assertTrue(ci.SetCommandOverrideCallback("breakpoint set", foo))
+ self.expect("breakpoint set -n main", substrs=["Breakpoint"])
More information about the lldb-commits
mailing list