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), &notInRevision);
        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;
}