MetaObject: store the QMetaType of the properties

Change-Id: I563e7232b70e94de4184f2c23a581319313dcf5c
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
Olivier Goffart 2019-12-05 16:14:14 +01:00
parent a68e4f3b96
commit 46f407126e
13 changed files with 97 additions and 123 deletions

View File

@ -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<qreal>());
#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<QVariant>()) {
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<QVariant>() && 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<QVariant>() && 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<const int *>(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<QVariant>())
argv[0] = &v;
else
argv[0] = v.data();

View File

@ -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;

View File

@ -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<QtPrivate::QMetaTypeInterface **>(buf + size);
if (buf) {
meta->d.metaTypes = types;
for (const auto &prop : d->properties) {
QMetaType mt(QMetaType::type(prop.type));
*types = reinterpret_cast<QtPrivate::QMetaTypeInterface *&>(mt);
types++;
}
}
size += sizeof(QMetaType) * d->properties.size();
}
// Align the final size and return it.
ALIGN(size, void *);
Q_ASSERT(!buf || size == expectedSize);

View File

@ -2764,6 +2764,11 @@ QMetaType QMetaType::fromType()
return QMetaType(QtPrivate::qMetaTypeIntefaceForType<T>());
}
template<typename... T>
QtPrivate::QMetaTypeInterface *const qt_metaTypeArray[] = {
QtPrivate::qMetaTypeIntefaceForType<T>()...
};
QT_END_NAMESPACE
#endif // QMETATYPE_H

View File

@ -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;

View File

@ -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<QByteArray, Property>::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<const uint *>(string_data);
obj->d.superdata = &QDBusAbstractInterface::staticMetaObject;
obj->d.metaTypes = reinterpret_cast<QtPrivate::QMetaTypeInterface *const *>(metaTypes);
}
#if 0

View File

@ -77,6 +77,7 @@ struct Q_DBUS_EXPORT QDBusMetaObject: public QMetaObject
{
delete [] reinterpret_cast<const char *>(d.stringdata);
delete [] d.data;
delete [] reinterpret_cast<const QMetaType *>(d.metaTypes);
}
// methods (slots & signals):

View File

@ -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();

View File

@ -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)

View File

@ -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<MyStruct>().id());
QCOMPARE(prop.metaType(), QMetaType::fromType<MyStruct>());
qRegisterMetaType<MyStruct>("MyStruct");
QCOMPARE(prop.userType(), QMetaType::type("MyStruct"));
prop = metaObject()->property(metaObject()->indexOfProperty("value4"));
QCOMPARE(prop.type(), QVariant::List);
QCOMPARE(prop.metaType(), QMetaType::fromType<QList<QVariant>>());
prop = metaObject()->property(metaObject()->indexOfProperty("value5"));
QCOMPARE(prop.type(), QVariant::List);

View File

@ -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<QString>());
{
MyGadget g;
QString hello = QLatin1String("hello");

View File

@ -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<PropertyObject::Alpha>().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<PropertyObject::Priority>().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>("PropertyObject::Priority");
@ -2028,7 +2030,8 @@ void tst_QObject::property()
QCOMPARE(qvariant_cast<PropertyObject::Priority>(object.property("priority")), PropertyObject::VeryHigh);
QVERIFY(object.setProperty("priority", "High"));
QCOMPARE(qvariant_cast<PropertyObject::Priority>(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<PropertyObject::Priority>(var), PropertyObject::High);

View File

@ -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<FooNamespace::Enum1>().id());
QCOMPARE(prop.toInt(), int(FooNamespace::Enum1::Key2));
}