QMetaObject: pass the QMetaTypes in variadic invoke/newInstance
[ChangeLog][QtCore][Meta Object] QMetaMethod::invoke(), QMetaObject::invokeMethod(), and QMetaObject::newInstance() are no longer limited to 10 arguments. [ChangeLog][QtCore][Meta Object] The use of the Q_ARG macro is no longer necessary when using QMetaMethod::invoke(), QMetaObject::invokeMethod(), and QMetaObject::newInstance(). Types may now be passed directly. Similarly, Q_RETURN_ARG can be replaced by the free function qReturnArg(). [ChangeLog][Potentially Source-Incompatible Changes] QMetaMethod::invoke(), QMetaObject::invokeMethod(), and QMetaObject::newInstance() no longer support passing forward-declared types in the argument list (it was possible to pass them by const-ref). From Qt 6.5 onwards, all types in the argument list must be fully defined. [ChangeLog][Potentially Source-Incompatible Changes] Attempting to use the internal types QArgument, QReturnArgument, QGenericArgument, or QGenericReturnArgument directly with QMetaMethod::invoke(), QMetaObject::invokeMethod() or QMetaObject::newInstance() may fail to compile. Those are internal types that were never meant to be used directly and will be removed in Qt 7. If really necessary, ensure all arguments passed to those functions are directly using those classes and not mixed with Q_ARG and Q_RETURN_ARG. Implementations of bindings to other languages should contact the Qt development mailing list to discuss options. Change-Id: I36b24183fbd041179f2ffffd1701e3e8e47e0fba Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
This commit is contained in:
parent
ba8c4b4ac6
commit
0380dd5051
@ -241,11 +241,12 @@ QObject *QMetaObject::newInstance(QGenericArgument val0,
|
||||
break;
|
||||
}
|
||||
|
||||
return newInstanceImpl(this, paramCount, parameters, typeNames);
|
||||
return newInstanceImpl(this, paramCount, parameters, typeNames, nullptr);
|
||||
}
|
||||
|
||||
QObject *QMetaObject::newInstanceImpl(const QMetaObject *mobj, qsizetype paramCount,
|
||||
const void **parameters, const char **typeNames)
|
||||
const void **parameters, const char **typeNames,
|
||||
const QtPrivate::QMetaTypeInterface **metaTypes)
|
||||
{
|
||||
if (!mobj->inherits(&QObject::staticMetaObject)) {
|
||||
qWarning("QMetaObject::newInstance: type %s does not inherit QObject", mobj->className());
|
||||
@ -262,6 +263,8 @@ QT_WARNING_DISABLE_GCC("-Wdangling-pointer")
|
||||
QMetaType returnValueMetaType = QMetaType::fromType<decltype(returnValue)>();
|
||||
parameters[0] = &returnValue;
|
||||
typeNames[0] = returnValueMetaType.name();
|
||||
if (metaTypes)
|
||||
metaTypes[0] = returnValueMetaType.iface();
|
||||
|
||||
QT_WARNING_POP
|
||||
|
||||
@ -275,7 +278,7 @@ QT_WARNING_POP
|
||||
// attempt to call
|
||||
QMetaMethodPrivate::InvokeFailReason r =
|
||||
QMetaMethodPrivate::invokeImpl(m, nullptr, Qt::DirectConnection, paramCount,
|
||||
parameters, typeNames);
|
||||
parameters, typeNames, metaTypes);
|
||||
if (r == QMetaMethodPrivate::InvokeFailReason::None)
|
||||
return returnValue;
|
||||
if (int(r) < 0)
|
||||
@ -1346,7 +1349,8 @@ QByteArray QMetaObject::normalizedSignature(const char *method)
|
||||
|
||||
Q_DECL_COLD_FUNCTION static inline bool
|
||||
printMethodNotFoundWarning(const QMetaObject *meta, QLatin1StringView name, qsizetype paramCount,
|
||||
const char *const *names)
|
||||
const char *const *names,
|
||||
const QtPrivate::QMetaTypeInterface * const *metaTypes)
|
||||
{
|
||||
// now find the candidates we couldn't use
|
||||
QByteArray candidateMessage;
|
||||
@ -1362,7 +1366,10 @@ printMethodNotFoundWarning(const QMetaObject *meta, QLatin1StringView name, qsiz
|
||||
|
||||
QVarLengthArray<char, 512> sig;
|
||||
for (qsizetype i = 1; i < paramCount; ++i) {
|
||||
sig.append(names[i], qstrlen(names[i]));
|
||||
if (names[i])
|
||||
sig.append(names[i], qstrlen(names[i]));
|
||||
else
|
||||
sig.append(metaTypes[i]->name, qstrlen(metaTypes[i]->name));
|
||||
sig.append(',');
|
||||
}
|
||||
if (paramCount != 1)
|
||||
@ -1472,12 +1479,13 @@ bool QMetaObject::invokeMethod(QObject *obj,
|
||||
if (qstrlen(typeNames[paramCount]) <= 0)
|
||||
break;
|
||||
}
|
||||
return invokeMethodImpl(obj, member, type, paramCount, parameters, typeNames);
|
||||
return invokeMethodImpl(obj, member, type, paramCount, parameters, typeNames, nullptr);
|
||||
}
|
||||
|
||||
bool QMetaObject::invokeMethodImpl(QObject *obj, const char *member, Qt::ConnectionType type,
|
||||
qsizetype paramCount, const void * const *parameters,
|
||||
const char * const *typeNames)
|
||||
const char * const *typeNames,
|
||||
const QtPrivate::QMetaTypeInterface * const *metaTypes)
|
||||
{
|
||||
if (!obj)
|
||||
return false;
|
||||
@ -1503,14 +1511,15 @@ bool QMetaObject::invokeMethodImpl(QObject *obj, const char *member, Qt::Connect
|
||||
|
||||
// attempt to call
|
||||
QMetaMethodPrivate::InvokeFailReason r =
|
||||
QMetaMethodPrivate::invokeImpl(m, obj, type, paramCount, parameters, typeNames);
|
||||
QMetaMethodPrivate::invokeImpl(m, obj, type, paramCount, parameters,
|
||||
typeNames, metaTypes);
|
||||
if (int(r) <= 0)
|
||||
return r == QMetaMethodPrivate::InvokeFailReason::None;
|
||||
}
|
||||
}
|
||||
|
||||
// This method doesn't belong to us; print out a nice warning with candidates.
|
||||
return printMethodNotFoundWarning(obj->metaObject(), name, paramCount, typeNames);
|
||||
return printMethodNotFoundWarning(obj->metaObject(), name, paramCount, typeNames, metaTypes);
|
||||
}
|
||||
|
||||
bool QMetaObject::invokeMethodImpl(QObject *object, QtPrivate::QSlotObjectBase *slot, Qt::ConnectionType type, void *ret)
|
||||
@ -2410,25 +2419,27 @@ bool QMetaMethod::invoke(QObject *object,
|
||||
if (qstrlen(typeNames[paramCount]) <= 0)
|
||||
break;
|
||||
}
|
||||
return invokeImpl(*this, object, connectionType, paramCount, param, typeNames);
|
||||
return invokeImpl(*this, object, connectionType, paramCount, param, typeNames, nullptr);
|
||||
}
|
||||
|
||||
bool QMetaMethod::invokeImpl(QMetaMethod self, void *target, Qt::ConnectionType connectionType,
|
||||
qsizetype paramCount, const void *const *parameters,
|
||||
const char *const *typeNames)
|
||||
const char *const *typeNames,
|
||||
const QtPrivate::QMetaTypeInterface *const *metaTypes)
|
||||
{
|
||||
if (!target || !self.mobj)
|
||||
return false;
|
||||
QMetaMethodPrivate::InvokeFailReason r =
|
||||
QMetaMethodPrivate::invokeImpl(self, target, connectionType, paramCount, parameters, typeNames);
|
||||
|
||||
QMetaMethodPrivate::invokeImpl(self, target, connectionType, paramCount, parameters,
|
||||
typeNames, metaTypes);
|
||||
if (Q_LIKELY(r == QMetaMethodPrivate::InvokeFailReason::None))
|
||||
return true;
|
||||
|
||||
if (int(r) >= int(QMetaMethodPrivate::InvokeFailReason::FormalParameterMismatch)) {
|
||||
int n = int(r) - int(QMetaMethodPrivate::InvokeFailReason::FormalParameterMismatch);
|
||||
qWarning("QMetaMethod::invoke: cannot convert formal parameter %d from %s in call to %s::%s",
|
||||
n, typeNames[n + 1], self.mobj->className(), self.methodSignature().constData());
|
||||
n, typeNames[n + 1] ? typeNames[n + 1] : metaTypes[n + 1]->name,
|
||||
self.mobj->className(), self.methodSignature().constData());
|
||||
}
|
||||
if (r == QMetaMethodPrivate::InvokeFailReason::TooFewArguments) {
|
||||
qWarning("QMetaMethod::invoke: too few arguments (%d) in call to %s::%s",
|
||||
@ -2440,10 +2451,13 @@ bool QMetaMethod::invokeImpl(QMetaMethod self, void *target, Qt::ConnectionType
|
||||
auto QMetaMethodInvoker::invokeImpl(QMetaMethod self, void *target,
|
||||
Qt::ConnectionType connectionType,
|
||||
qsizetype paramCount, const void *const *parameters,
|
||||
const char *const *typeNames) -> InvokeFailReason
|
||||
const char *const *typeNames,
|
||||
const QtPrivate::QMetaTypeInterface *const *metaTypes) -> InvokeFailReason
|
||||
{
|
||||
auto object = static_cast<QObject *>(target);
|
||||
auto priv = QMetaMethodPrivate::get(&self);
|
||||
constexpr bool MetaTypesAreOptional = QT_VERSION < QT_VERSION_CHECK(7, 0, 0);
|
||||
auto methodMetaTypes = priv->parameterMetaTypeInterfaces();
|
||||
auto param = const_cast<void **>(parameters);
|
||||
|
||||
Q_ASSERT(priv->mobj);
|
||||
@ -2453,6 +2467,7 @@ auto QMetaMethodInvoker::invokeImpl(QMetaMethod self, void *target,
|
||||
Q_ASSERT(paramCount >= 1); // includes the return type
|
||||
Q_ASSERT(parameters);
|
||||
Q_ASSERT(typeNames);
|
||||
Q_ASSERT(MetaTypesAreOptional || metaTypes);
|
||||
|
||||
if ((paramCount - 1) < qsizetype(priv->data.argc()))
|
||||
return InvokeFailReason::TooFewArguments;
|
||||
@ -2460,23 +2475,45 @@ auto QMetaMethodInvoker::invokeImpl(QMetaMethod self, void *target,
|
||||
// 0 is the return type, 1 is the first formal parameter
|
||||
auto checkTypesAreCompatible = [=](int idx) {
|
||||
uint typeInfo = priv->parameterTypeInfo(idx - 1);
|
||||
QLatin1StringView userTypeName(typeNames[idx]);
|
||||
QLatin1StringView userTypeName(typeNames[idx] ? typeNames[idx] : metaTypes[idx]->name);
|
||||
|
||||
if ((typeInfo & IsUnresolvedType) == 0) {
|
||||
// this is a built-in type
|
||||
return int(typeInfo) == QMetaType::fromName(userTypeName).id();
|
||||
if (MetaTypesAreOptional && !metaTypes)
|
||||
return int(typeInfo) == QMetaType::fromName(userTypeName).id();
|
||||
return int(typeInfo) == metaTypes[idx]->typeId;
|
||||
}
|
||||
|
||||
// compare strings
|
||||
QLatin1StringView methodTypeName = stringDataView(priv->mobj, typeInfo & TypeNameIndexMask);
|
||||
if (methodTypeName == userTypeName)
|
||||
if ((MetaTypesAreOptional && !metaTypes) || !metaTypes[idx]) {
|
||||
// compatibility call, compare strings
|
||||
if (methodTypeName == userTypeName)
|
||||
return true;
|
||||
|
||||
// maybe the user type needs normalization
|
||||
QByteArray normalized = normalizeTypeInternal(userTypeName.begin(), userTypeName.end());
|
||||
return methodTypeName == QLatin1StringView(normalized);
|
||||
}
|
||||
|
||||
QMetaType userType(metaTypes[idx]);
|
||||
Q_ASSERT(userType.isValid());
|
||||
if (QMetaType(methodMetaTypes[idx - 1]) == userType)
|
||||
return true;
|
||||
|
||||
// maybe the user type needs normalization
|
||||
QByteArray normalized = normalizeTypeInternal(userTypeName.begin(), userTypeName.end());
|
||||
return methodTypeName == QLatin1StringView(normalized);
|
||||
// if the parameter type was NOT only forward-declared, it MUST have
|
||||
// matched
|
||||
if (methodMetaTypes[idx - 1])
|
||||
return false;
|
||||
|
||||
// resolve from the name moc stored for us
|
||||
QMetaType resolved = QMetaType::fromName(methodTypeName);
|
||||
return resolved == userType;
|
||||
};
|
||||
|
||||
// force all types to be registered, just in case
|
||||
for (qsizetype i = 0; metaTypes && i < paramCount; ++i)
|
||||
QMetaType(metaTypes[i]).registerType();
|
||||
|
||||
// check formal parameters first (overload set)
|
||||
for (qsizetype i = 1; i < paramCount; ++i) {
|
||||
if (!checkTypesAreCompatible(i))
|
||||
@ -2497,6 +2534,14 @@ auto QMetaMethodInvoker::invokeImpl(QMetaMethod self, void *target,
|
||||
return InvokeFailReason::ConstructorCallWithoutResult;
|
||||
}
|
||||
|
||||
if (!MetaTypesAreOptional || metaTypes) {
|
||||
if (metaTypes[0]->typeId != QMetaType::QObjectStar) {
|
||||
qWarning("QMetaMethod::invokeMethod: cannot convert QObject* to %s on constructor call %s",
|
||||
metaTypes[0]->name, self.methodSignature().constData());
|
||||
return InvokeFailReason::ReturnTypeMismatch;
|
||||
}
|
||||
}
|
||||
|
||||
int idx = priv->ownConstructorMethodIndex();
|
||||
if (priv->mobj->static_metacall(QMetaObject::CreateInstance, idx, param) >= 0)
|
||||
return InvokeFailReason::ConstructorCallFailed;
|
||||
@ -2506,10 +2551,11 @@ auto QMetaMethodInvoker::invokeImpl(QMetaMethod self, void *target,
|
||||
// regular type - check return type
|
||||
if (parameters[0]) {
|
||||
if (!checkTypesAreCompatible(0)) {
|
||||
const char *retType = typeNames[0] ? typeNames[0] : metaTypes[0]->name;
|
||||
qWarning("QMetaMethod::invokeMethod: return type mismatch for method %s::%s:"
|
||||
" cannot convert from %s to %s during invocation",
|
||||
priv->mobj->className(), priv->methodSignature().constData(),
|
||||
priv->rawReturnTypeName(), typeNames[0]);
|
||||
priv->rawReturnTypeName(), retType);
|
||||
return InvokeFailReason::ReturnTypeMismatch;
|
||||
}
|
||||
}
|
||||
@ -2561,8 +2607,12 @@ auto QMetaMethodInvoker::invokeImpl(QMetaMethod self, void *target,
|
||||
|
||||
// fill in the meta types first
|
||||
for (int i = 1; i < paramCount; ++i) {
|
||||
types[i] = priv->parameterMetaType(i - 1);
|
||||
types[i] = QMetaType(methodMetaTypes[i - 1]);
|
||||
if (!types[i].iface() && (!MetaTypesAreOptional || metaTypes))
|
||||
types[i] = QMetaType(metaTypes[i]);
|
||||
if (!types[i].iface())
|
||||
types[i] = priv->parameterMetaType(i - 1);
|
||||
if (!types[i].iface() && typeNames[i])
|
||||
types[i] = QMetaType::fromName(typeNames[i]);
|
||||
if (!types[i].iface()) {
|
||||
qWarning("QMetaMethod::invoke: Unable to handle unregistered datatype '%s'",
|
||||
|
@ -141,7 +141,7 @@ public:
|
||||
{
|
||||
auto h = QtPrivate::invokeMethodHelper(r, std::forward<Args>(arguments)...);
|
||||
return invokeImpl(*this, obj, c, h.parameterCount(), h.parameters.data(),
|
||||
h.typeNames.data());
|
||||
h.typeNames.data(), h.metaTypes.data());
|
||||
}
|
||||
|
||||
template <typename... Args> QtPrivate::Invoke::IfNotOldStyleArgs<bool, Args...>
|
||||
@ -167,7 +167,7 @@ public:
|
||||
{
|
||||
auto h = QtPrivate::invokeMethodHelper(r, std::forward<Args>(arguments)...);
|
||||
return invokeImpl(*this, gadget, Qt::ConnectionType(-1), h.parameterCount(),
|
||||
h.parameters.data(), h.typeNames.data());
|
||||
h.parameters.data(), h.typeNames.data(), h.metaTypes.data());
|
||||
}
|
||||
|
||||
template <typename... Args> QtPrivate::Invoke::IfNotOldStyleArgs<bool, Args...>
|
||||
@ -190,7 +190,8 @@ public:
|
||||
|
||||
private:
|
||||
static bool invokeImpl(QMetaMethod self, void *target, Qt::ConnectionType, qsizetype paramCount,
|
||||
const void *const *parameters, const char *const *typeNames);
|
||||
const void *const *parameters, const char *const *typeNames,
|
||||
const QtPrivate::QMetaTypeInterface *const *metaTypes);
|
||||
static QMetaMethod fromSignalImpl(const QMetaObject *, void **);
|
||||
static QMetaMethod fromRelativeMethodIndex(const QMetaObject *mobj, int index);
|
||||
static QMetaMethod fromRelativeConstructorIndex(const QMetaObject *mobj, int index);
|
||||
|
@ -160,7 +160,8 @@ public:
|
||||
// shadows the public function
|
||||
static InvokeFailReason Q_CORE_EXPORT
|
||||
invokeImpl(QMetaMethod self, void *target, Qt::ConnectionType, qsizetype paramCount,
|
||||
const void *const *parameters, const char *const *typeNames);
|
||||
const void *const *parameters, const char *const *typeNames,
|
||||
const QtPrivate::QMetaTypeInterface *const *metaTypes);
|
||||
};
|
||||
|
||||
struct QMetaObjectPrivate
|
||||
|
@ -70,7 +70,7 @@ class QMetaClassInfo;
|
||||
|
||||
namespace QtPrivate {
|
||||
class QMetaTypeInterface;
|
||||
template<typename T> constexpr auto typenameHelper();
|
||||
template<typename T> constexpr const QMetaTypeInterface *qMetaTypeInterfaceForType();
|
||||
}
|
||||
|
||||
struct QMethodRawArguments
|
||||
@ -130,12 +130,14 @@ public:
|
||||
|
||||
struct QMetaMethodArgument
|
||||
{
|
||||
const QtPrivate::QMetaTypeInterface *metaType;
|
||||
const char *name;
|
||||
const void *data;
|
||||
};
|
||||
|
||||
struct QMetaMethodReturnArgument
|
||||
{
|
||||
const QtPrivate::QMetaTypeInterface *metaType;
|
||||
const char *name;
|
||||
void *data;
|
||||
};
|
||||
@ -154,62 +156,70 @@ template <typename T, typename... Args> using IfNotOldStyleArgs = T;
|
||||
|
||||
template <typename T> inline QMetaMethodArgument argument(const char *name, const T &t)
|
||||
{
|
||||
return { name, std::addressof(t) };
|
||||
if constexpr ((std::is_lvalue_reference_v<T> && std::is_const_v<std::remove_reference_t<T>>) ||
|
||||
!std::is_reference_v<T>) {
|
||||
return { qMetaTypeInterfaceForType<T>(), name, std::addressof(t) };
|
||||
} else {
|
||||
return { nullptr, name, std::addressof(t) };
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T> inline QMetaMethodReturnArgument returnArgument(const char *name, T &t)
|
||||
{
|
||||
return { name, std::addressof(t) };
|
||||
return { qMetaTypeInterfaceForType<T>(), 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();
|
||||
return nullptr;
|
||||
}
|
||||
template <typename T> inline const void *dataHelper(const T &t)
|
||||
{
|
||||
return std::addressof(t);
|
||||
}
|
||||
template <typename T> inline const QMetaTypeInterface *metaTypeHelper(const T &)
|
||||
{
|
||||
return qMetaTypeInterfaceForType<T>();
|
||||
}
|
||||
|
||||
inline const char *typenameHelper(QMetaMethodArgument a)
|
||||
{ return a.name; }
|
||||
inline const void *dataHelper(QMetaMethodArgument a)
|
||||
{ return a.data; }
|
||||
inline const QMetaTypeInterface *metaTypeHelper(QMetaMethodArgument a)
|
||||
{ return a.metaType; }
|
||||
|
||||
inline const char *typenameHelper(const char *) = delete;
|
||||
template <typename T> inline const void *dataHelper(const char *) = delete;
|
||||
inline const QMetaTypeInterface *metaTypeHelper(const char *) = delete;
|
||||
inline const char *typenameHelper(const char16_t *) = delete;
|
||||
template <typename T> inline const void *dataHelper(const char16_t *) = delete;
|
||||
inline const QMetaTypeInterface *metaTypeHelper(const char16_t *) = delete;
|
||||
|
||||
} // namespace QtPrivate::Invoke
|
||||
|
||||
template <typename... Args> inline auto invokeMethodHelper(QMetaMethodReturnArgument r, Args &&... arguments)
|
||||
template <typename... Args> inline auto invokeMethodHelper(QMetaMethodReturnArgument r, const Args &... arguments)
|
||||
{
|
||||
std::array params = { const_cast<const void *>(r.data), Invoke::dataHelper(arguments)... };
|
||||
std::array names = { r.name, Invoke::typenameHelper(arguments)... };
|
||||
std::array types = { r.metaType, Invoke::metaTypeHelper(arguments)... };
|
||||
static_assert(params.size() == types.size());
|
||||
static_assert(params.size() == names.size());
|
||||
|
||||
struct R {
|
||||
decltype(params) parameters;
|
||||
decltype(names) typeNames;
|
||||
decltype(types) metaTypes;
|
||||
constexpr qsizetype parameterCount() const { return qsizetype(parameters.size()); }
|
||||
};
|
||||
return R { params, names };
|
||||
return R { params, names, types };
|
||||
}
|
||||
} // namespace QtPrivate
|
||||
|
||||
template <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);
|
||||
}
|
||||
return QtPrivate::Invoke::returnArgument(nullptr, data);
|
||||
}
|
||||
|
||||
struct Q_CORE_EXPORT QMetaObject
|
||||
@ -351,7 +361,7 @@ struct Q_CORE_EXPORT QMetaObject
|
||||
{
|
||||
auto h = QtPrivate::invokeMethodHelper(r, std::forward<Args>(arguments)...);
|
||||
return invokeMethodImpl(obj, member, c, h.parameterCount(), h.parameters.data(),
|
||||
h.typeNames.data());
|
||||
h.typeNames.data(), h.metaTypes.data());
|
||||
}
|
||||
|
||||
template <typename... Args> static
|
||||
@ -476,7 +486,8 @@ struct Q_CORE_EXPORT QMetaObject
|
||||
newInstance(Args &&... arguments) const
|
||||
{
|
||||
auto h = QtPrivate::invokeMethodHelper(QMetaMethodReturnArgument{}, std::forward<Args>(arguments)...);
|
||||
return newInstanceImpl(this, h.parameterCount(), h.parameters.data(), h.typeNames.data());
|
||||
return newInstanceImpl(this, h.parameterCount(), h.parameters.data(),
|
||||
h.typeNames.data(), h.metaTypes.data());
|
||||
}
|
||||
|
||||
enum Call {
|
||||
@ -538,10 +549,12 @@ struct Q_CORE_EXPORT QMetaObject
|
||||
|
||||
private:
|
||||
static bool invokeMethodImpl(QObject *object, const char *member, Qt::ConnectionType type,
|
||||
qsizetype parameterCount, const void *const *parameters, const char *const *names);
|
||||
qsizetype parameterCount, const void *const *parameters, const char *const *names,
|
||||
const QtPrivate::QMetaTypeInterface * const *metaTypes);
|
||||
static bool invokeMethodImpl(QObject *object, QtPrivate::QSlotObjectBase *slot, Qt::ConnectionType type, void *ret);
|
||||
static QObject *newInstanceImpl(const QMetaObject *mobj, qsizetype parameterCount,
|
||||
const void **parameters, const char **typeNames);
|
||||
const void **parameters, const char **typeNames,
|
||||
const QtPrivate::QMetaTypeInterface **metaTypes);
|
||||
friend class QTimer;
|
||||
};
|
||||
|
||||
|
@ -2,7 +2,6 @@
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
|
||||
|
||||
#include "forwarddeclared.h"
|
||||
#include "qeasingcurve.h"
|
||||
|
||||
struct MyForwardDeclaredType { };
|
||||
static MyForwardDeclaredType t;
|
||||
@ -16,18 +15,3 @@ MyForwardDeclaredType *getForwardDeclaredPointer() noexcept
|
||||
{
|
||||
return &t;
|
||||
}
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
const QEasingCurve &getEasingCurve() noexcept
|
||||
{
|
||||
return *getEasingCurvePointer();
|
||||
}
|
||||
|
||||
QEasingCurve *getEasingCurvePointer() noexcept
|
||||
{
|
||||
static QEasingCurve curve;
|
||||
return &curve;
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
@ -4,18 +4,9 @@
|
||||
#ifndef FORWARDDECLARED_H
|
||||
#define FORWARDDECLARED_H
|
||||
|
||||
#include <qglobal.h>
|
||||
|
||||
struct MyForwardDeclaredType; // and ONLY forward-declared
|
||||
|
||||
const MyForwardDeclaredType &getForwardDeclaredType() noexcept;
|
||||
MyForwardDeclaredType *getForwardDeclaredPointer() noexcept;
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QEasingCurve;
|
||||
|
||||
const QEasingCurve &getEasingCurve() noexcept;
|
||||
QEasingCurve *getEasingCurvePointer() noexcept;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // FORWARDDECLARED_H
|
||||
|
@ -31,14 +31,6 @@ Q_DECLARE_METATYPE(const QMetaObject *)
|
||||
# define Q_NO_ARG
|
||||
#endif
|
||||
|
||||
#ifdef QEASINGCURVE_H
|
||||
# error "Please make sure qeasingcurve.h is not #include'd here! " \
|
||||
"We need QEasingCurve to be only forward-declared."
|
||||
#endif
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QEasingCurve;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
struct MyStruct
|
||||
{
|
||||
int i;
|
||||
@ -519,7 +511,6 @@ public slots:
|
||||
qint64 sl14();
|
||||
qlonglong *sl15(qlonglong *);
|
||||
MyForwardDeclaredType *sl16(MyForwardDeclaredType *);
|
||||
void sl17(const QEasingCurve &curve);
|
||||
|
||||
void overloadedSlot();
|
||||
void overloadedSlot(int, int);
|
||||
@ -636,8 +627,6 @@ MyForwardDeclaredType *QtTestObject::sl16(MyForwardDeclaredType *ptr)
|
||||
slotResult += "null";
|
||||
return getForwardDeclaredPointer();
|
||||
}
|
||||
void QtTestObject::sl17(const QEasingCurve &)
|
||||
{ slotResult = "sl17"; }
|
||||
|
||||
void QtTestObject::overloadedSlot()
|
||||
{ slotResult = "overloadedSlot"; }
|
||||
@ -819,11 +808,8 @@ void tst_QMetaObject::invokeMetaMember()
|
||||
QCOMPARE(forwardPtr, getForwardDeclaredPointer());
|
||||
QCOMPARE(obj.slotResult, QString("sl16:null"));
|
||||
|
||||
// forward-declared builtin
|
||||
obj.slotResult.clear();
|
||||
QVERIFY(QMetaObject::invokeMethod(&obj, "sl17", Q_ARG(QEasingCurve, getEasingCurve())));
|
||||
QCOMPARE(obj.slotResult, "sl17");
|
||||
|
||||
#ifndef QT_NO_DATA_RELOCATION // this doesn't work with the new API on Windows
|
||||
#endif
|
||||
// test overloads
|
||||
QVERIFY(QMetaObject::invokeMethod(&obj, "overloadedSlot" Q_NO_ARG));
|
||||
QCOMPARE(obj.slotResult, QString("overloadedSlot"));
|
||||
@ -990,11 +976,6 @@ void tst_QMetaObject::invokeMetaMemberNoMacros()
|
||||
QCOMPARE(forwardPtr, getForwardDeclaredPointer());
|
||||
QCOMPARE(obj.slotResult, QString("sl16:null"));
|
||||
|
||||
// forward-declared builtin
|
||||
obj.slotResult.clear();
|
||||
QVERIFY(QMetaObject::invokeMethod(&obj, "sl17", getEasingCurve()));
|
||||
QCOMPARE(obj.slotResult, "sl17");
|
||||
|
||||
// test overloads
|
||||
QVERIFY(QMetaObject::invokeMethod(&obj, "overloadedSlot"));
|
||||
QCOMPARE(obj.slotResult, QString("overloadedSlot"));
|
||||
@ -1131,12 +1112,14 @@ void tst_QMetaObject::invokeQueuedMetaMember()
|
||||
qApp->processEvents(QEventLoop::AllEvents);
|
||||
QCOMPARE(obj.slotResult, QString("sl15"));
|
||||
|
||||
// forward-declared builtin
|
||||
// since Qt 6.5, this works even for pointers to forward-declared types
|
||||
obj.slotResult.clear();
|
||||
QVERIFY(QMetaObject::invokeMethod(&obj, "sl17", Qt::QueuedConnection, Q_ARG(QEasingCurve, getEasingCurve())));
|
||||
QVERIFY(QMetaObject::invokeMethod(&obj, "sl16", Qt::QueuedConnection, Q_ARG(MyForwardDeclaredType*, getForwardDeclaredPointer())));
|
||||
qApp->processEvents(QEventLoop::AllEvents);
|
||||
QCOMPARE(obj.slotResult, "sl17");
|
||||
QCOMPARE(obj.slotResult, QString("sl16:notnull"));
|
||||
|
||||
#ifndef QT_NO_DATA_RELOCATION // this doesn't work with the new API on Windows
|
||||
#endif
|
||||
// test overloads
|
||||
QVERIFY(QMetaObject::invokeMethod(&obj, "overloadedSlot", Qt::QueuedConnection Q_NO_ARG));
|
||||
qApp->processEvents(QEventLoop::AllEvents);
|
||||
@ -1184,6 +1167,7 @@ void tst_QMetaObject::invokeQueuedMetaMember()
|
||||
QVERIFY(!QMetaObject::invokeMethod(&obj, "testReference", Qt::QueuedConnection, Q_ARG(QString&, refStr)));
|
||||
QCOMPARE(refStr, "whatever");
|
||||
|
||||
#ifdef USE_COMPAT_Q_ARG // this doesn't compile with the new API
|
||||
obj.slotResult.clear();
|
||||
{
|
||||
const MyForwardDeclaredType &t = getForwardDeclaredType();
|
||||
@ -1201,12 +1185,7 @@ void tst_QMetaObject::invokeQueuedMetaMember()
|
||||
Q_ARG(QString, a1), Q_ARG(MyForwardDeclaredType, t)));
|
||||
QVERIFY(obj.slotResult.isEmpty());
|
||||
}
|
||||
|
||||
obj.slotResult.clear();
|
||||
QTest::ignoreMessage(QtWarningMsg, "QMetaMethod::invoke: Unable to handle unregistered datatype 'MyForwardDeclaredType*'");
|
||||
QVERIFY(!QMetaObject::invokeMethod(&obj, "sl16", Qt::QueuedConnection, Q_ARG(MyForwardDeclaredType*, getForwardDeclaredPointer())));
|
||||
qApp->processEvents(QEventLoop::AllEvents);
|
||||
QVERIFY(obj.slotResult.isEmpty());
|
||||
#endif
|
||||
}
|
||||
|
||||
// this is a copy-paste-adapt of the above
|
||||
@ -1241,11 +1220,10 @@ void tst_QMetaObject::invokeQueuedMetaMemberNoMacro()
|
||||
qApp->processEvents(QEventLoop::AllEvents);
|
||||
QCOMPARE(obj.slotResult, QString("sl15"));
|
||||
|
||||
// forward-declared builtin
|
||||
obj.slotResult.clear();
|
||||
QVERIFY(QMetaObject::invokeMethod(&obj, "sl17", Qt::QueuedConnection, getEasingCurve()));
|
||||
QVERIFY(QMetaObject::invokeMethod(&obj, "sl16", Qt::QueuedConnection, getForwardDeclaredPointer()));
|
||||
qApp->processEvents(QEventLoop::AllEvents);
|
||||
QCOMPARE(obj.slotResult, "sl17");
|
||||
QCOMPARE(obj.slotResult, QString("sl16:notnull"));
|
||||
|
||||
// test overloads
|
||||
QVERIFY(QMetaObject::invokeMethod(&obj, "overloadedSlot", Qt::QueuedConnection));
|
||||
@ -1297,6 +1275,7 @@ void tst_QMetaObject::invokeQueuedMetaMemberNoMacro()
|
||||
// QVERIFY(!QMetaObject::invokeMethod(&obj, "testReference", Qt::QueuedConnection, Q_ARG(QString&, refStr)));
|
||||
// QCOMPARE(refStr, "whatever");
|
||||
|
||||
#if 0 // this won't even compile any more
|
||||
obj.slotResult.clear();
|
||||
{
|
||||
const MyForwardDeclaredType &t = getForwardDeclaredType();
|
||||
@ -1314,12 +1293,7 @@ void tst_QMetaObject::invokeQueuedMetaMemberNoMacro()
|
||||
a1, t));
|
||||
QVERIFY(obj.slotResult.isEmpty());
|
||||
}
|
||||
|
||||
obj.slotResult.clear();
|
||||
QTest::ignoreMessage(QtWarningMsg, "QMetaMethod::invoke: Unable to handle unregistered datatype 'MyForwardDeclaredType*'");
|
||||
QVERIFY(!QMetaObject::invokeMethod(&obj, "sl16", Qt::QueuedConnection, getForwardDeclaredPointer()));
|
||||
qApp->processEvents(QEventLoop::AllEvents);
|
||||
QVERIFY(obj.slotResult.isEmpty());
|
||||
#endif
|
||||
}
|
||||
|
||||
void tst_QMetaObject::invokeQueuedPointer()
|
||||
@ -1505,11 +1479,8 @@ void tst_QMetaObject::invokeBlockingQueuedMetaMember()
|
||||
QCOMPARE(forwardPtr, getForwardDeclaredPointer());
|
||||
QCOMPARE(obj.slotResult, QString("sl16:null"));
|
||||
|
||||
// forward-declared builtin
|
||||
obj.slotResult.clear();
|
||||
QVERIFY(QMetaObject::invokeMethod(&obj, "sl17", Qt::BlockingQueuedConnection, Q_ARG(QEasingCurve, getEasingCurve())));
|
||||
QCOMPARE(obj.slotResult, "sl17");
|
||||
|
||||
#ifndef QT_NO_DATA_RELOCATION // this doesn't work with the new API on Windows
|
||||
#endif
|
||||
// test overloads
|
||||
QVERIFY(QMetaObject::invokeMethod(&obj, "overloadedSlot", Qt::BlockingQueuedConnection Q_NO_ARG));
|
||||
QCOMPARE(obj.slotResult, QString("overloadedSlot"));
|
||||
@ -1681,11 +1652,6 @@ void tst_QMetaObject::invokeBlockingQueuedMetaMemberNoMacros()
|
||||
QCOMPARE(forwardPtr, getForwardDeclaredPointer());
|
||||
QCOMPARE(obj.slotResult, QString("sl16:null"));
|
||||
|
||||
// forward-declared builtin
|
||||
obj.slotResult.clear();
|
||||
QVERIFY(QMetaObject::invokeMethod(&obj, "sl17", Qt::BlockingQueuedConnection, getEasingCurve()));
|
||||
QCOMPARE(obj.slotResult, "sl17");
|
||||
|
||||
// test overloads
|
||||
QVERIFY(QMetaObject::invokeMethod(&obj, "overloadedSlot", Qt::BlockingQueuedConnection));
|
||||
QCOMPARE(obj.slotResult, QString("overloadedSlot"));
|
||||
@ -1968,6 +1934,12 @@ void tst_QMetaObject::invokeTypedefTypes()
|
||||
QCOMPARE(spy.count(), 1);
|
||||
QCOMPARE(spy.at(0).count(), 1);
|
||||
QCOMPARE(spy.at(0).at(0), QVariant(arg));
|
||||
|
||||
spy.clear();
|
||||
QVERIFY(QMetaObject::invokeMethod(&obj, "sig_custom", arg));
|
||||
QCOMPARE(spy.count(), 1);
|
||||
QCOMPARE(spy.at(0).count(), 1);
|
||||
QCOMPARE(spy.at(0).at(0), QVariant(arg));
|
||||
}
|
||||
|
||||
void tst_QMetaObject::invokeException()
|
||||
@ -2809,7 +2781,4 @@ void tst_QMetaObject::notifySignalsInParentClass()
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QMetaObject)
|
||||
|
||||
static_assert(!QtPrivate::is_complete<QEasingCurve, void>::value,
|
||||
"QEasingCurve must only be forward-declared at this point");
|
||||
#include "tst_qmetaobject.moc"
|
||||
|
Loading…
x
Reference in New Issue
Block a user