summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThiago Macieira <thiago.macieira@intel.com>2022-08-01 11:12:20 -0700
committerThiago Macieira <thiago.macieira@intel.com>2022-08-30 22:29:07 -0300
commitfe92b080658f0d8609e2a2a69e5ec2b51dd7bf9d (patch)
treec2e3db61402091538966b89547dbf680e3948be9
parent191419e98040d7aa7c306d3ec2776d5c143d8c2d (diff)
QMetaObject: add a new, variadic invoke/invokeMethod/newInstance
[ChangeLog][QtCore][Meta Objects] The QMetaObject::invokeMethod() taking a method name by string, QMetaObject::newInstance(), and QMetaMethod::invoke() now support more than 10 arguments. [ChangeLog][QtCore][Meta Objects] The use of the Q_ARG and Q_RETURN_ARG macros is now optional with QMetaObject::invokeMethod(), QMetaObject::newInstance(), and QMetaMethod::invoke(): the type name will be obtained from the C++ type (the same as QMetaType). The function qReturnArg() can be used in place of the Q_RETURN_ARG macro. The macros are still useful in rare conditions where the type was typedef'ed from its original name. Change-Id: I36b24183fbd041179f2ffffd17022a2b48c7639b Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
-rw-r--r--src/corelib/kernel/qmetaobject.cpp98
-rw-r--r--src/corelib/kernel/qmetaobject.h51
-rw-r--r--src/corelib/kernel/qobjectdefs.h146
-rw-r--r--tests/auto/corelib/global/qlogging/tst_qlogging.cpp4
-rw-r--r--tests/auto/corelib/kernel/qmetaobject/CMakeLists.txt8
-rw-r--r--tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp643
6 files changed, 890 insertions, 60 deletions
diff --git a/src/corelib/kernel/qmetaobject.cpp b/src/corelib/kernel/qmetaobject.cpp
index d007d05050..7142a17050 100644
--- a/src/corelib/kernel/qmetaobject.cpp
+++ b/src/corelib/kernel/qmetaobject.cpp
@@ -223,22 +223,13 @@ QObject *QMetaObject::newInstance(QGenericArgument val0,
QGenericArgument val8,
QGenericArgument val9) const
{
- if (!inherits(&QObject::staticMetaObject))
- {
- qWarning("QMetaObject::newInstance: type %s does not inherit QObject", className());
- return nullptr;
- }
-
- QObject *returnValue = nullptr;
- QMetaType returnValueMetaType = QMetaType::fromType<decltype(returnValue)>();
-
const char *typeNames[] = {
- returnValueMetaType.name(),
+ nullptr,
val0.name(), val1.name(), val2.name(), val3.name(), val4.name(),
val5.name(), val6.name(), val7.name(), val8.name(), val9.name()
};
const void *parameters[] = {
- &returnValue,
+ nullptr,
val0.data(), val1.data(), val2.data(), val3.data(), val4.data(),
val5.data(), val6.data(), val7.data(), val8.data(), val9.data()
};
@@ -250,10 +241,34 @@ QObject *QMetaObject::newInstance(QGenericArgument val0,
break;
}
+ return newInstanceImpl(this, paramCount, parameters, typeNames);
+}
+
+QObject *QMetaObject::newInstanceImpl(const QMetaObject *mobj, qsizetype paramCount,
+ const void **parameters, const char **typeNames)
+{
+ if (!mobj->inherits(&QObject::staticMetaObject)) {
+ qWarning("QMetaObject::newInstance: type %s does not inherit QObject", mobj->className());
+ return nullptr;
+ }
+
+QT_WARNING_PUSH
+#if Q_CC_GNU >= 1200
+QT_WARNING_DISABLE_GCC("-Wdangling-pointer")
+#endif
+
+ // set the return type
+ QObject *returnValue = nullptr;
+ QMetaType returnValueMetaType = QMetaType::fromType<decltype(returnValue)>();
+ parameters[0] = &returnValue;
+ typeNames[0] = returnValueMetaType.name();
+
+QT_WARNING_POP
+
// find the constructor
- auto priv = QMetaObjectPrivate::get(this);
+ auto priv = QMetaObjectPrivate::get(mobj);
for (int i = 0; i < priv->constructorCount; ++i) {
- QMetaMethod m = QMetaMethod::fromRelativeConstructorIndex(this, i);
+ QMetaMethod m = QMetaMethod::fromRelativeConstructorIndex(mobj, i);
if (m.parameterCount() != (paramCount - 1))
continue;
@@ -1457,6 +1472,19 @@ bool QMetaObject::invokeMethod(QObject *obj,
if (qstrlen(typeNames[paramCount]) <= 0)
break;
}
+ return invokeMethodImpl(obj, member, type, paramCount, parameters, typeNames);
+}
+
+bool QMetaObject::invokeMethodImpl(QObject *obj, const char *member, Qt::ConnectionType type,
+ qsizetype paramCount, const void * const *parameters,
+ const char * const *typeNames)
+{
+ if (!obj)
+ return false;
+
+ Q_ASSERT(paramCount >= 1); // includes the return type
+ Q_ASSERT(parameters);
+ Q_ASSERT(typeNames);
// find the method
QLatin1StringView name(member);
@@ -2382,9 +2410,17 @@ bool QMetaMethod::invoke(QObject *object,
if (qstrlen(typeNames[paramCount]) <= 0)
break;
}
+ return invokeImpl(*this, object, connectionType, paramCount, param, typeNames);
+}
+bool QMetaMethod::invokeImpl(QMetaMethod self, void *target, Qt::ConnectionType connectionType,
+ qsizetype paramCount, const void *const *parameters,
+ const char *const *typeNames)
+{
+ if (!target || !self.mobj)
+ return false;
QMetaMethodPrivate::InvokeFailReason r =
- QMetaMethodPrivate::invokeImpl(*this, object, connectionType, paramCount, param, typeNames);
+ QMetaMethodPrivate::invokeImpl(self, target, connectionType, paramCount, parameters, typeNames);
if (Q_LIKELY(r == QMetaMethodPrivate::InvokeFailReason::None))
return true;
@@ -2392,11 +2428,11 @@ bool QMetaMethod::invoke(QObject *object,
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], mobj->className(), methodSignature().constData());
+ n, typeNames[n + 1], self.mobj->className(), self.methodSignature().constData());
}
if (r == QMetaMethodPrivate::InvokeFailReason::TooFewArguments) {
qWarning("QMetaMethod::invoke: too few arguments (%d) in call to %s::%s",
- int(paramCount), mobj->className(), methodSignature().constData());
+ int(paramCount), self.mobj->className(), self.methodSignature().constData());
}
return false;
}
@@ -2412,7 +2448,8 @@ auto QMetaMethodInvoker::invokeImpl(QMetaMethod self, void *target,
Q_ASSERT(priv->mobj);
Q_ASSERT(self.methodType() == Constructor || object);
- Q_ASSERT(self.methodType() == Constructor || priv->mobj->cast(object));
+ Q_ASSERT(self.methodType() == Constructor || connectionType == Qt::ConnectionType(-1) ||
+ priv->mobj->cast(object));
Q_ASSERT(paramCount >= 1); // includes the return type
Q_ASSERT(parameters);
Q_ASSERT(typeNames);
@@ -2477,18 +2514,23 @@ auto QMetaMethodInvoker::invokeImpl(QMetaMethod self, void *target,
}
}
- Qt::HANDLE currentThreadId = QThread::currentThreadId();
- QThread *objectThread = object->thread();
- bool receiverInSameThread = false;
- if (objectThread)
- receiverInSameThread = currentThreadId == QThreadData::get2(objectThread)->threadId.loadRelaxed();
+ Qt::HANDLE currentThreadId = nullptr;
+ QThread *objectThread = nullptr;
+ auto receiverInSameThread = [&]() {
+ if (!currentThreadId) {
+ currentThreadId = QThread::currentThreadId();
+ objectThread = object->thread();
+ }
+ if (objectThread)
+ return currentThreadId == QThreadData::get2(objectThread)->threadId.loadRelaxed();
+ return false;
+ };
// check connection type
- if (connectionType == Qt::AutoConnection) {
- connectionType = receiverInSameThread
- ? Qt::DirectConnection
- : Qt::QueuedConnection;
- }
+ if (connectionType == Qt::AutoConnection)
+ connectionType = receiverInSameThread() ? Qt::DirectConnection : Qt::QueuedConnection;
+ else if (connectionType == Qt::ConnectionType(-1))
+ connectionType = Qt::DirectConnection;
#if !QT_CONFIG(thread)
if (connectionType == Qt::BlockingQueuedConnection) {
@@ -2536,7 +2578,7 @@ auto QMetaMethodInvoker::invokeImpl(QMetaMethod self, void *target,
QCoreApplication::postEvent(object, event.release());
} else { // blocking queued connection
#if QT_CONFIG(thread)
- if (receiverInSameThread) {
+ if (receiverInSameThread()) {
qWarning("QMetaMethod::invoke: Dead lock detected in BlockingQueuedConnection: "
"Receiver is %s(%p)", priv->mobj->className(), object);
return InvokeFailReason::DeadLockDetected;
diff --git a/src/corelib/kernel/qmetaobject.h b/src/corelib/kernel/qmetaobject.h
index 0740acef60..735f26caa2 100644
--- a/src/corelib/kernel/qmetaobject.h
+++ b/src/corelib/kernel/qmetaobject.h
@@ -45,6 +45,7 @@ public:
inline const QMetaObject *enclosingMetaObject() const { return mobj; }
+#if QT_VERSION <= QT_VERSION_CHECK(7, 0, 0)
bool invoke(QObject *object,
Qt::ConnectionType connectionType,
QGenericReturnArgument returnValue,
@@ -76,7 +77,7 @@ public:
}
inline bool invoke(QObject *object,
Qt::ConnectionType connectionType,
- QGenericArgument val0 = QGenericArgument(nullptr),
+ QGenericArgument val0,
QGenericArgument val1 = QGenericArgument(),
QGenericArgument val2 = QGenericArgument(),
QGenericArgument val3 = QGenericArgument(),
@@ -91,7 +92,7 @@ public:
val0, val1, val2, val3, val4, val5, val6, val7, val8, val9);
}
inline bool invoke(QObject *object,
- QGenericArgument val0 = QGenericArgument(nullptr),
+ QGenericArgument val0,
QGenericArgument val1 = QGenericArgument(),
QGenericArgument val2 = QGenericArgument(),
QGenericArgument val3 = QGenericArgument(),
@@ -118,7 +119,7 @@ public:
QGenericArgument val8 = QGenericArgument(),
QGenericArgument val9 = QGenericArgument()) const;
inline bool invokeOnGadget(void *gadget,
- QGenericArgument val0 = QGenericArgument(nullptr),
+ QGenericArgument val0,
QGenericArgument val1 = QGenericArgument(),
QGenericArgument val2 = QGenericArgument(),
QGenericArgument val3 = QGenericArgument(),
@@ -132,6 +133,48 @@ public:
return invokeOnGadget(gadget, QGenericReturnArgument(),
val0, val1, val2, val3, val4, val5, val6, val7, val8, val9);
}
+#endif
+
+ template <typename... Args> QtPrivate::Invoke::IfNotOldStyleArgs<bool, Args...>
+ invoke(QObject *obj, Qt::ConnectionType c, QMetaMethodReturnArgument r,
+ Args &&... arguments) const
+ {
+ auto h = QtPrivate::invokeMethodHelper(r, std::forward<Args>(arguments)...);
+ return invokeImpl(*this, obj, c, h.parameterCount(), h.parameters.data(),
+ h.typeNames.data());
+ }
+
+ template <typename... Args> QtPrivate::Invoke::IfNotOldStyleArgs<bool, Args...>
+ invoke(QObject *obj, Qt::ConnectionType c, Args &&... arguments) const
+ {
+ return invoke(obj, c, QMetaMethodReturnArgument{}, std::forward<Args>(arguments)...);
+ }
+
+ template <typename... Args> QtPrivate::Invoke::IfNotOldStyleArgs<bool, Args...>
+ invoke(QObject *obj, QMetaMethodReturnArgument r, Args &&... arguments) const
+ {
+ return invoke(obj, Qt::AutoConnection, r, std::forward<Args>(arguments)...);
+ }
+
+ template <typename... Args> QtPrivate::Invoke::IfNotOldStyleArgs<bool, Args...>
+ invoke(QObject *obj, Args &&... arguments) const
+ {
+ return invoke(obj, Qt::AutoConnection, std::forward<Args>(arguments)...);
+ }
+
+ template <typename... Args> QtPrivate::Invoke::IfNotOldStyleArgs<bool, Args...>
+ invokeOnGadget(void *gadget, QMetaMethodReturnArgument r, Args &&... arguments) const
+ {
+ auto h = QtPrivate::invokeMethodHelper(r, std::forward<Args>(arguments)...);
+ return invokeImpl(*this, gadget, Qt::ConnectionType(-1), h.parameterCount(),
+ h.parameters.data(), h.typeNames.data());
+ }
+
+ template <typename... Args> QtPrivate::Invoke::IfNotOldStyleArgs<bool, Args...>
+ invokeOnGadget(void *gadget, Args &&... arguments) const
+ {
+ return invokeOnGadget(gadget, QMetaMethodReturnArgument{}, std::forward<Args>(arguments)...);
+ }
inline bool isValid() const { return mobj != nullptr; }
@@ -146,6 +189,8 @@ public:
}
private:
+ static bool invokeImpl(QMetaMethod self, void *target, Qt::ConnectionType, qsizetype paramCount,
+ const void *const *parameters, const char *const *typeNames);
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/qobjectdefs.h b/src/corelib/kernel/qobjectdefs.h
index 8309e43d89..7d324e4b8e 100644
--- a/src/corelib/kernel/qobjectdefs.h
+++ b/src/corelib/kernel/qobjectdefs.h
@@ -59,8 +59,8 @@ Q_CORE_EXPORT const char *qFlagLocation(const char *method);
# endif
#endif // QT_NO_META_MACROS
-#define Q_ARG(type, data) QArgument<type >(#type, data)
-#define Q_RETURN_ARG(type, data) QReturnArgument<type >(#type, data)
+#define Q_ARG(Type, data) QtPrivate::Invoke::argument<Type>(QT_STRINGIFY(Type), data)
+#define Q_RETURN_ARG(Type, data) QtPrivate::Invoke::returnArgument<Type>(QT_STRINGIFY(Type), data)
class QObject;
class QMetaMethod;
@@ -70,6 +70,7 @@ class QMetaClassInfo;
namespace QtPrivate {
class QMetaTypeInterface;
+template<typename T> constexpr auto typenameHelper();
}
struct QMethodRawArguments
@@ -77,6 +78,7 @@ struct QMethodRawArguments
void **arguments;
};
+#if QT_VERSION <= QT_VERSION_CHECK(7, 0, 0)
class Q_CORE_EXPORT QGenericArgument
{
public:
@@ -124,6 +126,91 @@ public:
: QGenericReturnArgument(aName, static_cast<void *>(&aData))
{}
};
+#endif
+
+struct QMetaMethodArgument
+{
+ const char *name;
+ const void *data;
+};
+
+struct QMetaMethodReturnArgument
+{
+ const char *name;
+ void *data;
+};
+
+namespace QtPrivate {
+namespace Invoke {
+#if QT_VERSION <= QT_VERSION_CHECK(7, 0, 0)
+template <typename... Args> struct AreOldStyleArgs :
+ std::disjunction<std::is_base_of<QGenericArgument, Args>...>
+{};
+template <typename T, typename... Args> using IfNotOldStyleArgs =
+ std::enable_if_t<!AreOldStyleArgs<Args...>::value, T>;
+#else
+template <typename T, typename... Args> using IfNotOldStyleArgs = T;
+#endif
+
+template <typename T> inline QMetaMethodArgument argument(const char *name, const T &t)
+{
+ return { name, std::addressof(t) };
+}
+
+template <typename T> inline QMetaMethodReturnArgument returnArgument(const char *name, T &t)
+{
+ return { name, std::addressof(t) };
+}
+
+template <typename T> inline const char *typenameHelper(const T &)
+{
+ // duplicated from the QMetaTypeInterface, FIXME
+ static constexpr auto name = QtPrivate::typenameHelper<T>();
+ return name.data();
+}
+template <typename T> inline const void *dataHelper(const T &t)
+{
+ return std::addressof(t);
+}
+
+inline const char *typenameHelper(QMetaMethodArgument a)
+{ return a.name; }
+inline const void *dataHelper(QMetaMethodArgument a)
+{ return a.data; }
+
+inline const char *typenameHelper(const char *) = delete;
+template <typename T> inline const void *dataHelper(const char *) = delete;
+inline const char *typenameHelper(const char16_t *) = delete;
+template <typename T> inline const void *dataHelper(const char16_t *) = delete;
+
+} // namespace QtPrivate::Invoke
+
+template <typename... Args> inline auto invokeMethodHelper(QMetaMethodReturnArgument r, Args &&... arguments)
+{
+ std::array params = { const_cast<const void *>(r.data), Invoke::dataHelper(arguments)... };
+ std::array names = { r.name, Invoke::typenameHelper(arguments)... };
+ static_assert(params.size() == names.size());
+
+ struct R {
+ decltype(params) parameters;
+ decltype(names) typeNames;
+ constexpr qsizetype parameterCount() const { return qsizetype(parameters.size()); }
+ };
+ return R { params, names };
+}
+} // namespace QtPrivate
+
+template <typename T> inline QMetaMethodReturnArgument qReturnArg(T &&) = delete;
+template <typename T> inline QMetaMethodReturnArgument qReturnArg(T &data)
+{
+ if constexpr (std::is_same_v<T, const char *>) {
+ // 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);
+ }
+}
struct Q_CORE_EXPORT QMetaObject
{
@@ -191,6 +278,7 @@ struct Q_CORE_EXPORT QMetaObject
static void activate(QObject *sender, const QMetaObject *, int local_signal_index, void **argv);
static void activate(QObject *sender, int signal_offset, int local_signal_index, void **argv);
+#if QT_VERSION <= QT_VERSION_CHECK(7, 0, 0)
static bool invokeMethod(QObject *obj, const char *member,
Qt::ConnectionType,
QGenericReturnArgument ret,
@@ -224,7 +312,7 @@ struct Q_CORE_EXPORT QMetaObject
static inline bool invokeMethod(QObject *obj, const char *member,
Qt::ConnectionType type,
- QGenericArgument val0 = QGenericArgument(nullptr),
+ QGenericArgument val0,
QGenericArgument val1 = QGenericArgument(),
QGenericArgument val2 = QGenericArgument(),
QGenericArgument val3 = QGenericArgument(),
@@ -240,7 +328,7 @@ struct Q_CORE_EXPORT QMetaObject
}
static inline bool invokeMethod(QObject *obj, const char *member,
- QGenericArgument val0 = QGenericArgument(nullptr),
+ QGenericArgument val0,
QGenericArgument val1 = QGenericArgument(),
QGenericArgument val2 = QGenericArgument(),
QGenericArgument val3 = QGenericArgument(),
@@ -254,6 +342,41 @@ struct Q_CORE_EXPORT QMetaObject
return invokeMethod(obj, member, Qt::AutoConnection, QGenericReturnArgument(), val0,
val1, val2, val3, val4, val5, val6, val7, val8, val9);
}
+#endif // Qt < 7.0
+
+ template <typename... Args> static
+ QtPrivate::Invoke::IfNotOldStyleArgs<bool, Args...>
+ invokeMethod(QObject *obj, const char *member, Qt::ConnectionType c,
+ QMetaMethodReturnArgument r, Args &&... arguments)
+ {
+ auto h = QtPrivate::invokeMethodHelper(r, std::forward<Args>(arguments)...);
+ return invokeMethodImpl(obj, member, c, h.parameterCount(), h.parameters.data(),
+ h.typeNames.data());
+ }
+
+ template <typename... Args> static
+ QtPrivate::Invoke::IfNotOldStyleArgs<bool, Args...>
+ invokeMethod(QObject *obj, const char *member, Qt::ConnectionType c, Args &&... arguments)
+ {
+ QMetaMethodReturnArgument r = {};
+ return invokeMethod(obj, member, c, r, std::forward<Args>(arguments)...);
+ }
+
+ template <typename... Args> static
+ QtPrivate::Invoke::IfNotOldStyleArgs<bool, Args...>
+ invokeMethod(QObject *obj, const char *member, QMetaMethodReturnArgument r,
+ Args &&... arguments)
+ {
+ return invokeMethod(obj, member, Qt::AutoConnection, r, std::forward<Args>(arguments)...);
+ }
+
+ template <typename... Args> static
+ QtPrivate::Invoke::IfNotOldStyleArgs<bool, Args...>
+ invokeMethod(QObject *obj, const char *member, Args &&... arguments)
+ {
+ QMetaMethodReturnArgument r = {};
+ return invokeMethod(obj, member, Qt::AutoConnection, r, std::forward<Args>(arguments)...);
+ }
#ifdef Q_CLANG_QDOC
template<typename Functor, typename FunctorReturnType>
@@ -336,7 +459,8 @@ struct Q_CORE_EXPORT QMetaObject
#endif
- QObject *newInstance(QGenericArgument val0 = QGenericArgument(nullptr),
+#if QT_VERSION <= QT_VERSION_CHECK(7, 0, 0)
+ QObject *newInstance(QGenericArgument val0,
QGenericArgument val1 = QGenericArgument(),
QGenericArgument val2 = QGenericArgument(),
QGenericArgument val3 = QGenericArgument(),
@@ -346,6 +470,14 @@ struct Q_CORE_EXPORT QMetaObject
QGenericArgument val7 = QGenericArgument(),
QGenericArgument val8 = QGenericArgument(),
QGenericArgument val9 = QGenericArgument()) const;
+#endif
+
+ template <typename... Args> QtPrivate::Invoke::IfNotOldStyleArgs<QObject *, Args...>
+ newInstance(Args &&... arguments) const
+ {
+ auto h = QtPrivate::invokeMethodHelper(QMetaMethodReturnArgument{}, std::forward<Args>(arguments)...);
+ return newInstanceImpl(this, h.parameterCount(), h.parameters.data(), h.typeNames.data());
+ }
enum Call {
InvokeMetaMethod,
@@ -405,7 +537,11 @@ struct Q_CORE_EXPORT QMetaObject
} d;
private:
+ static bool invokeMethodImpl(QObject *object, const char *member, Qt::ConnectionType type,
+ qsizetype parameterCount, const void *const *parameters, const char *const *names);
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);
friend class QTimer;
};
diff --git a/tests/auto/corelib/global/qlogging/tst_qlogging.cpp b/tests/auto/corelib/global/qlogging/tst_qlogging.cpp
index df0cb5ae77..be27ab65b9 100644
--- a/tests/auto/corelib/global/qlogging/tst_qlogging.cpp
+++ b/tests/auto/corelib/global/qlogging/tst_qlogging.cpp
@@ -732,12 +732,12 @@ void tst_qmessagehandler::qMessagePattern_data()
// Q_OBJECT macro hence the ?helper? frame
"[MyClass::myFunction|MyClass::mySlot1|?" BACKTRACE_HELPER_NAME "?|",
- // QMetaObject::invokeMethod calls internal function
+ // QMetaObject::invokeMethodImpl calls internal function
// (QMetaMethodPrivate::invokeImpl, at the tims of this writing), which
// will usually show only as ?libQt6Core.so? or equivalent, so we skip
// end of backtrace, actual message
- "|" QT_NAMESPACE_STR "QMetaObject::invokeMethod] from_a_function 34"
+ "|" QT_NAMESPACE_STR "QMetaObject::invokeMethodImpl] from_a_function 34"
};
QTest::newRow("backtrace") << "[%{backtrace}] %{message}" << true << expectedBacktrace;
#endif
diff --git a/tests/auto/corelib/kernel/qmetaobject/CMakeLists.txt b/tests/auto/corelib/kernel/qmetaobject/CMakeLists.txt
index 30368e5c52..a4361d4779 100644
--- a/tests/auto/corelib/kernel/qmetaobject/CMakeLists.txt
+++ b/tests/auto/corelib/kernel/qmetaobject/CMakeLists.txt
@@ -20,3 +20,11 @@ qt_internal_add_test(tst_qmetaobject
Qt::CorePrivate
)
+qt_internal_add_test(tst_qmetaobject_compat
+ SOURCES
+ ${tst_qmetaobject_SOURCES}
+ DEFINES
+ USE_COMPAT_Q_ARG=1
+ PUBLIC_LIBRARIES
+ Qt::CorePrivate
+)
diff --git a/tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp b/tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp
index 005b58fcb8..26945b727e 100644
--- a/tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp
+++ b/tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp
@@ -14,6 +14,23 @@ Q_DECLARE_METATYPE(const QMetaObject *)
#include "forwarddeclared.h"
+#ifdef USE_COMPAT_Q_ARG
+# define tst_QMetaObject tst_QMetaObject_CompatQArg
+# if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0)
+# error "This is a Qt 6 compatibility check test"
+# endif
+
+# undef Q_ARG
+# undef Q_RETURN_ARG
+# define Q_ARG(type, data) QArgument<type >(#type, data)
+# define Q_RETURN_ARG(type, data) QReturnArgument<type >(#type, data)
+# define Q_NO_ARG , QGenericArgument()
+#else
+// This macro is used to force the overload selection to the compat
+// (non-variadic) code above
+# 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."
@@ -279,13 +296,17 @@ public:
private slots:
void connectSlotsByName();
void invokeMetaMember();
+ void invokeMetaMemberNoMacros();
void invokePointer();
void invokeQueuedMetaMember();
+ void invokeQueuedMetaMemberNoMacro();
void invokeQueuedPointer();
void invokeBlockingQueuedMetaMember();
+ void invokeBlockingQueuedMetaMemberNoMacros();
void invokeBlockingQueuedPointer();
void invokeCustomTypes();
void invokeMetaConstructor();
+ void invokeMetaConstructorNoMacro();
void invokeTypedefTypes();
void invokeException();
void invokeQueuedAutoRegister();
@@ -307,6 +328,7 @@ private slots:
void classInfo();
void metaMethod();
+ void metaMethodNoMacro();
void indexOfMethod_data();
void indexOfMethod();
@@ -651,6 +673,7 @@ void QtTestObject::staticFunction0()
qint64 QtTestObject::staticFunction1()
{ staticResult = "staticFunction1"; return Q_INT64_C(123456789)*123456789; }
+// this test is duplicated below
void tst_QMetaObject::invokeMetaMember()
{
QtTestObject obj;
@@ -661,17 +684,17 @@ void tst_QMetaObject::invokeMetaMember()
// Test nullptr
char *nullCharArray = nullptr;
const char *nullConstCharArray = nullptr;
- QVERIFY(!QMetaObject::invokeMethod(nullptr, nullCharArray));
- QVERIFY(!QMetaObject::invokeMethod(nullptr, nullConstCharArray));
- QVERIFY(!QMetaObject::invokeMethod(nullptr, "sl0"));
- QVERIFY(!QMetaObject::invokeMethod(&obj, nullCharArray));
- QVERIFY(!QMetaObject::invokeMethod(&obj, nullConstCharArray));
- QVERIFY(!QMetaObject::invokeMethod(&obj, nullCharArray, Qt::AutoConnection));
- QVERIFY(!QMetaObject::invokeMethod(&obj, nullConstCharArray, Qt::AutoConnection));
+ QVERIFY(!QMetaObject::invokeMethod(nullptr, nullCharArray Q_NO_ARG));
+ QVERIFY(!QMetaObject::invokeMethod(nullptr, nullConstCharArray Q_NO_ARG));
+ QVERIFY(!QMetaObject::invokeMethod(nullptr, "sl0" Q_NO_ARG));
+ QVERIFY(!QMetaObject::invokeMethod(&obj, nullCharArray Q_NO_ARG));
+ QVERIFY(!QMetaObject::invokeMethod(&obj, nullConstCharArray Q_NO_ARG));
+ QVERIFY(!QMetaObject::invokeMethod(&obj, nullCharArray, Qt::AutoConnection Q_NO_ARG));
+ QVERIFY(!QMetaObject::invokeMethod(&obj, nullConstCharArray, Qt::AutoConnection Q_NO_ARG));
QVERIFY(!QMetaObject::invokeMethod(&obj, nullCharArray, Qt::AutoConnection, QGenericReturnArgument()));
QVERIFY(!QMetaObject::invokeMethod(&obj, nullConstCharArray, Qt::AutoConnection, QGenericReturnArgument()));
- QVERIFY(QMetaObject::invokeMethod(&obj, "sl0"));
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sl0" Q_NO_ARG));
QCOMPARE(obj.slotResult, QString("sl0"));
QVERIFY(QMetaObject::invokeMethod(&obj, "sl1", Q_ARG(QString, t1)));
@@ -710,17 +733,19 @@ void tst_QMetaObject::invokeMetaMember()
Q_ARG(QString, t7), Q_ARG(QString, t8), Q_ARG(QString, t9)));
QCOMPARE(obj.slotResult, QString("sl9:123456789"));
- QVERIFY(QMetaObject::invokeMethod(&obj, "sl11"));
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sl11" Q_NO_ARG));
QCOMPARE(obj.slotResult, QString("sl11"));
- QVERIFY(QMetaObject::invokeMethod(&obj, "testSender"));
+ QVERIFY(QMetaObject::invokeMethod(&obj, "testSender" Q_NO_ARG));
QCOMPARE(obj.slotResult, QString("0x0"));
QString refStr("whatever");
+#ifdef USE_COMPAT_Q_ARG
QVERIFY(QMetaObject::invokeMethod(&obj, "testReference", QGenericArgument("QString&", &refStr)));
QCOMPARE(obj.slotResult, QString("testReference:whatever"));
QCOMPARE(refStr, QString("gotcha"));
obj.slotResult.clear();
+#endif
refStr = "whatever";
QVERIFY(QMetaObject::invokeMethod(&obj, "testReference", Q_ARG(QString&, refStr)));
QCOMPARE(obj.slotResult, QString("testReference:whatever"));
@@ -800,7 +825,7 @@ void tst_QMetaObject::invokeMetaMember()
QCOMPARE(obj.slotResult, "sl17");
// test overloads
- QVERIFY(QMetaObject::invokeMethod(&obj, "overloadedSlot"));
+ QVERIFY(QMetaObject::invokeMethod(&obj, "overloadedSlot" Q_NO_ARG));
QCOMPARE(obj.slotResult, QString("overloadedSlot"));
QVERIFY(QMetaObject::invokeMethod(&obj, "overloadedSlot", Q_ARG(int, 1)));
QCOMPARE(obj.slotResult, QString("overloadedSlot:1"));
@@ -808,7 +833,7 @@ void tst_QMetaObject::invokeMetaMember()
QCOMPARE(obj.slotResult, QString("overloadedSlot:1,42"));
//test signals
- QVERIFY(QMetaObject::invokeMethod(&obj, "sig0"));
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sig0" Q_NO_ARG));
QCOMPARE(obj.slotResult, QString("sl0"));
QVERIFY(QMetaObject::invokeMethod(&obj, "sig1", Q_ARG(QString, "baba")));
@@ -838,6 +863,177 @@ void tst_QMetaObject::invokeMetaMember()
QCOMPARE(obj.slotResult, QString("sl1:hehe"));
}
+// this is a copy-paste-adapt of the above
+void tst_QMetaObject::invokeMetaMemberNoMacros()
+{
+ QtTestObject obj;
+
+ QString t1("1"); QString t2("2"); QString t3("3"); QString t4("4"); QString t5("5");
+ QString t6("6"); QString t7("7"); QString t8("8"); QString t9("9"); QString t10("X");
+
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sl0"));
+ QCOMPARE(obj.slotResult, QString("sl0"));
+
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sl1", t1));
+ QCOMPARE(obj.slotResult, QString("sl1:1"));
+
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sl2", qAsConst(t1), t2));
+ QCOMPARE(obj.slotResult, QString("sl2:12"));
+
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sl3", t1, t2, t3));
+ QCOMPARE(obj.slotResult, QString("sl3:123"));
+
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sl4", t1, t2, t3,
+ t4));
+ QCOMPARE(obj.slotResult, QString("sl4:1234"));
+
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sl5", t1, t2, t3,
+ t4, QStringLiteral("5")));
+ QCOMPARE(obj.slotResult, QString("sl5:12345"));
+
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sl6", t1, t2, t3,
+ t4, t5, t6));
+ QCOMPARE(obj.slotResult, QString("sl6:123456"));
+
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sl7", t1, t2, t3,
+ t4, t5, t6,
+ t7));
+ QCOMPARE(obj.slotResult, QString("sl7:1234567"));
+
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sl8", t1, t2, t3,
+ t4, t5, t6,
+ t7, t8));
+ QCOMPARE(obj.slotResult, QString("sl8:12345678"));
+
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sl9", t1, t2, t3,
+ t4, t5, t6,
+ t7, t8, t9));
+ QCOMPARE(obj.slotResult, QString("sl9:123456789"));
+
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sl11"));
+ QCOMPARE(obj.slotResult, QString("sl11"));
+
+ QVERIFY(QMetaObject::invokeMethod(&obj, "testSender"));
+ QCOMPARE(obj.slotResult, QString("0x0"));
+
+ // this is not working for now
+// QString refStr("whatever");
+// QVERIFY(QMetaObject::invokeMethod(&obj, "testReference", refStr));
+// QCOMPARE(obj.slotResult, QString("testReference:whatever"));
+// QCOMPARE(refStr, QString("gotcha"));
+
+ qint64 ll1 = -1;
+ quint64 ll2 = 0;
+ QVERIFY(QMetaObject::invokeMethod(&obj,
+ "testLongLong",
+ ll1,
+ ll2));
+ QCOMPARE(obj.slotResult, QString("testLongLong:-1,0"));
+
+ QString exp;
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sl1", qReturnArg(exp), QStringLiteral("bubu")));
+ QCOMPARE(exp, QString("yessir"));
+ QCOMPARE(obj.slotResult, QString("sl1:bubu"));
+
+ QObject *ptr = nullptr;
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sl11", qReturnArg(ptr)));
+ QCOMPARE(ptr, (QObject *)&obj);
+ QCOMPARE(obj.slotResult, QString("sl11"));
+ // try again with a space:
+ ptr = nullptr;
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sl11", qReturnArg(ptr)));
+ QCOMPARE(ptr, (QObject *)&obj);
+ QCOMPARE(obj.slotResult, QString("sl11"));
+
+ const char *ptr2 = nullptr;
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sl12", qReturnArg(ptr2)));
+ QVERIFY(ptr2 != nullptr);
+ QCOMPARE(obj.slotResult, QString("sl12"));
+ // try again with a space:
+ ptr2 = nullptr;
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sl12", qReturnArg(ptr2)));
+ QVERIFY(ptr2 != nullptr);
+ QCOMPARE(obj.slotResult, QString("sl12"));
+
+ // test w/ template args
+ QList<QString> returnValue, argument;
+ argument << QString("one") << QString("two") << QString("three");
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sl13",
+ qReturnArg(returnValue),
+ argument));
+ QCOMPARE(returnValue, argument);
+ QCOMPARE(obj.slotResult, QString("sl13"));
+
+ // return qint64
+ qint64 return64;
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sl14",
+ qReturnArg(return64)));
+ QCOMPARE(return64, Q_INT64_C(123456789)*123456789);
+ QCOMPARE(obj.slotResult, QString("sl14"));
+
+ // pointers
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sl15", &return64));
+ QCOMPARE(obj.slotResult, QString("sl15"));
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sl16", getForwardDeclaredPointer()));
+ QCOMPARE(obj.slotResult, QString("sl16:notnull"));
+
+ obj.slotResult.clear();
+ qint64 *return64Ptr;
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sl15", qReturnArg(return64Ptr), &return64));
+ QCOMPARE(return64Ptr, &return64);
+ QCOMPARE(obj.slotResult, QString("sl15"));
+
+ obj.slotResult.clear();
+ MyForwardDeclaredType *forwardPtr = nullptr;
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sl16", qReturnArg(forwardPtr),
+ forwardPtr));
+ 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"));
+ QVERIFY(QMetaObject::invokeMethod(&obj, "overloadedSlot", 1));
+ QCOMPARE(obj.slotResult, QString("overloadedSlot:1"));
+ QVERIFY(QMetaObject::invokeMethod(&obj, "overloadedSlot", 1, 42));
+ QCOMPARE(obj.slotResult, QString("overloadedSlot:1,42"));
+
+ //test signals
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sig0"));
+ QCOMPARE(obj.slotResult, QString("sl0"));
+
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sig1", QStringLiteral("baba")));
+ QCOMPARE(obj.slotResult, QString("sl1:baba"));
+
+ exp.clear();
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sig1", qReturnArg(exp), QStringLiteral("hehe")));
+ QCOMPARE(exp, QString("yessir"));
+ QCOMPARE(obj.slotResult, QString("sl1:hehe"));
+
+ QTest::ignoreMessage(QtWarningMsg, "QMetaObject::invokeMethod: No such method QtTestObject::doesNotExist()");
+ QVERIFY(!QMetaObject::invokeMethod(&obj, "doesNotExist"));
+ QTest::ignoreMessage(QtWarningMsg, "QMetaObject::invokeMethod: No such method QtTestObject::sl1(QString)(QString)");
+ QVERIFY(!QMetaObject::invokeMethod(&obj, "sl1(QString)", QStringLiteral("arg")));
+ QTest::ignoreMessage(QtWarningMsg, "QMetaObject::invokeMethod: No such method QtTestObject::sl3(QString)\n"
+ "Candidates are:\n sl3(QString,QString,QString)");
+ QVERIFY(!QMetaObject::invokeMethod(&obj, "sl3", QStringLiteral("arg")));
+ QTest::ignoreMessage(QtWarningMsg, "QMetaObject::invokeMethod: No such method QtTestObject::sl1(QString,QString,QString)\n"
+ "Candidates are:\n sl1(QString)");
+ QVERIFY(!QMetaObject::invokeMethod(&obj, "sl1", QStringLiteral("arg"), QStringLiteral("arg"), QStringLiteral("arg")));
+ QTest::ignoreMessage(QtWarningMsg, "QMetaObject::invokeMethod: No such method QtTestObject::testReference(QString)\n"
+ "Candidates are:\n testReference(QString&)");
+ QVERIFY(!QMetaObject::invokeMethod(&obj, "testReference", exp));
+
+ //should not have changed since last test.
+ QCOMPARE(exp, QString("yessir"));
+ QCOMPARE(obj.slotResult, QString("sl1:hehe"));
+}
+
void testFunction(){}
@@ -908,7 +1104,7 @@ void tst_QMetaObject::invokeQueuedMetaMember()
{
QtTestObject obj;
- QVERIFY(QMetaObject::invokeMethod(&obj, "sl0", Qt::QueuedConnection));
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sl0", Qt::QueuedConnection Q_NO_ARG));
QVERIFY(obj.slotResult.isEmpty());
qApp->processEvents(QEventLoop::AllEvents);
QCOMPARE(obj.slotResult, QString("sl0"));
@@ -942,7 +1138,7 @@ void tst_QMetaObject::invokeQueuedMetaMember()
QCOMPARE(obj.slotResult, "sl17");
// test overloads
- QVERIFY(QMetaObject::invokeMethod(&obj, "overloadedSlot", Qt::QueuedConnection));
+ QVERIFY(QMetaObject::invokeMethod(&obj, "overloadedSlot", Qt::QueuedConnection Q_NO_ARG));
qApp->processEvents(QEventLoop::AllEvents);
QCOMPARE(obj.slotResult, QString("overloadedSlot"));
QVERIFY(QMetaObject::invokeMethod(&obj, "overloadedSlot", Qt::QueuedConnection, Q_ARG(int, 1)));
@@ -955,7 +1151,7 @@ void tst_QMetaObject::invokeQueuedMetaMember()
// signals
obj.slotResult.clear();
- QVERIFY(QMetaObject::invokeMethod(&obj, "sig0", Qt::QueuedConnection));
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sig0", Qt::QueuedConnection Q_NO_ARG));
QVERIFY(obj.slotResult.isEmpty());
qApp->processEvents(QEventLoop::AllEvents);
QCOMPARE(obj.slotResult, QString("sl0"));
@@ -1013,6 +1209,119 @@ void tst_QMetaObject::invokeQueuedMetaMember()
QVERIFY(obj.slotResult.isEmpty());
}
+// this is a copy-paste-adapt of the above
+void tst_QMetaObject::invokeQueuedMetaMemberNoMacro()
+{
+ QtTestObject obj;
+
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sl0", Qt::QueuedConnection));
+ QVERIFY(obj.slotResult.isEmpty());
+ qApp->processEvents(QEventLoop::AllEvents);
+ QCOMPARE(obj.slotResult, QString("sl0"));
+ obj.slotResult = QString();
+
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sl1", Qt::QueuedConnection, QString("hallo")));
+ QVERIFY(obj.slotResult.isEmpty());
+ qApp->processEvents(QEventLoop::AllEvents);
+ QCOMPARE(obj.slotResult, QString("sl1:hallo"));
+ obj.slotResult = QString();
+
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sl9", Qt::QueuedConnection, QStringLiteral("1"), QStringLiteral("2"),
+ QStringLiteral("3"), QStringLiteral("4"), QStringLiteral("5"),
+ QStringLiteral("6"), QStringLiteral("7"), QStringLiteral("8"),
+ QStringLiteral("9")));
+ QVERIFY(obj.slotResult.isEmpty());
+ qApp->processEvents(QEventLoop::AllEvents);
+ QCOMPARE(obj.slotResult, QString("sl9:123456789"));
+
+ // pointers
+ qint64 return64;
+ obj.slotResult.clear();
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sl15", Qt::QueuedConnection, &return64));
+ qApp->processEvents(QEventLoop::AllEvents);
+ QCOMPARE(obj.slotResult, QString("sl15"));
+
+ // forward-declared builtin
+ obj.slotResult.clear();
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sl17", Qt::QueuedConnection, getEasingCurve()));
+ qApp->processEvents(QEventLoop::AllEvents);
+ QCOMPARE(obj.slotResult, "sl17");
+
+ // test overloads
+ QVERIFY(QMetaObject::invokeMethod(&obj, "overloadedSlot", Qt::QueuedConnection));
+ qApp->processEvents(QEventLoop::AllEvents);
+ QCOMPARE(obj.slotResult, QString("overloadedSlot"));
+ QVERIFY(QMetaObject::invokeMethod(&obj, "overloadedSlot", Qt::QueuedConnection, 1));
+ qApp->processEvents(QEventLoop::AllEvents);
+ QCOMPARE(obj.slotResult, QString("overloadedSlot:1"));
+ QVERIFY(QMetaObject::invokeMethod(&obj, "overloadedSlot", Qt::QueuedConnection, 1, 42));
+ qApp->processEvents(QEventLoop::AllEvents);
+ QCOMPARE(obj.slotResult, QString("overloadedSlot:1,42"));
+
+ // signals
+
+ obj.slotResult.clear();
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sig0", Qt::QueuedConnection));
+ QVERIFY(obj.slotResult.isEmpty());
+ qApp->processEvents(QEventLoop::AllEvents);
+ QCOMPARE(obj.slotResult, QString("sl0"));
+
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sig1", Qt::QueuedConnection, QStringLiteral("gogo")));
+ qApp->processEvents(QEventLoop::AllEvents);
+ QCOMPARE(obj.slotResult, QString("sl1:gogo"));
+
+ QString exp;
+ QTest::ignoreMessage(QtWarningMsg, "QMetaMethod::invoke: Unable to invoke methods with return values in queued connections");
+ QVERIFY(!QMetaObject::invokeMethod(&obj, "sig1", Qt::QueuedConnection, qReturnArg(exp),
+ QStringLiteral("nono")));
+
+ qint64 ll1 = -1;
+ quint64 ll2 = 0;
+ QVERIFY(QMetaObject::invokeMethod(&obj,
+ "testLongLong",
+ Qt::QueuedConnection,
+ ll1,
+ ll2));
+ qApp->processEvents(QEventLoop::AllEvents);
+ QCOMPARE(obj.slotResult, QString("testLongLong:-1,0"));
+
+ QTest::ignoreMessage(QtWarningMsg, "QMetaObject::invokeMethod: No such method QtTestObject::testReference(QString)\n"
+ "Candidates are:\n testReference(QString&)");
+ QVERIFY(!QMetaObject::invokeMethod(&obj, "testReference", exp));
+ QCOMPARE(obj.slotResult, QString("testLongLong:-1,0"));
+ QVERIFY(exp.isEmpty());
+
+ // this doesn't work yet
+// QString refStr = "whatever";
+// QTest::ignoreMessage(QtWarningMsg, "QMetaMethod::invoke: Unable to handle unregistered datatype 'QString&'");
+// QVERIFY(!QMetaObject::invokeMethod(&obj, "testReference", Qt::QueuedConnection, Q_ARG(QString&, refStr)));
+// QCOMPARE(refStr, "whatever");
+
+ obj.slotResult.clear();
+ {
+ const MyForwardDeclaredType &t = getForwardDeclaredType();
+ QTest::ignoreMessage(QtWarningMsg, "QMetaMethod::invoke: Unable to handle unregistered datatype 'MyForwardDeclaredType'");
+ QVERIFY(!QMetaObject::invokeMethod(&obj, "slotWithUnregisteredParameterType", Qt::QueuedConnection, t));
+ QVERIFY(obj.slotResult.isEmpty());
+ }
+
+ obj.slotResult.clear();
+ {
+ QString a1("Cannot happen");
+ const MyForwardDeclaredType &t = getForwardDeclaredType();
+ QTest::ignoreMessage(QtWarningMsg, "QMetaMethod::invoke: Unable to handle unregistered datatype 'MyForwardDeclaredType'");
+ QVERIFY(!QMetaObject::invokeMethod(&obj, "slotWithOneUnregisteredParameterType", Qt::QueuedConnection,
+ 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());
+}
+
void tst_QMetaObject::invokeQueuedPointer()
{
QtTestObject obj;
@@ -1062,7 +1371,7 @@ void tst_QMetaObject::invokeQueuedPointer()
QCOMPARE(countedStructObjectsCount, 0);
}
-
+// this test is duplicated below
void tst_QMetaObject::invokeBlockingQueuedMetaMember()
{
QThread t;
@@ -1109,17 +1418,19 @@ void tst_QMetaObject::invokeBlockingQueuedMetaMember()
Q_ARG(QString, t7), Q_ARG(QString, t8), Q_ARG(QString, t9)));
QCOMPARE(obj.slotResult, QString("sl9:123456789"));
- QVERIFY(QMetaObject::invokeMethod(&obj, "sl11", Qt::BlockingQueuedConnection));
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sl11", Qt::BlockingQueuedConnection Q_NO_ARG));
QCOMPARE(obj.slotResult, QString("sl11"));
- QVERIFY(QMetaObject::invokeMethod(&obj, "testSender", Qt::BlockingQueuedConnection));
+ QVERIFY(QMetaObject::invokeMethod(&obj, "testSender", Qt::BlockingQueuedConnection Q_NO_ARG));
QCOMPARE(obj.slotResult, QString("0x0"));
QString refStr("whatever");
+#ifdef USE_COMPAT_Q_ARG
QVERIFY(QMetaObject::invokeMethod(&obj, "testReference", Qt::BlockingQueuedConnection, QGenericArgument("QString&", &refStr)));
QCOMPARE(obj.slotResult, QString("testReference:whatever"));
QCOMPARE(refStr, QString("gotcha"));
obj.slotResult.clear();
+#endif
refStr = "whatever";
QVERIFY(QMetaObject::invokeMethod(&obj, "testReference", Qt::BlockingQueuedConnection, Q_ARG(QString&, refStr)));
QCOMPARE(obj.slotResult, QString("testReference:whatever"));
@@ -1200,7 +1511,7 @@ void tst_QMetaObject::invokeBlockingQueuedMetaMember()
QCOMPARE(obj.slotResult, "sl17");
// test overloads
- QVERIFY(QMetaObject::invokeMethod(&obj, "overloadedSlot", Qt::BlockingQueuedConnection));
+ QVERIFY(QMetaObject::invokeMethod(&obj, "overloadedSlot", Qt::BlockingQueuedConnection Q_NO_ARG));
QCOMPARE(obj.slotResult, QString("overloadedSlot"));
QVERIFY(QMetaObject::invokeMethod(&obj, "overloadedSlot", Qt::BlockingQueuedConnection, Q_ARG(int, 1)));
QCOMPARE(obj.slotResult, QString("overloadedSlot:1"));
@@ -1208,7 +1519,7 @@ void tst_QMetaObject::invokeBlockingQueuedMetaMember()
QCOMPARE(obj.slotResult, QString("overloadedSlot:1,42"));
//test signals
- QVERIFY(QMetaObject::invokeMethod(&obj, "sig0", Qt::BlockingQueuedConnection));
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sig0", Qt::BlockingQueuedConnection Q_NO_ARG));
QCOMPARE(obj.slotResult, QString("sl0"));
QVERIFY(QMetaObject::invokeMethod(&obj, "sig1", Qt::BlockingQueuedConnection, Q_ARG(QString, "baba")));
@@ -1220,7 +1531,7 @@ void tst_QMetaObject::invokeBlockingQueuedMetaMember()
QCOMPARE(obj.slotResult, QString("sl1:hehe"));
QTest::ignoreMessage(QtWarningMsg, "QMetaObject::invokeMethod: No such method QtTestObject::doesNotExist()");
- QVERIFY(!QMetaObject::invokeMethod(&obj, "doesNotExist", Qt::BlockingQueuedConnection));
+ QVERIFY(!QMetaObject::invokeMethod(&obj, "doesNotExist", Qt::BlockingQueuedConnection Q_NO_ARG));
QTest::ignoreMessage(QtWarningMsg, "QMetaObject::invokeMethod: No such method QtTestObject::sl1(QString)(QString)");
QVERIFY(!QMetaObject::invokeMethod(&obj, "sl1(QString)", Qt::BlockingQueuedConnection, Q_ARG(QString, "arg")));
QTest::ignoreMessage(QtWarningMsg, "QMetaObject::invokeMethod: No such method QtTestObject::sl3(QString)\n"
@@ -1240,7 +1551,182 @@ void tst_QMetaObject::invokeBlockingQueuedMetaMember()
QVERIFY(QMetaObject::invokeMethod(&obj, "moveToThread", Qt::BlockingQueuedConnection, Q_ARG(QThread*, QThread::currentThread())));
t.quit();
QVERIFY(t.wait());
+}
+
+// this is a copy-paste-adapt of the above
+void tst_QMetaObject::invokeBlockingQueuedMetaMemberNoMacros()
+{
+ QThread t;
+ t.start();
+ QtTestObject obj;
+ obj.moveToThread(&t);
+
+ QString t1("1"); QString t2("2"); QString t3("3"); QString t4("4"); QString t5("5");
+ QString t6("6"); QString t7("7"); QString t8("8"); QString t9("9"); QString t10("X");
+
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sl1", Qt::BlockingQueuedConnection, t1));
+ QCOMPARE(obj.slotResult, QString("sl1:1"));
+
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sl2", Qt::BlockingQueuedConnection, t1, t2));
+ QCOMPARE(obj.slotResult, QString("sl2:12"));
+
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sl3", Qt::BlockingQueuedConnection, t1, t2, t3));
+ QCOMPARE(obj.slotResult, QString("sl3:123"));
+
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sl4", Qt::BlockingQueuedConnection, t1, t2,
+ t3, t4));
+ QCOMPARE(obj.slotResult, QString("sl4:1234"));
+
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sl5", Qt::BlockingQueuedConnection, t1, t2,
+ t3, t4, QStringLiteral("5")));
+ QCOMPARE(obj.slotResult, QString("sl5:12345"));
+
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sl6", Qt::BlockingQueuedConnection, t1, t2,
+ t3, t4, t5, t6));
+ QCOMPARE(obj.slotResult, QString("sl6:123456"));
+
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sl7", Qt::BlockingQueuedConnection, t1, t2,
+ t3, t4, t5, t6,
+ t7));
+ QCOMPARE(obj.slotResult, QString("sl7:1234567"));
+
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sl8", Qt::BlockingQueuedConnection, t1, t2,
+ t3, t4, t5, t6,
+ t7, t8));
+ QCOMPARE(obj.slotResult, QString("sl8:12345678"));
+
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sl9", Qt::BlockingQueuedConnection, t1, t2,
+ t3, t4, t5, t6,
+ t7, t8, t9));
+ QCOMPARE(obj.slotResult, QString("sl9:123456789"));
+
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sl11", Qt::BlockingQueuedConnection));
+ QCOMPARE(obj.slotResult, QString("sl11"));
+
+ QVERIFY(QMetaObject::invokeMethod(&obj, "testSender", Qt::BlockingQueuedConnection));
+ QCOMPARE(obj.slotResult, QString("0x0"));
+
+ // this is not working
+// QString refStr("whatever");
+// QVERIFY(QMetaObject::invokeMethod(&obj, "testReference", Qt::BlockingQueuedConnection, refStr));
+// QCOMPARE(obj.slotResult, QString("testReference:whatever"));
+// QCOMPARE(refStr, QString("gotcha"));
+
+ qint64 ll1 = -1;
+ quint64 ll2 = 0;
+ QVERIFY(QMetaObject::invokeMethod(&obj,
+ "testLongLong",
+ Qt::BlockingQueuedConnection,
+ ll1,
+ ll2));
+ QCOMPARE(obj.slotResult, QString("testLongLong:-1,0"));
+
+ QString exp;
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sl1", Qt::BlockingQueuedConnection, qReturnArg(exp), QStringLiteral("bubu")));
+ QCOMPARE(exp, QString("yessir"));
+ QCOMPARE(obj.slotResult, QString("sl1:bubu"));
+
+ QObject *ptr = nullptr;
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sl11", Qt::BlockingQueuedConnection, qReturnArg(ptr)));
+ QCOMPARE(ptr, (QObject *)&obj);
+ QCOMPARE(obj.slotResult, QString("sl11"));
+ // try again with a space:
+ ptr = nullptr;
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sl11", Qt::BlockingQueuedConnection, qReturnArg(ptr)));
+ QCOMPARE(ptr, (QObject *)&obj);
+ QCOMPARE(obj.slotResult, QString("sl11"));
+
+ const char *ptr2 = 0;
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sl12", Qt::BlockingQueuedConnection, qReturnArg(ptr2)));
+ QVERIFY(ptr2 != 0);
+ QCOMPARE(obj.slotResult, QString("sl12"));
+ // try again with a space:
+ ptr2 = 0;
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sl12", Qt::BlockingQueuedConnection, qReturnArg(ptr2)));
+ QVERIFY(ptr2 != 0);
+ QCOMPARE(obj.slotResult, QString("sl12"));
+
+ // test w/ template args
+ QList<QString> returnValue, argument;
+ argument << QString("one") << QString("two") << QString("three");
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sl13", Qt::BlockingQueuedConnection,
+ qReturnArg(returnValue),
+ argument));
+ QCOMPARE(returnValue, argument);
+ QCOMPARE(obj.slotResult, QString("sl13"));
+
+ // return qint64
+ qint64 return64;
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sl14", Qt::BlockingQueuedConnection,
+ qReturnArg(return64)));
+ QCOMPARE(return64, Q_INT64_C(123456789)*123456789);
+ QCOMPARE(obj.slotResult, QString("sl14"));
+
+ // pointers
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sl15", Qt::BlockingQueuedConnection, &return64));
+ QCOMPARE(obj.slotResult, QString("sl15"));
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sl16", Qt::BlockingQueuedConnection, getForwardDeclaredPointer()));
+ QCOMPARE(obj.slotResult, QString("sl16:notnull"));
+
+ obj.slotResult.clear();
+ qint64 *return64Ptr;
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sl15", Qt::BlockingQueuedConnection, qReturnArg(return64Ptr), &return64));
+ QCOMPARE(return64Ptr, &return64);
+ QCOMPARE(obj.slotResult, QString("sl15"));
+
+ obj.slotResult.clear();
+ MyForwardDeclaredType *forwardPtr = nullptr;
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sl16", Qt::BlockingQueuedConnection, qReturnArg(forwardPtr),
+ forwardPtr));
+ 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"));
+ QVERIFY(QMetaObject::invokeMethod(&obj, "overloadedSlot", Qt::BlockingQueuedConnection, 1));
+ QCOMPARE(obj.slotResult, QString("overloadedSlot:1"));
+ QVERIFY(QMetaObject::invokeMethod(&obj, "overloadedSlot", Qt::BlockingQueuedConnection, 1, 42));
+ QCOMPARE(obj.slotResult, QString("overloadedSlot:1,42"));
+
+ //test signals
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sig0", Qt::BlockingQueuedConnection));
+ QCOMPARE(obj.slotResult, QString("sl0"));
+
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sig1", Qt::BlockingQueuedConnection, QStringLiteral("baba")));
+ QCOMPARE(obj.slotResult, QString("sl1:baba"));
+
+ exp.clear();
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sig1", Qt::BlockingQueuedConnection, qReturnArg(exp), QStringLiteral("hehe")));
+ QCOMPARE(exp, QString("yessir"));
+ QCOMPARE(obj.slotResult, QString("sl1:hehe"));
+
+ QTest::ignoreMessage(QtWarningMsg, "QMetaObject::invokeMethod: No such method QtTestObject::doesNotExist()");
+ QVERIFY(!QMetaObject::invokeMethod(&obj, "doesNotExist", Qt::BlockingQueuedConnection));
+ QTest::ignoreMessage(QtWarningMsg, "QMetaObject::invokeMethod: No such method QtTestObject::sl1(QString)(QString)");
+ QVERIFY(!QMetaObject::invokeMethod(&obj, "sl1(QString)", Qt::BlockingQueuedConnection, QStringLiteral("arg")));
+ QTest::ignoreMessage(QtWarningMsg, "QMetaObject::invokeMethod: No such method QtTestObject::sl3(QString)\n"
+ "Candidates are:\n sl3(QString,QString,QString)");
+ QVERIFY(!QMetaObject::invokeMethod(&obj, "sl3", Qt::BlockingQueuedConnection, QStringLiteral("arg")));
+ QTest::ignoreMessage(QtWarningMsg, "QMetaObject::invokeMethod: No such method QtTestObject::sl1(QString,QString,QString)\n"
+ "Candidates are:\n sl1(QString)");
+ QVERIFY(!QMetaObject::invokeMethod(&obj, "sl1", Qt::BlockingQueuedConnection, QStringLiteral("arg"), QStringLiteral("arg"), QStringLiteral("arg")));
+ QTest::ignoreMessage(QtWarningMsg, "QMetaObject::invokeMethod: No such method QtTestObject::testReference(QString)\n"
+ "Candidates are:\n testReference(QString&)");
+ QVERIFY(!QMetaObject::invokeMethod(&obj, "testReference", Qt::BlockingQueuedConnection, exp));
+
+ //should not have changed since last test.
+ QCOMPARE(exp, QString("yessir"));
+ QCOMPARE(obj.slotResult, QString("sl1:hehe"));
+ QVERIFY(QMetaObject::invokeMethod(&obj, "moveToThread", Qt::BlockingQueuedConnection, QThread::currentThread()));
+ t.quit();
+ QVERIFY(t.wait());
}
void tst_QMetaObject::invokeBlockingQueuedPointer()
@@ -1366,6 +1852,10 @@ void tst_QMetaObject::invokeCustomTypes()
QCOMPARE(obj.sum, 0);
QVERIFY(QMetaObject::invokeMethod(&obj, "sl1", Q_ARG(MyType, tp)));
QCOMPARE(obj.sum, 3);
+
+ obj.sum = 0;
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sl1", tp));
+ QCOMPARE(obj.sum, 3);
}
namespace NamespaceWithConstructibleClass
@@ -1381,13 +1871,16 @@ public:
}
+// this test is duplicated below
void tst_QMetaObject::invokeMetaConstructor()
{
const QMetaObject *mo = &QtTestObject::staticMetaObject;
+#ifdef USE_COMPAT_Q_ARG
{
- QObject *obj = mo->newInstance();
+ QObject *obj = mo->newInstance(QGenericArgument());
QVERIFY(!obj);
}
+#endif
{
QtTestObject obj;
QObject *obj2 = mo->newInstance(Q_ARG(QObject*, &obj));
@@ -1430,6 +1923,38 @@ void tst_QMetaObject::invokeMetaConstructor()
}
}
+// this is a copy-paste-adapt of the above
+void tst_QMetaObject::invokeMetaConstructorNoMacro()
+{
+ const QMetaObject *mo = &QtTestObject::staticMetaObject;
+ {
+ QObject *obj = mo->newInstance();
+ QVERIFY(!obj);
+ }
+ {
+ QtTestObject obj;
+ QObject *obj2 = mo->newInstance(static_cast<QObject *>(&obj));
+ QVERIFY(obj2 != 0);
+ QCOMPARE(obj2->parent(), (QObject*)&obj);
+ QVERIFY(qobject_cast<QtTestObject*>(obj2) != 0);
+ }
+ // class in namespace
+ const QMetaObject *nsmo = &NamespaceWithConstructibleClass::ConstructibleClass::staticMetaObject;
+ {
+ QtTestObject obj;
+ QObject *obj2 = nsmo->newInstance(static_cast<QObject *>(&obj));
+ QVERIFY(obj2 != 0);
+ QCOMPARE(obj2->parent(), (QObject*)&obj);
+ QVERIFY(qobject_cast<NamespaceWithConstructibleClass::ConstructibleClass*>(obj2) != 0);
+ }
+ // gadget shouldn't return a valid pointer
+ {
+ QCOMPARE(MyGadget::staticMetaObject.constructorCount(), 1);
+ QTest::ignoreMessage(QtWarningMsg, "QMetaObject::newInstance: type MyGadget does not inherit QObject");
+ QVERIFY(!MyGadget::staticMetaObject.newInstance());
+ }
+}
+
void tst_QMetaObject::invokeTypedefTypes()
{
qRegisterMetaType<CustomString>("CustomString");
@@ -1457,6 +1982,14 @@ void tst_QMetaObject::invokeException()
QFAIL("Did not throw");
} catch(ObjectException &) {}
QCOMPARE(countedStructObjectsCount, 0);
+
+ try {
+ CountedStruct s;
+ QVERIFY(QMetaObject::invokeMethod(&obj, "throwingSlot", qReturnArg(s),
+ s, s));
+ QFAIL("Did not throw");
+ } catch(ObjectException &) {}
+ QCOMPARE(countedStructObjectsCount, 0);
#else
QSKIP("Needs exceptions");
#endif
@@ -1478,6 +2011,18 @@ void tst_QMetaObject::invokeQueuedAutoRegister()
qApp->processEvents(QEventLoop::AllEvents);
QCOMPARE(obj.slotResult,
QString("slotWithRegistrableArgument:myShared-myShared-myShared-myShared-00"));
+
+ obj.slotResult.clear();
+ QVERIFY(QMetaObject::invokeMethod(
+ &obj, "slotWithRegistrableArgument", Qt::QueuedConnection,
+ shared.data(), QPointer<QtTestObject>(shared.data()),
+ QSharedPointer<QtTestObject>(shared), QWeakPointer<QtTestObject>(shared),
+ QList<QtTestObject *>(),
+ QList<QtTestObject *>()));
+ QVERIFY(obj.slotResult.isEmpty());
+ qApp->processEvents(QEventLoop::AllEvents);
+ QCOMPARE(obj.slotResult,
+ QString("slotWithRegistrableArgument:myShared-myShared-myShared-myShared-00"));
}
void tst_QMetaObject::normalizedSignature_data()
@@ -1811,6 +2356,7 @@ void tst_QMetaObject::classInfo()
QCOMPARE(QLatin1String(b.metaObject()->classInfo(index).value()), QLatin1String("Christopher Pike"));
}
+// this test is duplicated below
void tst_QMetaObject::metaMethod()
{
QString str("foo");
@@ -1863,6 +2409,59 @@ void tst_QMetaObject::metaMethod()
QCOMPARE(obj.slotResult, QString("sl13"));
}
+// this is a copy-paste-adapt of the above
+void tst_QMetaObject::metaMethodNoMacro()
+{
+ QString str("foo");
+ QString ret("bar");
+ QMetaMethod method;
+ QVERIFY(!method.invoke(this));
+ QVERIFY(!method.invoke(this, str));
+ QVERIFY(!method.invoke(this, qReturnArg(ret), str));
+ QCOMPARE(str, QString("foo"));
+ QCOMPARE(ret, QString("bar"));
+
+ QtTestObject obj;
+ QString t1("1"); QString t2("2"); QString t3("3"); QString t4("4"); QString t5("5");
+ QString t6("6"); QString t7("7"); QString t8("8"); QString t9("9"); QString t10("X");
+
+ int index = QtTestObject::staticMetaObject.indexOfMethod("sl5(QString,QString,QString,QString,QString)");
+ QVERIFY(index > 0);
+ method = QtTestObject::staticMetaObject.method(index);
+ //wrong args
+ QTest::ignoreMessage(QtWarningMsg, "QMetaMethod::invoke: too few arguments (5) in call to QtTestObject::sl5(QString,QString,QString,QString,QString)");
+ QVERIFY(!method.invoke(&obj, QStringLiteral("1"), QStringLiteral("2"), QStringLiteral("3"), QStringLiteral("4")));
+ //QVERIFY(!method.invoke(&obj, "1", "2", "3", "4", "5", "6"));
+ //QVERIFY(!method.invoke(&obj, "1", "2", "3", "4", 5));
+ QTest::ignoreMessage(QtWarningMsg, "QMetaMethod::invokeMethod: return type mismatch for method "
+ "QtTestObject::sl5(QString,QString,QString,QString,QString): "
+ "cannot convert from void to QString during invocation");
+ QVERIFY(!method.invoke(&obj, qReturnArg(ret), QStringLiteral("1"), QStringLiteral("2"), QStringLiteral("3"), QStringLiteral("4"), QStringLiteral("5")));
+
+ //wrong object
+ //QVERIFY(!method.invoke(this, "1", "2", "3", "4", "5"));
+ QVERIFY(!method.invoke(0, QStringLiteral("1"), QStringLiteral("2"), QStringLiteral("3"), QStringLiteral("4"), QStringLiteral("5")));
+ QCOMPARE(ret, QString("bar"));
+ QCOMPARE(obj.slotResult, QString());
+
+ QVERIFY(method.invoke(&obj, QStringLiteral("1"), QStringLiteral("2"), QStringLiteral("3"), QStringLiteral("4"), QStringLiteral("5")));
+ QCOMPARE(obj.slotResult, QString("sl5:12345"));
+
+ index = QtTestObject::staticMetaObject.indexOfMethod("sl13(QList<QString>)");
+ QVERIFY(index > 0);
+ QMetaMethod sl13 = QtTestObject::staticMetaObject.method(index);
+ QList<QString> returnValue, argument;
+ argument << QString("one") << QString("two") << QString("three");
+ //wrong object
+ //QVERIFY(!sl13.invoke(this, qReturnArg(returnValue), argument));
+ QVERIFY(!sl13.invoke(0, qReturnArg(returnValue), argument));
+ QVERIFY(returnValue.isEmpty());
+
+ QVERIFY(sl13.invoke(&obj, qReturnArg(returnValue), argument));
+ QCOMPARE(returnValue, argument);
+ QCOMPARE(obj.slotResult, QString("sl13"));
+}
+
void tst_QMetaObject::indexOfMethod_data()
{
QTest::addColumn<QObject *>("object");