-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[lldb][api-test] Add API test for SBCommandInterpreter::CommandOverrideCallback #94518
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[lldb][api-test] Add API test for SBCommandInterpreter::CommandOverrideCallback #94518
Conversation
@llvm/pr-subscribers-lldb Author: Chelsea Cassanova (chelcassanova) Changes
Full diff: https://github.com/llvm/llvm-project/pull/94518.diff 4 Files Affected:
diff --git a/lldb/bindings/python/python-typemaps.swig b/lldb/bindings/python/python-typemaps.swig
index 8d4b740e5f35c..1bf93c59fbc7b 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,32 @@ 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;
+ }
+
+ // FIXME (filcab): We can't currently check if our callback is already
+ // LLDBSwigPythonCallPythonSBDebuggerTerminateCallback (to DECREF the previous
+ // baton) nor can we just remove all traces of a callback, if we want to
+ // revert to a file logging mechanism.
+
+ // 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..0a332cb0a2ff4 100644
--- a/lldb/bindings/python/python-wrapper.swig
+++ b/lldb/bindings/python/python-wrapper.swig
@@ -1099,6 +1099,19 @@ static void LLDBSwigPythonCallPythonSBDebuggerTerminateCallback(lldb::user_id_t
}
}
+static bool LLDBSwigPythonCallPythonSBCommandInterpreterSetCommandOverrideCallback(void *baton, const char **argv) {
+ bool b = false;
+ if (baton != Py_None) {
+ SWIG_PYTHON_THREAD_BEGIN_BLOCK;
+ PyObject *result = PyObject_CallFunction(
+ reinterpret_cast<PyObject *>(baton), const_cast<char *>("s"), argv); // WRONG!!!!!
+ b = result ? PyObject_IsTrue(result) : false;
+ Py_XDECREF(result);
+ SWIG_PYTHON_THREAD_END_BLOCK;
+ }
+ return b;
+}
+
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..067f37f88096d
--- /dev/null
+++ b/lldb/test/API/python_api/interpreter/TestCommandOverrideCallback.py
@@ -0,0 +1,30 @@
+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")
+
+ # Create a target by the debugger.
+ target = self.dbg.CreateTarget(exe)
+ self.assertTrue(target, VALID_TARGET)
+
+ # Retrieve the associated command interpreter from our debugger.
+ ci = self.dbg.GetCommandInterpreter()
+ self.assertTrue(ci, VALID_COMMAND_INTERPRETER)
+
+ override_string = "what"
+ def foo(string):
+ nonlocal override_string
+ override_string = string
+ return False
+
+ self.assertTrue(ci.SetCommandOverrideCallback("breakpoint", foo))
|
✅ With the latest revision this PR passed the Python code formatter. |
90602ed
to
e4ba69a
Compare
if (baton != Py_None) { | ||
SWIG_PYTHON_THREAD_BEGIN_BLOCK; | ||
PyObject *result = PyObject_CallFunction( | ||
reinterpret_cast<PyObject *>(baton), const_cast<char *>("s"), argv); // WRONG!!!!! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You need to convert your char**
into a PyList
of PyString
before passing it here I think
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, forgot to do this here when I cleaned this up and you can see the comment from that 😅
SWIG_fail; | ||
} | ||
|
||
// FIXME (filcab): We can't currently check if our callback is already |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
filcab ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd say remove the FIXME entirely, it shouldn't apply to this.
As a side note, I think in the LLVM project we generally discourage the pattern of FIXME (name)
and TODO (name)
. Maybe we should go clean up the original instance too? :p
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not opposed to that, this same message appears for the other 2 callbacks.
SWIG_fail; | ||
} | ||
|
||
// FIXME (filcab): We can't currently check if our callback is already |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd say remove the FIXME entirely, it shouldn't apply to this.
As a side note, I think in the LLVM project we generally discourage the pattern of FIXME (name)
and TODO (name)
. Maybe we should go clean up the original instance too? :p
} | ||
|
||
%typemap(typecheck) (lldb::CommandOverrideCallback callback, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
stray line?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup, I kind of wish that SWIG had a formatter like clang-format
.
@@ -1099,6 +1099,19 @@ static void LLDBSwigPythonCallPythonSBDebuggerTerminateCallback(lldb::user_id_t | |||
} | |||
} | |||
|
|||
static bool LLDBSwigPythonCallPythonSBCommandInterpreterSetCommandOverrideCallback(void *baton, const char **argv) { | |||
bool b = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you change the name b
to something with more meaning? Maybe something like ret_val
?
self.build() | ||
exe = self.getBuildArtifact("a.out") | ||
|
||
# Create a target by the debugger. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this comment is helpful because it's telling me what the code is doing, not why it's doing it. I'd suggest removing it because pretty much every test does this.
target = self.dbg.CreateTarget(exe) | ||
self.assertTrue(target, VALID_TARGET) | ||
|
||
# Retrieve the associated command interpreter from our debugger. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same for this comment.
e4ba69a
to
44e8cab
Compare
SWIG_fail; | ||
} | ||
|
||
// Don't lose the callback reference |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: missing period.
def foo(*command_args): | ||
pass | ||
|
||
self.assertTrue(ci.SetCommandOverrideCallback("breakpoint set", foo)) | ||
self.expect("breakpoint set -n main", substrs=["Breakpoint"]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't test the baton or the fact that the function was called. You should have the foo callback modify a variable or something and verify that the function has been called.
44e8cab
to
a721558
Compare
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.
a721558
to
4e40f07
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
…ndOverrideCallback (llvm#94518)" This reverts commit 7cff05a. The API test that was added erroneously imports a module that isn't needed and wouldn't be found which causes a test failures. This reversion removes that import.
…llvm#95181) …andOverrideCallback (llvm#94518)" This reverts commit 7cff05a. The API test that was added erroneously imports a module that isn't needed and wouldn't be found which causes a test failures. This reversion removes that import. (cherry picked from commit 3d86eeb)
SBCommandInterpreter::CommandOverrideCallback
was not being exposed to the Python API has no coverage in theAPI 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.