diff --git a/src/corelib/kernel/qmetaobject.cpp b/src/corelib/kernel/qmetaobject.cpp index 7142a17050b..2a4fc7ebea3 100644 --- a/src/corelib/kernel/qmetaobject.cpp +++ b/src/corelib/kernel/qmetaobject.cpp @@ -241,11 +241,12 @@ QObject *QMetaObject::newInstance(QGenericArgument val0, break; } - return newInstanceImpl(this, paramCount, parameters, typeNames); + return newInstanceImpl(this, paramCount, parameters, typeNames, nullptr); } QObject *QMetaObject::newInstanceImpl(const QMetaObject *mobj, qsizetype paramCount, - const void **parameters, const char **typeNames) + const void **parameters, const char **typeNames, + const QtPrivate::QMetaTypeInterface **metaTypes) { if (!mobj->inherits(&QObject::staticMetaObject)) { qWarning("QMetaObject::newInstance: type %s does not inherit QObject", mobj->className()); @@ -262,6 +263,8 @@ QT_WARNING_DISABLE_GCC("-Wdangling-pointer") QMetaType returnValueMetaType = QMetaType::fromType(); parameters[0] = &returnValue; typeNames[0] = returnValueMetaType.name(); + if (metaTypes) + metaTypes[0] = returnValueMetaType.iface(); QT_WARNING_POP @@ -275,7 +278,7 @@ QT_WARNING_POP // attempt to call QMetaMethodPrivate::InvokeFailReason r = QMetaMethodPrivate::invokeImpl(m, nullptr, Qt::DirectConnection, paramCount, - parameters, typeNames); + parameters, typeNames, metaTypes); if (r == QMetaMethodPrivate::InvokeFailReason::None) return returnValue; if (int(r) < 0) @@ -1346,7 +1349,8 @@ QByteArray QMetaObject::normalizedSignature(const char *method) Q_DECL_COLD_FUNCTION static inline bool printMethodNotFoundWarning(const QMetaObject *meta, QLatin1StringView name, qsizetype paramCount, - const char *const *names) + const char *const *names, + const QtPrivate::QMetaTypeInterface * const *metaTypes) { // now find the candidates we couldn't use QByteArray candidateMessage; @@ -1362,7 +1366,10 @@ printMethodNotFoundWarning(const QMetaObject *meta, QLatin1StringView name, qsiz QVarLengthArray sig; for (qsizetype i = 1; i < paramCount; ++i) { - sig.append(names[i], qstrlen(names[i])); + if (names[i]) + sig.append(names[i], qstrlen(names[i])); + else + sig.append(metaTypes[i]->name, qstrlen(metaTypes[i]->name)); sig.append(','); } if (paramCount != 1) @@ -1472,12 +1479,13 @@ bool QMetaObject::invokeMethod(QObject *obj, if (qstrlen(typeNames[paramCount]) <= 0) break; } - return invokeMethodImpl(obj, member, type, paramCount, parameters, typeNames); + return invokeMethodImpl(obj, member, type, paramCount, parameters, typeNames, nullptr); } bool QMetaObject::invokeMethodImpl(QObject *obj, const char *member, Qt::ConnectionType type, qsizetype paramCount, const void * const *parameters, - const char * const *typeNames) + const char * const *typeNames, + const QtPrivate::QMetaTypeInterface * const *metaTypes) { if (!obj) return false; @@ -1503,14 +1511,15 @@ bool QMetaObject::invokeMethodImpl(QObject *obj, const char *member, Qt::Connect // attempt to call QMetaMethodPrivate::InvokeFailReason r = - QMetaMethodPrivate::invokeImpl(m, obj, type, paramCount, parameters, typeNames); + QMetaMethodPrivate::invokeImpl(m, obj, type, paramCount, parameters, + typeNames, metaTypes); if (int(r) <= 0) return r == QMetaMethodPrivate::InvokeFailReason::None; } } // This method doesn't belong to us; print out a nice warning with candidates. - return printMethodNotFoundWarning(obj->metaObject(), name, paramCount, typeNames); + return printMethodNotFoundWarning(obj->metaObject(), name, paramCount, typeNames, metaTypes); } bool QMetaObject::invokeMethodImpl(QObject *object, QtPrivate::QSlotObjectBase *slot, Qt::ConnectionType type, void *ret) @@ -2410,25 +2419,27 @@ bool QMetaMethod::invoke(QObject *object, if (qstrlen(typeNames[paramCount]) <= 0) break; } - return invokeImpl(*this, object, connectionType, paramCount, param, typeNames); + return invokeImpl(*this, object, connectionType, paramCount, param, typeNames, nullptr); } bool QMetaMethod::invokeImpl(QMetaMethod self, void *target, Qt::ConnectionType connectionType, qsizetype paramCount, const void *const *parameters, - const char *const *typeNames) + const char *const *typeNames, + const QtPrivate::QMetaTypeInterface *const *metaTypes) { if (!target || !self.mobj) return false; QMetaMethodPrivate::InvokeFailReason r = - QMetaMethodPrivate::invokeImpl(self, target, connectionType, paramCount, parameters, typeNames); - + QMetaMethodPrivate::invokeImpl(self, target, connectionType, paramCount, parameters, + typeNames, metaTypes); if (Q_LIKELY(r == QMetaMethodPrivate::InvokeFailReason::None)) return true; if (int(r) >= int(QMetaMethodPrivate::InvokeFailReason::FormalParameterMismatch)) { int n = int(r) - int(QMetaMethodPrivate::InvokeFailReason::FormalParameterMismatch); qWarning("QMetaMethod::invoke: cannot convert formal parameter %d from %s in call to %s::%s", - n, typeNames[n + 1], self.mobj->className(), self.methodSignature().constData()); + n, typeNames[n + 1] ? typeNames[n + 1] : metaTypes[n + 1]->name, + self.mobj->className(), self.methodSignature().constData()); } if (r == QMetaMethodPrivate::InvokeFailReason::TooFewArguments) { qWarning("QMetaMethod::invoke: too few arguments (%d) in call to %s::%s", @@ -2440,10 +2451,13 @@ bool QMetaMethod::invokeImpl(QMetaMethod self, void *target, Qt::ConnectionType auto QMetaMethodInvoker::invokeImpl(QMetaMethod self, void *target, Qt::ConnectionType connectionType, qsizetype paramCount, const void *const *parameters, - const char *const *typeNames) -> InvokeFailReason + const char *const *typeNames, + const QtPrivate::QMetaTypeInterface *const *metaTypes) -> InvokeFailReason { auto object = static_cast(target); auto priv = QMetaMethodPrivate::get(&self); + constexpr bool MetaTypesAreOptional = QT_VERSION < QT_VERSION_CHECK(7, 0, 0); + auto methodMetaTypes = priv->parameterMetaTypeInterfaces(); auto param = const_cast(parameters); Q_ASSERT(priv->mobj); @@ -2453,6 +2467,7 @@ auto QMetaMethodInvoker::invokeImpl(QMetaMethod self, void *target, Q_ASSERT(paramCount >= 1); // includes the return type Q_ASSERT(parameters); Q_ASSERT(typeNames); + Q_ASSERT(MetaTypesAreOptional || metaTypes); if ((paramCount - 1) < qsizetype(priv->data.argc())) return InvokeFailReason::TooFewArguments; @@ -2460,23 +2475,45 @@ auto QMetaMethodInvoker::invokeImpl(QMetaMethod self, void *target, // 0 is the return type, 1 is the first formal parameter auto checkTypesAreCompatible = [=](int idx) { uint typeInfo = priv->parameterTypeInfo(idx - 1); - QLatin1StringView userTypeName(typeNames[idx]); + QLatin1StringView userTypeName(typeNames[idx] ? typeNames[idx] : metaTypes[idx]->name); if ((typeInfo & IsUnresolvedType) == 0) { // this is a built-in type - return int(typeInfo) == QMetaType::fromName(userTypeName).id(); + if (MetaTypesAreOptional && !metaTypes) + return int(typeInfo) == QMetaType::fromName(userTypeName).id(); + return int(typeInfo) == metaTypes[idx]->typeId; } - // compare strings QLatin1StringView methodTypeName = stringDataView(priv->mobj, typeInfo & TypeNameIndexMask); - if (methodTypeName == userTypeName) + if ((MetaTypesAreOptional && !metaTypes) || !metaTypes[idx]) { + // compatibility call, compare strings + if (methodTypeName == userTypeName) + return true; + + // maybe the user type needs normalization + QByteArray normalized = normalizeTypeInternal(userTypeName.begin(), userTypeName.end()); + return methodTypeName == QLatin1StringView(normalized); + } + + QMetaType userType(metaTypes[idx]); + Q_ASSERT(userType.isValid()); + if (QMetaType(methodMetaTypes[idx - 1]) == userType) return true; - // maybe the user type needs normalization - QByteArray normalized = normalizeTypeInternal(userTypeName.begin(), userTypeName.end()); - return methodTypeName == QLatin1StringView(normalized); + // if the parameter type was NOT only forward-declared, it MUST have + // matched + if (methodMetaTypes[idx - 1]) + return false; + + // resolve from the name moc stored for us + QMetaType resolved = QMetaType::fromName(methodTypeName); + return resolved == userType; }; + // force all types to be registered, just in case + for (qsizetype i = 0; metaTypes && i < paramCount; ++i) + QMetaType(metaTypes[i]).registerType(); + // check formal parameters first (overload set) for (qsizetype i = 1; i < paramCount; ++i) { if (!checkTypesAreCompatible(i)) @@ -2497,6 +2534,14 @@ auto QMetaMethodInvoker::invokeImpl(QMetaMethod self, void *target, return InvokeFailReason::ConstructorCallWithoutResult; } + if (!MetaTypesAreOptional || metaTypes) { + if (metaTypes[0]->typeId != QMetaType::QObjectStar) { + qWarning("QMetaMethod::invokeMethod: cannot convert QObject* to %s on constructor call %s", + metaTypes[0]->name, self.methodSignature().constData()); + return InvokeFailReason::ReturnTypeMismatch; + } + } + int idx = priv->ownConstructorMethodIndex(); if (priv->mobj->static_metacall(QMetaObject::CreateInstance, idx, param) >= 0) return InvokeFailReason::ConstructorCallFailed; @@ -2506,10 +2551,11 @@ auto QMetaMethodInvoker::invokeImpl(QMetaMethod self, void *target, // regular type - check return type if (parameters[0]) { if (!checkTypesAreCompatible(0)) { + const char *retType = typeNames[0] ? typeNames[0] : metaTypes[0]->name; qWarning("QMetaMethod::invokeMethod: return type mismatch for method %s::%s:" " cannot convert from %s to %s during invocation", priv->mobj->className(), priv->methodSignature().constData(), - priv->rawReturnTypeName(), typeNames[0]); + priv->rawReturnTypeName(), retType); return InvokeFailReason::ReturnTypeMismatch; } } @@ -2561,8 +2607,12 @@ auto QMetaMethodInvoker::invokeImpl(QMetaMethod self, void *target, // fill in the meta types first for (int i = 1; i < paramCount; ++i) { - types[i] = priv->parameterMetaType(i - 1); + types[i] = QMetaType(methodMetaTypes[i - 1]); + if (!types[i].iface() && (!MetaTypesAreOptional || metaTypes)) + types[i] = QMetaType(metaTypes[i]); if (!types[i].iface()) + types[i] = priv->parameterMetaType(i - 1); + if (!types[i].iface() && typeNames[i]) types[i] = QMetaType::fromName(typeNames[i]); if (!types[i].iface()) { qWarning("QMetaMethod::invoke: Unable to handle unregistered datatype '%s'", diff --git a/src/corelib/kernel/qmetaobject.h b/src/corelib/kernel/qmetaobject.h index 735f26caa20..c7cee536a61 100644 --- a/src/corelib/kernel/qmetaobject.h +++ b/src/corelib/kernel/qmetaobject.h @@ -141,7 +141,7 @@ public: { auto h = QtPrivate::invokeMethodHelper(r, std::forward(arguments)...); return invokeImpl(*this, obj, c, h.parameterCount(), h.parameters.data(), - h.typeNames.data()); + h.typeNames.data(), h.metaTypes.data()); } template QtPrivate::Invoke::IfNotOldStyleArgs @@ -167,7 +167,7 @@ public: { auto h = QtPrivate::invokeMethodHelper(r, std::forward(arguments)...); return invokeImpl(*this, gadget, Qt::ConnectionType(-1), h.parameterCount(), - h.parameters.data(), h.typeNames.data()); + h.parameters.data(), h.typeNames.data(), h.metaTypes.data()); } template QtPrivate::Invoke::IfNotOldStyleArgs @@ -190,7 +190,8 @@ public: private: static bool invokeImpl(QMetaMethod self, void *target, Qt::ConnectionType, qsizetype paramCount, - const void *const *parameters, const char *const *typeNames); + const void *const *parameters, const char *const *typeNames, + const QtPrivate::QMetaTypeInterface *const *metaTypes); static QMetaMethod fromSignalImpl(const QMetaObject *, void **); static QMetaMethod fromRelativeMethodIndex(const QMetaObject *mobj, int index); static QMetaMethod fromRelativeConstructorIndex(const QMetaObject *mobj, int index); diff --git a/src/corelib/kernel/qmetaobject_p.h b/src/corelib/kernel/qmetaobject_p.h index f54dae6d06f..c93a82196ed 100644 --- a/src/corelib/kernel/qmetaobject_p.h +++ b/src/corelib/kernel/qmetaobject_p.h @@ -160,7 +160,8 @@ public: // shadows the public function static InvokeFailReason Q_CORE_EXPORT invokeImpl(QMetaMethod self, void *target, Qt::ConnectionType, qsizetype paramCount, - const void *const *parameters, const char *const *typeNames); + const void *const *parameters, const char *const *typeNames, + const QtPrivate::QMetaTypeInterface *const *metaTypes); }; struct QMetaObjectPrivate diff --git a/src/corelib/kernel/qobjectdefs.h b/src/corelib/kernel/qobjectdefs.h index 7d324e4b8e0..2c28585a48e 100644 --- a/src/corelib/kernel/qobjectdefs.h +++ b/src/corelib/kernel/qobjectdefs.h @@ -70,7 +70,7 @@ class QMetaClassInfo; namespace QtPrivate { class QMetaTypeInterface; -template constexpr auto typenameHelper(); +template constexpr const QMetaTypeInterface *qMetaTypeInterfaceForType(); } struct QMethodRawArguments @@ -130,12 +130,14 @@ public: struct QMetaMethodArgument { + const QtPrivate::QMetaTypeInterface *metaType; const char *name; const void *data; }; struct QMetaMethodReturnArgument { + const QtPrivate::QMetaTypeInterface *metaType; const char *name; void *data; }; @@ -154,62 +156,70 @@ template using IfNotOldStyleArgs = T; template inline QMetaMethodArgument argument(const char *name, const T &t) { - return { name, std::addressof(t) }; + if constexpr ((std::is_lvalue_reference_v && std::is_const_v>) || + !std::is_reference_v) { + return { qMetaTypeInterfaceForType(), name, std::addressof(t) }; + } else { + return { nullptr, name, std::addressof(t) }; + } } template inline QMetaMethodReturnArgument returnArgument(const char *name, T &t) { - return { name, std::addressof(t) }; + return { qMetaTypeInterfaceForType(), name, std::addressof(t) }; } template inline const char *typenameHelper(const T &) { - // duplicated from the QMetaTypeInterface, FIXME - static constexpr auto name = QtPrivate::typenameHelper(); - return name.data(); + return nullptr; } template inline const void *dataHelper(const T &t) { return std::addressof(t); } +template inline const QMetaTypeInterface *metaTypeHelper(const T &) +{ + return qMetaTypeInterfaceForType(); +} inline const char *typenameHelper(QMetaMethodArgument a) { return a.name; } inline const void *dataHelper(QMetaMethodArgument a) { return a.data; } +inline const QMetaTypeInterface *metaTypeHelper(QMetaMethodArgument a) +{ return a.metaType; } inline const char *typenameHelper(const char *) = delete; template inline const void *dataHelper(const char *) = delete; +inline const QMetaTypeInterface *metaTypeHelper(const char *) = delete; inline const char *typenameHelper(const char16_t *) = delete; template inline const void *dataHelper(const char16_t *) = delete; +inline const QMetaTypeInterface *metaTypeHelper(const char16_t *) = delete; } // namespace QtPrivate::Invoke -template inline auto invokeMethodHelper(QMetaMethodReturnArgument r, Args &&... arguments) +template inline auto invokeMethodHelper(QMetaMethodReturnArgument r, const Args &... arguments) { std::array params = { const_cast(r.data), Invoke::dataHelper(arguments)... }; std::array names = { r.name, Invoke::typenameHelper(arguments)... }; + std::array types = { r.metaType, Invoke::metaTypeHelper(arguments)... }; + static_assert(params.size() == types.size()); static_assert(params.size() == names.size()); struct R { decltype(params) parameters; decltype(names) typeNames; + decltype(types) metaTypes; constexpr qsizetype parameterCount() const { return qsizetype(parameters.size()); } }; - return R { params, names }; + return R { params, names, types }; } } // namespace QtPrivate template inline QMetaMethodReturnArgument qReturnArg(T &&) = delete; template inline QMetaMethodReturnArgument qReturnArg(T &data) { - if constexpr (std::is_same_v) { - // need to go around the = delete above - return QtPrivate::Invoke::returnArgument("const char *", data); - } else { - const char *name = QtPrivate::Invoke::typenameHelper(data); - return QtPrivate::Invoke::returnArgument(name, data); - } + return QtPrivate::Invoke::returnArgument(nullptr, data); } struct Q_CORE_EXPORT QMetaObject @@ -351,7 +361,7 @@ struct Q_CORE_EXPORT QMetaObject { auto h = QtPrivate::invokeMethodHelper(r, std::forward(arguments)...); return invokeMethodImpl(obj, member, c, h.parameterCount(), h.parameters.data(), - h.typeNames.data()); + h.typeNames.data(), h.metaTypes.data()); } template static @@ -476,7 +486,8 @@ struct Q_CORE_EXPORT QMetaObject newInstance(Args &&... arguments) const { auto h = QtPrivate::invokeMethodHelper(QMetaMethodReturnArgument{}, std::forward(arguments)...); - return newInstanceImpl(this, h.parameterCount(), h.parameters.data(), h.typeNames.data()); + return newInstanceImpl(this, h.parameterCount(), h.parameters.data(), + h.typeNames.data(), h.metaTypes.data()); } enum Call { @@ -538,10 +549,12 @@ struct Q_CORE_EXPORT QMetaObject private: static bool invokeMethodImpl(QObject *object, const char *member, Qt::ConnectionType type, - qsizetype parameterCount, const void *const *parameters, const char *const *names); + qsizetype parameterCount, const void *const *parameters, const char *const *names, + const QtPrivate::QMetaTypeInterface * const *metaTypes); static bool invokeMethodImpl(QObject *object, QtPrivate::QSlotObjectBase *slot, Qt::ConnectionType type, void *ret); static QObject *newInstanceImpl(const QMetaObject *mobj, qsizetype parameterCount, - const void **parameters, const char **typeNames); + const void **parameters, const char **typeNames, + const QtPrivate::QMetaTypeInterface **metaTypes); friend class QTimer; }; diff --git a/tests/auto/corelib/kernel/qmetaobject/forwarddeclared.cpp b/tests/auto/corelib/kernel/qmetaobject/forwarddeclared.cpp index d2477f86f05..8772bc4e613 100644 --- a/tests/auto/corelib/kernel/qmetaobject/forwarddeclared.cpp +++ b/tests/auto/corelib/kernel/qmetaobject/forwarddeclared.cpp @@ -2,7 +2,6 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "forwarddeclared.h" -#include "qeasingcurve.h" struct MyForwardDeclaredType { }; static MyForwardDeclaredType t; @@ -16,18 +15,3 @@ MyForwardDeclaredType *getForwardDeclaredPointer() noexcept { return &t; } - -QT_BEGIN_NAMESPACE - -const QEasingCurve &getEasingCurve() noexcept -{ - return *getEasingCurvePointer(); -} - -QEasingCurve *getEasingCurvePointer() noexcept -{ - static QEasingCurve curve; - return &curve; -} - -QT_END_NAMESPACE diff --git a/tests/auto/corelib/kernel/qmetaobject/forwarddeclared.h b/tests/auto/corelib/kernel/qmetaobject/forwarddeclared.h index 83fdb0f8190..89fb0839c1a 100644 --- a/tests/auto/corelib/kernel/qmetaobject/forwarddeclared.h +++ b/tests/auto/corelib/kernel/qmetaobject/forwarddeclared.h @@ -4,18 +4,9 @@ #ifndef FORWARDDECLARED_H #define FORWARDDECLARED_H -#include - struct MyForwardDeclaredType; // and ONLY forward-declared const MyForwardDeclaredType &getForwardDeclaredType() noexcept; MyForwardDeclaredType *getForwardDeclaredPointer() noexcept; -QT_BEGIN_NAMESPACE -class QEasingCurve; - -const QEasingCurve &getEasingCurve() noexcept; -QEasingCurve *getEasingCurvePointer() noexcept; -QT_END_NAMESPACE - #endif // FORWARDDECLARED_H diff --git a/tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp b/tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp index 26945b727eb..2efecc01cb4 100644 --- a/tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp +++ b/tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp @@ -31,14 +31,6 @@ Q_DECLARE_METATYPE(const QMetaObject *) # define Q_NO_ARG #endif -#ifdef QEASINGCURVE_H -# error "Please make sure qeasingcurve.h is not #include'd here! " \ - "We need QEasingCurve to be only forward-declared." -#endif -QT_BEGIN_NAMESPACE -class QEasingCurve; -QT_END_NAMESPACE - struct MyStruct { int i; @@ -519,7 +511,6 @@ public slots: qint64 sl14(); qlonglong *sl15(qlonglong *); MyForwardDeclaredType *sl16(MyForwardDeclaredType *); - void sl17(const QEasingCurve &curve); void overloadedSlot(); void overloadedSlot(int, int); @@ -636,8 +627,6 @@ MyForwardDeclaredType *QtTestObject::sl16(MyForwardDeclaredType *ptr) slotResult += "null"; return getForwardDeclaredPointer(); } -void QtTestObject::sl17(const QEasingCurve &) -{ slotResult = "sl17"; } void QtTestObject::overloadedSlot() { slotResult = "overloadedSlot"; } @@ -819,11 +808,8 @@ void tst_QMetaObject::invokeMetaMember() QCOMPARE(forwardPtr, getForwardDeclaredPointer()); QCOMPARE(obj.slotResult, QString("sl16:null")); - // forward-declared builtin - obj.slotResult.clear(); - QVERIFY(QMetaObject::invokeMethod(&obj, "sl17", Q_ARG(QEasingCurve, getEasingCurve()))); - QCOMPARE(obj.slotResult, "sl17"); - +#ifndef QT_NO_DATA_RELOCATION // this doesn't work with the new API on Windows +#endif // test overloads QVERIFY(QMetaObject::invokeMethod(&obj, "overloadedSlot" Q_NO_ARG)); QCOMPARE(obj.slotResult, QString("overloadedSlot")); @@ -990,11 +976,6 @@ void tst_QMetaObject::invokeMetaMemberNoMacros() QCOMPARE(forwardPtr, getForwardDeclaredPointer()); QCOMPARE(obj.slotResult, QString("sl16:null")); - // forward-declared builtin - obj.slotResult.clear(); - QVERIFY(QMetaObject::invokeMethod(&obj, "sl17", getEasingCurve())); - QCOMPARE(obj.slotResult, "sl17"); - // test overloads QVERIFY(QMetaObject::invokeMethod(&obj, "overloadedSlot")); QCOMPARE(obj.slotResult, QString("overloadedSlot")); @@ -1131,12 +1112,14 @@ void tst_QMetaObject::invokeQueuedMetaMember() qApp->processEvents(QEventLoop::AllEvents); QCOMPARE(obj.slotResult, QString("sl15")); - // forward-declared builtin + // since Qt 6.5, this works even for pointers to forward-declared types obj.slotResult.clear(); - QVERIFY(QMetaObject::invokeMethod(&obj, "sl17", Qt::QueuedConnection, Q_ARG(QEasingCurve, getEasingCurve()))); + QVERIFY(QMetaObject::invokeMethod(&obj, "sl16", Qt::QueuedConnection, Q_ARG(MyForwardDeclaredType*, getForwardDeclaredPointer()))); qApp->processEvents(QEventLoop::AllEvents); - QCOMPARE(obj.slotResult, "sl17"); + QCOMPARE(obj.slotResult, QString("sl16:notnull")); +#ifndef QT_NO_DATA_RELOCATION // this doesn't work with the new API on Windows +#endif // test overloads QVERIFY(QMetaObject::invokeMethod(&obj, "overloadedSlot", Qt::QueuedConnection Q_NO_ARG)); qApp->processEvents(QEventLoop::AllEvents); @@ -1184,6 +1167,7 @@ void tst_QMetaObject::invokeQueuedMetaMember() QVERIFY(!QMetaObject::invokeMethod(&obj, "testReference", Qt::QueuedConnection, Q_ARG(QString&, refStr))); QCOMPARE(refStr, "whatever"); +#ifdef USE_COMPAT_Q_ARG // this doesn't compile with the new API obj.slotResult.clear(); { const MyForwardDeclaredType &t = getForwardDeclaredType(); @@ -1201,12 +1185,7 @@ void tst_QMetaObject::invokeQueuedMetaMember() Q_ARG(QString, a1), Q_ARG(MyForwardDeclaredType, t))); QVERIFY(obj.slotResult.isEmpty()); } - - obj.slotResult.clear(); - QTest::ignoreMessage(QtWarningMsg, "QMetaMethod::invoke: Unable to handle unregistered datatype 'MyForwardDeclaredType*'"); - QVERIFY(!QMetaObject::invokeMethod(&obj, "sl16", Qt::QueuedConnection, Q_ARG(MyForwardDeclaredType*, getForwardDeclaredPointer()))); - qApp->processEvents(QEventLoop::AllEvents); - QVERIFY(obj.slotResult.isEmpty()); +#endif } // this is a copy-paste-adapt of the above @@ -1241,11 +1220,10 @@ void tst_QMetaObject::invokeQueuedMetaMemberNoMacro() qApp->processEvents(QEventLoop::AllEvents); QCOMPARE(obj.slotResult, QString("sl15")); - // forward-declared builtin obj.slotResult.clear(); - QVERIFY(QMetaObject::invokeMethod(&obj, "sl17", Qt::QueuedConnection, getEasingCurve())); + QVERIFY(QMetaObject::invokeMethod(&obj, "sl16", Qt::QueuedConnection, getForwardDeclaredPointer())); qApp->processEvents(QEventLoop::AllEvents); - QCOMPARE(obj.slotResult, "sl17"); + QCOMPARE(obj.slotResult, QString("sl16:notnull")); // test overloads QVERIFY(QMetaObject::invokeMethod(&obj, "overloadedSlot", Qt::QueuedConnection)); @@ -1297,6 +1275,7 @@ void tst_QMetaObject::invokeQueuedMetaMemberNoMacro() // QVERIFY(!QMetaObject::invokeMethod(&obj, "testReference", Qt::QueuedConnection, Q_ARG(QString&, refStr))); // QCOMPARE(refStr, "whatever"); +#if 0 // this won't even compile any more obj.slotResult.clear(); { const MyForwardDeclaredType &t = getForwardDeclaredType(); @@ -1314,12 +1293,7 @@ void tst_QMetaObject::invokeQueuedMetaMemberNoMacro() a1, t)); QVERIFY(obj.slotResult.isEmpty()); } - - obj.slotResult.clear(); - QTest::ignoreMessage(QtWarningMsg, "QMetaMethod::invoke: Unable to handle unregistered datatype 'MyForwardDeclaredType*'"); - QVERIFY(!QMetaObject::invokeMethod(&obj, "sl16", Qt::QueuedConnection, getForwardDeclaredPointer())); - qApp->processEvents(QEventLoop::AllEvents); - QVERIFY(obj.slotResult.isEmpty()); +#endif } void tst_QMetaObject::invokeQueuedPointer() @@ -1505,11 +1479,8 @@ void tst_QMetaObject::invokeBlockingQueuedMetaMember() QCOMPARE(forwardPtr, getForwardDeclaredPointer()); QCOMPARE(obj.slotResult, QString("sl16:null")); - // forward-declared builtin - obj.slotResult.clear(); - QVERIFY(QMetaObject::invokeMethod(&obj, "sl17", Qt::BlockingQueuedConnection, Q_ARG(QEasingCurve, getEasingCurve()))); - QCOMPARE(obj.slotResult, "sl17"); - +#ifndef QT_NO_DATA_RELOCATION // this doesn't work with the new API on Windows +#endif // test overloads QVERIFY(QMetaObject::invokeMethod(&obj, "overloadedSlot", Qt::BlockingQueuedConnection Q_NO_ARG)); QCOMPARE(obj.slotResult, QString("overloadedSlot")); @@ -1681,11 +1652,6 @@ void tst_QMetaObject::invokeBlockingQueuedMetaMemberNoMacros() QCOMPARE(forwardPtr, getForwardDeclaredPointer()); QCOMPARE(obj.slotResult, QString("sl16:null")); - // forward-declared builtin - obj.slotResult.clear(); - QVERIFY(QMetaObject::invokeMethod(&obj, "sl17", Qt::BlockingQueuedConnection, getEasingCurve())); - QCOMPARE(obj.slotResult, "sl17"); - // test overloads QVERIFY(QMetaObject::invokeMethod(&obj, "overloadedSlot", Qt::BlockingQueuedConnection)); QCOMPARE(obj.slotResult, QString("overloadedSlot")); @@ -1968,6 +1934,12 @@ void tst_QMetaObject::invokeTypedefTypes() QCOMPARE(spy.count(), 1); QCOMPARE(spy.at(0).count(), 1); QCOMPARE(spy.at(0).at(0), QVariant(arg)); + + spy.clear(); + QVERIFY(QMetaObject::invokeMethod(&obj, "sig_custom", arg)); + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.at(0).count(), 1); + QCOMPARE(spy.at(0).at(0), QVariant(arg)); } void tst_QMetaObject::invokeException() @@ -2809,7 +2781,4 @@ void tst_QMetaObject::notifySignalsInParentClass() } QTEST_MAIN(tst_QMetaObject) - -static_assert(!QtPrivate::is_complete::value, - "QEasingCurve must only be forward-declared at this point"); #include "tst_qmetaobject.moc"