diff options
author | Fabian Kosmale <fabian.kosmale@qt.io> | 2021-03-31 16:02:19 +0200 |
---|---|---|
committer | Fabian Kosmale <fabian.kosmale@qt.io> | 2021-04-01 10:14:16 +0200 |
commit | e7e4eba6875c0f375c4fd03af9b3ed9ea44d0ba1 (patch) | |
tree | 4eb678905c64a8a91fcf6ea45114f78cacb6e1a5 | |
parent | 4a77e2593f281456d25c9b2dd5df400c3e588e4c (diff) |
QV4QObjectWrapper: Store the whole signal
90be89d771425044a84e9e79e4e668e065acc825 changed the connection logic to
actually pass the receiver to connect in order to fix disconnect
cleanup. However, we omitted to change QObjectSlotDispatcher::impl
accordingly. The previous logic was:
- store the index of the signal in signalIndex
- In impl, in the call case, we would get passed the emitting object
(sic!) as the receiver parameter. Then we would use the object and the
signal index to obtain the QMetaMethod.
- From the QMetaMethod, we could get the signal's number of parameters.
After the aforementioned change, that does not work anymore: The
receiver is now the actual receiver of the signal, thus we get the wrong
method, and potentially the wrong number of parameters.
To fix this, we now store the complete QMetaMethod of the signal.
Pick-to: 6.1
Change-Id: I868c51edf24a61d14eaf958ed7942da27f54a5c3
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
-rw-r--r-- | src/qml/jsruntime/qv4qobjectwrapper.cpp | 13 | ||||
-rw-r--r-- | src/qml/qml/qqmlmetaobject.cpp | 2 | ||||
-rw-r--r-- | src/qml/qml/qqmlmetaobject_p.h | 4 | ||||
-rw-r--r-- | tests/auto/qml/qqmlecmascript/data/scriptConnect.7.qml | 11 | ||||
-rw-r--r-- | tests/auto/qml/qqmlecmascript/testtypes.cpp | 3 | ||||
-rw-r--r-- | tests/auto/qml/qqmlecmascript/testtypes.h | 14 | ||||
-rw-r--r-- | tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp | 8 |
7 files changed, 46 insertions, 9 deletions
diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index 4fb5851e42..34ff43caab 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -975,15 +975,15 @@ struct QObjectSlotDispatcher : public QtPrivate::QSlotObjectBase { QV4::PersistentValue function; QV4::PersistentValue thisObject; - int signalIndex; + QMetaMethod signal; QObjectSlotDispatcher() : QtPrivate::QSlotObjectBase(&impl) - , signalIndex(-1) {} - static void impl(int which, QSlotObjectBase *this_, QObject *r, void **metaArgs, bool *ret) + static void impl(int which, QSlotObjectBase *this_, QObject *receiver, void **metaArgs, bool *ret) { + Q_UNUSED(receiver); switch (which) { case Destroy: { delete static_cast<QObjectSlotDispatcher*>(this_); @@ -999,7 +999,7 @@ struct QObjectSlotDispatcher : public QtPrivate::QSlotObjectBase break; QQmlMetaObject::ArgTypeStorage storage; - QQmlMetaObject(r).methodParameterTypes(This->signalIndex, &storage, nullptr); + QQmlMetaObject::methodParameterTypes(This->signal, &storage, nullptr); int argCount = storage.size(); @@ -1107,7 +1107,8 @@ ReturnedValue QObjectWrapper::method_connect(const FunctionObject *b, const Valu if (!signalObject) THROW_GENERIC_ERROR("Function.prototype.connect: cannot connect to deleted QObject"); - if (signalObject->metaObject()->method(signalIndex).methodType() != QMetaMethod::Signal) + auto signalMetaMethod = signalObject->metaObject()->method(signalIndex); + if (signalMetaMethod.methodType() != QMetaMethod::Signal) THROW_GENERIC_ERROR("Function.prototype.connect: this object is not a signal"); QV4::ScopedFunctionObject f(scope); @@ -1127,7 +1128,7 @@ ReturnedValue QObjectWrapper::method_connect(const FunctionObject *b, const Valu THROW_GENERIC_ERROR("Function.prototype.connect: target this is not an object"); QV4::QObjectSlotDispatcher *slot = new QV4::QObjectSlotDispatcher; - slot->signalIndex = signalIndex; + slot->signal = signalMetaMethod; slot->thisObject.set(scope.engine, object); slot->function.set(scope.engine, f); diff --git a/src/qml/qml/qqmlmetaobject.cpp b/src/qml/qml/qqmlmetaobject.cpp index 585920a99f..5a86cd6988 100644 --- a/src/qml/qml/qqmlmetaobject.cpp +++ b/src/qml/qml/qqmlmetaobject.cpp @@ -131,7 +131,7 @@ bool QQmlMetaObject::constructorParameterTypes(int index, ArgTypeStorage *dummy, } bool QQmlMetaObject::methodParameterTypes(const QMetaMethod &m, ArgTypeStorage *argStorage, - QByteArray *unknownTypeError) const + QByteArray *unknownTypeError) { Q_ASSERT(argStorage); diff --git a/src/qml/qml/qqmlmetaobject_p.h b/src/qml/qml/qqmlmetaobject_p.h index 0cb440b38c..14e1a0c088 100644 --- a/src/qml/qml/qqmlmetaobject_p.h +++ b/src/qml/qml/qqmlmetaobject_p.h @@ -111,10 +111,10 @@ public: // we need a helper to find the correct meta object and property/method index. static void resolveGadgetMethodOrPropertyIndex(QMetaObject::Call type, const QMetaObject **metaObject, int *index); + static bool methodParameterTypes(const QMetaMethod &method, ArgTypeStorage *argStorage, + QByteArray *unknownTypeError); protected: const QMetaObject *_m = nullptr; - bool methodParameterTypes(const QMetaMethod &method, ArgTypeStorage *argStorage, - QByteArray *unknownTypeError) const; }; diff --git a/tests/auto/qml/qqmlecmascript/data/scriptConnect.7.qml b/tests/auto/qml/qqmlecmascript/data/scriptConnect.7.qml new file mode 100644 index 0000000000..9dab8d7815 --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/scriptConnect.7.qml @@ -0,0 +1,11 @@ +import Qt.test +import QtQml + +QtObject { + readonly property Sender s: Sender {id: sender} + readonly property Receiver r: Receiver {id: receiver} + Component.onCompleted: () => { + sender.sig1.connect(receiver.slot1) + sender.sig1() + } +} diff --git a/tests/auto/qml/qqmlecmascript/testtypes.cpp b/tests/auto/qml/qqmlecmascript/testtypes.cpp index fb3f4ae041..209433d46c 100644 --- a/tests/auto/qml/qqmlecmascript/testtypes.cpp +++ b/tests/auto/qml/qqmlecmascript/testtypes.cpp @@ -557,6 +557,9 @@ void registerTypes() qmlRegisterType<ClassWithQProperty>("Qt.test", 1, 0, "ClassWithQProperty"); qmlRegisterType<ClassWithQObjectProperty>("Qt.test", 1, 0, "ClassWithQObjectProperty"); qmlRegisterType<ClassWithQProperty2>("Qt.test", 1, 0, "ClassWithQProperty2"); + + qmlRegisterType<Receiver>("Qt.test", 1,0, "Receiver"); + qmlRegisterType<Sender>("Qt.test", 1,0, "Sender"); } #include "testtypes.moc" diff --git a/tests/auto/qml/qqmlecmascript/testtypes.h b/tests/auto/qml/qqmlecmascript/testtypes.h index 705d72bf75..34f612e276 100644 --- a/tests/auto/qml/qqmlecmascript/testtypes.h +++ b/tests/auto/qml/qqmlecmascript/testtypes.h @@ -1824,6 +1824,20 @@ public: QProperty<int> complex; }; +struct Sender : QObject +{ + Q_OBJECT +signals: + void sig1(); +}; + +struct Receiver : QObject +{ + Q_OBJECT +public slots: + int slot1(int i, int j, int k) {return i+j+k;} +}; + void registerTypes(); #endif // TESTTYPES_H diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp index c109107591..47b85f35c8 100644 --- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp +++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp @@ -3624,6 +3624,14 @@ void tst_qqmlecmascript::scriptConnect() delete object; } + + { + QRegularExpression msg {".*scriptConnect.7.qml:9: Error: Insufficient arguments"}; + QTest::ignoreMessage(QtMsgType::QtWarningMsg, msg); + QQmlComponent component(&engine, testFileUrl("scriptConnect.7.qml")); + QScopedPointer<QObject> root { component.create() }; + QVERIFY2(root, qPrintable(component.errorString())); + } } void tst_qqmlecmascript::scriptDisconnect() |