diff options
| author | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2023-08-21 15:44:45 +0200 |
|---|---|---|
| committer | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2023-08-22 11:44:25 +0200 |
| commit | f048d13b4f042b04d94007fba951ed3080ccf8c9 (patch) | |
| tree | 5b3c56aee6b9205296b528b968ad3fe946900e03 /sources/pyside6/libpyside/qobjectconnect.cpp | |
| parent | 7b83f501c5e8dd0af7d09e739d395dcfaaad2f74 (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
Pick-to: 6.5
Change-Id: I01591a4e948daa19caf75eaa8f803acb17b66550
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Cristian Maureira-Fredes <cristian.maureira-fredes@qt.io>
Diffstat (limited to 'sources/pyside6/libpyside/qobjectconnect.cpp')
| -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; |
