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; }
bool QmcTypeUnitComponentAndAliasResolver::addAliases() { // add aliases //QmcUnitAlias al = {0, 0, 0, 8, 0, 0, 24}; //qmcTypeUnit->unit->aliases.append(al); // see QQmlComponentAndAliasResolver::resolve int effectiveAliasIndex = -1; int effectivePropertyIndex = -1; int effectiveSignalIndex = -1; int currentObjectIndex = -1; QQmlPropertyCache *propertyCache = NULL; foreach (const QmcUnitAlias &alias, qmcTypeUnit->unit->aliases) { if ((int)alias.objectIndex != currentObjectIndex) { currentObjectIndex = alias.objectIndex; effectiveAliasIndex = 0; propertyCache = qmcTypeUnit->propertyCaches.at(alias.objectIndex); effectivePropertyIndex = propertyCache->propertyIndexCacheStart + propertyCache->propertyIndexCache.count(); effectiveSignalIndex = propertyCache->signalHandlerIndexCacheStart + propertyCache->propertyIndexCache.count(); } Q_ASSERT(propertyCache); QQmlVMEMetaData::AliasData aliasData; aliasData.contextIdx = alias.contextIndex; aliasData.propertyIdx = alias.targetPropertyIndex; aliasData.propType = alias.propertyType; aliasData.flags = alias.flags; aliasData.notifySignal = alias.notifySignal; typedef QQmlVMEMetaData VMD; QByteArray &dynamicData = qmcTypeUnit->vmeMetaObjects[alias.objectIndex]; Q_ASSERT(!dynamicData.isEmpty()); VMD *vmd = (QQmlVMEMetaData *)dynamicData.data(); *(vmd->aliasData() + effectiveAliasIndex++) = aliasData; Q_ASSERT(dynamicData.isDetached()); // TBD: propertyCache const QV4::CompiledData::Object *obj = qmcTypeUnit->compiledData->qmlUnit->objectAt(alias.objectIndex); Q_ASSERT(obj); Q_ASSERT(alias.propertyIndex < obj->nProperties); const QV4::CompiledData::Property *p = &obj->propertyTable()[alias.propertyIndex]; Q_ASSERT(p); QString propertyName = qmcTypeUnit->stringAt(p->nameIndex); const QString aliasPropertyValue = qmcTypeUnit->stringAt(p->aliasPropertyValueIndex); //const int idIndex = p->aliasIdValueIndex; const int targetObjectIndex = alias.targetObjectIndex; #if 0 const int idIndex = p->aliasIdValueIndex; const int targetObjectIndex = _idToObjectIndex.value(idIndex, -1); if (targetObjectIndex == -1) { recordError(p->aliasLocation, tr("Invalid alias reference. Unable to find id \"%1\"").arg(stringAt(idIndex))); return false; } #endif QStringRef property; QStringRef subProperty; const int propertySeparator = aliasPropertyValue.indexOf(QLatin1Char('.')); if (propertySeparator != -1) { property = aliasPropertyValue.leftRef(propertySeparator); subProperty = aliasPropertyValue.midRef(propertySeparator + 1); } else property = QStringRef(&aliasPropertyValue, 0, aliasPropertyValue.length()); quint32 propertyFlags = QQmlPropertyData::IsAlias; int type = 0; bool writable = false; bool resettable = false; if (property.isEmpty()) { const QV4::CompiledData::Object *targetObject = qmcTypeUnit->compiledData->qmlUnit->objectAt(targetObjectIndex); QQmlCompiledData::TypeReference *typeRef = qmcTypeUnit->compiledData->resolvedTypes.value(targetObject->inheritedTypeNameIndex); Q_ASSERT(typeRef); if (typeRef->type) type = typeRef->type->typeId(); else type = typeRef->component->metaTypeId; //flags |= QML_ALIAS_FLAG_PTR; propertyFlags |= QQmlPropertyData::IsQObjectDerived; } else { QQmlPropertyCache *targetCache = qmcTypeUnit->propertyCaches.at(targetObjectIndex); Q_ASSERT(targetCache); QmlIR::PropertyResolver resolver(targetCache); QQmlPropertyData *targetProperty = resolver.property(property.toString()); if (!targetProperty || targetProperty->coreIndex > 0x0000FFFF) { return false; } //propIdx = targetProperty->coreIndex; type = targetProperty->propType; writable = targetProperty->isWritable(); resettable = targetProperty->isResettable(); //notifySignal = targetProperty->notifyIndex; if (!subProperty.isEmpty()) { QQmlValueType *valueType = QQmlValueTypeFactory::valueType(type); if (!valueType) { return false; } //propType = type; int valueTypeIndex = valueType->metaObject()->indexOfProperty(subProperty.toString().toUtf8().constData()); if (valueTypeIndex == -1) { return false; } Q_ASSERT(valueTypeIndex <= 0x0000FFFF); //propIdx |= (valueTypeIndex << 16); if (valueType->metaObject()->property(valueTypeIndex).isEnumType()) type = QVariant::Int; else type = valueType->metaObject()->property(valueTypeIndex).userType(); } else { if (targetProperty->isEnum()) { type = QVariant::Int; } else { // Copy type flags propertyFlags |= targetProperty->getFlags() & QQmlPropertyData::PropTypeFlagMask; if (targetProperty->isVarProperty()) propertyFlags |= QQmlPropertyData::IsQVariant; #if 0 if (targetProperty->isQObject()) flags |= QML_ALIAS_FLAG_PTR; #endif } } } if (!(p->flags & QV4::CompiledData::Property::IsReadOnly) && writable) propertyFlags |= QQmlPropertyData::IsWritable; else propertyFlags &= ~QQmlPropertyData::IsWritable; if (resettable) propertyFlags |= QQmlPropertyData::IsResettable; else propertyFlags &= ~QQmlPropertyData::IsResettable; if ((int)alias.propertyIndex == obj->indexOfDefaultProperty) propertyCache->_defaultPropertyName = propertyName; propertyCache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++, type, effectiveSignalIndex++); } return true; }