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>
This commit is contained in:
parent
191419e980
commit
fe92b08065
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
)
|
||||
|
@ -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");
|
||||
|
Loading…
x
Reference in New Issue
Block a user