From 46f407126ef3e94d59254012cdc34d6a4ad2faf2 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Thu, 5 Dec 2019 16:14:14 +0100 Subject: MetaObject: store the QMetaType of the properties Change-Id: I563e7232b70e94de4184f2c23a581319313dcf5c Reviewed-by: Thiago Macieira --- src/corelib/kernel/qmetaobject.cpp | 154 +++++---------------- src/corelib/kernel/qmetaobject.h | 1 + src/corelib/kernel/qmetaobjectbuilder.cpp | 15 ++ src/corelib/kernel/qmetatype.h | 5 + src/corelib/kernel/qobjectdefs.h | 5 + src/dbus/qdbusmetaobject.cpp | 6 + src/dbus/qdbusmetaobject_p.h | 1 + .../themes/genericunix/dbustray/qdbustrayicon_p.h | 1 + src/tools/moc/generator.cpp | 12 ++ .../corelib/kernel/qmetaobject/tst_qmetaobject.cpp | 4 +- .../kernel/qmetaproperty/tst_qmetaproperty.cpp | 1 + tests/auto/corelib/kernel/qobject/tst_qobject.cpp | 13 +- tests/auto/tools/moc/tst_moc.cpp | 2 +- 13 files changed, 97 insertions(+), 123 deletions(-) diff --git a/src/corelib/kernel/qmetaobject.cpp b/src/corelib/kernel/qmetaobject.cpp index 62de104c30..9be99d8c6a 100644 --- a/src/corelib/kernel/qmetaobject.cpp +++ b/src/corelib/kernel/qmetaobject.cpp @@ -2833,10 +2833,6 @@ QByteArray QMetaEnum::valueToKeys(int value) const The enum needs to be declared with Q_ENUM. */ -static QByteArray qualifiedName(const QMetaEnum &e) -{ - return QByteArray(e.scope()) + "::" + e.name(); -} /*! \class QMetaProperty @@ -2927,65 +2923,45 @@ const char *QMetaProperty::typeName() const Returns this property's type. The return value is one of the values of the QVariant::Type enumeration. - \sa userType(), typeName(), name() + \sa userType(), typeName(), name(), metaType() */ QVariant::Type QMetaProperty::type() const { - if (!mobj) - return QVariant::Invalid; - int handle = priv(mobj->d.data)->propertyData + 3*idx; - - Q_ASSERT(priv(mobj->d.data)->revision >= 7); - uint type = typeFromTypeInfo(mobj, mobj->d.data[handle + 1]); + uint type = userType(); if (type >= QMetaType::User) return QVariant::UserType; - if (type != QMetaType::UnknownType) - return QVariant::Type(type); - if (isEnumType()) { - int enumMetaTypeId = QMetaType::type(qualifiedName(menum)); - if (enumMetaTypeId == QMetaType::UnknownType) - return QVariant::Int; - } -#ifdef QT_COORD_TYPE - // qreal metatype must be resolved at runtime. - if (strcmp(typeName(), "qreal") == 0) - return QVariant::Type(qMetaTypeId()); -#endif - - return QVariant::UserType; + return QVariant::Type(type); } /*! \since 4.2 Returns this property's user type. The return value is one - of the values that are registered with QMetaType, or QMetaType::UnknownType if - the type is not registered. + of the values that are registered with QMetaType. - \sa type(), QMetaType, typeName() + This is equivalent to metaType().id() + + \sa type(), QMetaType, typeName(), metaType() */ int QMetaProperty::userType() const { if (!mobj) return QMetaType::UnknownType; - Q_ASSERT(priv(mobj->d.data)->revision >= 7); - int handle = priv(mobj->d.data)->propertyData + 3*idx; - int type = typeFromTypeInfo(mobj, mobj->d.data[handle + 1]); - if (type != QMetaType::UnknownType) - return type; - if (isEnumType()) { - type = QMetaType::type(qualifiedName(menum)); - if (type == QMetaType::UnknownType) { - type = registerPropertyType(); - if (type == QMetaType::UnknownType) - return QMetaType::Int; // Match behavior of QMetaType::type() - } - return type; - } - type = QMetaType::type(typeName()); - if (type != QMetaType::UnknownType) - return type; - return registerPropertyType(); + return QMetaType(mobj->d.metaTypes[idx]).id(); +} + +/*! + \since 6.0 + + Returns this property's QMetaType. + + \sa QMetaType + */ +QMetaType QMetaProperty::metaType() const +{ + if (!mobj) + return {}; + return QMetaType(mobj->d.metaTypes[idx]); } /*! @@ -3096,37 +3072,6 @@ QVariant QMetaProperty::read(const QObject *object) const if (!object || !mobj) return QVariant(); - uint t = QMetaType::Int; - if (isEnumType()) { - /* - try to create a QVariant that can be converted to this enum - type (only works if the enum has already been registered - with QMetaType) - */ - int enumMetaTypeId = QMetaType::type(qualifiedName(menum)); - if (enumMetaTypeId != QMetaType::UnknownType) - t = enumMetaTypeId; - } else { - int handle = priv(mobj->d.data)->propertyData + 3*idx; - const char *typeName = nullptr; - Q_ASSERT(priv(mobj->d.data)->revision >= 7); - uint typeInfo = mobj->d.data[handle + 1]; - if (!(typeInfo & IsUnresolvedType)) - t = typeInfo; - else { - typeName = rawStringData(mobj, typeInfo & TypeNameIndexMask); - t = QMetaType::type(typeName); - } - if (t == QMetaType::UnknownType) { - // Try to register the type and try again before reporting an error. - t = registerPropertyType(); - if (t == QMetaType::UnknownType) { - qWarning("QMetaProperty::read: Unable to handle unregistered datatype '%s' for property '%s::%s'", typeName, mobj->className(), name()); - return QVariant(); - } - } - } - // the status variable is changed by qt_metacall to indicate what it did // this feature is currently only used by Qt D-Bus and should not be depended // upon. Don't change it without looking into QDBusAbstractInterface first @@ -3135,10 +3080,11 @@ QVariant QMetaProperty::read(const QObject *object) const int status = -1; QVariant value; void *argv[] = { nullptr, &value, &status }; - if (t == QMetaType::QVariant) { + QMetaType t(mobj->d.metaTypes[idx]); + if (t == QMetaType::fromType()) { argv[0] = &value; } else { - value = QVariant(t, (void*)nullptr); + value = QVariant(t, nullptr); argv[0] = value.data(); } if (priv(mobj->d.data)->flags & PropertyAccessInStaticMetaCall && mobj->d.static_metacall) { @@ -3150,9 +3096,9 @@ QVariant QMetaProperty::read(const QObject *object) const if (status != -1) return value; - if (t != QMetaType::QVariant && argv[0] != value.data()) + if (t != QMetaType::fromType() && argv[0] != value.data()) // pointer or reference - return QVariant((QVariant::Type)t, argv[0]); + return QVariant(t, argv[0]); return value; } @@ -3173,9 +3119,10 @@ bool QMetaProperty::write(QObject *object, const QVariant &value) const return false; QVariant v = value; - uint t = QMetaType::UnknownType; - if (isEnumType()) { - if (v.userType() == QMetaType::QString) { + QMetaType t(mobj->d.metaTypes[idx]); + if (t != QMetaType::fromType() && t != v.metaType()) { + if (isEnumType() && !t.metaObject() && v.userType() == QMetaType::QString) { + // Assigning a string to a property of type Q_ENUMS (instead of Q_ENUM) bool ok; if (isFlagType()) v = QVariant(menum.keysToValue(value.toByteArray(), &ok)); @@ -3183,39 +3130,14 @@ bool QMetaProperty::write(QObject *object, const QVariant &value) const v = QVariant(menum.keyToValue(value.toByteArray(), &ok)); if (!ok) return false; - } else if (v.userType() != QMetaType::Int && v.userType() != QMetaType::UInt) { - int enumMetaTypeId = QMetaType::type(qualifiedName(menum)); - if ((enumMetaTypeId == QMetaType::UnknownType) || (v.userType() != enumMetaTypeId) || !v.constData()) - return false; - v = QVariant(*reinterpret_cast(v.constData())); - } - v.convert(QMetaType::Int); - } else { - int handle = priv(mobj->d.data)->propertyData + 3*idx; - const char *typeName = nullptr; - Q_ASSERT(priv(mobj->d.data)->revision >= 7); - uint typeInfo = mobj->d.data[handle + 1]; - if (!(typeInfo & IsUnresolvedType)) - t = typeInfo; - else { - typeName = rawStringData(mobj, typeInfo & TypeNameIndexMask); - t = QMetaType::type(typeName); - if (t == QMetaType::UnknownType) - t = registerPropertyType(); - if (t == QMetaType::UnknownType) - return false; - } - if (t != QMetaType::QVariant && int(t) != value.userType()) { - if (!value.isValid()) { - if (isResettable()) - return reset(object); - v = QVariant(t, nullptr); - } else if (!v.convert(t)) { - return false; - } + } else if (!value.isValid()) { + if (isResettable()) + return reset(object); + v = QVariant(t, nullptr); + } else if (!v.convert(t.id())) { + return false; } } - // the status variable is changed by qt_metacall to indicate what it did // this feature is currently only used by Qt D-Bus and should not be depended // upon. Don't change it without looking into QDBusAbstractInterface first @@ -3226,7 +3148,7 @@ bool QMetaProperty::write(QObject *object, const QVariant &value) const // interception of property writes. int flags = 0; void *argv[] = { nullptr, &v, &status, &flags }; - if (t == QMetaType::QVariant) + if (t == QMetaType::fromType()) argv[0] = &v; else argv[0] = v.data(); diff --git a/src/corelib/kernel/qmetaobject.h b/src/corelib/kernel/qmetaobject.h index d0c4b489a6..08adc495e0 100644 --- a/src/corelib/kernel/qmetaobject.h +++ b/src/corelib/kernel/qmetaobject.h @@ -250,6 +250,7 @@ public: const char *typeName() const; QVariant::Type type() const; int userType() const; + QMetaType metaType() const; int propertyIndex() const; int relativePropertyIndex() const; diff --git a/src/corelib/kernel/qmetaobjectbuilder.cpp b/src/corelib/kernel/qmetaobjectbuilder.cpp index d02708540a..cd5caad0a7 100644 --- a/src/corelib/kernel/qmetaobjectbuilder.cpp +++ b/src/corelib/kernel/qmetaobjectbuilder.cpp @@ -1196,6 +1196,7 @@ static int buildMetaObject(QMetaObjectBuilderPrivate *d, char *buf, if (!relocatable) meta->d.superdata = d->superClass; meta->d.relatedMetaObjects = nullptr; meta->d.extradata = nullptr; + meta->d.metaTypes = nullptr; meta->d.static_metacall = d->staticMetacallFunction; } @@ -1474,6 +1475,20 @@ static int buildMetaObject(QMetaObjectBuilderPrivate *d, char *buf, size += sizeof(SuperData) * (d->relatedMetaObjects.size() + 1); } + if (d->properties.size() > 0) { + ALIGN(size, QtPrivate::QMetaTypeInterface *); + auto types = reinterpret_cast(buf + size); + if (buf) { + meta->d.metaTypes = types; + for (const auto &prop : d->properties) { + QMetaType mt(QMetaType::type(prop.type)); + *types = reinterpret_cast(mt); + types++; + } + } + size += sizeof(QMetaType) * d->properties.size(); + } + // Align the final size and return it. ALIGN(size, void *); Q_ASSERT(!buf || size == expectedSize); diff --git a/src/corelib/kernel/qmetatype.h b/src/corelib/kernel/qmetatype.h index 8bc560dc6c..32d45b34ff 100644 --- a/src/corelib/kernel/qmetatype.h +++ b/src/corelib/kernel/qmetatype.h @@ -2764,6 +2764,11 @@ QMetaType QMetaType::fromType() return QMetaType(QtPrivate::qMetaTypeIntefaceForType()); } +template +QtPrivate::QMetaTypeInterface *const qt_metaTypeArray[] = { + QtPrivate::qMetaTypeIntefaceForType()... +}; + QT_END_NAMESPACE #endif // QMETATYPE_H diff --git a/src/corelib/kernel/qobjectdefs.h b/src/corelib/kernel/qobjectdefs.h index 657cb9940b..b84b5a503f 100644 --- a/src/corelib/kernel/qobjectdefs.h +++ b/src/corelib/kernel/qobjectdefs.h @@ -101,6 +101,10 @@ class QMetaEnum; class QMetaProperty; class QMetaClassInfo; +namespace QtPrivate { +class QMetaTypeInterface; +} + struct QMethodRawArguments { void **arguments; @@ -428,6 +432,7 @@ struct Q_CORE_EXPORT QMetaObject typedef void (*StaticMetacallFunction)(QObject *, QMetaObject::Call, int, void **); StaticMetacallFunction static_metacall; const SuperData *relatedMetaObjects; + QtPrivate::QMetaTypeInterface *const *metaTypes; void *extradata; //reserved for future use } d; diff --git a/src/dbus/qdbusmetaobject.cpp b/src/dbus/qdbusmetaobject.cpp index bfda2aa9b6..dcbed5a6f8 100644 --- a/src/dbus/qdbusmetaobject.cpp +++ b/src/dbus/qdbusmetaobject.cpp @@ -521,6 +521,9 @@ void QDBusMetaObjectGenerator::write(QDBusMetaObject *obj) offset += methodParametersDataSize; Q_ASSERT(offset == header->propertyData); + QMetaType *metaTypes = new QMetaType[properties.count()]; + int propertyId = 0; + // add each property signatureOffset = header->propertyDBusData; for (QMap::ConstIterator it = properties.constBegin(); @@ -535,6 +538,8 @@ void QDBusMetaObjectGenerator::write(QDBusMetaObject *obj) idata[signatureOffset++] = strings.enter(mp.signature); idata[signatureOffset++] = mp.type; + + metaTypes[propertyId++] = QMetaType(mp.type); } Q_ASSERT(offset == header->propertyDBusData); @@ -553,6 +558,7 @@ void QDBusMetaObjectGenerator::write(QDBusMetaObject *obj) obj->d.extradata = nullptr; obj->d.stringdata = reinterpret_cast(string_data); obj->d.superdata = &QDBusAbstractInterface::staticMetaObject; + obj->d.metaTypes = reinterpret_cast(metaTypes); } #if 0 diff --git a/src/dbus/qdbusmetaobject_p.h b/src/dbus/qdbusmetaobject_p.h index 89fccf9046..a4ed3c355c 100644 --- a/src/dbus/qdbusmetaobject_p.h +++ b/src/dbus/qdbusmetaobject_p.h @@ -77,6 +77,7 @@ struct Q_DBUS_EXPORT QDBusMetaObject: public QMetaObject { delete [] reinterpret_cast(d.stringdata); delete [] d.data; + delete [] reinterpret_cast(d.metaTypes); } // methods (slots & signals): diff --git a/src/platformsupport/themes/genericunix/dbustray/qdbustrayicon_p.h b/src/platformsupport/themes/genericunix/dbustray/qdbustrayicon_p.h index 7034a7edb4..edc115742c 100644 --- a/src/platformsupport/themes/genericunix/dbustray/qdbustrayicon_p.h +++ b/src/platformsupport/themes/genericunix/dbustray/qdbustrayicon_p.h @@ -83,6 +83,7 @@ class QDBusTrayIcon: public QPlatformSystemTrayIcon Q_PROPERTY(QString attentionIconName READ attentionIconName NOTIFY attention) Q_PROPERTY(QIcon attentionIcon READ attentionIcon NOTIFY attention) Q_PROPERTY(QDBusPlatformMenu *menu READ menu NOTIFY menuChanged) + Q_MOC_INCLUDE("qdbusplatformmenu_p.h") public: QDBusTrayIcon(); diff --git a/src/tools/moc/generator.cpp b/src/tools/moc/generator.cpp index 93bc4d8c4e..b4fe6a765e 100644 --- a/src/tools/moc/generator.cpp +++ b/src/tools/moc/generator.cpp @@ -552,6 +552,18 @@ void Generator::generateCode() fprintf(out, " nullptr,\n"); else fprintf(out, " qt_meta_extradata_%s,\n", qualifiedClassNameIdentifier.constData()); + + if (cdef->propertyList.isEmpty()) { + fprintf(out, " nullptr,\n"); + } else { + fprintf(out, "qt_metaTypeArray<\n"); + for (int i = 0; i < cdef->propertyList.count(); ++i) { + const PropertyDef &p = cdef->propertyList.at(i); + fprintf(out, "%s%s", i == 0 ? "" : ", ", p.type.data()); + } + fprintf(out, ">,\n"); + } + fprintf(out, " nullptr\n} };\n\n"); if (!cdef->hasQObject) diff --git a/tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp b/tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp index bcd4a66782..9db2bb241a 100644 --- a/tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp +++ b/tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp @@ -1446,13 +1446,15 @@ void tst_QMetaObject::customPropertyType() QMetaProperty prop = metaObject()->property(metaObject()->indexOfProperty("value3")); QCOMPARE(prop.type(), QVariant::UserType); - QCOMPARE(prop.userType(), 0); + QCOMPARE(prop.userType(), QMetaType::fromType().id()); + QCOMPARE(prop.metaType(), QMetaType::fromType()); qRegisterMetaType("MyStruct"); QCOMPARE(prop.userType(), QMetaType::type("MyStruct")); prop = metaObject()->property(metaObject()->indexOfProperty("value4")); QCOMPARE(prop.type(), QVariant::List); + QCOMPARE(prop.metaType(), QMetaType::fromType>()); prop = metaObject()->property(metaObject()->indexOfProperty("value5")); QCOMPARE(prop.type(), QVariant::List); diff --git a/tests/auto/corelib/kernel/qmetaproperty/tst_qmetaproperty.cpp b/tests/auto/corelib/kernel/qmetaproperty/tst_qmetaproperty.cpp index cc67fc7884..43ed535019 100644 --- a/tests/auto/corelib/kernel/qmetaproperty/tst_qmetaproperty.cpp +++ b/tests/auto/corelib/kernel/qmetaproperty/tst_qmetaproperty.cpp @@ -138,6 +138,7 @@ void tst_QMetaProperty::gadget() const QMetaObject *mo = &MyGadget::staticMetaObject; QMetaProperty valueProp = mo->property(mo->indexOfProperty("value")); QVERIFY(valueProp.isValid()); + QCOMPARE(valueProp.metaType(), QMetaType::fromType()); { MyGadget g; QString hello = QLatin1String("hello"); diff --git a/tests/auto/corelib/kernel/qobject/tst_qobject.cpp b/tests/auto/corelib/kernel/qobject/tst_qobject.cpp index 5ce70f7a0e..b1d3ea19d6 100644 --- a/tests/auto/corelib/kernel/qobject/tst_qobject.cpp +++ b/tests/auto/corelib/kernel/qobject/tst_qobject.cpp @@ -1914,7 +1914,7 @@ void tst_QObject::property() property = mo->property(mo->indexOfProperty("alpha")); QVERIFY(property.isEnumType()); QCOMPARE(property.typeName(), "Alpha"); - QCOMPARE(property.type(), QVariant::Int); + QCOMPARE(property.userType(), QMetaType::fromType().id()); QVariant var = object.property("alpha"); QVERIFY(!var.isNull()); @@ -1925,7 +1925,8 @@ void tst_QObject::property() QCOMPARE(object.property("alpha").toInt(), int(PropertyObject::Alpha2)); QVERIFY(object.setProperty("alpha", "Alpha1")); QCOMPARE(object.property("alpha").toInt(), int(PropertyObject::Alpha1)); - QVERIFY(!object.setProperty("alpha", QVariant())); + QVERIFY(object.setProperty("alpha", QVariant())); + QCOMPARE(object.property("alpha").toInt(), 0); QVERIFY(mo->indexOfProperty("number") != -1); QCOMPARE(object.property("number").toInt(), 0); @@ -1995,7 +1996,7 @@ void tst_QObject::property() property = mo->property(mo->indexOfProperty("priority")); QVERIFY(property.isEnumType()); QCOMPARE(property.typeName(), "Priority"); - QCOMPARE(property.type(), QVariant::Int); + QCOMPARE(property.userType(), QMetaType::fromType().id()); var = object.property("priority"); QVERIFY(!var.isNull()); @@ -2006,7 +2007,8 @@ void tst_QObject::property() QCOMPARE(object.property("priority").toInt(), int(PropertyObject::VeryHigh)); QVERIFY(object.setProperty("priority", "High")); QCOMPARE(object.property("priority").toInt(), int(PropertyObject::High)); - QVERIFY(!object.setProperty("priority", QVariant())); + QVERIFY(object.setProperty("priority", QVariant())); + QCOMPARE(object.property("priority").toInt(), 0); // now it's registered, so it works as expected int priorityMetaTypeId = qRegisterMetaType("PropertyObject::Priority"); @@ -2028,7 +2030,8 @@ void tst_QObject::property() QCOMPARE(qvariant_cast(object.property("priority")), PropertyObject::VeryHigh); QVERIFY(object.setProperty("priority", "High")); QCOMPARE(qvariant_cast(object.property("priority")), PropertyObject::High); - QVERIFY(!object.setProperty("priority", QVariant())); + QVERIFY(object.setProperty("priority", QVariant())); + QCOMPARE(object.property("priority").toInt(), 0); var = object.property("priority"); QCOMPARE(qvariant_cast(var), PropertyObject::High); diff --git a/tests/auto/tools/moc/tst_moc.cpp b/tests/auto/tools/moc/tst_moc.cpp index 08c604e37e..31fe68a64e 100644 --- a/tests/auto/tools/moc/tst_moc.cpp +++ b/tests/auto/tools/moc/tst_moc.cpp @@ -3945,7 +3945,7 @@ void tst_Moc::testQNamespace() EnumFromNamespaceClass obj; const QVariant prop = obj.property("prop"); - QCOMPARE(prop.type(), QMetaType::Int); + QCOMPARE(prop.userType(), QMetaType::fromType().id()); QCOMPARE(prop.toInt(), int(FooNamespace::Enum1::Key2)); } -- cgit v1.2.3