From 2386537c2469a97501a305c6b3138231b907a67f Mon Sep 17 00:00:00 2001 From: Lawrence D'Anna Date: Sat, 19 Oct 2019 07:05:33 +0000 Subject: [LLDB] bugfix: command script add -f doesn't work for some callables Summary: When users define a debugger command from python, they provide a callable object. Because the signature of the function has been extended, LLDB needs to inspect the number of parameters the callable can take. The rule it was using to decide was weird, apparently not tested, and giving wrong results for some kinds of python callables. This patch replaces the weird rule with a simple one: if the callable can take 5 arguments, it gets the 5 argument version of the signature. Otherwise it gets the old 4 argument version. It also adds tests with a bunch of different kinds of python callables with both 4 and 5 arguments. Reviewers: JDevlieghere, clayborg, labath, jingham Reviewed By: labath Subscribers: lldb-commits Tags: #lldb Differential Revision: https://reviews.llvm.org/D69014 llvm-svn: 375333 --- .../ScriptInterpreter/Python/PythonDataObjects.cpp | 20 ++++++++++++++------ .../ScriptInterpreter/Python/PythonDataObjects.h | 7 +++++-- 2 files changed, 19 insertions(+), 8 deletions(-) (limited to 'lldb/source/Plugins/ScriptInterpreter/Python') diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp index 1fb9355b9ee..2b70762e368 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp +++ b/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp @@ -876,21 +876,23 @@ Expected PythonCallable::GetArgInfo() const { result.count = cantFail(As(pyarginfo.get().GetAttribute("count"))); result.has_varargs = cantFail(As(pyarginfo.get().GetAttribute("has_varargs"))); - result.is_bound_method = + bool is_method = cantFail(As(pyarginfo.get().GetAttribute("is_bound_method"))); + result.max_positional_args = + result.has_varargs ? ArgInfo::UNBOUNDED : result.count; // FIXME emulate old broken behavior - if (result.is_bound_method) + if (is_method) result.count++; #else - + bool is_bound_method = false; PyObject *py_func_obj = m_py_obj; if (PyMethod_Check(py_func_obj)) { py_func_obj = PyMethod_GET_FUNCTION(py_func_obj); PythonObject im_self = GetAttributeValue("im_self"); if (im_self.IsValid() && !im_self.IsNone()) - result.is_bound_method = true; + is_bound_method = true; } else { // see if this is a callable object with an __call__ method if (!PyFunction_Check(py_func_obj)) { @@ -899,9 +901,9 @@ Expected PythonCallable::GetArgInfo() const { auto __callable__ = __call__.AsType(); if (__callable__.IsValid()) { py_func_obj = PyMethod_GET_FUNCTION(__callable__.get()); - PythonObject im_self = GetAttributeValue("im_self"); + PythonObject im_self = __callable__.GetAttributeValue("im_self"); if (im_self.IsValid() && !im_self.IsNone()) - result.is_bound_method = true; + is_bound_method = true; } } } @@ -916,12 +918,18 @@ Expected PythonCallable::GetArgInfo() const { result.count = code->co_argcount; result.has_varargs = !!(code->co_flags & CO_VARARGS); + result.max_positional_args = result.has_varargs + ? ArgInfo::UNBOUNDED + : (result.count - (int)is_bound_method); #endif return result; } +constexpr unsigned + PythonCallable::ArgInfo::UNBOUNDED; // FIXME delete after c++17 + PythonCallable::ArgInfo PythonCallable::GetNumArguments() const { auto arginfo = GetArgInfo(); if (!arginfo) { diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h b/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h index 5823f740a53..0cdb63f17c9 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h +++ b/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h @@ -604,6 +604,11 @@ public: using TypedPythonObject::TypedPythonObject; struct ArgInfo { + /* the largest number of positional arguments this callable + * can accept, or UNBOUNDED, ie UINT_MAX if it's a varargs + * function and can accept an arbitrary number */ + unsigned max_positional_args; + static constexpr unsigned UNBOUNDED = UINT_MAX; // FIXME c++17 inline /* the number of positional arguments, including optional ones, * and excluding varargs. If this is a bound method, then the * count will still include a +1 for self. @@ -614,8 +619,6 @@ public: int count; /* does the callable have positional varargs? */ bool has_varargs : 1; // FIXME delete this - /* is the callable a bound method written in python? */ - bool is_bound_method : 1; // FIXME delete this }; static bool Check(PyObject *py_obj); -- cgit v1.2.3