diff options
Diffstat (limited to 'src/qml/compiler/qqmltypecompiler.cpp')
-rw-r--r-- | src/qml/compiler/qqmltypecompiler.cpp | 96 |
1 files changed, 75 insertions, 21 deletions
diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp index 0c4ebcdf01..dd4f15d0e6 100644 --- a/src/qml/compiler/qqmltypecompiler.cpp +++ b/src/qml/compiler/qqmltypecompiler.cpp @@ -323,27 +323,8 @@ bool QQmlPropertyCacheCreator::buildMetaObjects() propertyCaches.resize(qmlObjects.count()); vmeMetaObjects.resize(qmlObjects.count()); - for (int i = 0; i < qmlObjects.count(); ++i) { - const QtQml::QmlObject *obj = qmlObjects.at(i); - - // If the object has no type, then it's probably a nested object definition as part - // of a group property. - const bool objectHasType = !stringAt(obj->inheritedTypeNameIndex).isEmpty(); - if (objectHasType) { - QQmlCompiledData::TypeReference typeRef = resolvedTypes->value(obj->inheritedTypeNameIndex); - QQmlPropertyCache *baseTypeCache = typeRef.createPropertyCache(QQmlEnginePrivate::get(enginePrivate)); - Q_ASSERT(baseTypeCache); - - bool needVMEMetaObject = obj->properties->count != 0 || obj->qmlSignals->count != 0 || obj->functions->count != 0; - if (needVMEMetaObject) { - if (!createMetaObject(i, obj, baseTypeCache)) - return false; - } else { - propertyCaches[i] = baseTypeCache; - baseTypeCache->addref(); - } - } - } + if (!buildMetaObjectRecursively(compiler->rootObjectIndex(), /*referencing object*/-1, /*instantiating binding*/0)) + return false; compiler->setVMEMetaObjects(vmeMetaObjects); compiler->setPropertyCaches(propertyCaches); @@ -352,6 +333,79 @@ bool QQmlPropertyCacheCreator::buildMetaObjects() return true; } +bool QQmlPropertyCacheCreator::buildMetaObjectRecursively(int objectIndex, int referencingObjectIndex, const QV4::CompiledData::Binding *instantiatingBinding) +{ + const QmlObject *obj = qmlObjects.at(objectIndex); + + QQmlPropertyCache *baseTypeCache = 0; + + bool needVMEMetaObject = obj->properties->count != 0 || obj->qmlSignals->count != 0 || obj->functions->count != 0; + if (!needVMEMetaObject) { + for (const QtQml::Binding *binding = obj->bindings->first; binding; binding = binding->next) { + if (binding->type == QV4::CompiledData::Binding::Type_Object && (binding->flags & QV4::CompiledData::Binding::IsOnAssignment)) { + + // On assignments are implemented using value interceptors, which require a VME meta object. + needVMEMetaObject = true; + + // If the on assignment is inside a group property, we need to distinguish between QObject based + // group properties and value type group properties. For the former the base type is derived from + // the property that references us, for the latter we only need a meta-object on the referencing object + // because interceptors can't go to the shared value type instances. + if (instantiatingBinding && instantiatingBinding->type == QV4::CompiledData::Binding::Type_GroupProperty) { + QQmlPropertyCache *parentCache = propertyCaches.at(referencingObjectIndex); + Q_ASSERT(parentCache); + Q_ASSERT(!stringAt(instantiatingBinding->propertyNameIndex).isEmpty()); + + bool notInRevision = false; + QQmlPropertyData *pd = PropertyResolver(parentCache).property(stringAt(instantiatingBinding->propertyNameIndex), ¬InRevision); + Q_ASSERT(pd); + if (QQmlValueTypeFactory::isValueType(pd->propType)) { + needVMEMetaObject = false; + if (!ensureMetaObject(referencingObjectIndex)) + return false; + } else if (pd->isQObject()) { + baseTypeCache = enginePrivate->rawPropertyCacheForType(pd->propType); + Q_ASSERT(baseTypeCache); + } + } + break; + } + } + } + + QString typeName = stringAt(obj->inheritedTypeNameIndex); + if (!typeName.isEmpty()) { + QQmlCompiledData::TypeReference typeRef = resolvedTypes->value(obj->inheritedTypeNameIndex); + baseTypeCache = typeRef.createPropertyCache(QQmlEnginePrivate::get(enginePrivate)); + Q_ASSERT(baseTypeCache); + } + + if (needVMEMetaObject) { + if (!createMetaObject(objectIndex, obj, baseTypeCache)) + return false; + } else if (baseTypeCache) { + propertyCaches[objectIndex] = baseTypeCache; + baseTypeCache->addref(); + } + + for (const QtQml::Binding *binding = obj->bindings->first; binding; binding = binding->next) + if (binding->type >= QV4::CompiledData::Binding::Type_Object) + if (!buildMetaObjectRecursively(binding->value.objectIndex, objectIndex, binding)) + return false; + + return true; +} + +bool QQmlPropertyCacheCreator::ensureMetaObject(int objectIndex) +{ + if (!vmeMetaObjects.at(objectIndex).isEmpty()) + return true; + const QtQml::QmlObject *obj = qmlObjects.at(objectIndex); + QQmlCompiledData::TypeReference typeRef = resolvedTypes->value(obj->inheritedTypeNameIndex); + QQmlPropertyCache *baseTypeCache = typeRef.createPropertyCache(QQmlEnginePrivate::get(enginePrivate)); + return createMetaObject(objectIndex, obj, baseTypeCache); +} + bool QQmlPropertyCacheCreator::createMetaObject(int objectIndex, const QtQml::QmlObject *obj, QQmlPropertyCache *baseTypeCache) { QQmlPropertyCache *cache = baseTypeCache->copyAndReserve(QQmlEnginePrivate::get(enginePrivate), |