aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFriedemann Kleint <Friedemann.Kleint@qt.io>2023-08-21 15:44:45 +0200
committerQt Cherry-pick Bot <cherrypick_bot@qt-project.org>2023-08-22 10:41:40 +0000
commit9ef8a2ee49d47c7ed1094bc0ecc6b18ffe76712f (patch)
tree4be7f5d09c4491e3216cbdecf7d9532fcfa9b10d
parentfa61e6bf40244f11105505298cd9094eff7aa447 (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.cpp34
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;