From 4d5a048d96f1161e2059315d0fe350fdcebb2e05 Mon Sep 17 00:00:00 2001 From: Fabian Kosmale Date: Tue, 18 Aug 2020 16:36:53 +0200 Subject: [PATCH] Improve connect: Use existing metatypes if possible As there is now a chance that a QMetaMethod already contains the metatypes for its arguments, we can just query it directly (and use the fallback to name lookup logic that already exists there). This also allows us to avoid creating a QList of names, and only requires us to do a name lookup in case the connection actually fails. Change-Id: Idda30bc4b538a94476ae6c533776c22340f0030d Reviewed-by: Thiago Macieira --- src/corelib/kernel/qmetaobject.cpp | 21 +++++++++++++ src/corelib/kernel/qmetaobject.h | 1 + src/corelib/kernel/qobject.cpp | 31 ++++++++++--------- .../kernel/qmetamethod/tst_qmetamethod.cpp | 27 ++++++++++++++++ 4 files changed, 65 insertions(+), 15 deletions(-) diff --git a/src/corelib/kernel/qmetaobject.cpp b/src/corelib/kernel/qmetaobject.cpp index e584fbba8e..f0cef22b6f 100644 --- a/src/corelib/kernel/qmetaobject.cpp +++ b/src/corelib/kernel/qmetaobject.cpp @@ -207,6 +207,7 @@ public: inline uint parameterTypeInfo(int index) const; inline int parameterType(int index) const; inline void getParameterTypes(int *types) const; + inline QByteArray parameterTypeName(int index) const; inline QList parameterTypes() const; inline QList parameterNames() const; inline QByteArray tag() const; @@ -1780,6 +1781,12 @@ void QMetaMethodPrivate::getParameterTypes(int *types) const } } +QByteArray QMetaMethodPrivate::parameterTypeName(int index) const +{ + int paramsIndex = parametersDataIndex(); + return typeNameFromTypeInfo(mobj, mobj->d.data[paramsIndex + index]); +} + QList QMetaMethodPrivate::parameterTypes() const { Q_ASSERT(priv(mobj->d.data)->revision >= 7); @@ -1960,6 +1967,20 @@ QList QMetaMethod::parameterTypes() const return QMetaMethodPrivate::get(this)->parameterTypes(); } +/*! + \since 6.0 + Returns the name of the type at position \a index + If there is no parameter at \a index, returns an empty QByteArray + + \sa parameterNames() + */ +QByteArray QMetaMethod::parameterTypeName(int index) const +{ + if (!mobj || index < 0 || index >= parameterCount()) + return {}; + return QMetaMethodPrivate::get(this)->parameterTypeName(index); +} + /*! Returns a list of parameter names. diff --git a/src/corelib/kernel/qmetaobject.h b/src/corelib/kernel/qmetaobject.h index d013bfce65..8136e04dc9 100644 --- a/src/corelib/kernel/qmetaobject.h +++ b/src/corelib/kernel/qmetaobject.h @@ -63,6 +63,7 @@ public: QMetaType parameterMetaType(int index) const; void getParameterTypes(int *types) const; QList parameterTypes() const; + QByteArray parameterTypeName(int index) const; QList parameterNames() const; const char *tag() const; enum Access { Private, Protected, Public }; diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index 1b8646947e..54229a9f71 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -95,28 +95,29 @@ QAbstractDynamicMetaObject::~QAbstractDynamicMetaObject() { } -static int *queuedConnectionTypes(const QList &typeNames) +static int *queuedConnectionTypes(const QMetaMethod& method) { - int *types = new int [typeNames.count() + 1]; - Q_CHECK_PTR(types); - for (int i = 0; i < typeNames.count(); ++i) { - const QByteArray typeName = typeNames.at(i); - if (typeName.endsWith('*')) - types[i] = QMetaType::VoidStar; + const auto parameterCount = method.parameterCount(); + int *typeIds = new int [parameterCount + 1]; + Q_CHECK_PTR(typeIds); + for (int i = 0; i < parameterCount; ++i) { + const QMetaType metaType = method.parameterMetaType(i); + if (metaType.flags() & QMetaType::IsPointer) + typeIds[i] = QMetaType::VoidStar; else - types[i] = QMetaType::fromName(typeName).id(); - - if (!types[i]) { + typeIds[i] = metaType.id(); + if (!typeIds[i]) { + const QByteArray typeName = method.parameterTypeName(i); qWarning("QObject::connect: Cannot queue arguments of type '%s'\n" "(Make sure '%s' is registered using qRegisterMetaType().)", typeName.constData(), typeName.constData()); - delete [] types; + delete [] typeIds; return nullptr; } } - types[typeNames.count()] = 0; + typeIds[parameterCount] = 0; - return types; + return typeIds; } static int *queuedConnectionTypes(const QArgumentType *argumentTypes, int argc) @@ -2871,7 +2872,7 @@ QMetaObject::Connection QObject::connect(const QObject *sender, const QMetaMetho int *types = nullptr; if ((type == Qt::QueuedConnection) - && !(types = queuedConnectionTypes(signal.parameterTypes()))) + && !(types = queuedConnectionTypes(signal))) return QMetaObject::Connection(nullptr); #ifndef QT_NO_DEBUG @@ -3615,7 +3616,7 @@ static void queued_activate(QObject *sender, int signal, QObjectPrivate::Connect const int *argumentTypes = c->argumentTypes.loadRelaxed(); if (!argumentTypes) { QMetaMethod m = QMetaObjectPrivate::signal(sender->metaObject(), signal); - argumentTypes = queuedConnectionTypes(m.parameterTypes()); + argumentTypes = queuedConnectionTypes(m); if (!argumentTypes) // cannot queue arguments argumentTypes = &DIRECT_CONNECTION_ONLY; if (!c->argumentTypes.testAndSetOrdered(nullptr, argumentTypes)) { diff --git a/tests/auto/corelib/kernel/qmetamethod/tst_qmetamethod.cpp b/tests/auto/corelib/kernel/qmetamethod/tst_qmetamethod.cpp index 03c76aba5d..942f075723 100644 --- a/tests/auto/corelib/kernel/qmetamethod/tst_qmetamethod.cpp +++ b/tests/auto/corelib/kernel/qmetamethod/tst_qmetamethod.cpp @@ -52,6 +52,8 @@ private slots: void returnMetaType(); void parameterMetaType(); + + void parameterTypeName(); }; struct CustomType { }; @@ -632,6 +634,12 @@ void tst_QMetaMethod::method() QCOMPARE(QMetaType::fromName(method.typeName()), QMetaType::fromName(returnTypeName)); } + // check that parameterNames and parameterTypeName agree + const auto methodParmaterTypes = method.parameterTypes(); + for (int i = 0; i< methodParmaterTypes.size(); ++i) { + QCOMPARE(methodParmaterTypes[i], method.parameterTypeName(i)); + } + if (method.parameterTypes() != parameterTypeNames) { // QMetaMethod should always produce semantically equivalent typenames QList actualTypeNames = method.parameterTypes(); @@ -839,5 +847,24 @@ void tst_QMetaMethod::parameterMetaType() } +void tst_QMetaMethod::parameterTypeName() +{ + auto mo = MyTestClass::staticMetaObject; + const auto normalized = QMetaObject::normalizedSignature("doStuff(int, float, MyGadget)"); + const int idx = mo.indexOfSlot(normalized); + QMetaMethod mm = mo.method(idx); + { + // check invalid indices + QVERIFY(mm.parameterTypeName(-1).isEmpty()); + QVERIFY(mm.parameterTypeName(3).isEmpty()); + } + { + QCOMPARE(mm.parameterTypeName(0), QByteArray("int")); + QCOMPARE(mm.parameterTypeName(1), QByteArray("float")); + QCOMPARE(mm.parameterTypeName(2), QByteArray("MyGadget")); + } +} + + QTEST_MAIN(tst_QMetaMethod) #include "tst_qmetamethod.moc"