diff options
Diffstat (limited to 'sources/shiboken6/libshiboken/signature/signature.cpp')
-rw-r--r-- | sources/shiboken6/libshiboken/signature/signature.cpp | 184 |
1 files changed, 111 insertions, 73 deletions
diff --git a/sources/shiboken6/libshiboken/signature/signature.cpp b/sources/shiboken6/libshiboken/signature/signature.cpp index 624d55a3e..3255cb56d 100644 --- a/sources/shiboken6/libshiboken/signature/signature.cpp +++ b/sources/shiboken6/libshiboken/signature/signature.cpp @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt for Python. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2020 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only //////////////////////////////////////////////////////////////////////////// // @@ -49,13 +13,16 @@ // General documentation can be found in `signature_doc.rst`. // +#include "signature.h" +#include "signature_p.h" + #include "basewrapper.h" #include "autodecref.h" #include "sbkstring.h" #include "sbkstaticstrings.h" #include "sbkstaticstrings_p.h" +#include "sbkfeature_base.h" -#include "signature_p.h" #include <structmember.h> using namespace Shiboken; @@ -86,6 +53,11 @@ PyObject *GetClassOrModOf(PyObject *ob) Py_INCREF(ob); return ob; } +#ifdef PYPY_VERSION + // PYSIDE-535: PyPy has a special builtin method that acts almost like PyCFunction. + if (Py_TYPE(ob) == PepBuiltinMethod_TypePtr) + return _get_class_of_bm(ob); +#endif if (PyType_IsSubtype(Py_TYPE(ob), &PyCFunction_Type)) return _get_class_of_cf(ob); if (Py_TYPE(ob) == PepStaticMethod_TypePtr) @@ -113,7 +85,7 @@ PyObject *GetTypeKey(PyObject *ob) module_name.reset(PyObject_GetAttr(ob, PyMagicName::name())); return Py_BuildValue("O", module_name.object()); } - AutoDecRef class_name(_get_qualname(ob)); + AutoDecRef class_name(PyObject_GetAttr(ob, PyMagicName::qualname())); if (class_name.isNull()) { Py_FatalError("Signature: missing class name in GetTypeKey"); return nullptr; @@ -123,7 +95,7 @@ PyObject *GetTypeKey(PyObject *ob) static PyObject *empty_dict = nullptr; -PyObject *TypeKey_to_PropsDict(PyObject *type_key, PyObject *obtype) +PyObject *TypeKey_to_PropsDict(PyObject *type_key) { PyObject *dict = PyDict_GetItem(pyside_globals->arg_dict, type_key); if (dict == nullptr) { @@ -164,6 +136,24 @@ static PyObject *_GetSignature_Cached(PyObject *props, PyObject *func_kind, PyOb return Py_INCREF(value), value; } +#ifdef PYPY_VERSION +PyObject *GetSignature_Method(PyObject *obfunc, PyObject *modifier) +{ + AutoDecRef obtype_mod(GetClassOrModOf(obfunc)); + AutoDecRef type_key(GetTypeKey(obtype_mod)); + if (type_key.isNull()) + Py_RETURN_NONE; + PyObject *dict = TypeKey_to_PropsDict(type_key); + if (dict == nullptr) + return nullptr; + AutoDecRef func_name(PyObject_GetAttr(obfunc, PyMagicName::name())); + PyObject *props = !func_name.isNull() ? PyDict_GetItem(dict, func_name) : nullptr; + if (props == nullptr) + Py_RETURN_NONE; + return _GetSignature_Cached(props, PyName::method(), modifier); +} +#endif + PyObject *GetSignature_Function(PyObject *obfunc, PyObject *modifier) { // make sure that we look into PyCFunction, only... @@ -173,7 +163,7 @@ PyObject *GetSignature_Function(PyObject *obfunc, PyObject *modifier) AutoDecRef type_key(GetTypeKey(obtype_mod)); if (type_key.isNull()) Py_RETURN_NONE; - PyObject *dict = TypeKey_to_PropsDict(type_key, obtype_mod); + PyObject *dict = TypeKey_to_PropsDict(type_key); if (dict == nullptr) return nullptr; AutoDecRef func_name(PyObject_GetAttr(obfunc, PyMagicName::name())); @@ -183,7 +173,7 @@ PyObject *GetSignature_Function(PyObject *obfunc, PyObject *modifier) int flags = PyCFunction_GET_FLAGS(obfunc); PyObject *func_kind; - if (PyModule_Check(obtype_mod)) + if (PyModule_Check(obtype_mod.object())) func_kind = PyName::function(); else if (flags & METH_CLASS) func_kind = PyName::classmethod(); @@ -201,13 +191,13 @@ PyObject *GetSignature_Wrapper(PyObject *ob, PyObject *modifier) AutoDecRef class_key(GetTypeKey(objclass)); if (func_name.isNull() || objclass.isNull() || class_key.isNull()) return nullptr; - PyObject *dict = TypeKey_to_PropsDict(class_key, objclass); + PyObject *dict = TypeKey_to_PropsDict(class_key); if (dict == nullptr) return nullptr; PyObject *props = PyDict_GetItem(dict, func_name); if (props == nullptr) { // handle `__init__` like the class itself - if (strcmp(String::toCString(func_name), "__init__") == 0) + if (PyUnicode_CompareWithASCIIString(func_name, "__init__") == 0) return GetSignature_TypeMod(objclass, modifier); Py_RETURN_NONE; } @@ -219,7 +209,7 @@ PyObject *GetSignature_TypeMod(PyObject *ob, PyObject *modifier) AutoDecRef ob_name(PyObject_GetAttr(ob, PyMagicName::name())); AutoDecRef ob_key(GetTypeKey(ob)); - PyObject *dict = TypeKey_to_PropsDict(ob_key, ob); + PyObject *dict = TypeKey_to_PropsDict(ob_key); if (dict == nullptr) return nullptr; PyObject *props = PyDict_GetItem(dict, ob_name); @@ -237,9 +227,17 @@ PyObject *GetSignature_TypeMod(PyObject *ob, PyObject *modifier) // The `modifier` argument is a string that is passed in from `loader.py`. // Configuration what the modifiers mean is completely in Python. // +// PYSIDE-2101: The __signature__ attribute is gone due to rlcompleter. +// PyObject *get_signature_intern(PyObject *ob, PyObject *modifier) { +#ifdef PYPY_VERSION + // PYSIDE-535: PyPy has a special builtin method that acts almost like PyCFunction. + if (Py_TYPE(ob) == PepBuiltinMethod_TypePtr) { + return pyside_bm_get___signature__(ob, modifier); + } +#endif if (PyType_IsSubtype(Py_TYPE(ob), &PyCFunction_Type)) return pyside_cf_get___signature__(ob, modifier); if (Py_TYPE(ob) == PepStaticMethod_TypePtr) @@ -250,6 +248,9 @@ PyObject *get_signature_intern(PyObject *ob, PyObject *modifier) return pyside_tp_get___signature__(ob, modifier); if (Py_TYPE(ob) == &PyWrapperDescr_Type) return pyside_wd_get___signature__(ob, modifier); + // For classmethods we use the simple wrapper description implementation. + if (Py_TYPE(ob) == &PyClassMethodDescr_Type) + return pyside_wd_get___signature__(ob, modifier); return nullptr; } @@ -258,8 +259,6 @@ static PyObject *get_signature(PyObject * /* self */, PyObject *args) PyObject *ob; PyObject *modifier = nullptr; - init_module_1(); - if (!PyArg_ParseTuple(args, "O|O", &ob, &modifier)) return nullptr; if (Py_TYPE(ob) == PepFunction_TypePtr) @@ -291,14 +290,25 @@ static PyObject *feature_import(PyObject * /* self */, PyObject *args, PyObject if (import_func == nullptr) { Py_FatalError("builtins has no \"__orig_import__\" function"); } - return PyObject_Call(import_func, args, kwds); + ret = PyObject_Call(import_func, args, kwds); + if (ret) { + // PYSIDE-2029: Intercept after the import to search for PySide usage. + PyObject *post = PyObject_CallFunctionObjArgs(pyside_globals->feature_imported_func, + ret, nullptr); + Py_XDECREF(post); + if (post == nullptr) { + Py_DECREF(ret); + return nullptr; + } + } + return ret; } PyMethodDef signature_methods[] = { - {"__feature_import__", (PyCFunction)feature_import, METH_VARARGS | METH_KEYWORDS}, + {"__feature_import__", (PyCFunction)feature_import, METH_VARARGS | METH_KEYWORDS, nullptr}, {"get_signature", (PyCFunction)get_signature, METH_VARARGS, - "get the __signature__, but pass an optional string parameter"}, - {nullptr, nullptr} + "get the signature, passing an optional string parameter"}, + {nullptr, nullptr, 0, nullptr} }; //////////////////////////////////////////////////////////////////////////// @@ -321,7 +331,6 @@ PyMethodDef signature_methods[] = { static int PySide_BuildSignatureArgs(PyObject *obtype_mod, const char *signatures[]) { - init_module_1(); AutoDecRef type_key(GetTypeKey(obtype_mod)); /* * PYSIDE-996: Avoid string overflow in MSVC, which has a limit of @@ -349,7 +358,6 @@ PyObject *PySide_BuildSignatureProps(PyObject *type_key) * We simply pick up the arguments that we stored here and replace * them by the function result. */ - init_module_2(); if (type_key == nullptr) return nullptr; PyObject *numkey = PyDict_GetItem(pyside_globals->arg_dict, type_key); @@ -379,8 +387,24 @@ PyObject *PySide_BuildSignatureProps(PyObject *type_key) // //////////////////////////////////////////////////////////////////////////// +#ifdef PYPY_VERSION +static bool get_lldebug_flag() +{ + auto *dic = PySys_GetObject("pypy_translation_info"); + int lldebug = PyObject_IsTrue(PyDict_GetItemString(dic, "translation.lldebug")); + int lldebug0 = PyObject_IsTrue(PyDict_GetItemString(dic, "translation.lldebug0")); + return lldebug || lldebug0; +} + +#endif + static int PySide_FinishSignatures(PyObject *module, const char *signatures[]) { +#ifdef PYPY_VERSION + static const bool have_problem = get_lldebug_flag(); + if (have_problem) + return 0; // crash with lldebug at `PyDict_Next` +#endif /* * Initialization of module functions and resolving of static methods. */ @@ -407,8 +431,6 @@ static int PySide_FinishSignatures(PyObject *module, const char *signatures[]) if (PyCFunction_Check(func)) if (PyDict_SetItem(pyside_globals->map_dict, func, module) < 0) return -1; - if (_finish_nested_classes(obdict) < 0) - return -1; // The finish_import function will not work the first time since phase 2 // was not yet run. But that is ok, because the first import is always for // the shiboken module (or a test module). @@ -430,9 +452,12 @@ static int PySide_FinishSignatures(PyObject *module, const char *signatures[]) int InitSignatureStrings(PyTypeObject *type, const char *signatures[]) { + // PYSIDE-2404: This function now also builds the mapping for static methods. + // It was one missing spot to let Lazy import work. + init_shibokensupport_module(); auto *ob_type = reinterpret_cast<PyObject *>(type); int ret = PySide_BuildSignatureArgs(ob_type, signatures); - if (ret < 0) { + if (ret < 0 || _build_func_to_type(ob_type) < 0) { PyErr_Print(); PyErr_SetNone(PyExc_ImportError); } @@ -449,7 +474,17 @@ void FinishSignatureInitialization(PyObject *module, const char *signatures[]) * Still, it is not possible to call init phase 2 from here, * because the import is still running. Do it from Python! */ - if ( PySide_PatchTypes() < 0 + init_shibokensupport_module(); + +#ifndef PYPY_VERSION + static const bool patch_types = true; +#else + // PYSIDE-535: On PyPy we cannot patch builtin types. This can be + // re-implemented later. For now, we use `get_signature`, instead. + static const bool patch_types = false; +#endif + + if ((patch_types && PySide_PatchTypes() < 0) || PySide_FinishSignatures(module, signatures) < 0) { PyErr_Print(); PyErr_SetNone(PyExc_ImportError); @@ -491,7 +526,11 @@ static PyObject *adjustFuncName(const char *func_name) return nullptr; // Run `eval` on the type string to get the object. + // PYSIDE-1710: If the eval does not work, return the given string. AutoDecRef obtype(PyRun_String(_path, Py_eval_input, ns, ns)); + if (obtype.isNull()) + return String::fromCString(func_name); + if (PyModule_Check(obtype.object())) { // This is a plain function. Return the unmangled name. return String::fromCString(func_name); @@ -500,8 +539,8 @@ static PyObject *adjustFuncName(const char *func_name) // Find the feature flags auto type = reinterpret_cast<PyTypeObject *>(obtype.object()); - auto dict = type->tp_dict; - int id = SbkObjectType_GetReserved(type); + AutoDecRef dict(PepType_GetDict(type)); + int id = currentSelectId(type); id = id < 0 ? 0 : id; // if undefined, set to zero auto lower = id & 0x01; auto is_prop = id & 0x02; @@ -509,7 +548,7 @@ static PyObject *adjustFuncName(const char *func_name) // Compute all needed info. PyObject *name = String::getSnakeCaseName(_name, lower); - PyObject *prop_name; + PyObject *prop_name{}; if (is_prop) { PyObject *prop_methods = PyDict_GetItem(dict, PyMagicName::property_methods()); prop_name = PyDict_GetItem(prop_methods, name); @@ -521,36 +560,37 @@ static PyObject *adjustFuncName(const char *func_name) // Finally, generate the correct path expression. char _buf[250 + 1] = {}; - if (is_prop) { + if (prop_name) { auto _prop_name = String::toCString(prop_name); if (is_class_prop) - sprintf(_buf, "%s.__dict__['%s'].fset", _path, _prop_name); + snprintf(_buf, sizeof(_buf), "%s.__dict__['%s'].fset", _path, _prop_name); else - sprintf(_buf, "%s.%s.fset", _path, _prop_name); + snprintf(_buf, sizeof(_buf), "%s.%s.fset", _path, _prop_name); } else { auto _name = String::toCString(name); - sprintf(_buf, "%s.%s", _path, _name); + snprintf(_buf, sizeof(_buf), "%s.%s", _path, _name); } return String::fromCString(_buf); } void SetError_Argument(PyObject *args, const char *func_name, PyObject *info) { + init_shibokensupport_module(); /* * This function replaces the type error construction with extra * overloads parameter in favor of using the signature module. * Error messages are rare, so we do it completely in Python. */ - init_module_1(); - init_module_2(); // PYSIDE-1305: Handle errors set by fillQtProperties. if (PyErr_Occurred()) { PyObject *e, *v, *t; // Note: These references are all borrowed. PyErr_Fetch(&e, &v, &t); + Py_DECREF(e); info = v; + Py_XDECREF(t); } // PYSIDE-1019: Modify the function name expression according to feature. AutoDecRef new_func_name(adjustFuncName(func_name)); @@ -581,21 +621,19 @@ void SetError_Argument(PyObject *args, const char *func_name, PyObject *info) * But the __doc__ attribute existed already by inheritance, and calling * PyType_Modified() is not supported. So we added the getsets explicitly * to the metatype. + * + * PYSIDE-2101: The __signature__ attribute is gone due to rlcompleter. */ -PyObject *Sbk_TypeGet___signature__(PyObject *ob, PyObject *modifier) -{ - return pyside_tp_get___signature__(ob, modifier); -} - PyObject *Sbk_TypeGet___doc__(PyObject *ob) { + init_shibokensupport_module(); return pyside_tp_get___doc__(ob); } PyObject *GetFeatureDict() { - init_module_1(); + init_shibokensupport_module(); return pyside_globals->feature_dict; } |