aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/qml/qqmlglobal.cpp
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2023-06-22 12:03:28 +0200
committerUlf Hermann <ulf.hermann@qt.io>2023-06-23 21:23:05 +0200
commit29f3bbb0622f2449741b45e002a059850993561c (patch)
tree9ca92bf486cbf9609e46ea0792ddac6021118d4f /src/qml/qml/qqmlglobal.cpp
parent8889089d0fd8ab93f623a98992588087e45399a5 (diff)
QtQml: Improve qmlobject_can_qml_cast
Composite types don't readily expose their metaobjects because they are expensive to create. We can use the property caches instead. Change-Id: Idd5cc96d22489b9d0868d3955bf373c479e17c69 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'src/qml/qml/qqmlglobal.cpp')
-rw-r--r--src/qml/qml/qqmlglobal.cpp45
1 files changed, 39 insertions, 6 deletions
diff --git a/src/qml/qml/qqmlglobal.cpp b/src/qml/qml/qqmlglobal.cpp
index 730687fc2f..045b6fc948 100644
--- a/src/qml/qml/qqmlglobal.cpp
+++ b/src/qml/qml/qqmlglobal.cpp
@@ -924,12 +924,45 @@ bool qmlobject_can_cpp_cast(QObject *object, const QMetaObject *mo)
return object->metaObject()->inherits(mo);
}
-bool qmlobject_can_qml_cast(QObject *object, const QMetaObject *mo)
-{
- Q_ASSERT(mo);
- if (const QQmlData *ddata = ddata_for_cast(object))
- return ddata->propertyCache->metaObject()->inherits(mo);
- return object->metaObject()->inherits(mo);
+bool qmlobject_can_qml_cast(QObject *object, const QQmlType &type)
+{
+ Q_ASSERT(type.isValid());
+
+ // A non-composite type will always have a metaobject.
+ const QMetaObject *typeMetaObject = type.metaObject();
+ const QQmlPropertyCache::ConstPtr typePropertyCache = typeMetaObject
+ ? QQmlPropertyCache::ConstPtr()
+ : QQmlMetaType::findPropertyCacheInCompositeTypes(type.typeId());
+
+ if (const QQmlData *ddata = ddata_for_cast(object)) {
+ for (const QQmlPropertyCache *propertyCache = ddata->propertyCache.data(); propertyCache;
+ propertyCache = propertyCache->parent().data()) {
+
+ if (typeMetaObject) {
+ // Prefer the metaobject inheritance mechanism, since it is more accurate.
+ //
+ // Assume the object can be casted to the type. Then, if we have a type metaobject,
+ // the object's property cache inheritance has to contain it. Otherwise we would
+ // end up with diverging metaobject hierarchies if we created the object's
+ // metaobject. This would be a disaster.
+ if (const QMetaObject *objectMetaObject = propertyCache->metaObject())
+ return objectMetaObject->inherits(typeMetaObject);
+ } else {
+ // This is a best effort attempt. There are a number of ways for the
+ // property caches to be unrelated but the types still convertible.
+ // Multiple property caches can hold the same metaobject, for example for
+ // versions of non-composite types.
+ if (propertyCache == typePropertyCache.data())
+ return true;
+ }
+ }
+ }
+
+ // If nothing else works, we have to create the metaobjects.
+
+ return object->metaObject()->inherits(typeMetaObject
+ ? typeMetaObject
+ : (typePropertyCache ? typePropertyCache->createMetaObject() : nullptr));
}
QT_END_NAMESPACE