diff options
Diffstat (limited to 'sources/shiboken2/libshiboken')
-rw-r--r-- | sources/shiboken2/libshiboken/basewrapper.cpp | 104 | ||||
-rw-r--r-- | sources/shiboken2/libshiboken/basewrapper.h | 5 | ||||
-rw-r--r-- | sources/shiboken2/libshiboken/bindingmanager.cpp | 28 | ||||
-rw-r--r-- | sources/shiboken2/libshiboken/bindingmanager.h | 2 | ||||
-rw-r--r-- | sources/shiboken2/libshiboken/pep384impl.cpp | 3 | ||||
-rw-r--r-- | sources/shiboken2/libshiboken/pep384impl.h | 2 | ||||
-rw-r--r-- | sources/shiboken2/libshiboken/sbkstring.cpp | 44 | ||||
-rw-r--r-- | sources/shiboken2/libshiboken/sbkstring.h | 1 |
8 files changed, 152 insertions, 37 deletions
diff --git a/sources/shiboken2/libshiboken/basewrapper.cpp b/sources/shiboken2/libshiboken/basewrapper.cpp index 5c2dc7807..a602688ec 100644 --- a/sources/shiboken2/libshiboken/basewrapper.cpp +++ b/sources/shiboken2/libshiboken/basewrapper.cpp @@ -97,21 +97,7 @@ static PyObject *SbkObjectTypeTpNew(PyTypeObject *metatype, PyObject *args, PyOb static SelectableFeatureHook SelectFeatureSet = nullptr; -void initSelectableFeature(SelectableFeatureHook func) -{ - SelectFeatureSet = func; -} - -// PYSIDE-1019: Switch type's tp_dict to the currently active namespace. -static PyObject *Sbk_TypeGet___dict__(PyTypeObject *type, void *context) -{ - auto dict = type->tp_dict; - if (dict == NULL) - Py_RETURN_NONE; - if (SelectFeatureSet != nullptr) - dict = SelectFeatureSet(type); - return PyDictProxy_New(dict); -} +static PyObject *Sbk_TypeGet___dict__(PyTypeObject *type, void *context); // forward // PYSIDE-908: The function PyType_Modified does not work in PySide, so we need to // explicitly pass __doc__. For __signature__ it _did_ actually work, because @@ -140,26 +126,12 @@ static PyObject *SbkObjectType_repr(PyObject *type) #endif // PY_VERSION_HEX < 0x03000000 -// PYSIDE-1019: Switch type's tp_dict to the currently active namespace. -static PyObject *(*type_getattro)(PyObject *type, PyObject *name); - -static PyObject *mangled_type_getattro(PyTypeObject *type, PyObject *name) -{ - /* - * Note: This `type_getattro` version is only the default that comes - * from `PyType_Type.tp_getattro`. This does *not* interfere in any way - * with the complex `tp_getattro` of `QObject` and other instances. - * What we change here is the meta class of `QObject`. - */ - if (SelectFeatureSet != nullptr) - type->tp_dict = SelectFeatureSet(type); - return type_getattro(reinterpret_cast<PyObject *>(type), name); -} +static PyObject *(*type_getattro)(PyObject *type, PyObject *name); // forward +static PyObject *mangled_type_getattro(PyTypeObject *type, PyObject *name); // forward static PyType_Slot SbkObjectType_Type_slots[] = { {Py_tp_dealloc, reinterpret_cast<void *>(SbkObjectTypeDealloc)}, {Py_tp_getattro, reinterpret_cast<void *>(mangled_type_getattro)}, - {Py_tp_setattro, reinterpret_cast<void *>(PyObject_GenericSetAttr)}, {Py_tp_base, static_cast<void *>(&PyType_Type)}, {Py_tp_alloc, reinterpret_cast<void *>(PyType_GenericAlloc)}, {Py_tp_new, reinterpret_cast<void *>(SbkObjectTypeTpNew)}, @@ -340,7 +312,12 @@ static int SbkObject_clear(PyObject *self) return 0; } +static PyObject *SbkObject_GenericGetAttr(PyObject *obj, PyObject *name); +static int SbkObject_GenericSetAttr(PyObject *obj, PyObject *name, PyObject *value); + static PyType_Slot SbkObject_Type_slots[] = { + {Py_tp_getattro, reinterpret_cast<void *>(SbkObject_GenericGetAttr)}, + {Py_tp_setattro, reinterpret_cast<void *>(SbkObject_GenericSetAttr)}, {Py_tp_dealloc, reinterpret_cast<void *>(SbkDeallocWrapperWithPrivateDtor)}, {Py_tp_traverse, reinterpret_cast<void *>(SbkObject_traverse)}, {Py_tp_clear, reinterpret_cast<void *>(SbkObject_clear)}, @@ -533,6 +510,71 @@ void SbkObjectTypeDealloc(PyObject *pyObj) } } +////////////////////////////////////////////////////////////////////////////// +// +// PYSIDE-1019: Support switchable extensions +// +// We simply exchange the complete class dicts. +// This is done in +// - mangled_type_getattro which replaces +// - Sbk_TypeGet___dict__ +// - SbkObjectType_replace_getattro +// - SbkObjectType_replace_setattro +// + +void initSelectableFeature(SelectableFeatureHook func) +{ + SelectFeatureSet = func; +} + +static PyObject *mangled_type_getattro(PyTypeObject *type, PyObject *name) +{ + /* + * Note: This `type_getattro` version is only the default that comes + * from `PyType_Type.tp_getattro`. This does *not* interfere in any way + * with the complex `tp_getattro` of `QObject` and other instances. + * What we change here is the meta class of `QObject`. + */ + if (SelectFeatureSet != nullptr) + type->tp_dict = SelectFeatureSet(type); + return type_getattro(reinterpret_cast<PyObject *>(type), name); +} + +static PyObject *Sbk_TypeGet___dict__(PyTypeObject *type, void *context) +{ + /* + * This is the override for getting a dict. + */ + auto dict = type->tp_dict; + if (dict == NULL) + Py_RETURN_NONE; + if (SelectFeatureSet != nullptr) + dict = SelectFeatureSet(type); + return PyDictProxy_New(dict); +} + +// These functions replace the standard PyObject_Generic(Get|Set)Attr functions. +// They provide the default that "object" inherits. +// Everything else is directly handled by an insertion PyObject_GenericGetAttr +static PyObject *SbkObject_GenericGetAttr(PyObject *obj, PyObject *name) +{ + auto type = Py_TYPE(obj); + if (SelectFeatureSet != nullptr) + type->tp_dict = SelectFeatureSet(type); + return PyObject_GenericGetAttr(obj, name); +} + +static int SbkObject_GenericSetAttr(PyObject *obj, PyObject *name, PyObject *value) +{ + auto type = Py_TYPE(obj); + if (SelectFeatureSet != nullptr) + type->tp_dict = SelectFeatureSet(type); + return PyObject_GenericSetAttr(obj, name, value); +} + +// +////////////////////////////////////////////////////////////////////////////// + static PyObject *SbkObjectTypeTpNew(PyTypeObject *metatype, PyObject *args, PyObject *kwds) { // Check if all bases are new style before calling type.tp_new diff --git a/sources/shiboken2/libshiboken/basewrapper.h b/sources/shiboken2/libshiboken/basewrapper.h index a4a8629fb..47ea89577 100644 --- a/sources/shiboken2/libshiboken/basewrapper.h +++ b/sources/shiboken2/libshiboken/basewrapper.h @@ -93,9 +93,14 @@ typedef void (*ObjectDestructor)(void *); typedef void (*SubTypeInitHook)(SbkObjectType *, PyObject *, PyObject *); +// PYSIDE-1019: Set the function to select the current feature. typedef PyObject *(*SelectableFeatureHook)(PyTypeObject *); LIBSHIBOKEN_API void initSelectableFeature(SelectableFeatureHook func); +// PYSIDE-1019: Publish the start of setattro. +LIBSHIBOKEN_API void SbkObject_NotifySetAttr(PyObject *obj, PyObject *name, PyObject *value); + + extern LIBSHIBOKEN_API PyTypeObject *SbkObjectType_TypeF(void); extern LIBSHIBOKEN_API SbkObjectType *SbkObject_TypeF(void); diff --git a/sources/shiboken2/libshiboken/bindingmanager.cpp b/sources/shiboken2/libshiboken/bindingmanager.cpp index 1c38da81c..b35a02ef4 100644 --- a/sources/shiboken2/libshiboken/bindingmanager.cpp +++ b/sources/shiboken2/libshiboken/bindingmanager.cpp @@ -44,6 +44,7 @@ #include "sbkdbg.h" #include "gilstate.h" #include "sbkstring.h" +#include "sbkstaticstrings.h" #include "debugfreehook.h" #include <cstddef> @@ -273,7 +274,19 @@ SbkObject *BindingManager::retrieveWrapper(const void *cptr) return iter->second; } -PyObject *BindingManager::getOverride(const void *cptr, PyObject *methodName) +static bool mangleNameFlag(PyTypeObject *type) +{ + // PYSIDE-1019: See if a dict is set with a snake_case bit. + static PyTypeObject *old_dict_type = Py_TYPE(PyType_Type.tp_dict); + auto dict = type->tp_dict; + if (Py_TYPE(dict) == old_dict_type) + return false; + Shiboken::AutoDecRef select_id(PyObject_GetAttr(dict, Shiboken::PyName::select_id())); + auto id = PyInt_AsSsize_t(select_id); + return (id & 1) != 0; +} + +PyObject *BindingManager::getOverride(const void *cptr, PyObject *methodNameCache[2], const char *methodName) { SbkObject *wrapper = retrieveWrapper(cptr); // The refcount can be 0 if the object is dieing and someone called @@ -281,15 +294,22 @@ PyObject *BindingManager::getOverride(const void *cptr, PyObject *methodName) if (!wrapper || reinterpret_cast<const PyObject *>(wrapper)->ob_refcnt == 0) return nullptr; + bool flag = mangleNameFlag(Py_TYPE(wrapper)); + PyObject *pyMethodName = methodNameCache[flag]; // borrowed + if (pyMethodName == nullptr) { + pyMethodName = Shiboken::String::getSnakeCaseName(methodName, flag); + methodNameCache[flag] = pyMethodName; + } + if (wrapper->ob_dict) { - PyObject *method = PyDict_GetItem(wrapper->ob_dict, methodName); + PyObject *method = PyDict_GetItem(wrapper->ob_dict, pyMethodName); if (method) { Py_INCREF(reinterpret_cast<PyObject *>(method)); return method; } } - PyObject *method = PyObject_GetAttr(reinterpret_cast<PyObject *>(wrapper), methodName); + PyObject *method = PyObject_GetAttr(reinterpret_cast<PyObject *>(wrapper), pyMethodName); if (method && PyMethod_Check(method) && PyMethod_GET_SELF(method) == reinterpret_cast<PyObject *>(wrapper)) { @@ -301,7 +321,7 @@ PyObject *BindingManager::getOverride(const void *cptr, PyObject *methodName) for (int i = 1; i < PyTuple_GET_SIZE(mro) - 1; i++) { auto *parent = reinterpret_cast<PyTypeObject *>(PyTuple_GET_ITEM(mro, i)); if (parent->tp_dict) { - defaultMethod = PyDict_GetItem(parent->tp_dict, methodName); + defaultMethod = PyDict_GetItem(parent->tp_dict, pyMethodName); if (defaultMethod && PyMethod_GET_FUNCTION(method) != defaultMethod) return method; } diff --git a/sources/shiboken2/libshiboken/bindingmanager.h b/sources/shiboken2/libshiboken/bindingmanager.h index 0bcde196f..8882f402e 100644 --- a/sources/shiboken2/libshiboken/bindingmanager.h +++ b/sources/shiboken2/libshiboken/bindingmanager.h @@ -73,7 +73,7 @@ public: void addToDeletionInMainThread(const DestructorEntry &); SbkObject *retrieveWrapper(const void *cptr); - PyObject *getOverride(const void *cptr, PyObject *methodName); + PyObject *getOverride(const void *cptr, PyObject *methodNameCache[2], const char *methodName); void addClassInheritance(SbkObjectType *parent, SbkObjectType *child); /** diff --git a/sources/shiboken2/libshiboken/pep384impl.cpp b/sources/shiboken2/libshiboken/pep384impl.cpp index 4149bbcbf..57d3de261 100644 --- a/sources/shiboken2/libshiboken/pep384impl.cpp +++ b/sources/shiboken2/libshiboken/pep384impl.cpp @@ -86,6 +86,7 @@ static PyMemberDef probe_members[] = { #define probe_tp_repr make_dummy(2) #define probe_tp_call make_dummy(3) #define probe_tp_getattro make_dummy(16) +#define probe_tp_setattro make_dummy(17) #define probe_tp_str make_dummy(4) #define probe_tp_traverse make_dummy(5) #define probe_tp_clear make_dummy(6) @@ -108,6 +109,7 @@ static PyType_Slot typeprobe_slots[] = { {Py_tp_repr, probe_tp_repr}, {Py_tp_call, probe_tp_call}, {Py_tp_getattro, probe_tp_getattro}, + {Py_tp_setattro, probe_tp_setattro}, {Py_tp_str, probe_tp_str}, {Py_tp_traverse, probe_tp_traverse}, {Py_tp_clear, probe_tp_clear}, @@ -153,6 +155,7 @@ check_PyTypeObject_valid() || probe_tp_repr != check->tp_repr || probe_tp_call != check->tp_call || probe_tp_getattro != check->tp_getattro + || probe_tp_setattro != check->tp_setattro || probe_tp_str != check->tp_str || probe_tp_traverse != check->tp_traverse || probe_tp_clear != check->tp_clear diff --git a/sources/shiboken2/libshiboken/pep384impl.h b/sources/shiboken2/libshiboken/pep384impl.h index 2a14d6543..973cf06ce 100644 --- a/sources/shiboken2/libshiboken/pep384impl.h +++ b/sources/shiboken2/libshiboken/pep384impl.h @@ -99,7 +99,7 @@ typedef struct _typeobject { ternaryfunc tp_call; reprfunc tp_str; getattrofunc tp_getattro; - void *X17; // setattrofunc tp_setattro; + setattrofunc tp_setattro; void *X18; // PyBufferProcs *tp_as_buffer; unsigned long tp_flags; void *X20; // const char *tp_doc; diff --git a/sources/shiboken2/libshiboken/sbkstring.cpp b/sources/shiboken2/libshiboken/sbkstring.cpp index 092745d3d..ed8b61fc8 100644 --- a/sources/shiboken2/libshiboken/sbkstring.cpp +++ b/sources/shiboken2/libshiboken/sbkstring.cpp @@ -271,5 +271,49 @@ PyObject *createStaticString(const char *str) return result; } +/////////////////////////////////////////////////////////////////////// +// +// PYSIDE-1019: Helper function for snake_case vs. camelCase names +// --------------------------------------------------------------- +// +// When renaming dict entries, `BindingManager::getOverride` must +// use adapted names. +// +// This might become more complex when we need to register +// exceptions from this rule. +// + +PyObject *getSnakeCaseName(const char *name, bool lower) +{ + /* + * Convert `camelCase` to `snake_case`. + * Gives up when there are two consecutive upper chars. + * + * Also functions beginning with `gl` followed by upper case stay + * unchanged since that are the special OpenGL functions. + */ + if (!lower + || strlen(name) < 3 + || (name[0] == 'g' && name[1] == 'l' && isupper(name[2]))) + return createStaticString(name); + + char new_name[200 + 1] = {}; + const char *p = name; + char *q = new_name; + for (; *p && q - new_name < 200; ++p, ++q) { + if (isupper(*p)) { + if (p != name && isupper(*(p - 1))) + return createStaticString(name); + *q = '_'; + ++q; + *q = tolower(*p); + } + else { + *q = *p; + } + } + return createStaticString(new_name); +} + } // namespace String } // namespace Shiboken diff --git a/sources/shiboken2/libshiboken/sbkstring.h b/sources/shiboken2/libshiboken/sbkstring.h index 84d7768c5..3475d3acd 100644 --- a/sources/shiboken2/libshiboken/sbkstring.h +++ b/sources/shiboken2/libshiboken/sbkstring.h @@ -61,6 +61,7 @@ namespace String LIBSHIBOKEN_API int compare(PyObject *val1, const char *val2); LIBSHIBOKEN_API Py_ssize_t len(PyObject *str); LIBSHIBOKEN_API PyObject *createStaticString(const char *str); + LIBSHIBOKEN_API PyObject *getSnakeCaseName(const char *name, bool lower); } // namespace String } // namespace Shiboken |