bool PropertyCacheCreator::ensureMetaObject(int objectIndex) { if (!vmeMetaObjects.at(objectIndex).isEmpty()) return true; const QmlIR::Object *obj = qmlObjects.at(objectIndex); QQmlCompiledData::TypeReference *typeRef = resolvedTypes->value(obj->inheritedTypeNameIndex); Q_ASSERT(typeRef); QQmlPropertyCache *baseTypeCache = typeRef->createPropertyCache(QQmlEnginePrivate::get(enginePrivate)); return createMetaObject(objectIndex, obj, baseTypeCache); }
DosQMetaObject::DosQMetaObject(DosIQMetaObjectPtr superClassMetaObject, const QString &className, const SignalDefinitions &signalDefinitions, const SlotDefinitions &slotDefinitions, const PropertyDefinitions &propertyDefinitions) : BaseDosQMetaObject(nullptr) , m_superClassDosMetaObject(std::move(superClassMetaObject)) , m_signalIndexByName(QHash<QString, int>()) , m_propertySlots(QHash<QString, QPair<int, int>>()) { // We do the metaobject initialization here because // we must wait for both maps to be initialized before filling them m_metaObject.reset(createMetaObject(className, signalDefinitions, slotDefinitions, propertyDefinitions)); }
bool PropertyCacheCreator::buildMetaObjectRecursively(int objectIndex, int referencingObjectIndex, const QV4::CompiledData::Binding *instantiatingBinding) { const QmlIR::Object *obj = qmlObjects.at(objectIndex); QQmlPropertyCache *baseTypeCache = 0; QQmlPropertyData *instantiatingProperty = 0; if (instantiatingBinding && instantiatingBinding->type == QV4::CompiledData::Binding::Type_GroupProperty) { Q_ASSERT(referencingObjectIndex >= 0); QQmlPropertyCache *parentCache = propertyCaches.at(referencingObjectIndex); Q_ASSERT(parentCache); Q_ASSERT(instantiatingBinding->propertyNameIndex != 0); bool notInRevision = false; instantiatingProperty = QmlIR::PropertyResolver(parentCache).property(stringAt(instantiatingBinding->propertyNameIndex), ¬InRevision); if (instantiatingProperty) { if (instantiatingProperty->isQObject()) { baseTypeCache = enginePrivate->rawPropertyCacheForType(instantiatingProperty->propType); Q_ASSERT(baseTypeCache); } else if (QQmlValueType *vt = QQmlValueTypeFactory::valueType(instantiatingProperty->propType)) { baseTypeCache = enginePrivate->cache(vt->metaObject()); Q_ASSERT(baseTypeCache); } } } bool needVMEMetaObject = obj->propertyCount() != 0 || obj->signalCount() != 0 || obj->functionCount() != 0; if (!needVMEMetaObject) { for (const QmlIR::Binding *binding = obj->firstBinding(); 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 (instantiatingProperty && QQmlValueTypeFactory::isValueType(instantiatingProperty->propType)) { needVMEMetaObject = false; if (!ensureMetaObject(referencingObjectIndex)) return false; } break; } } } if (obj->inheritedTypeNameIndex != 0) { QQmlCompiledData::TypeReference *typeRef = resolvedTypes->value(obj->inheritedTypeNameIndex); Q_ASSERT(typeRef); if (typeRef->isFullyDynamicType) { if (obj->propertyCount() > 0) { compiler->recordError(obj->location, tr("Fully dynamic types cannot declare new properties.")); return false; } if (obj->signalCount() > 0) { compiler->recordError(obj->location, tr("Fully dynamic types cannot declare new signals.")); return false; } if (obj->functionCount() > 0) { compiler->recordError(obj->location, tr("Fully Dynamic types cannot declare new functions.")); return false; } } baseTypeCache = typeRef->createPropertyCache(QQmlEnginePrivate::get(enginePrivate)); Q_ASSERT(baseTypeCache); } else if (instantiatingBinding && instantiatingBinding->isAttachedProperty()) { QQmlCompiledData::TypeReference *typeRef = resolvedTypes->value(instantiatingBinding->propertyNameIndex); Q_ASSERT(typeRef); const QMetaObject *attachedMo = typeRef->type ? typeRef->type->attachedPropertiesType() : 0; if (!attachedMo) { compiler->recordError(instantiatingBinding->location, tr("Non-existent attached object")); return false; } baseTypeCache = enginePrivate->cache(attachedMo); Q_ASSERT(baseTypeCache); } if (needVMEMetaObject) { if (!createMetaObject(objectIndex, obj, baseTypeCache)) return false; } else if (baseTypeCache) { propertyCaches[objectIndex] = baseTypeCache; baseTypeCache->addref(); } if (propertyCaches.at(objectIndex)) { for (const QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) if (binding->type >= QV4::CompiledData::Binding::Type_Object) { if (!buildMetaObjectRecursively(binding->value.objectIndex, objectIndex, binding)) return false; } } return true; }