diff options
author | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2024-04-29 08:21:20 +0200 |
---|---|---|
committer | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2024-05-06 10:57:26 +0200 |
commit | 28d04cae204881392ddc0826a570d05ba82c5ee0 (patch) | |
tree | 1086e21a2afe528d70b2694894fe1f2bdf1b1e8c /sources/shiboken6/libshiboken/basewrapper.cpp | |
parent | 9fcc3066412e23e92eb05d30dcad858f8ca1cd90 (diff) |
shiboken6: Make multiple inheritance cast check less restrictive
The old code would not allow to downcast if a special cast function
exists somewhere in the class hierarchy (as is the case for example
for QWidget inheriting QObject and QPaintDevice).
Make the check more fine-grained by actually checking whether the base
class is a direct, single line inheritance base class of the type
passed in. This makes the mechanism work for widgets.
The corresponding test can then be relaxed.
Task-number: PYSIDE-868
Change-Id: Id81fd9c3080e42009fc84e06a9bab1c8856f2c0c
Reviewed-by: Cristian Maureira-Fredes <cristian.maureira-fredes@qt.io>
Diffstat (limited to 'sources/shiboken6/libshiboken/basewrapper.cpp')
-rw-r--r-- | sources/shiboken6/libshiboken/basewrapper.cpp | 22 |
1 files changed, 21 insertions, 1 deletions
diff --git a/sources/shiboken6/libshiboken/basewrapper.cpp b/sources/shiboken6/libshiboken/basewrapper.cpp index 823078735..c11fbbfb2 100644 --- a/sources/shiboken6/libshiboken/basewrapper.cpp +++ b/sources/shiboken6/libshiboken/basewrapper.cpp @@ -1055,6 +1055,26 @@ bool hasSpecialCastFunction(PyTypeObject *sbkType) return d != nullptr && d->mi_specialcast != nullptr; } +// Find whether base is a direct single line base class of type +// (no multiple inheritance), that is, a C++ pointer cast can safely be done. +static bool isDirectAncestor(PyTypeObject *type, PyTypeObject *base) +{ + if (type == base) + return true; + if (PyTuple_Size(type->tp_bases) == 0) + return false; + auto *sbkObjectType = SbkObject_TypeF(); + auto *firstBase = reinterpret_cast<PyTypeObject *>(PyTuple_GetItem(type->tp_bases, 0)); + return firstBase != sbkObjectType + && PyType_IsSubtype(type, sbkObjectType) != 0 + && isDirectAncestor(firstBase, base); +} + +bool canDowncastTo(PyTypeObject *baseType, PyTypeObject *targetType) +{ + return isDirectAncestor(targetType, baseType); +} + } // namespace ObjectType @@ -1466,7 +1486,7 @@ PyObject *newObjectForPointer(PyTypeObject *instanceType, // PYSIDE-868: In case of multiple inheritance, (for example, // a function returning a QPaintDevice * from a QWidget *), // use instance type to avoid pointer offset errors. - return exactType != nullptr && Shiboken::ObjectType::hasSpecialCastFunction(exactType) + return exactType != nullptr && !Shiboken::ObjectType::canDowncastTo(instanceType, exactType) ? newObjectForType(instanceType, cptr, hasOwnership) : newObjectWithHeuristicsHelper(instanceType, exactType, cptr, hasOwnership); } |