diff options
Diffstat (limited to 'src/qml/qml/qqmlcompiler.cpp')
-rw-r--r-- | src/qml/qml/qqmlcompiler.cpp | 1049 |
1 files changed, 511 insertions, 538 deletions
diff --git a/src/qml/qml/qqmlcompiler.cpp b/src/qml/qml/qqmlcompiler.cpp index b00f4b3294..2e26d94047 100644 --- a/src/qml/qml/qqmlcompiler.cpp +++ b/src/qml/qml/qqmlcompiler.cpp @@ -44,7 +44,6 @@ #include "qqmlpropertyvaluesource.h" #include "qqmlcomponent.h" #include <private/qmetaobjectbuilder_p.h> -#include <private/qfastmetabuilder_p.h> #include "qqmlstringconverters_p.h" #include "qqmlengine_p.h" #include "qqmlengine.h" @@ -217,8 +216,7 @@ bool QQmlCompiler::isSignalPropertyName(const QHashedStringRef &name) This test corresponds to action taken by genLiteralAssignment(). Any change made here, must have a corresponding action in genLiteralAssigment(). */ -bool QQmlCompiler::testLiteralAssignment(QQmlScript::Property *prop, - QQmlScript::Value *v) +bool QQmlCompiler::testLiteralAssignment(QQmlScript::Property *prop, QQmlScript::Value *v) { const QQmlScript::Variant &value = v->value; @@ -226,7 +224,7 @@ bool QQmlCompiler::testLiteralAssignment(QQmlScript::Property *prop, COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString())); if (prop->core.isEnum()) { - QMetaProperty p = prop->parent->metaObject()->property(prop->index); + QMetaProperty p = prop->parent->metatype->firstCppMetaObject()->property(prop->index); int enumValue; bool ok; if (p.isFlagType()) { @@ -438,7 +436,7 @@ void QQmlCompiler::genLiteralAssignment(QQmlScript::Property *prop, if (v->value.isNumber()) { double n = v->value.asNumber(); if (double(int(n)) == n) { - if (prop->core.isVMEProperty()) { + if (prop->core.isVarProperty()) { Instruction::StoreVarInteger instr; instr.propertyIndex = prop->index; instr.value = int(n); @@ -450,7 +448,7 @@ void QQmlCompiler::genLiteralAssignment(QQmlScript::Property *prop, output->addInstruction(instr); } } else { - if (prop->core.isVMEProperty()) { + if (prop->core.isVarProperty()) { Instruction::StoreVarDouble instr; instr.propertyIndex = prop->index; instr.value = n; @@ -463,7 +461,7 @@ void QQmlCompiler::genLiteralAssignment(QQmlScript::Property *prop, } } } else if (v->value.isBoolean()) { - if (prop->core.isVMEProperty()) { + if (prop->core.isVarProperty()) { Instruction::StoreVarBool instr; instr.propertyIndex = prop->index; instr.value = v->value.asBoolean(); @@ -475,7 +473,7 @@ void QQmlCompiler::genLiteralAssignment(QQmlScript::Property *prop, output->addInstruction(instr); } } else { - if (prop->core.isVMEProperty()) { + if (prop->core.isVarProperty()) { Instruction::StoreVar instr; instr.propertyIndex = prop->index; instr.value = output->indexForString(v->value.asString()); @@ -944,15 +942,18 @@ void QQmlCompiler::compileTree(QQmlScript::Object *tree) output->addInstruction(done); Q_ASSERT(tree->metatype); - - if (tree->metadata.isEmpty()) { - output->root = tree->metatype; + if (!tree->synthdata.isEmpty()) { + enginePrivate->registerCompositeType(output); + } else if (output->types.at(tree->type).component) { + output->metaTypeId = output->types.at(tree->type).component->metaTypeId; + output->listMetaTypeId = output->types.at(tree->type).component->listMetaTypeId; } else { - static_cast<QMetaObject &>(output->rootData) = *tree->metaObject(); - output->root = &output->rootData; + Q_ASSERT(output->types.at(tree->type).type); + output->metaTypeId = output->types.at(tree->type).type->typeId(); + output->listMetaTypeId = output->types.at(tree->type).type->qListTypeId(); } - if (!tree->metadata.isEmpty()) - enginePrivate->registerCompositeType(output->root); + if (!tree->synthdata.isEmpty()) + enginePrivate->registerCompositeType(output); } static bool QStringList_contains(const QStringList &list, const QHashedStringRef &string) @@ -970,11 +971,11 @@ bool QQmlCompiler::buildObject(QQmlScript::Object *obj, const BindingContext &ct componentStats->componentStat.objects++; Q_ASSERT (obj->type != -1); - const QQmlCompiledData::TypeReference &tr = output->types.at(obj->type); - obj->metatype = tr.metaObject(); + QQmlCompiledData::TypeReference &tr = output->types[obj->type]; + obj->metatype = tr.createPropertyCache(engine); - // This object is a "Component" element - if (tr.type && obj->metatype == &QQmlComponent::staticMetaObject) { + // This object is a "Component" element. + if (tr.type && obj->metatype->metaObject() == &QQmlComponent::staticMetaObject) { COMPILE_CHECK(buildComponent(obj, ctxt)); return true; } @@ -999,7 +1000,7 @@ bool QQmlCompiler::buildObject(QQmlScript::Object *obj, const BindingContext &ct // Create the synthesized meta object, ignoring aliases COMPILE_CHECK(checkDynamicMeta(obj)); COMPILE_CHECK(mergeDynamicMetaProperties(obj)); - COMPILE_CHECK(buildDynamicMeta(obj, IgnoreAliases)); + COMPILE_CHECK(buildDynamicMeta(obj, Normal)); // Find the native type and check for the QQmlParserStatus interface QQmlType *type = toQmlType(obj); @@ -1036,54 +1037,22 @@ bool QQmlCompiler::buildObject(QQmlScript::Object *obj, const BindingContext &ct Property *explicitProperty = 0; - const QMetaObject *mo = obj->metatype; - int idx = mo->indexOfClassInfo("DefaultProperty"); - if (idx != -1) { - QMetaClassInfo info = mo->classInfo(idx); - const char *p = info.value(); - if (p) { - int plen = 0; - char ord = 0; - while (char c = p[plen++]) { ord |= c; }; - --plen; - - if (ord & 0x80) { - // Utf8 - unoptimal, but seldom hit - QString *s = pool->NewString(QString::fromUtf8(p, plen)); - QHashedStringRef r(*s); - - if (obj->propertiesHashField.test(r.hash())) { - for (Property *ep = obj->properties.first(); ep; ep = obj->properties.next(ep)) { - if (ep->name() == r) { - explicitProperty = ep; - break; - } - } - } + QString defaultPropertyName = obj->metatype->defaultPropertyName(); + if (!defaultPropertyName.isEmpty()) { + QString *s = pool->NewString(defaultPropertyName); + QHashedStringRef r(*s); - if (!explicitProperty) - defaultProperty->setName(r); - - } else { - QHashedCStringRef r(p, plen); - - if (obj->propertiesHashField.test(r.hash())) { - for (Property *ep = obj->properties.first(); ep; ep = obj->properties.next(ep)) { - if (ep->name() == r) { - explicitProperty = ep; - break; - } - } - } - - if (!explicitProperty) { - // Set the default property name - QChar *buffer = pool->NewRawArray<QChar>(r.length()); - r.writeUtf16(buffer); - defaultProperty->setName(QHashedStringRef(buffer, r.length(), r.hash())); + if (obj->propertiesHashField.test(r.hash())) { + for (Property *ep = obj->properties.first(); ep; ep = obj->properties.next(ep)) { + if (ep->name() == r) { + explicitProperty = ep; + break; } } } + + if (!explicitProperty) + defaultProperty->setName(r); } if (explicitProperty && !explicitProperty->value && !explicitProperty->values.isEmpty()) { @@ -1189,7 +1158,7 @@ bool QQmlCompiler::buildObject(QQmlScript::Object *obj, const BindingContext &ct void QQmlCompiler::genObject(QQmlScript::Object *obj) { QQmlCompiledData::TypeReference &tr = output->types[obj->type]; - if (tr.type && obj->metatype == &QQmlComponent::staticMetaObject) { + if (tr.type && obj->metatype->metaObject() == &QQmlComponent::staticMetaObject) { genComponent(obj); return; } @@ -1240,9 +1209,8 @@ void QQmlCompiler::genObject(QQmlScript::Object *obj) } // Setup the synthesized meta object if necessary - if (!obj->metadata.isEmpty()) { + if (!obj->synthdata.isEmpty()) { Instruction::StoreMetaObject meta; - meta.data = output->indexForByteArray(obj->metadata); meta.aliasData = output->indexForByteArray(obj->synthdata); meta.propertyCache = output->propertyCaches.count(); @@ -1250,17 +1218,6 @@ void QQmlCompiler::genObject(QQmlScript::Object *obj) Q_ASSERT(propertyCache); propertyCache->addref(); - // Add flag for alias properties - if (!obj->synthdata.isEmpty()) { - const QQmlVMEMetaData *vmeMetaData = - reinterpret_cast<const QQmlVMEMetaData *>(obj->synthdata.constData()); - for (int ii = 0; ii < vmeMetaData->aliasCount; ++ii) { - int index = obj->metaObject()->propertyOffset() + vmeMetaData->propertyCount + ii; - QQmlPropertyData *data = propertyCache->property(index); - data->setFlags(data->getFlags() | QQmlPropertyData::IsAlias); - } - } - if (obj == unitRoot) { propertyCache->addref(); output->rootPropertyCache = propertyCache; @@ -1388,11 +1345,14 @@ void QQmlCompiler::genObjectBody(QQmlScript::Object *obj) fetch.line = prop->location.start.line; output->addInstruction(fetch); - if (!prop->value->metadata.isEmpty()) { + if (!prop->value->synthdata.isEmpty()) { Instruction::StoreMetaObject meta; - meta.data = output->indexForByteArray(prop->value->metadata); meta.aliasData = output->indexForByteArray(prop->value->synthdata); - meta.propertyCache = -1; + meta.propertyCache = output->propertyCaches.count(); + QQmlPropertyCache *propertyCache = prop->value->synthCache; + Q_ASSERT(propertyCache); + propertyCache->addref(); + output->propertyCaches << propertyCache; output->addInstruction(meta); } @@ -1665,7 +1625,7 @@ int QQmlCompiler::translationContextIndex() bool QQmlCompiler::buildSignal(QQmlScript::Property *prop, QQmlScript::Object *obj, const BindingContext &ctxt) { - Q_ASSERT(obj->metaObject()); + Q_ASSERT(obj->metatype); const QHashedStringRef &propName = prop->name(); @@ -1754,9 +1714,6 @@ bool QQmlCompiler::buildProperty(QQmlScript::Property *prop, if (prop->isEmpty()) COMPILE_EXCEPTION(prop, tr("Empty property assignment")); - const QMetaObject *metaObject = obj->metaObject(); - Q_ASSERT(metaObject); - if (isAttachedPropertyName(prop->name())) { // Setup attached property data @@ -1784,7 +1741,7 @@ bool QQmlCompiler::buildProperty(QQmlScript::Property *prop, Q_ASSERT(type->attachedPropertiesFunction()); prop->index = type->attachedPropertiesId(); - prop->value->metatype = type->attachedPropertiesType(); + prop->value->metatype = enginePrivate->cache(type->attachedPropertiesType()); } else { // Setup regular property data bool notInRevision = false; @@ -1803,13 +1760,13 @@ bool QQmlCompiler::buildProperty(QQmlScript::Property *prop, prop->index = d->coreIndex; prop->core = *d; } else if (prop->isDefault) { - QMetaProperty p = QQmlMetaType::defaultProperty(metaObject); - QQmlPropertyData defaultPropertyData; - defaultPropertyData.load(p, engine); - if (p.name()) - prop->setName(QLatin1String(p.name())); - prop->core = defaultPropertyData; - prop->index = prop->core.coreIndex; + QString defaultPropertyName = obj->metatype->defaultPropertyName(); + + if (!defaultPropertyName.isEmpty()) { + prop->setName(defaultPropertyName); + prop->core = *obj->metatype->defaultProperty(); + prop->index = prop->core.coreIndex; + } } // We can't error here as the "id" property does not require a @@ -1901,7 +1858,7 @@ bool QQmlCompiler::buildPropertyInNamespace(QQmlImportNamespace *ns, Q_ASSERT(type->attachedPropertiesFunction()); prop->index = type->index(); - prop->value->metatype = type->attachedPropertiesType(); + prop->value->metatype = enginePrivate->cache(type->attachedPropertiesType()); COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt)); } @@ -1979,7 +1936,7 @@ void QQmlCompiler::genPropertyAssignment(QQmlScript::Property *prop, } else if (prop->type == QMetaType::QVariant) { - if (prop->core.isVMEProperty()) { + if (prop->core.isVarProperty()) { Instruction::StoreVarObject store; store.line = v->object->location.start.line; store.propertyIndex = prop->index; @@ -2178,7 +2135,7 @@ bool QQmlCompiler::buildGroupedProperty(QQmlScript::Property *prop, } else { // Load the nested property's meta type - prop->value->metatype = enginePrivate->metaObjectForType(prop->type); + prop->value->metatype = enginePrivate->propertyCacheForType(prop->type); if (!prop->value->metatype) COMPILE_EXCEPTION(prop, tr("Invalid grouped property access")); @@ -2206,7 +2163,7 @@ bool QQmlCompiler::buildValueTypeProperty(QObject *type, if (obj->defaultProperty) COMPILE_EXCEPTION(obj, tr("Invalid property use")); - obj->metatype = type->metaObject(); + obj->metatype = enginePrivate->cache(type); for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) { @@ -2396,22 +2353,22 @@ bool QQmlCompiler::buildPropertyObjectAssignment(QQmlScript::Property *prop, // meta object earlier to test for assignability. It doesn't matter // that there may still be outstanding synthesized meta object changes // on this type, as they are not relevant for assignability testing - v->object->metatype = output->types.at(v->object->type).metaObject(); - Q_ASSERT(v->object->metaObject()); + v->object->metatype = output->types[v->object->type].createPropertyCache(engine); + Q_ASSERT(v->object->metatype); // We want to raw metaObject here as the raw metaobject is the // actual property type before we applied any extensions that might // effect the properties on the type, but don't effect assignability - const QMetaObject *propertyMetaObject = enginePrivate->rawMetaObjectForType(prop->type); + QQmlPropertyCache *propertyMetaObject = enginePrivate->rawPropertyCacheForType(prop->type); // Will be true if the assgned type inherits propertyMetaObject bool isAssignable = false; // Determine isAssignable value if (propertyMetaObject) { - const QMetaObject *c = v->object->metatype; - while(c) { - isAssignable |= (QQmlPropertyPrivate::equal(c, propertyMetaObject)); - c = c->superClass(); + QQmlPropertyCache *c = v->object->metatype; + while (c && !isAssignable) { + isAssignable |= c == propertyMetaObject; + c = c->parent(); } } @@ -2420,12 +2377,12 @@ bool QQmlCompiler::buildPropertyObjectAssignment(QQmlScript::Property *prop, COMPILE_CHECK(buildObject(v->object, ctxt)); v->type = Value::CreatedObject; - } else if (propertyMetaObject == &QQmlComponent::staticMetaObject) { + } else if (propertyMetaObject && propertyMetaObject->metaObject() == &QQmlComponent::staticMetaObject) { // Automatic "Component" insertion QQmlScript::Object *root = v->object; QQmlScript::Object *component = pool->New<Object>(); component->type = componentTypeRef(); - component->metatype = &QQmlComponent::staticMetaObject; + component->metatype = enginePrivate->cache(&QQmlComponent::staticMetaObject); component->location = root->location; QQmlScript::Value *componentValue = pool->New<Value>(); componentValue->object = root; @@ -2465,8 +2422,8 @@ bool QQmlCompiler::buildPropertyOnAssignment(QQmlScript::Property *prop, // meta object earlier to test for assignability. It doesn't matter // that there may still be outstanding synthesized meta object changes // on this type, as they are not relevant for assignability testing - v->object->metatype = output->types.at(v->object->type).metaObject(); - Q_ASSERT(v->object->metaObject()); + v->object->metatype = output->types[v->object->type].createPropertyCache(engine); + Q_ASSERT(v->object->metatype); // Will be true if the assigned type inherits QQmlPropertyValueSource bool isPropertyValue = false; @@ -2481,7 +2438,7 @@ bool QQmlCompiler::buildPropertyOnAssignment(QQmlScript::Property *prop, // Assign as a property value source COMPILE_CHECK(buildObject(v->object, ctxt)); - if (isPropertyInterceptor && prop->parent->synthdata.isEmpty()) + if (isPropertyInterceptor && baseObj->synthdata.isEmpty()) buildDynamicMeta(baseObj, ForceCreation); v->type = isPropertyValue ? Value::ValueSource : Value::ValueInterceptor; } else { @@ -2537,7 +2494,7 @@ bool QQmlCompiler::testQualifiedEnumAssignment(QQmlScript::Property *prop, if (!prop->core.isEnum() && !isIntProp) return true; - QMetaProperty mprop = obj->metaObject()->property(prop->index); + QMetaProperty mprop = obj->metatype->firstCppMetaObject()->property(prop->index); if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration) COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString())); @@ -2775,7 +2732,27 @@ bool QQmlCompiler::mergeDynamicMetaProperties(QQmlScript::Object *obj) return true; } -Q_GLOBAL_STATIC(QAtomicInt, classIndexCounter) +#include <private/qqmljsparser_p.h> + +static QStringList astNodeToStringList(QQmlJS::AST::Node *node) +{ + if (node->kind == QQmlJS::AST::Node::Kind_IdentifierExpression) { + QString name = + static_cast<QQmlJS::AST::IdentifierExpression *>(node)->name.toString(); + return QStringList() << name; + } else if (node->kind == QQmlJS::AST::Node::Kind_FieldMemberExpression) { + QQmlJS::AST::FieldMemberExpression *expr = static_cast<QQmlJS::AST::FieldMemberExpression *>(node); + + QStringList rv = astNodeToStringList(expr->base); + if (rv.isEmpty()) + return rv; + rv.append(expr->name.toString()); + return rv; + } + return QStringList(); +} + +static QAtomicInt classIndexCounter(0); bool QQmlCompiler::buildDynamicMeta(QQmlScript::Object *obj, DynamicMetaMode mode) { @@ -2788,74 +2765,7 @@ bool QQmlCompiler::buildDynamicMeta(QQmlScript::Object *obj, DynamicMetaMode mod obj->dynamicSlots.isEmpty()) return true; - bool resolveAlias = (mode == ResolveAliases); - - const Object::DynamicProperty *defaultProperty = 0; - int aliasCount = 0; - int varPropCount = 0; - int totalPropCount = 0; - int firstPropertyVarIndex = 0; - - for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) { - - if (p->type == Object::DynamicProperty::Alias) - aliasCount++; - if (p->type == Object::DynamicProperty::Var) - varPropCount++; - - if (p->isDefaultProperty && - (resolveAlias || p->type != Object::DynamicProperty::Alias)) - defaultProperty = p; - - if (!resolveAlias) { - // No point doing this for both the alias and non alias cases - QQmlPropertyData *d = property(obj, p->name); - if (d && d->isFinal()) - COMPILE_EXCEPTION(p, tr("Cannot override FINAL property")); - } - } - - bool buildData = resolveAlias || aliasCount == 0; - - QByteArray dynamicData; - if (buildData) { - typedef QQmlVMEMetaData VMD; - - dynamicData = QByteArray(sizeof(QQmlVMEMetaData) + - (obj->dynamicProperties.count() - aliasCount) * sizeof(VMD::PropertyData) + - obj->dynamicSlots.count() * sizeof(VMD::MethodData) + - aliasCount * sizeof(VMD::AliasData), 0); - } - - int uniqueClassId = classIndexCounter()->fetchAndAddRelaxed(1); - - QByteArray newClassName = obj->metatype->className(); - newClassName.append("_QML_"); - newClassName.append(QByteArray::number(uniqueClassId)); - - if (compileState->root == obj && !compileState->nested) { - QString path = output->url.path(); - int lastSlash = path.lastIndexOf(QLatin1Char('/')); - if (lastSlash > -1) { - QString nameBase = path.mid(lastSlash + 1, path.length()-lastSlash-5); - if (!nameBase.isEmpty() && nameBase.at(0).isUpper()) - newClassName = nameBase.toUtf8() + "_QMLTYPE_" + QByteArray::number(uniqueClassId); - } - } - - // Size of the array that describes parameter types & names - int paramDataSize = (obj->aggregateDynamicSignalParameterCount() + obj->aggregateDynamicSlotParameterCount()) * 2 - + obj->dynamicProperties.count() // for Changed() signals return types - // Return "parameters" don't have names - - (obj->dynamicSignals.count() + obj->dynamicSlots.count()); - - QFastMetaBuilder builder; - int paramIndex; - QFastMetaBuilder::StringRef classNameRef = builder.init(newClassName.length(), - obj->dynamicProperties.count() - (resolveAlias?0:aliasCount), - obj->dynamicSlots.count(), - obj->dynamicSignals.count() + obj->dynamicProperties.count(), - defaultProperty?1:0, paramDataSize, ¶mIndex); + Q_ASSERT(obj->synthCache == 0); struct TypeData { Object::DynamicProperty::Type dtype; @@ -2876,456 +2786,521 @@ bool QQmlCompiler::buildDynamicMeta(QQmlScript::Object *obj, DynamicMetaMode mod }; static const int builtinTypeCount = sizeof(builtinTypes) / sizeof(TypeData); - // Reserve dynamic properties - if (obj->dynamicProperties.count()) { - typedef QQmlVMEMetaData VMD; + QByteArray newClassName; - int effectivePropertyIndex = 0; - for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) { + if (compileState->root == obj && !compileState->nested) { + QString path = output->url.path(); + int lastSlash = path.lastIndexOf(QLatin1Char('/')); + if (lastSlash > -1) { + QString nameBase = path.mid(lastSlash + 1, path.length()-lastSlash-5); + if (!nameBase.isEmpty() && nameBase.at(0).isUpper()) + newClassName = nameBase.toUtf8() + "_QMLTYPE_" + + QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1)); + } + } + if (newClassName.isEmpty()) { + newClassName = QQmlMetaObject(obj->metatype).className(); + newClassName.append("_QML_"); + newClassName.append(QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1))); + } + QQmlPropertyCache *cache = obj->metatype->copyAndReserve(engine, obj->dynamicProperties.count(), + obj->dynamicProperties.count() + + obj->dynamicSignals.count() + + obj->dynamicSlots.count(), + obj->dynamicProperties.count() + + obj->dynamicSignals.count()); - // Reserve space for name - if (p->type != Object::DynamicProperty::Alias || resolveAlias) - p->nameRef = builder.newString(p->name.utf8length()); + cache->_dynamicClassName = newClassName; - int metaType = 0; - int propertyType = 0; // for VMD - bool readonly = false; + int cStringNameCount = 0; - if (p->type == Object::DynamicProperty::Alias) { - continue; - } else if (p->type < builtinTypeCount) { - Q_ASSERT(builtinTypes[p->type].dtype == p->type); - metaType = builtinTypes[p->type].metaType; - propertyType = metaType; + int aliasCount = 0; + int varPropCount = 0; - } else { - Q_ASSERT(p->type == Object::DynamicProperty::CustomList || - p->type == Object::DynamicProperty::Custom); - - // XXX don't double resolve this in the case of an alias run - - QByteArray customTypeName; - QQmlType *qmltype = 0; - QString url; - if (!unit->imports().resolveType(p->customType, &qmltype, &url, 0, 0, 0)) - COMPILE_EXCEPTION(p, tr("Invalid property type")); - - if (!qmltype) { - QQmlTypeData *tdata = enginePrivate->typeLoader.getType(QUrl(url)); - Q_ASSERT(tdata); - Q_ASSERT(tdata->isComplete()); - customTypeName = tdata->compiledData()->root->className(); - tdata->release(); - } else { - customTypeName = qmltype->typeName(); - } + for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; + p = obj->dynamicProperties.next(p)) { - if (p->type == Object::DynamicProperty::Custom) { - customTypeName += '*'; - propertyType = QMetaType::QObjectStar; - } else { - readonly = true; - customTypeName = QByteArrayLiteral("QQmlListProperty<") + customTypeName + '>'; - propertyType = qMetaTypeId<QQmlListProperty<QObject> >(); - } + if (p->type == Object::DynamicProperty::Alias) + aliasCount++; + else if (p->type == Object::DynamicProperty::Var) + varPropCount++; - metaType = QMetaType::type(customTypeName); - Q_ASSERT(metaType != QMetaType::UnknownType); - Q_ASSERT(metaType != QMetaType::Void); - } + if (p->name.isLatin1()) { + p->nameIndex = cStringNameCount; + cStringNameCount += p->name.length() + 7 /* strlen("Changed") */; + } - if (p->type == Object::DynamicProperty::Var) - continue; + // No point doing this for both the alias and non alias cases + QQmlPropertyData *d = property(obj, p->name); + if (d && d->isFinal()) + COMPILE_EXCEPTION(p, tr("Cannot override FINAL property")); + } - if (p->isReadOnly) - readonly = true; + for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) { + if (s->name.isLatin1()) { + s->nameIndex = cStringNameCount; + cStringNameCount += s->name.length(); + } + } - if (buildData) { - VMD *vmd = (QQmlVMEMetaData *)dynamicData.data(); - vmd->propertyCount++; - (vmd->propertyData() + effectivePropertyIndex)->propertyType = propertyType; - } + for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) { + if (s->name.isLatin1()) { + s->nameIndex = cStringNameCount; + cStringNameCount += s->name.length(); + } + } - builder.setProperty(effectivePropertyIndex, p->nameRef, metaType, - readonly?QFastMetaBuilder::None:QFastMetaBuilder::Writable, - effectivePropertyIndex); + char *cStringData = 0; + if (cStringNameCount) { + cache->_dynamicStringData.resize(cStringNameCount); + cStringData = cache->_dynamicStringData.data(); - p->changedNameRef = builder.newString(p->name.utf8length() + Changed_string.size()); - builder.setSignal(effectivePropertyIndex, p->changedNameRef, paramIndex); - paramIndex++; + for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; + p = obj->dynamicProperties.next(p)) { - effectivePropertyIndex++; - } + if (p->nameIndex == -1) continue; - if (varPropCount) { - VMD *vmd = (QQmlVMEMetaData *)dynamicData.data(); - if (buildData) - vmd->varPropertyCount = varPropCount; - firstPropertyVarIndex = effectivePropertyIndex; - totalPropCount = varPropCount + effectivePropertyIndex; - for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) { - if (p->type == Object::DynamicProperty::Var) { - if (buildData) { - vmd->propertyCount++; - (vmd->propertyData() + effectivePropertyIndex)->propertyType = QMetaType::QVariant; - } + char *myData = cStringData + p->nameIndex; + for (int ii = 0; ii < p->name.length(); ++ii) + *myData++ = p->name.at(ii).unicode(); + *myData++ = 'C'; *myData++ = 'h'; *myData++ = 'a'; *myData++ = 'n'; + *myData++ = 'g'; *myData++ = 'e'; *myData++ = 'd'; + } - builder.setProperty(effectivePropertyIndex, p->nameRef, - QMetaType::QVariant, - p->isReadOnly?QFastMetaBuilder::None:QFastMetaBuilder::Writable, - effectivePropertyIndex); + for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) { - p->changedNameRef = builder.newString(p->name.utf8length() + Changed_string.size()); - builder.setSignal(effectivePropertyIndex, p->changedNameRef, paramIndex); - paramIndex++; + if (s->nameIndex == -1) continue; - effectivePropertyIndex++; - } - } + char *myData = cStringData + s->nameIndex; + for (int ii = 0; ii < s->name.length(); ++ii) + *myData++ = s->name.at(ii).unicode(); } - - if (aliasCount) { - int aliasIndex = 0; - for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) { - if (p->type == Object::DynamicProperty::Alias) { - if (resolveAlias) { - Q_ASSERT(buildData); - ((QQmlVMEMetaData *)dynamicData.data())->aliasCount++; - COMPILE_CHECK(compileAlias(builder, dynamicData, obj, effectivePropertyIndex, - aliasIndex, *p)); - } - // Even if we aren't resolving the alias, we need a fake signal so that the - // metaobject remains consistent across the resolve and non-resolve alias runs - p->changedNameRef = builder.newString(p->name.utf8length() + Changed_string.size()); - builder.setSignal(effectivePropertyIndex, p->changedNameRef, paramIndex); - paramIndex++; - effectivePropertyIndex++; - aliasIndex++; - } - } + + for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; + s = obj->dynamicSignals.next(s)) { + + if (s->nameIndex == -1) continue; + + char *myData = cStringData + s->nameIndex; + for (int ii = 0; ii < s->name.length(); ++ii) + *myData++ = s->name.at(ii).unicode(); } } - // Reserve default property - QFastMetaBuilder::StringRef defPropRef; - if (defaultProperty) { - defPropRef = builder.newString(int(sizeof("DefaultProperty")) - 1); - builder.setClassInfo(0, defPropRef, defaultProperty->nameRef); + QByteArray dynamicData; + typedef QQmlVMEMetaData VMD; + + dynamicData = QByteArray(sizeof(QQmlVMEMetaData) + + obj->dynamicProperties.count() * sizeof(VMD::PropertyData) + + obj->dynamicSlots.count() * sizeof(VMD::MethodData) + + aliasCount * sizeof(VMD::AliasData), 0); + + int effectivePropertyIndex = cache->propertyIndexCacheStart; + int effectiveMethodIndex = cache->methodIndexCacheStart; + + // First set up notify signals for properties - first normal, then var, then alias + enum { NSS_Normal = 0, NSS_Var = 1, NSS_Alias = 2 }; + for (int ii = NSS_Normal; ii <= NSS_Alias; ++ii) { // 0 == normal, 1 == var, 2 == alias + + if (ii == NSS_Var && varPropCount == 0) continue; + else if (ii == NSS_Alias && aliasCount == 0) continue; + + for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; + p = obj->dynamicProperties.next(p)) { + + if ((ii == NSS_Normal && (p->type == Object::DynamicProperty::Alias || + p->type == Object::DynamicProperty::Var)) || + ((ii == NSS_Var) && (p->type != Object::DynamicProperty::Var)) || + ((ii == NSS_Alias) && (p->type != Object::DynamicProperty::Alias))) + continue; + + quint32 flags = QQmlPropertyData::IsSignal | QQmlPropertyData::IsFunction | + QQmlPropertyData::IsVMESignal; + + if (p->nameIndex != -1) { + QHashedCStringRef changedSignalName(cStringData + p->nameIndex, + p->name.length() + 7 /* strlen("Changed") */); + cache->appendSignal(changedSignalName, flags, effectiveMethodIndex++); + } else { + QString changedSignalName = p->name.toString() + QLatin1String("Changed"); + + cache->appendSignal(changedSignalName, flags, effectiveMethodIndex++); + } + } } - // Reserve dynamic signals - int signalIndex = 0; + // Dynamic signals for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) { + int paramCount = s->parameterNames.count(); - s->nameRef = builder.newString(s->name.utf8length()); + QList<QByteArray> names; + QVarLengthArray<int, 10> paramTypes(paramCount?(paramCount + 1):0); - int paramCount = s->parameterNames.count(); - QVarLengthArray<int, 10> paramTypes(paramCount); if (paramCount) { - s->parameterNamesRef = pool->NewRawList<QFastMetaBuilder::StringRef>(paramCount); + paramTypes[0] = paramCount; + for (int i = 0; i < paramCount; ++i) { - s->parameterNamesRef[i] = builder.newString(s->parameterNames.at(i).utf8length()); Q_ASSERT(s->parameterTypes.at(i) < builtinTypeCount); - paramTypes[i] = builtinTypes[s->parameterTypes.at(i)].metaType; + paramTypes[i + 1] = builtinTypes[s->parameterTypes.at(i)].metaType; + names.append(s->parameterNames.at(i).toString().toUtf8()); } } - if (buildData) - ((QQmlVMEMetaData *)dynamicData.data())->signalCount++; - - builder.setSignal(signalIndex + obj->dynamicProperties.count(), s->nameRef, - paramIndex, paramCount, paramTypes.constData(), s->parameterNamesRef.data()); - paramIndex += paramCount*2 + 1; - ++signalIndex; + ((QQmlVMEMetaData *)dynamicData.data())->signalCount++; + + quint32 flags = QQmlPropertyData::IsSignal | QQmlPropertyData::IsFunction | + QQmlPropertyData::IsVMESignal; + if (paramCount) + flags |= QQmlPropertyData::HasArguments; + + if (s->nameIndex != -1) { + QHashedCStringRef name(cStringData + s->nameIndex, s->name.length(), s->name.hash()); + cache->appendSignal(name, flags, effectiveMethodIndex++, + paramCount?paramTypes.constData():0, names); + } else { + QString name = s->name.toString(); + cache->appendSignal(name, flags, effectiveMethodIndex++, + paramCount?paramTypes.constData():0, names); + } } - // Reserve dynamic slots - if (obj->dynamicSlots.count()) { - typedef QQmlVMEMetaData VMD; + // Dynamic slots + for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) { + int paramCount = s->parameterNames.count(); - int methodIndex = 0; - for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) { - s->nameRef = builder.newString(s->name.utf8length()); - int paramCount = s->parameterNames.count(); - - QVarLengthArray<int, 10> paramTypes(paramCount); - if (paramCount) { - s->parameterNamesRef = pool->NewRawList<QFastMetaBuilder::StringRef>(paramCount); - for (int i = 0; i < paramCount; ++i) { - s->parameterNamesRef[i] = builder.newString(s->parameterNames.at(i).size()); - paramTypes[i] = QMetaType::QVariant; - } - } + quint32 flags = QQmlPropertyData::IsFunction | QQmlPropertyData::IsVMEFunction; - builder.setMethod(methodIndex, s->nameRef, paramIndex, paramCount, - paramTypes.constData(), s->parameterNamesRef.data(), QMetaType::QVariant); - paramIndex += paramCount*2 + 1; - - if (buildData) { - QString funcScript; - int namesSize = 0; - if (paramCount) namesSize += s->parameterNamesLength() + (paramCount - 1 /* commas */); - funcScript.reserve(int(sizeof("(function ")) - 1 + s->name.length() + 1 /* lparen */ + - namesSize + 1 /* rparen */ + s->body.length() + 1 /* rparen */); - funcScript = QLatin1String("(function ") + s->name.toString() + QLatin1Char('('); - for (int jj = 0; jj < paramCount; ++jj) { - if (jj) funcScript.append(QLatin1Char(',')); - funcScript.append(QLatin1String(s->parameterNames.at(jj))); - } - funcScript += QLatin1Char(')') + s->body + QLatin1Char(')'); + if (paramCount) + flags |= QQmlPropertyData::HasArguments; - QByteArray utf8 = funcScript.toUtf8(); - VMD::MethodData methodData = { s->parameterNames.count(), 0, - utf8.length(), - s->location.start.line }; + if (s->nameIndex != -1) { + QHashedCStringRef name(cStringData + s->nameIndex, s->name.length(), s->name.hash()); + cache->appendMethod(name, flags, effectiveMethodIndex++, s->parameterNames); + } else { + QString name = s->name.toString(); + cache->appendMethod(name, flags, effectiveMethodIndex++, s->parameterNames); + } + } - VMD *vmd = (QQmlVMEMetaData *)dynamicData.data(); - vmd->methodCount++; - VMD::MethodData &md = *(vmd->methodData() + methodIndex); - md = methodData; - md.bodyOffset = dynamicData.size(); + // Dynamic properties (except var and aliases) + effectiveMethodIndex = cache->methodIndexCacheStart; + for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; + p = obj->dynamicProperties.next(p)) { - dynamicData.append((const char *)utf8.constData(), utf8.length()); - } + if (p->type == Object::DynamicProperty::Alias || + p->type == Object::DynamicProperty::Var) + continue; + int propertyType = 0; + int vmePropertyType = 0; + quint32 propertyFlags = 0; - methodIndex++; - } - } + if (p->type < builtinTypeCount) { + propertyType = builtinTypes[p->type].metaType; + vmePropertyType = propertyType; - // Now allocate properties - for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) { + if (p->type == Object::DynamicProperty::Variant) + propertyFlags |= QQmlPropertyData::IsQVariant; + } else { + Q_ASSERT(p->type == Object::DynamicProperty::CustomList || + p->type == Object::DynamicProperty::Custom); - char *d = p->changedNameRef.data(); - p->name.writeUtf8(d); - strcpy(d + p->name.utf8length(), "Changed"); - p->changedNameRef.loadByteArrayData(); + QQmlType *qmltype = 0; + QString url; + if (!unit->imports().resolveType(p->customType.toString(), &qmltype, &url, 0, 0, 0)) + COMPILE_EXCEPTION(p, tr("Invalid property type")); - if (p->type == Object::DynamicProperty::Alias && !resolveAlias) - continue; + if (!qmltype) { + QQmlTypeData *tdata = enginePrivate->typeLoader.getType(QUrl(url)); + Q_ASSERT(tdata); + Q_ASSERT(tdata->isComplete()); - p->nameRef.load(p->name); - } + QQmlCompiledData *data = tdata->compiledData(); - // Allocate default property if necessary - if (defaultProperty) - defPropRef.load("DefaultProperty"); + if (p->type == Object::DynamicProperty::Custom) { + propertyType = data->metaTypeId; + vmePropertyType = QMetaType::QObjectStar; + } else { + propertyType = data->listMetaTypeId; + vmePropertyType = qMetaTypeId<QQmlListProperty<QObject> >(); + } - // Now allocate signals - for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) { + tdata->release(); + } else { + if (p->type == Object::DynamicProperty::Custom) { + propertyType = qmltype->typeId(); + vmePropertyType = QMetaType::QObjectStar; + } else { + propertyType = qmltype->qListTypeId(); + vmePropertyType = qMetaTypeId<QQmlListProperty<QObject> >(); + } + } - s->nameRef.load(s->name); + if (p->type == Object::DynamicProperty::Custom) + propertyFlags |= QQmlPropertyData::IsQObjectDerived; + else + propertyFlags |= QQmlPropertyData::IsQList; + } - for (int jj = 0; jj < s->parameterNames.count(); ++jj) - s->parameterNamesRef[jj].load(s->parameterNames.at(jj)); - } + if (!p->isReadOnly && p->type != Object::DynamicProperty::CustomList) + propertyFlags |= QQmlPropertyData::IsWritable; - // Now allocate methods - for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) { - s->nameRef.load(s->name); + if (p->nameIndex != -1) { + QHashedCStringRef propertyName(cStringData + p->nameIndex, p->name.length(), + p->name.hash()); + if (p->isDefaultProperty) cache->_defaultPropertyName = propertyName.toUtf16(); + cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++, + propertyType, effectiveMethodIndex); + } else { + QString propertyName = p->name.toString(); + if (p->isDefaultProperty) cache->_defaultPropertyName = propertyName; + cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++, + propertyType, effectiveMethodIndex); + } - for (int jj = 0; jj < s->parameterNames.count(); ++jj) - s->parameterNamesRef[jj].load(s->parameterNames.at(jj).constData()); - } + effectiveMethodIndex++; - // Now allocate class name - classNameRef.load(newClassName); + VMD *vmd = (QQmlVMEMetaData *)dynamicData.data(); + (vmd->propertyData() + vmd->propertyCount)->propertyType = vmePropertyType; + vmd->propertyCount++; + } - obj->metadata = builder.toData(); - builder.fromData(&obj->extObject, obj->metatype, obj->metadata); + // Now do var properties + for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p && varPropCount; + p = obj->dynamicProperties.next(p)) { - if (mode == IgnoreAliases && aliasCount) - compileState->aliasingObjects.append(obj); + if (p->type != Object::DynamicProperty::Var) + continue; - obj->synthdata = dynamicData; + quint32 propertyFlags = QQmlPropertyData::IsVarProperty; + if (!p->isReadOnly) + propertyFlags |= QQmlPropertyData::IsWritable; + + VMD *vmd = (QQmlVMEMetaData *)dynamicData.data(); + (vmd->propertyData() + vmd->propertyCount)->propertyType = QMetaType::QVariant; + vmd->propertyCount++; + ((QQmlVMEMetaData *)dynamicData.data())->varPropertyCount++; + + if (p->nameIndex != -1) { + QHashedCStringRef propertyName(cStringData + p->nameIndex, p->name.length(), + p->name.hash()); + if (p->isDefaultProperty) cache->_defaultPropertyName = propertyName.toUtf16(); + cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++, + QMetaType::QVariant, effectiveMethodIndex); + } else { + QString propertyName = p->name.toString(); + if (p->isDefaultProperty) cache->_defaultPropertyName = propertyName; + cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++, + QMetaType::QVariant, effectiveMethodIndex); + } - if (obj->synthCache) { - obj->synthCache->release(); - obj->synthCache = 0; + effectiveMethodIndex++; } - if (obj->type != -1) { - QQmlPropertyCache *superCache = output->types[obj->type].createPropertyCache(engine); - QQmlPropertyCache *cache = - superCache->copyAndAppend(engine, &obj->extObject, - QQmlPropertyData::NoFlags, - QQmlPropertyData::IsVMEFunction, - QQmlPropertyData::IsVMESignal); + // Alias property count. Actual data is setup in buildDynamicMetaAliases + ((QQmlVMEMetaData *)dynamicData.data())->aliasCount = aliasCount; + + // Dynamic slot data - comes after the property data + for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) { + int paramCount = s->parameterNames.count(); - // now we modify the flags appropriately for var properties. - int propertyOffset = obj->extObject.propertyOffset(); - QQmlPropertyData *currPropData = 0; - for (int pvi = firstPropertyVarIndex; pvi < totalPropCount; ++pvi) { - currPropData = cache->property(pvi + propertyOffset); - currPropData->setFlags(currPropData->getFlags() | QQmlPropertyData::IsVMEProperty); + QString funcScript; + int namesSize = 0; + if (paramCount) namesSize += s->parameterNamesLength() + (paramCount - 1 /* commas */); + funcScript.reserve(strlen("(function ") + s->name.length() + 1 /* lparen */ + + namesSize + 1 /* rparen */ + s->body.length() + 1 /* rparen */); + funcScript = QLatin1String("(function ") + s->name.toString() + QLatin1Char('('); + for (int jj = 0; jj < paramCount; ++jj) { + if (jj) funcScript.append(QLatin1Char(',')); + funcScript.append(QLatin1String(s->parameterNames.at(jj))); } + funcScript += QLatin1Char(')') + s->body + QLatin1Char(')'); + + QByteArray utf8 = funcScript.toUtf8(); + VMD::MethodData methodData = { s->parameterNames.count(), + dynamicData.size(), + utf8.length(), + s->location.start.line }; + + VMD *vmd = (QQmlVMEMetaData *)dynamicData.data(); + VMD::MethodData &md = *(vmd->methodData() + vmd->methodCount); + vmd->methodCount++; + md = methodData; - obj->synthCache = cache; + dynamicData.append((const char *)utf8.constData(), utf8.length()); } + if (aliasCount) + compileState->aliasingObjects.append(obj); + + obj->synthdata = dynamicData; + obj->synthCache = cache; + obj->metatype = cache; + return true; } -bool QQmlCompiler::checkValidId(QQmlScript::Value *v, const QString &val) +bool QQmlCompiler::buildDynamicMetaAliases(QQmlScript::Object *obj) { - if (val.isEmpty()) - COMPILE_EXCEPTION(v, tr( "Invalid empty ID")); + Q_ASSERT(obj->synthCache); - QChar ch = val.at(0); - if (ch.isLetter() && !ch.isLower()) - COMPILE_EXCEPTION(v, tr( "IDs cannot start with an uppercase letter")); + QByteArray &dynamicData = obj->synthdata; - QChar u(QLatin1Char('_')); - if (!ch.isLetter() && ch != u) - COMPILE_EXCEPTION(v, tr( "IDs must start with a letter or underscore")); + QQmlPropertyCache *cache = obj->synthCache; + char *cStringData = cache->_dynamicStringData.data(); - for (int ii = 1; ii < val.count(); ++ii) { - ch = val.at(ii); - if (!ch.isLetterOrNumber() && ch != u) - COMPILE_EXCEPTION(v, tr( "IDs must contain only letters, numbers, and underscores")); - } + int effectiveMethodIndex = cache->methodIndexCacheStart + cache->propertyIndexCache.count(); + int effectivePropertyIndex = cache->propertyIndexCacheStart + cache->propertyIndexCache.count(); + int effectiveAliasIndex = 0; - if (enginePrivate->v8engine()->illegalNames().contains(val)) - COMPILE_EXCEPTION(v, tr( "ID illegally masks global JavaScript property")); + for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; + p = obj->dynamicProperties.next(p)) { - return true; -} + if (p->type != Object::DynamicProperty::Alias) + continue; -#include <private/qqmljsparser_p.h> + if (!p->defaultValue) + COMPILE_EXCEPTION(obj, tr("No property alias location")); -static QStringList astNodeToStringList(QQmlJS::AST::Node *node) -{ - if (node->kind == QQmlJS::AST::Node::Kind_IdentifierExpression) { - QString name = - static_cast<QQmlJS::AST::IdentifierExpression *>(node)->name.toString(); - return QStringList() << name; - } else if (node->kind == QQmlJS::AST::Node::Kind_FieldMemberExpression) { - QQmlJS::AST::FieldMemberExpression *expr = static_cast<QQmlJS::AST::FieldMemberExpression *>(node); + if (!p->defaultValue->values.isOne() || + p->defaultValue->values.first()->object || + !p->defaultValue->values.first()->value.isScript()) + COMPILE_EXCEPTION(p->defaultValue, tr("Invalid alias location")); - QStringList rv = astNodeToStringList(expr->base); - if (rv.isEmpty()) - return rv; - rv.append(expr->name.toString()); - return rv; - } - return QStringList(); -} + QQmlJS::AST::Node *node = p->defaultValue->values.first()->value.asAST(); + Q_ASSERT(node); -bool QQmlCompiler::compileAlias(QFastMetaBuilder &builder, - QByteArray &data, - QQmlScript::Object *obj, - int propIndex, int aliasIndex, - Object::DynamicProperty &prop) -{ - Q_ASSERT(!prop.nameRef.isEmpty()); - if (!prop.defaultValue) - COMPILE_EXCEPTION(obj, tr("No property alias location")); + QStringList alias = astNodeToStringList(node); + if (alias.count() < 1 || alias.count() > 3) + COMPILE_EXCEPTION(p->defaultValue, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>")); - if (!prop.defaultValue->values.isOne() || - prop.defaultValue->values.first()->object || - !prop.defaultValue->values.first()->value.isScript()) - COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location")); + QQmlScript::Object *idObject = compileState->ids.value(alias.at(0)); + if (!idObject) + COMPILE_EXCEPTION(p->defaultValue, tr("Invalid alias reference. Unable to find id \"%1\"").arg(alias.at(0))); - QQmlJS::AST::Node *node = prop.defaultValue->values.first()->value.asAST(); - if (!node) - COMPILE_EXCEPTION(obj, tr("No property alias location")); // ### Can this happen? + int propIdx = -1; + int notifySignal = -1; + int flags = 0; + int type = 0; + bool writable = false; + bool resettable = false; - QStringList alias = astNodeToStringList(node); + quint32 propertyFlags = QQmlPropertyData::IsAlias; - if (alias.count() < 1 || alias.count() > 3) - COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>")); + if (alias.count() == 2 || alias.count() == 3) { + QQmlPropertyData *property = this->property(idObject, alias.at(1)); - QQmlScript::Object *idObject = compileState->ids.value(alias.at(0)); - if (!idObject) - COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. Unable to find id \"%1\"").arg(alias.at(0))); + if (!property || property->coreIndex > 0xFFFF) + COMPILE_EXCEPTION(p->defaultValue, tr("Invalid alias location")); - QByteArray typeName; + propIdx = property->coreIndex; + type = property->propType; - int propIdx = -1; - int flags = 0; - int type = 0; - bool writable = false; - bool resettable = false; - if (alias.count() == 2 || alias.count() == 3) { - propIdx = indexOfProperty(idObject, alias.at(1)); + writable = property->isWritable(); + resettable = property->isResettable(); + notifySignal = property->notifyIndex; - if (-1 == propIdx) { - COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location")); - } else if (propIdx > 0xFFFF) { - COMPILE_EXCEPTION(prop.defaultValue, tr("Alias property exceeds alias bounds")); - } + if (alias.count() == 3) { + QQmlValueType *valueType = enginePrivate->valueTypes[type]; // XXX threadsafe? + if (!valueType) + COMPILE_EXCEPTION(p->defaultValue, tr("Invalid alias location")); - QMetaProperty aliasProperty = idObject->metaObject()->property(propIdx); - if (!aliasProperty.isScriptable()) - COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location")); + propIdx |= ((unsigned int)type) << 24; + int valueTypeIndex = + valueType->metaObject()->indexOfProperty(alias.at(2).toUtf8().constData()); + if (valueTypeIndex == -1) + COMPILE_EXCEPTION(p->defaultValue, tr("Invalid alias location")); + Q_ASSERT(valueTypeIndex <= 0xFF); - writable = aliasProperty.isWritable() && !prop.isReadOnly; - resettable = aliasProperty.isResettable() && !prop.isReadOnly; + propIdx |= (valueTypeIndex << 16); + if (valueType->metaObject()->property(valueTypeIndex).isEnumType()) + type = QVariant::Int; + else + type = valueType->metaObject()->property(valueTypeIndex).userType(); - type = aliasProperty.userType(); + } else { + if (property->isEnum()) { + type = QVariant::Int; + } else { + // Copy type flags + propertyFlags |= property->getFlags() & QQmlPropertyData::PropTypeFlagMask; - if (alias.count() == 3) { - QQmlValueType *valueType = enginePrivate->valueTypes[aliasProperty.type()]; - if (!valueType) - COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location")); + if (property->isVarProperty()) + propertyFlags |= QQmlPropertyData::IsQVariant; - propIdx |= ((unsigned int)aliasProperty.type()) << 24; + if (property->isQObject()) + flags |= QML_ALIAS_FLAG_PTR; + } + } + } else { + Q_ASSERT(idObject->type != -1); // How else did it get an id? - int valueTypeIndex = valueType->metaObject()->indexOfProperty(alias.at(2).toUtf8().constData()); - if (valueTypeIndex == -1) - COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location")); - Q_ASSERT(valueTypeIndex <= 0xFF); - - aliasProperty = valueType->metaObject()->property(valueTypeIndex); - propIdx |= (valueTypeIndex << 16); + const QQmlCompiledData::TypeReference &ref = output->types.at(idObject->type); + if (ref.type) + type = ref.type->typeId(); + else + type = ref.component->metaTypeId; - // update the property type - type = aliasProperty.userType(); + flags |= QML_ALIAS_FLAG_PTR; + propertyFlags |= QQmlPropertyData::IsQObjectDerived; } - if (aliasProperty.isEnumType()) - typeName = "int"; // Avoid introducing a dependency on the aliased metaobject - else - typeName = aliasProperty.typeName(); - } else { - Q_ASSERT(idObject->type != -1); // How else did it get an id? + QQmlVMEMetaData::AliasData aliasData = { idObject->idIndex, propIdx, flags, notifySignal }; + + typedef QQmlVMEMetaData VMD; + VMD *vmd = (QQmlVMEMetaData *)dynamicData.data(); + *(vmd->aliasData() + effectiveAliasIndex++) = aliasData; - const QQmlCompiledData::TypeReference &ref = output->types.at(idObject->type); - if (ref.type) - typeName = ref.type->typeName(); + if (!p->isReadOnly && writable) + propertyFlags |= QQmlPropertyData::IsWritable; else - typeName = ref.component->root->className(); + propertyFlags &= ~QQmlPropertyData::IsWritable; - typeName += '*'; + if (resettable) + propertyFlags |= QQmlPropertyData::IsResettable; + else + propertyFlags &= ~QQmlPropertyData::IsResettable; + + if (p->nameIndex != -1) { + QHashedCStringRef propertyName(cStringData + p->nameIndex, p->name.length(), + p->name.hash()); + if (p->isDefaultProperty) cache->_defaultPropertyName = propertyName.toUtf16(); + cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++, + type, effectiveMethodIndex++); + } else { + QString propertyName = p->name.toString(); + if (p->isDefaultProperty) cache->_defaultPropertyName = propertyName; + cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++, + type, effectiveMethodIndex++); + } } - if (typeName.endsWith('*')) - flags |= QML_ALIAS_FLAG_PTR; + return true; +} - if (type == QMetaType::UnknownType) { - Q_ASSERT(!typeName.isEmpty()); - type = QMetaType::type(typeName); - Q_ASSERT(type != QMetaType::UnknownType); - Q_ASSERT(type != QMetaType::Void); - } +bool QQmlCompiler::checkValidId(QQmlScript::Value *v, const QString &val) +{ + if (val.isEmpty()) + COMPILE_EXCEPTION(v, tr( "Invalid empty ID")); - QQmlVMEMetaData::AliasData aliasData = { idObject->idIndex, propIdx, flags }; + QChar ch = val.at(0); + if (ch.isLetter() && !ch.isLower()) + COMPILE_EXCEPTION(v, tr( "IDs cannot start with an uppercase letter")); - typedef QQmlVMEMetaData VMD; - VMD *vmd = (QQmlVMEMetaData *)data.data(); - *(vmd->aliasData() + aliasIndex) = aliasData; + QChar u(QLatin1Char('_')); + if (!ch.isLetter() && ch != u) + COMPILE_EXCEPTION(v, tr( "IDs must start with a letter or underscore")); - int propertyFlags = 0; - if (writable) - propertyFlags |= QFastMetaBuilder::Writable; - if (resettable) - propertyFlags |= QFastMetaBuilder::Resettable; + for (int ii = 1; ii < val.count(); ++ii) { + ch = val.at(ii); + if (!ch.isLetterOrNumber() && ch != u) + COMPILE_EXCEPTION(v, tr( "IDs must contain only letters, numbers, and underscores")); + } - builder.setProperty(propIndex, prop.nameRef, type, - (QFastMetaBuilder::PropertyFlag)propertyFlags, - propIndex); + if (enginePrivate->v8engine()->illegalNames().contains(val)) + COMPILE_EXCEPTION(v, tr( "ID illegally masks global JavaScript property")); return true; } @@ -3336,7 +3311,7 @@ bool QQmlCompiler::buildBinding(QQmlScript::Value *value, { Q_ASSERT(prop->index != -1); Q_ASSERT(prop->parent); - Q_ASSERT(prop->parent->metaObject()); + Q_ASSERT(prop->parent->metatype); if (!prop->core.isWritable() && !prop->core.isQList() && !prop->isReadOnlyDeclaration) COMPILE_EXCEPTION(prop, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString())); @@ -3546,8 +3521,7 @@ QQmlCompiler::genValueTypeData(QQmlScript::Property *valueTypeProp, QQmlScript::Property *prop) { typedef QQmlPropertyPrivate QDPP; - return QDPP::saveValueType(prop->parent->metaObject(), prop->index, - enginePrivate->valueTypes[prop->type]->metaObject(), + return QDPP::saveValueType(prop->core, enginePrivate->valueTypes[prop->type]->metaObject(), valueTypeProp->index, engine); } @@ -3558,7 +3532,7 @@ bool QQmlCompiler::completeComponentBuild() for (Object *aliasObject = compileState->aliasingObjects.first(); aliasObject; aliasObject = compileState->aliasingObjects.next(aliasObject)) - COMPILE_CHECK(buildDynamicMeta(aliasObject, ResolveAliases)); + COMPILE_CHECK(buildDynamicMetaAliases(aliasObject)); QV4Compiler::Expression expr(unit->imports()); expr.component = compileState->root; @@ -3733,13 +3707,13 @@ void QQmlCompiler::dumpStats() */ bool QQmlCompiler::canCoerce(int to, QQmlScript::Object *from) { - const QMetaObject *toMo = enginePrivate->rawMetaObjectForType(to); - const QMetaObject *fromMo = from->metaObject(); + QQmlPropertyCache *toMo = enginePrivate->rawPropertyCacheForType(to); + QQmlPropertyCache *fromMo = from->metatype; while (fromMo) { - if (QQmlPropertyPrivate::equal(fromMo, toMo)) + if (fromMo == toMo) return true; - fromMo = fromMo->superClass(); + fromMo = fromMo->parent(); } return false; } @@ -3762,8 +3736,7 @@ QQmlType *QQmlCompiler::toQmlType(QQmlScript::Object *from) if (from->type != -1 && output->types.at(from->type).type) return output->types.at(from->type).type; - // ### Optimize - const QMetaObject *mo = from->metatype; + const QMetaObject *mo = from->metatype->firstCppMetaObject(); QQmlType *type = 0; while (!type && mo) { type = QQmlMetaType::qmlType(mo); @@ -3774,7 +3747,7 @@ QQmlType *QQmlCompiler::toQmlType(QQmlScript::Object *from) QStringList QQmlCompiler::deferredProperties(QQmlScript::Object *obj) { - const QMetaObject *mo = obj->metatype; + const QMetaObject *mo = obj->metatype->firstCppMetaObject(); int idx = mo->indexOfClassInfo("DeferredPropertyNames"); if (idx == -1) @@ -3795,7 +3768,7 @@ QQmlCompiler::property(QQmlScript::Object *object, int index) else if (object->type != -1) cache = output->types[object->type].createPropertyCache(engine); else - cache = QQmlEnginePrivate::get(engine)->cache(object->metaObject()); + cache = object->metatype; return cache->property(index); } @@ -3812,7 +3785,7 @@ QQmlCompiler::property(QQmlScript::Object *object, const QHashedStringRef &name, else if (object->type != -1) cache = output->types[object->type].createPropertyCache(engine); else - cache = QQmlEnginePrivate::get(engine)->cache(object->metaObject()); + cache = object->metatype; QQmlPropertyData *d = cache->property(name); @@ -3841,7 +3814,7 @@ QQmlCompiler::signal(QQmlScript::Object *object, const QHashedStringRef &name, b else if (object->type != -1) cache = output->types[object->type].createPropertyCache(engine); else - cache = QQmlEnginePrivate::get(engine)->cache(object->metaObject()); + cache = object->metatype; QQmlPropertyData *d = cache->property(name); |