diff options
author | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2023-08-21 15:44:45 +0200 |
---|---|---|
committer | Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> | 2023-08-22 10:41:40 +0000 |
commit | 9ef8a2ee49d47c7ed1094bc0ecc6b18ffe76712f (patch) | |
tree | 4be7f5d09c4491e3216cbdecf7d9532fcfa9b10d | |
parent | fa61e6bf40244f11105505298cd9094eff7aa447 (diff) |
Fix connections to base class slots falling back to global receiver
Narrow the test condition for pre-Jira bug 1019 to check whether the
receiver method is not declared in the same class in which the slot
returned by the MetaObject search is declared.
Fixes: PYSIDE-2418
Change-Id: I01591a4e948daa19caf75eaa8f803acb17b66550
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Cristian Maureira-Fredes <cristian.maureira-fredes@qt.io>
(cherry picked from commit f048d13b4f042b04d94007fba951ed3080ccf8c9)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
-rw-r--r-- | sources/pyside6/libpyside/qobjectconnect.cpp | 34 |
1 files changed, 30 insertions, 4 deletions
diff --git a/sources/pyside6/libpyside/qobjectconnect.cpp b/sources/pyside6/libpyside/qobjectconnect.cpp index 72c80645f..de6f74b14 100644 --- a/sources/pyside6/libpyside/qobjectconnect.cpp +++ b/sources/pyside6/libpyside/qobjectconnect.cpp @@ -15,6 +15,8 @@ #include <QtCore/QMetaMethod> #include <QtCore/QObject> +#include <string_view> + static bool isMethodDecorator(PyObject *method, bool is_pymethod, PyObject *self) { Shiboken::AutoDecRef methodName(PyObject_GetAttr(method, Shiboken::PyMagicName::name())); @@ -69,6 +71,25 @@ QDebug operator<<(QDebug d, const GetReceiverResult &r) } #endif // QT_NO_DEBUG_STREAM +static const char *getQualifiedName(PyObject *ob) +{ + Shiboken::AutoDecRef qualNameP(PyObject_GetAttr(ob, Shiboken::PyMagicName::qualname())); + return qualNameP.isNull() + ? nullptr : Shiboken::String::toCString(qualNameP.object()); +} + +// Determine whether a method is declared in a class using qualified name lookup. +static bool isDeclaredIn(PyObject *method, const char *className) +{ + bool result = false; + if (auto *qualifiedNameC = getQualifiedName(PyMethod_Function(method))) { + std::string_view qualifiedName(qualifiedNameC); + if (const auto dot = qualifiedName.rfind('.'); dot != std::string::npos) + result = qualifiedName.substr(0, dot) == className; + } + return result; +} + static GetReceiverResult getReceiver(QObject *source, const char *signal, PyObject *callback) { @@ -111,10 +132,15 @@ static GetReceiverResult getReceiver(QObject *source, const char *signal, result.usingGlobalReceiver).toLatin1(); const QMetaObject *metaObject = result.receiver->metaObject(); result.slotIndex = metaObject->indexOfSlot(result.callbackSig.constData()); - if (result.slotIndex != -1 && result.slotIndex < metaObject->methodOffset() - && PyMethod_Check(callback)) { - result.usingGlobalReceiver = true; - } + if (PyMethod_Check(callback) != 0 && result.slotIndex != -1) { + // Find the class in which the slot is declared. + while (result.slotIndex < metaObject->methodOffset()) + metaObject = metaObject->superClass(); + // If the Python callback is not declared in the same class, assume it is + // a Python override. Resort to global receiver (PYSIDE-2418). + if (!isDeclaredIn(callback, metaObject->className())) + result.usingGlobalReceiver = true; + } } const auto receiverThread = result.receiver ? result.receiver->thread() : nullptr; |