diff options
Diffstat (limited to 'src/qml')
-rw-r--r-- | src/qml/compiler/qqmlirbuilder.cpp | 292 | ||||
-rw-r--r-- | src/qml/compiler/qqmlirbuilder_p.h | 14 | ||||
-rw-r--r-- | src/qml/compiler/qqmltypecompiler.cpp | 130 | ||||
-rw-r--r-- | src/qml/compiler/qv4compileddata_p.h | 32 | ||||
-rw-r--r-- | src/qml/qml/qqmlobjectcreator.cpp | 2 |
5 files changed, 282 insertions, 188 deletions
diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp index bd4261493c..ac59c04e87 100644 --- a/src/qml/compiler/qqmlirbuilder.cpp +++ b/src/qml/compiler/qqmlirbuilder.cpp @@ -80,8 +80,10 @@ void Object::init(QQmlJS::MemoryPool *pool, int typeNameIndex, int id, const QQm location.column = loc.startColumn; idIndex = id; - indexOfDefaultProperty = -1; + indexOfDefaultPropertyOrAlias = -1; + defaultPropertyIsAlias = false; properties = pool->New<PoolList<Property> >(); + aliases = pool->New<PoolList<Alias> >(); qmlSignals = pool->New<PoolList<Signal> >(); bindings = pool->New<PoolList<Binding> >(); functions = pool->New<PoolList<Function> >(); @@ -145,15 +147,42 @@ QString Object::appendProperty(Property *prop, const QString &propertyName, bool const int index = target->properties->append(prop); if (isDefaultProperty) { - if (target->indexOfDefaultProperty != -1) { + if (target->indexOfDefaultPropertyOrAlias != -1) { *errorLocation = defaultToken; return tr("Duplicate default property"); } - target->indexOfDefaultProperty = index; + target->indexOfDefaultPropertyOrAlias = index; } return QString(); // no error } +QString Object::appendAlias(Alias *alias, const QString &aliasName, bool isDefaultProperty, const QQmlJS::AST::SourceLocation &defaultToken, QQmlJS::AST::SourceLocation *errorLocation) +{ + Object *target = declarationsOverride; + if (!target) + target = this; + + for (Alias *p = target->aliases->first; p; p = p->next) + if (p->nameIndex == alias->nameIndex) + return tr("Duplicate alias name"); + + if (aliasName.constData()->isUpper()) + return tr("Alias names cannot begin with an upper case letter"); + + const int index = target->aliases->append(alias); + + if (isDefaultProperty) { + if (target->indexOfDefaultPropertyOrAlias != -1) { + *errorLocation = defaultToken; + return tr("Duplicate default property"); + } + target->indexOfDefaultPropertyOrAlias = index; + target->defaultPropertyIsAlias = true; + } + + return QString(); // no error +} + void Object::appendFunction(QmlIR::Function *f) { Object *target = declarationsOverride; @@ -806,128 +835,86 @@ bool IRBuilder::visit(QQmlJS::AST::UiPublicMember *node) } } else { const QStringRef &memberType = node->memberType; - const QStringRef &name = node->name; - - bool typeFound = false; - QV4::CompiledData::Property::Type type; - if (memberType == QLatin1String("alias")) { - type = QV4::CompiledData::Property::Alias; - typeFound = true; - } + return appendAlias(node); + } else { + const QStringRef &name = node->name; - for (int ii = 0; !typeFound && ii < propTypeNameToTypesCount; ++ii) { - const TypeNameToType *t = propTypeNameToTypes + ii; - if (memberType == QLatin1String(t->name, static_cast<int>(t->nameLength))) { - type = t->type; - typeFound = true; + bool typeFound = false; + QV4::CompiledData::Property::Type type; + + for (int ii = 0; !typeFound && ii < propTypeNameToTypesCount; ++ii) { + const TypeNameToType *t = propTypeNameToTypes + ii; + if (memberType == QLatin1String(t->name, static_cast<int>(t->nameLength))) { + type = t->type; + typeFound = true; + } } - } - if (!typeFound && memberType.at(0).isUpper()) { - const QStringRef &typeModifier = node->typeModifier; + if (!typeFound && memberType.at(0).isUpper()) { + const QStringRef &typeModifier = node->typeModifier; - if (typeModifier.isEmpty()) { - type = QV4::CompiledData::Property::Custom; - } else if (typeModifier == QLatin1String("list")) { - type = QV4::CompiledData::Property::CustomList; - } else { - recordError(node->typeModifierToken, QCoreApplication::translate("QQmlParser","Invalid property type modifier")); + if (typeModifier.isEmpty()) { + type = QV4::CompiledData::Property::Custom; + } else if (typeModifier == QLatin1String("list")) { + type = QV4::CompiledData::Property::CustomList; + } else { + recordError(node->typeModifierToken, QCoreApplication::translate("QQmlParser","Invalid property type modifier")); + return false; + } + typeFound = true; + } else if (!node->typeModifier.isNull()) { + recordError(node->typeModifierToken, QCoreApplication::translate("QQmlParser","Unexpected property type modifier")); return false; } - typeFound = true; - } else if (!node->typeModifier.isNull()) { - recordError(node->typeModifierToken, QCoreApplication::translate("QQmlParser","Unexpected property type modifier")); - return false; - } - - if (!typeFound) { - recordError(node->typeToken, QCoreApplication::translate("QQmlParser","Expected property type")); - return false; - } - - Property *property = New<Property>(); - property->flags = 0; - if (node->isReadonlyMember) - property->flags |= QV4::CompiledData::Property::IsReadOnly; - property->type = type; - if (type >= QV4::CompiledData::Property::Custom) - property->customTypeNameIndex = registerString(memberType.toString()); - else - property->customTypeNameIndex = emptyStringIndex; - const QString propName = name.toString(); - property->nameIndex = registerString(propName); - - QQmlJS::AST::SourceLocation loc = node->firstSourceLocation(); - property->location.line = loc.startLine; - property->location.column = loc.startColumn; - - property->aliasPropertyValueIndex = emptyStringIndex; - - if (type == QV4::CompiledData::Property::Alias) { - if (!node->statement && !node->binding) - COMPILE_EXCEPTION(loc, tr("No property alias location")); + if (!typeFound) { + recordError(node->typeToken, QCoreApplication::translate("QQmlParser","Expected property type")); + return false; + } - QQmlJS::AST::SourceLocation rhsLoc; - if (node->binding) - rhsLoc = node->binding->firstSourceLocation(); - else if (node->statement) - rhsLoc = node->statement->firstSourceLocation(); + Property *property = New<Property>(); + property->flags = 0; + if (node->isReadonlyMember) + property->flags |= QV4::CompiledData::Property::IsReadOnly; + property->type = type; + if (type >= QV4::CompiledData::Property::Custom) + property->customTypeNameIndex = registerString(memberType.toString()); else - rhsLoc = node->semicolonToken; - property->aliasLocation.line = rhsLoc.startLine; - property->aliasLocation.column = rhsLoc.startColumn; - - QStringList alias; - - if (QQmlJS::AST::ExpressionStatement *stmt = QQmlJS::AST::cast<QQmlJS::AST::ExpressionStatement*>(node->statement)) { - alias = astNodeToStringList(stmt->expression); - if (alias.isEmpty()) { - if (isStatementNodeScript(node->statement)) { - COMPILE_EXCEPTION(rhsLoc, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>")); - } else { - COMPILE_EXCEPTION(rhsLoc, tr("Invalid alias location")); - } - } - } else { - COMPILE_EXCEPTION(rhsLoc, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>")); - } + property->customTypeNameIndex = emptyStringIndex; - if (alias.count() < 1 || alias.count() > 3) - COMPILE_EXCEPTION(rhsLoc, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>")); + const QString propName = name.toString(); + property->nameIndex = registerString(propName); - property->aliasIdValueIndex = registerString(alias.first()); + QQmlJS::AST::SourceLocation loc = node->firstSourceLocation(); + property->location.line = loc.startLine; + property->location.column = loc.startColumn; - QString propertyValue = alias.value(1); - if (alias.count() == 3) - propertyValue += QLatin1Char('.') + alias.at(2); - property->aliasPropertyValueIndex = registerString(propertyValue); - } - QQmlJS::AST::SourceLocation errorLocation; - QString error; + QQmlJS::AST::SourceLocation errorLocation; + QString error; - if (illegalNames.contains(propName)) - error = tr("Illegal property name"); - else - error = _object->appendProperty(property, propName, node->isDefaultMember, node->defaultToken, &errorLocation); + if (illegalNames.contains(propName)) + error = tr("Illegal property name"); + else + error = _object->appendProperty(property, propName, node->isDefaultMember, node->defaultToken, &errorLocation); - if (!error.isEmpty()) { - if (errorLocation.startLine == 0) - errorLocation = node->identifierToken; + if (!error.isEmpty()) { + if (errorLocation.startLine == 0) + errorLocation = node->identifierToken; - recordError(errorLocation, error); - return false; - } + recordError(errorLocation, error); + return false; + } - qSwap(_propertyDeclaration, property); - if (node->binding) { - // process QML-like initializers (e.g. property Object o: Object {}) - QQmlJS::AST::Node::accept(node->binding, this); - } else if (node->statement && type != QV4::CompiledData::Property::Alias) { - appendBinding(node->identifierToken, node->identifierToken, _propertyDeclaration->nameIndex, node->statement); + qSwap(_propertyDeclaration, property); + if (node->binding) { + // process QML-like initializers (e.g. property Object o: Object {}) + QQmlJS::AST::Node::accept(node->binding, this); + } else if (node->statement) { + appendBinding(node->identifierToken, node->identifierToken, _propertyDeclaration->nameIndex, node->statement); + } + qSwap(_propertyDeclaration, property); } - qSwap(_propertyDeclaration, property); } return false; @@ -1132,6 +1119,79 @@ void IRBuilder::appendBinding(const QQmlJS::AST::SourceLocation &qualifiedNameLo } } +bool IRBuilder::appendAlias(QQmlJS::AST::UiPublicMember *node) +{ + Alias *alias = New<Alias>(); + alias->flags = 0; + if (node->isReadonlyMember) + alias->flags |= QV4::CompiledData::Alias::IsReadOnly; + + const QString propName = node->name.toString(); + alias->nameIndex = registerString(propName); + + QQmlJS::AST::SourceLocation loc = node->firstSourceLocation(); + alias->location.line = loc.startLine; + alias->location.column = loc.startColumn; + + alias->propertyIndex = emptyStringIndex; + + if (!node->statement && !node->binding) + COMPILE_EXCEPTION(loc, tr("No property alias location")); + + QQmlJS::AST::SourceLocation rhsLoc; + if (node->binding) + rhsLoc = node->binding->firstSourceLocation(); + else if (node->statement) + rhsLoc = node->statement->firstSourceLocation(); + else + rhsLoc = node->semicolonToken; + alias->referenceLocation.line = rhsLoc.startLine; + alias->referenceLocation.column = rhsLoc.startColumn; + + QStringList aliasReference; + + if (QQmlJS::AST::ExpressionStatement *stmt = QQmlJS::AST::cast<QQmlJS::AST::ExpressionStatement*>(node->statement)) { + aliasReference = astNodeToStringList(stmt->expression); + if (aliasReference.isEmpty()) { + if (isStatementNodeScript(node->statement)) { + COMPILE_EXCEPTION(rhsLoc, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>")); + } else { + COMPILE_EXCEPTION(rhsLoc, tr("Invalid alias location")); + } + } + } else { + COMPILE_EXCEPTION(rhsLoc, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>")); + } + + if (aliasReference.count() < 1 || aliasReference.count() > 3) + COMPILE_EXCEPTION(rhsLoc, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>")); + + alias->idIndex = registerString(aliasReference.first()); + + QString propertyValue = aliasReference.value(1); + if (aliasReference.count() == 3) + propertyValue += QLatin1Char('.') + aliasReference.at(2); + alias->propertyIndex = registerString(propertyValue); + + QQmlJS::AST::SourceLocation errorLocation; + QString error; + + if (illegalNames.contains(propName)) + error = tr("Illegal property name"); + else + error = _object->appendAlias(alias, propName, node->isDefaultMember, node->defaultToken, &errorLocation); + + if (!error.isEmpty()) { + if (errorLocation.startLine == 0) + errorLocation = node->identifierToken; + + recordError(errorLocation, error); + return false; + } + + return false; +} + Object *IRBuilder::bindingsTarget() const { if (_propertyDeclaration && _object->declarationsOverride) @@ -1313,7 +1373,7 @@ QV4::CompiledData::Unit *QmlUnitGenerator::generate(Document &output) int objectsSize = 0; foreach (Object *o, output.objects) { objectOffsets.insert(o, unitSize + importSize + objectOffsetTableSize + objectsSize); - objectsSize += QV4::CompiledData::Object::calculateSizeExcludingSignals(o->functionCount(), o->propertyCount(), o->signalCount(), o->bindingCount()); + objectsSize += QV4::CompiledData::Object::calculateSizeExcludingSignals(o->functionCount(), o->propertyCount(), o->aliasCount(), o->signalCount(), o->bindingCount()); int signalTableSize = 0; for (const Signal *s = o->firstSignal(); s; s = s->next) @@ -1358,7 +1418,8 @@ QV4::CompiledData::Unit *QmlUnitGenerator::generate(Document &output) QV4::CompiledData::Object *objectToWrite = reinterpret_cast<QV4::CompiledData::Object*>(objectPtr); objectToWrite->inheritedTypeNameIndex = o->inheritedTypeNameIndex; - objectToWrite->indexOfDefaultProperty = o->indexOfDefaultProperty; + objectToWrite->indexOfDefaultPropertyOrAlias = o->indexOfDefaultPropertyOrAlias; + objectToWrite->defaultPropertyIsAlias = o->defaultPropertyIsAlias; objectToWrite->idIndex = o->idIndex; objectToWrite->location = o->location; objectToWrite->locationOfIdProperty = o->locationOfIdProperty; @@ -1373,6 +1434,10 @@ QV4::CompiledData::Unit *QmlUnitGenerator::generate(Document &output) objectToWrite->offsetToProperties = nextOffset; nextOffset += objectToWrite->nProperties * sizeof(QV4::CompiledData::Property); + objectToWrite->nAliases = o->aliasCount(); + objectToWrite->offsetToAliases = nextOffset; + nextOffset += objectToWrite->nAliases * sizeof(QV4::CompiledData::Alias); + objectToWrite->nSignals = o->signalCount(); objectToWrite->offsetToSignals = nextOffset; nextOffset += objectToWrite->nSignals * sizeof(quint32); @@ -1392,6 +1457,13 @@ QV4::CompiledData::Unit *QmlUnitGenerator::generate(Document &output) propertiesPtr += sizeof(QV4::CompiledData::Property); } + char *aliasesPtr = objectPtr + objectToWrite->offsetToAliases; + for (const Alias *a = o->firstAlias(); a; a = a->next) { + QV4::CompiledData::Alias *aliasToWrite = reinterpret_cast<QV4::CompiledData::Alias*>(aliasesPtr); + *aliasToWrite = *a; + aliasesPtr += sizeof(QV4::CompiledData::Alias); + } + char *bindingPtr = objectPtr + objectToWrite->offsetToBindings; bindingPtr = writeBindings(bindingPtr, o, &QV4::CompiledData::Binding::isValueBindingNoAlias); bindingPtr = writeBindings(bindingPtr, o, &QV4::CompiledData::Binding::isSignalHandler); @@ -1420,7 +1492,7 @@ QV4::CompiledData::Unit *QmlUnitGenerator::generate(Document &output) signalPtr += size; } - objectPtr += QV4::CompiledData::Object::calculateSizeExcludingSignals(o->functionCount(), o->propertyCount(), o->signalCount(), o->bindingCount()); + objectPtr += QV4::CompiledData::Object::calculateSizeExcludingSignals(o->functionCount(), o->propertyCount(), o->aliasCount(), o->signalCount(), o->bindingCount()); objectPtr += signalTableSize; } diff --git a/src/qml/compiler/qqmlirbuilder_p.h b/src/qml/compiler/qqmlirbuilder_p.h index 18daab9ce4..060c888cd8 100644 --- a/src/qml/compiler/qqmlirbuilder_p.h +++ b/src/qml/compiler/qqmlirbuilder_p.h @@ -235,6 +235,11 @@ struct Binding : public QV4::CompiledData::Binding Binding *next; }; +struct Alias : public QV4::CompiledData::Alias +{ + Alias *next; +}; + struct Function { QQmlJS::AST::FunctionDeclaration *functionDeclaration; @@ -270,13 +275,16 @@ struct Q_QML_PRIVATE_EXPORT Object public: quint32 inheritedTypeNameIndex; quint32 idIndex; - int indexOfDefaultProperty; + int indexOfDefaultPropertyOrAlias : 31; + int defaultPropertyIsAlias : 1; QV4::CompiledData::Location location; QV4::CompiledData::Location locationOfIdProperty; const Property *firstProperty() const { return properties->first; } int propertyCount() const { return properties->count; } + const Alias *firstAlias() const { return aliases->first; } + int aliasCount() const { return aliases->count; } const Signal *firstSignal() const { return qmlSignals->first; } int signalCount() const { return qmlSignals->count; } Binding *firstBinding() const { return bindings->first; } @@ -294,6 +302,7 @@ public: QString appendSignal(Signal *signal); QString appendProperty(Property *prop, const QString &propertyName, bool isDefaultProperty, const QQmlJS::AST::SourceLocation &defaultToken, QQmlJS::AST::SourceLocation *errorLocation); + QString appendAlias(Alias *prop, const QString &aliasName, bool isDefaultProperty, const QQmlJS::AST::SourceLocation &defaultToken, QQmlJS::AST::SourceLocation *errorLocation); void appendFunction(QmlIR::Function *f); QString appendBinding(Binding *b, bool isListBinding); @@ -309,6 +318,7 @@ private: friend struct IRLoader; PoolList<Property> *properties; + PoolList<Alias> *aliases; PoolList<Signal> *qmlSignals; PoolList<Binding> *bindings; PoolList<Function> *functions; @@ -414,6 +424,8 @@ public: void appendBinding(const QQmlJS::AST::SourceLocation &qualifiedNameLocation, const QQmlJS::AST::SourceLocation &nameLocation, quint32 propertyNameIndex, QQmlJS::AST::Statement *value); void appendBinding(const QQmlJS::AST::SourceLocation &qualifiedNameLocation, const QQmlJS::AST::SourceLocation &nameLocation, quint32 propertyNameIndex, int objectIndex, bool isListItem = false, bool isOnAssignment = false); + bool appendAlias(QQmlJS::AST::UiPublicMember *node); + Object *bindingsTarget() const; bool setId(const QQmlJS::AST::SourceLocation &idLocation, QQmlJS::AST::Statement *value); diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp index fcb94a9645..fed0ec1f37 100644 --- a/src/qml/compiler/qqmltypecompiler.cpp +++ b/src/qml/compiler/qqmltypecompiler.cpp @@ -480,7 +480,7 @@ bool QQmlPropertyCacheCreator::buildMetaObjectRecursively(int objectIndex, int r } } - bool needVMEMetaObject = obj->propertyCount() != 0 || obj->signalCount() != 0 || obj->functionCount() != 0; + bool needVMEMetaObject = obj->propertyCount() != 0 || obj->aliasCount() != 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)) { @@ -507,7 +507,7 @@ bool QQmlPropertyCacheCreator::buildMetaObjectRecursively(int objectIndex, int r Q_ASSERT(typeRef); if (typeRef->isFullyDynamicType) { - if (obj->propertyCount() > 0) { + if (obj->propertyCount() > 0 || obj->aliasCount() > 0) { recordError(obj->location, tr("Fully dynamic types cannot declare new properties.")); return false; } @@ -586,9 +586,9 @@ bool QQmlPropertyCacheCreator::ensureMetaObject(int objectIndex) bool QQmlPropertyCacheCreator::createMetaObject(int objectIndex, const QmlIR::Object *obj, QQmlPropertyCache *baseTypeCache) { - QQmlPropertyCache *cache = baseTypeCache->copyAndReserve(obj->propertyCount(), - obj->functionCount() + obj->propertyCount() + obj->signalCount(), - obj->signalCount() + obj->propertyCount()); + QQmlPropertyCache *cache = baseTypeCache->copyAndReserve(obj->propertyCount() + obj->aliasCount(), + obj->functionCount() + obj->propertyCount() + obj->aliasCount() + obj->signalCount(), + obj->signalCount() + obj->propertyCount() + obj->aliasCount()); propertyCaches[objectIndex] = cache; struct TypeData { @@ -638,29 +638,40 @@ bool QQmlPropertyCacheCreator::createMetaObject(int objectIndex, const QmlIR::Ob cache->_dynamicClassName = newClassName; - int aliasCount = 0; int varPropCount = 0; QmlIR::PropertyResolver resolver(baseTypeCache); for (const QmlIR::Property *p = obj->firstProperty(); p; p = p->next) { - if (p->type == QV4::CompiledData::Property::Alias) - aliasCount++; - else if (p->type == QV4::CompiledData::Property::Var) + if (p->type == QV4::CompiledData::Property::Var) varPropCount++; - // No point doing this for both the alias and non alias cases bool notInRevision = false; QQmlPropertyData *d = resolver.property(stringAt(p->nameIndex), ¬InRevision); if (d && d->isFinal()) COMPILE_EXCEPTION(p, tr("Cannot override FINAL property")); } + for (const QmlIR::Alias *a = obj->firstAlias(); a; a = a->next) { + bool notInRevision = false; + QQmlPropertyData *d = resolver.property(stringAt(a->nameIndex), ¬InRevision); + if (d && d->isFinal()) + COMPILE_EXCEPTION(a, tr("Cannot override FINAL property")); + } + typedef QQmlVMEMetaData VMD; QByteArray &dynamicData = vmeMetaObjects[objectIndex] = QByteArray(sizeof(QQmlVMEMetaData) + obj->propertyCount() * sizeof(VMD::PropertyData) - + aliasCount * sizeof(VMD::AliasData), 0); + + obj->aliasCount() * sizeof(VMD::AliasData), 0); + + VMD *vmd = (QQmlVMEMetaData *)dynamicData.data(); + // Dynamic slot data - comes after the property data + vmd->methodCount = obj->functionCount(); + // Alias property count. Actual data is setup in resolveAliases() + vmd->aliasCount = obj->aliasCount(); + vmd->signalCount = obj->signalCount(); + vmd->propertyCount = obj->propertyCount(); int effectivePropertyIndex = cache->propertyIndexCacheStart; int effectiveMethodIndex = cache->methodIndexCacheStart; @@ -688,25 +699,25 @@ bool QQmlPropertyCacheCreator::createMetaObject(int objectIndex, const QmlIR::Ob } } - // First set up notify signals for properties - first normal, then var, then alias - enum { NSS_Normal = 0, NSS_Alias = 1 }; - for (int ii = NSS_Normal; ii <= NSS_Alias; ++ii) { // 0 == normal, 1 == var, 2 == alias + // Set up notify signals for properties - first normal, then alias + for (const QmlIR::Property *p = obj->firstProperty(); p; p = p->next) { + quint32 flags = QQmlPropertyData::IsSignal | QQmlPropertyData::IsFunction | + QQmlPropertyData::IsVMESignal; - if (ii == NSS_Alias && aliasCount == 0) continue; + QString changedSigName = stringAt(p->nameIndex) + QLatin1String("Changed"); + seenSignals.insert(changedSigName); - for (const QmlIR::Property *p = obj->firstProperty(); p; p = p->next) { - if ((ii == NSS_Normal && p->type == QV4::CompiledData::Property::Alias) || - (ii == NSS_Alias && p->type != QV4::CompiledData::Property::Alias)) - continue; + cache->appendSignal(changedSigName, flags, effectiveMethodIndex++); + } - quint32 flags = QQmlPropertyData::IsSignal | QQmlPropertyData::IsFunction | - QQmlPropertyData::IsVMESignal; + for (const QmlIR::Alias *a = obj->firstAlias(); a; a = a->next) { + quint32 flags = QQmlPropertyData::IsSignal | QQmlPropertyData::IsFunction | + QQmlPropertyData::IsVMESignal; - QString changedSigName = stringAt(p->nameIndex) + QLatin1String("Changed"); - seenSignals.insert(changedSigName); + QString changedSigName = stringAt(a->nameIndex) + QLatin1String("Changed"); + seenSignals.insert(changedSigName); - cache->appendSignal(changedSigName, flags, effectiveMethodIndex++); - } + cache->appendSignal(changedSigName, flags, effectiveMethodIndex++); } // Dynamic signals @@ -751,8 +762,6 @@ bool QQmlPropertyCacheCreator::createMetaObject(int objectIndex, const QmlIR::Ob } } - ((QQmlVMEMetaData *)dynamicData.data())->signalCount++; - quint32 flags = QQmlPropertyData::IsSignal | QQmlPropertyData::IsFunction | QQmlPropertyData::IsVMESignal; if (paramCount) @@ -794,14 +803,10 @@ bool QQmlPropertyCacheCreator::createMetaObject(int objectIndex, const QmlIR::Ob } - // Dynamic properties (except var and aliases) + // Dynamic properties int effectiveSignalIndex = cache->signalHandlerIndexCacheStart; int propertyIdx = 0; for (const QmlIR::Property *p = obj->firstProperty(); p; p = p->next, ++propertyIdx) { - - if (p->type == QV4::CompiledData::Property::Alias) - continue; - int propertyType = 0; int vmePropertyType = 0; quint32 propertyFlags = 0; @@ -863,24 +868,17 @@ bool QQmlPropertyCacheCreator::createMetaObject(int objectIndex, const QmlIR::Ob QString propertyName = stringAt(p->nameIndex); - if (propertyIdx == obj->indexOfDefaultProperty) cache->_defaultPropertyName = propertyName; + if (!obj->defaultPropertyIsAlias && propertyIdx == obj->indexOfDefaultPropertyOrAlias) + cache->_defaultPropertyName = propertyName; cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++, propertyType, effectiveSignalIndex); effectiveSignalIndex++; VMD *vmd = (QQmlVMEMetaData *)dynamicData.data(); - (vmd->propertyData() + vmd->propertyCount)->propertyType = vmePropertyType; - vmd->propertyCount++; + (vmd->propertyData() + propertyIdx)->propertyType = vmePropertyType; } - // Alias property count. Actual data is setup in buildDynamicMetaAliases - ((QQmlVMEMetaData *)dynamicData.data())->aliasCount = aliasCount; - - // Dynamic slot data - comes after the property data - VMD *vmd = (QQmlVMEMetaData *)dynamicData.data(); - vmd->methodCount = obj->functionCount(); - return true; } @@ -1301,7 +1299,7 @@ void QQmlAliasAnnotator::annotateBindingsToAliases() const QmlIR::Object *obj = qmlObjects.at(i); QmlIR::PropertyResolver resolver(propertyCache); - QQmlPropertyData *defaultProperty = obj->indexOfDefaultProperty != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty(); + QQmlPropertyData *defaultProperty = obj->indexOfDefaultPropertyOrAlias != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty(); for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) { if (!binding->isValueBinding()) @@ -1333,7 +1331,7 @@ void QQmlScriptStringScanner::scan() const QmlIR::Object *obj = qmlObjects.at(i); QmlIR::PropertyResolver resolver(propertyCache); - QQmlPropertyData *defaultProperty = obj->indexOfDefaultProperty != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty(); + QQmlPropertyData *defaultProperty = obj->indexOfDefaultPropertyOrAlias != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty(); for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) { if (binding->type != QV4::CompiledData::Binding::Type_Script) @@ -1373,7 +1371,7 @@ void QQmlComponentAndAliasResolver::findAndRegisterImplicitComponents(const QmlI { QmlIR::PropertyResolver propertyResolver(propertyCache); - QQmlPropertyData *defaultProperty = obj->indexOfDefaultProperty != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty(); + QQmlPropertyData *defaultProperty = obj->indexOfDefaultPropertyOrAlias != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty(); for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) { if (binding->type != QV4::CompiledData::Binding::Type_Object) @@ -1480,7 +1478,7 @@ bool QQmlComponentAndAliasResolver::resolve() if (obj->functionCount() > 0) COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new functions.")); - if (obj->propertyCount() > 0) + if (obj->propertyCount() > 0 || obj->aliasCount() > 0) COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new properties.")); if (obj->signalCount() > 0) COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new signals.")); @@ -1551,12 +1549,8 @@ bool QQmlComponentAndAliasResolver::collectIdsAndAliases(int objectIndex) _objectIndexToIdInScope->insert(objectIndex, _objectIndexToIdInScope->count()); } - for (const QmlIR::Property *property = obj->firstProperty(); property; property = property->next) { - if (property->type == QV4::CompiledData::Property::Alias) { - _objectsWithAliases.append(objectIndex); - break; - } - } + if (obj->aliasCount() > 0) + _objectsWithAliases.append(objectIndex); for (const QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) { if (binding->type != QV4::CompiledData::Binding::Type_Object @@ -1587,21 +1581,18 @@ bool QQmlComponentAndAliasResolver::resolveAliases() int effectivePropertyIndex = propertyCache->propertyIndexCacheStart + propertyCache->propertyIndexCache.count(); int effectiveAliasIndex = 0; - const QmlIR::Property *p = obj->firstProperty(); - for (int propertyIndex = 0; propertyIndex < obj->propertyCount(); ++propertyIndex, p = p->next) { - if (p->type != QV4::CompiledData::Property::Alias) - continue; - - const int idIndex = p->aliasIdValueIndex; + int aliasIndex = 0; + for (const QmlIR::Alias *alias = obj->firstAlias(); alias; alias = alias->next, ++aliasIndex) { + const int idIndex = alias->idIndex; 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))); + recordError(alias->referenceLocation, tr("Invalid alias reference. Unable to find id \"%1\"").arg(stringAt(idIndex))); return false; } const int targetId = _objectIndexToIdInScope->value(targetObjectIndex, -1); Q_ASSERT(targetId != -1); - const QString aliasPropertyValue = stringAt(p->aliasPropertyValueIndex); + const QString aliasPropertyValue = stringAt(alias->propertyIndex); QStringRef property; QStringRef subProperty; @@ -1642,7 +1633,7 @@ bool QQmlComponentAndAliasResolver::resolveAliases() QQmlPropertyData *targetProperty = resolver.property(property.toString()); if (!targetProperty || targetProperty->coreIndex > 0x0000FFFF) { - recordError(p->aliasLocation, tr("Invalid alias target location: %1").arg(property.toString())); + recordError(alias->referenceLocation, tr("Invalid alias target location: %1").arg(property.toString())); return false; } @@ -1656,7 +1647,7 @@ bool QQmlComponentAndAliasResolver::resolveAliases() if (!subProperty.isEmpty()) { const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(type); if (!valueTypeMetaObject) { - recordError(p->aliasLocation, tr("Invalid alias target location: %1").arg(subProperty.toString())); + recordError(alias->referenceLocation, tr("Invalid alias target location: %1").arg(subProperty.toString())); return false; } @@ -1665,7 +1656,7 @@ bool QQmlComponentAndAliasResolver::resolveAliases() int valueTypeIndex = valueTypeMetaObject->indexOfProperty(subProperty.toString().toUtf8().constData()); if (valueTypeIndex == -1) { - recordError(p->aliasLocation, tr("Invalid alias target location: %1").arg(subProperty.toString())); + recordError(alias->referenceLocation, tr("Invalid alias target location: %1").arg(subProperty.toString())); return false; } Q_ASSERT(valueTypeIndex <= 0x0000FFFF); @@ -1702,7 +1693,7 @@ bool QQmlComponentAndAliasResolver::resolveAliases() Q_ASSERT(dynamicData.isDetached()); - if (!(p->flags & QV4::CompiledData::Property::IsReadOnly) && writable) + if (!(alias->flags & QV4::CompiledData::Property::IsReadOnly) && writable) propertyFlags |= QQmlPropertyData::IsWritable; else propertyFlags &= ~QQmlPropertyData::IsWritable; @@ -1712,8 +1703,11 @@ bool QQmlComponentAndAliasResolver::resolveAliases() else propertyFlags &= ~QQmlPropertyData::IsResettable; - QString propertyName = stringAt(p->nameIndex); - if (propertyIndex == obj->indexOfDefaultProperty) propertyCache->_defaultPropertyName = propertyName; + QString propertyName = stringAt(alias->nameIndex); + + if (obj->defaultPropertyIsAlias && aliasIndex == obj->indexOfDefaultPropertyOrAlias) + propertyCache->_defaultPropertyName = propertyName; + propertyCache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++, type, effectiveSignalIndex++); @@ -1825,7 +1819,7 @@ bool QQmlPropertyValidator::validateObject(int objectIndex, const QV4::CompiledD QString defaultPropertyName; QQmlPropertyData *defaultProperty = 0; - if (obj->indexOfDefaultProperty != -1) { + if (obj->indexOfDefaultPropertyOrAlias != -1) { QQmlPropertyCache *cache = propertyCache->parent(); defaultPropertyName = cache->defaultPropertyName(); defaultProperty = cache->defaultProperty(); @@ -2545,7 +2539,7 @@ void QQmlDefaultPropertyMerger::mergeDefaultProperties(int objectIndex) QmlIR::Object *object = qmlObjects.at(objectIndex); - QString defaultProperty = object->indexOfDefaultProperty != -1 ? propertyCache->parent()->defaultPropertyName() : propertyCache->defaultPropertyName(); + QString defaultProperty = object->indexOfDefaultPropertyOrAlias != -1 ? propertyCache->parent()->defaultPropertyName() : propertyCache->defaultPropertyName(); QmlIR::Binding *bindingsToReinsert = 0; QmlIR::Binding *tail = 0; diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h index ac27124d70..27debc0ce8 100644 --- a/src/qml/compiler/qv4compileddata_p.h +++ b/src/qml/compiler/qv4compileddata_p.h @@ -351,7 +351,7 @@ struct Property enum Type { Var = 0, Variant, Int, Bool, Real, String, Url, Color, Font, Time, Date, DateTime, Rect, Point, Size, Vector2D, Vector3D, Vector4D, Matrix4x4, Quaternion, - Alias, Custom, CustomList }; + Custom, CustomList }; enum Flags { IsReadOnly = 0x1 @@ -360,13 +360,20 @@ struct Property quint32 nameIndex; quint32 type : 31; quint32 flags : 1; // readonly - union { - quint32 customTypeNameIndex; // If type >= Custom - quint32 aliasIdValueIndex; // If type == Alias + quint32 customTypeNameIndex; // If type >= Custom + Location location; +}; + +struct Alias { + enum Flags { + IsReadOnly = 0x1 }; - quint32 aliasPropertyValueIndex; + quint32 nameIndex; + quint32 idIndex; + quint32 propertyIndex : 31; + quint32 flags : 1; Location location; - Location aliasLocation; // If type == Alias + Location referenceLocation; }; struct Object @@ -376,11 +383,14 @@ struct Object // it will be the name of the attached type. quint32 inheritedTypeNameIndex; quint32 idIndex; - qint32 indexOfDefaultProperty; // -1 means no default property declared in this object + qint32 indexOfDefaultPropertyOrAlias : 31; // -1 means no default property declared in this object + quint32 defaultPropertyIsAlias : 1; quint32 nFunctions; quint32 offsetToFunctions; quint32 nProperties; quint32 offsetToProperties; + quint32 nAliases; + quint32 offsetToAliases; quint32 nSignals; quint32 offsetToSignals; // which in turn will be a table with offsets to variable-sized Signal objects quint32 nBindings; @@ -392,11 +402,12 @@ struct Object // Signal[] // Binding[] - static int calculateSizeExcludingSignals(int nFunctions, int nProperties, int nSignals, int nBindings) + static int calculateSizeExcludingSignals(int nFunctions, int nProperties, int nAliases, int nSignals, int nBindings) { return ( sizeof(Object) + nFunctions * sizeof(quint32) + nProperties * sizeof(Property) + + nAliases * sizeof(Alias) + nSignals * sizeof(quint32) + nBindings * sizeof(Binding) + 0x7 @@ -413,6 +424,11 @@ struct Object return reinterpret_cast<const Property*>(reinterpret_cast<const char *>(this) + offsetToProperties); } + const Alias *aliasTable() const + { + return reinterpret_cast<const Alias*>(reinterpret_cast<const char *>(this) + offsetToAliases); + } + const Binding *bindingTable() const { return reinterpret_cast<const Binding*>(reinterpret_cast<const char *>(this) + offsetToBindings); diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp index 2ffb1596f5..b8c12f70d1 100644 --- a/src/qml/qml/qqmlobjectcreator.cpp +++ b/src/qml/qml/qqmlobjectcreator.cpp @@ -664,7 +664,7 @@ void QQmlObjectCreator::setupBindings(const QBitArray &bindingsToSkip) if (qmlTypeForObject(_bindingTarget)) { quint32 bindingSkipList = 0; - QQmlPropertyData *defaultProperty = _compiledObject->indexOfDefaultProperty != -1 ? _propertyCache->parent()->defaultProperty() : _propertyCache->defaultProperty(); + QQmlPropertyData *defaultProperty = _compiledObject->indexOfDefaultPropertyOrAlias != -1 ? _propertyCache->parent()->defaultProperty() : _propertyCache->defaultProperty(); const QV4::CompiledData::Binding *binding = _compiledObject->bindingTable(); for (quint32 i = 0; i < _compiledObject->nBindings; ++i, ++binding) { |