aboutsummaryrefslogtreecommitdiffstats
path: root/sources/shiboken2/libshiboken/signature/signature.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'sources/shiboken2/libshiboken/signature/signature.cpp')
-rw-r--r--sources/shiboken2/libshiboken/signature/signature.cpp110
1 files changed, 106 insertions, 4 deletions
diff --git a/sources/shiboken2/libshiboken/signature/signature.cpp b/sources/shiboken2/libshiboken/signature/signature.cpp
index 085d751aa..1f36a09f3 100644
--- a/sources/shiboken2/libshiboken/signature/signature.cpp
+++ b/sources/shiboken2/libshiboken/signature/signature.cpp
@@ -209,8 +209,12 @@ PyObject *GetSignature_Wrapper(PyObject *ob, PyObject *modifier)
if (dict == nullptr)
return nullptr;
PyObject *props = PyDict_GetItem(dict, func_name);
- if (props == nullptr)
+ if (props == nullptr) {
+ // handle `__init__` like the class itself
+ if (strcmp(String::toCString(func_name), "__init__") == 0)
+ return GetSignature_TypeMod(objclass, modifier);
Py_RETURN_NONE;
+ }
return _GetSignature_Cached(props, PyName::method(), modifier);
}
@@ -431,7 +435,86 @@ void FinishSignatureInitialization(PyObject *module, const char *signatures[])
}
}
-void SetError_Argument(PyObject *args, const char *func_name)
+static PyObject *adjustFuncName(const char *func_name)
+{
+ /*
+ * PYSIDE-1019: Modify the function name expression according to feature.
+ *
+ * - snake_case
+ * The function name must be converted.
+ * - full_property
+ * The property name must be used and "fset" appended.
+ *
+ * modname.subname.classsname.propname.fset
+ *
+ * Class properties must use the expression
+ *
+ * modname.subname.classsname.__dict__['propname'].fset
+ *
+ * Note that fget is impossible because there are no parameters.
+ */
+ static const char mapping_name[] = "shibokensupport.signature.mapping";
+ static PyObject *sys_modules = PySys_GetObject("modules");
+ static PyObject *mapping = PyDict_GetItemString(sys_modules, mapping_name);
+ static PyObject *ns = PyModule_GetDict(mapping);
+
+ char _path[200 + 1] = {};
+ const char *_name = strrchr(func_name, '.');
+ strncat(_path, func_name, _name - func_name);
+ ++_name;
+
+ // This is a very cheap call into `mapping.py`.
+ PyObject *update_mapping = PyDict_GetItemString(ns, "update_mapping");
+ AutoDecRef res(PyObject_CallFunctionObjArgs(update_mapping, nullptr));
+ if (res.isNull())
+ return nullptr;
+
+ // Run `eval` on the type string to get the object.
+ AutoDecRef obtype(PyRun_String(_path, Py_eval_input, ns, ns));
+ if (PyModule_Check(obtype.object())) {
+ // This is a plain function. Return the unmangled name.
+ return String::fromCString(func_name);
+ }
+ assert(PyType_Check(obtype)); // This was not true for __init__!
+
+ // Find the feature flags
+ auto type = reinterpret_cast<PyTypeObject *>(obtype.object());
+ auto dict = type->tp_dict;
+ int id = SbkObjectType_GetReserved(type);
+ id = id < 0 ? 0 : id; // if undefined, set to zero
+ auto lower = id & 0x01;
+ auto is_prop = id & 0x02;
+ bool is_class_prop = false;
+
+ // Compute all needed info.
+ PyObject *name = String::getSnakeCaseName(_name, lower);
+ PyObject *prop_name;
+ if (is_prop) {
+ PyObject *prop_methods = PyDict_GetItem(dict, PyMagicName::property_methods());
+ prop_name = PyDict_GetItem(prop_methods, name);
+ if (prop_name != nullptr) {
+ PyObject *prop = PyDict_GetItem(dict, prop_name);
+ is_class_prop = Py_TYPE(prop) != &PyProperty_Type;
+ }
+ }
+
+ // Finally, generate the correct path expression.
+ char _buf[200 + 1] = {};
+ if (is_prop) {
+ auto _prop_name = String::toCString(prop_name);
+ if (is_class_prop)
+ sprintf(_buf, "%s.__dict__['%s'].fset", _path, _prop_name);
+ else
+ sprintf(_buf, "%s.%s.fset", _path, _prop_name);
+ }
+ else {
+ auto _name = String::toCString(name);
+ sprintf(_buf, "%s.%s", _path, _name);
+ }
+ return String::fromCString(_buf);
+}
+
+void SetError_Argument(PyObject *args, const char *func_name, PyObject *info)
{
/*
* This function replaces the type error construction with extra
@@ -440,8 +523,26 @@ void SetError_Argument(PyObject *args, const char *func_name)
*/
init_module_1();
init_module_2();
- AutoDecRef res(PyObject_CallFunction(pyside_globals->seterror_argument_func,
- const_cast<char *>("(Os)"), args, func_name));
+
+ // PYSIDE-1305: Handle errors set by fillQtProperties.
+ PyObject *err_val{};
+ if (PyErr_Occurred()) {
+ PyObject *e, *t;
+ PyErr_Fetch(&e, &err_val, &t);
+ info = err_val;
+ Py_XDECREF(&e);
+ Py_XDECREF(&t);
+ }
+ // PYSIDE-1019: Modify the function name expression according to feature.
+ AutoDecRef new_func_name(adjustFuncName(func_name));
+ if (new_func_name.isNull()) {
+ PyErr_Print();
+ Py_FatalError("seterror_argument failed to call update_mapping");
+ }
+ if (info == nullptr)
+ info = Py_None;
+ AutoDecRef res(PyObject_CallFunctionObjArgs(pyside_globals->seterror_argument_func,
+ args, new_func_name.object(), info, nullptr));
if (res.isNull()) {
PyErr_Print();
Py_FatalError("seterror_argument did not receive a result");
@@ -451,6 +552,7 @@ void SetError_Argument(PyObject *args, const char *func_name)
PyErr_Print();
Py_FatalError("unexpected failure in seterror_argument");
}
+ Py_XDECREF(err_val);
PyErr_SetObject(err, msg);
}