diff options
Diffstat (limited to 'src/qml/qml/qqmlobjectcreator.cpp')
-rw-r--r-- | src/qml/qml/qqmlobjectcreator.cpp | 1001 |
1 files changed, 200 insertions, 801 deletions
diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp index 3798129e8b..963b8272f4 100644 --- a/src/qml/qml/qqmlobjectcreator.cpp +++ b/src/qml/qml/qqmlobjectcreator.cpp @@ -42,7 +42,6 @@ #include "qqmlobjectcreator_p.h" #include <private/qqmlengine_p.h> -#include <private/qqmlabstractbinding_p.h> #include <private/qqmlvmemetaobject_p.h> #include <private/qv4function_p.h> #include <private/qv4functionobject_p.h> @@ -52,9 +51,10 @@ #include <private/qqmlboundsignal_p.h> #include <private/qqmltrace_p.h> #include <private/qqmlcomponentattached_p.h> -#include <QQmlComponent> #include <private/qqmlcomponent_p.h> -#include <private/qqmlcodegenerator_p.h> +#include <private/qqmlcustomparser_p.h> +#include <private/qqmlscriptstring_p.h> +#include <private/qqmlpropertyvalueinterceptor_p.h> QT_USE_NAMESPACE @@ -70,394 +70,6 @@ struct ActiveOCRestorer }; } -QQmlCompilePass::QQmlCompilePass(const QUrl &url, const QV4::CompiledData::QmlUnit *unit) - : url(url) - , qmlUnit(unit) -{ -} - -void QQmlCompilePass::recordError(const QV4::CompiledData::Location &location, const QString &description) -{ - QQmlError error; - error.setUrl(url); - error.setLine(location.line); - error.setColumn(location.column); - error.setDescription(description); - errors << error; -} - -#define COMPILE_EXCEPTION(token, desc) \ - { \ - recordError((token)->location, desc); \ - return false; \ - } - -static QAtomicInt classIndexCounter(0); - -QQmlPropertyCacheCreator::QQmlPropertyCacheCreator(QQmlEnginePrivate *enginePrivate, const QV4::CompiledData::QmlUnit *unit, const QUrl &url, const QQmlImports *imports, - QHash<int, QQmlCompiledData::TypeReference> *resolvedTypes) - : QQmlCompilePass(url, unit) - , enginePrivate(enginePrivate) - , imports(imports) - , resolvedTypes(resolvedTypes) -{ -} - -bool QQmlPropertyCacheCreator::create(const QV4::CompiledData::Object *obj, QQmlPropertyCache **resultCache, QByteArray *vmeMetaObjectData) -{ - Q_ASSERT(!stringAt(obj->inheritedTypeNameIndex).isEmpty()); - - QQmlCompiledData::TypeReference typeRef = resolvedTypes->value(obj->inheritedTypeNameIndex); - QQmlPropertyCache *baseTypeCache = typeRef.createPropertyCache(QQmlEnginePrivate::get(enginePrivate)); - Q_ASSERT(baseTypeCache); - if (obj->nProperties == 0 && obj->nSignals == 0 && obj->nFunctions == 0) { - *resultCache = baseTypeCache; - vmeMetaObjectData->clear(); - return true; - } - - QQmlPropertyCache *cache = baseTypeCache->copyAndReserve(QQmlEnginePrivate::get(enginePrivate), - obj->nProperties, - obj->nFunctions + obj->nProperties + obj->nSignals, - obj->nSignals + obj->nProperties); - *resultCache = cache; - - vmeMetaObjectData->clear(); - - struct TypeData { - QV4::CompiledData::Property::Type dtype; - int metaType; - } builtinTypes[] = { - { QV4::CompiledData::Property::Var, QMetaType::QVariant }, - { QV4::CompiledData::Property::Variant, QMetaType::QVariant }, - { QV4::CompiledData::Property::Int, QMetaType::Int }, - { QV4::CompiledData::Property::Bool, QMetaType::Bool }, - { QV4::CompiledData::Property::Real, QMetaType::Double }, - { QV4::CompiledData::Property::String, QMetaType::QString }, - { QV4::CompiledData::Property::Url, QMetaType::QUrl }, - { QV4::CompiledData::Property::Color, QMetaType::QColor }, - { QV4::CompiledData::Property::Font, QMetaType::QFont }, - { QV4::CompiledData::Property::Time, QMetaType::QTime }, - { QV4::CompiledData::Property::Date, QMetaType::QDate }, - { QV4::CompiledData::Property::DateTime, QMetaType::QDateTime }, - { QV4::CompiledData::Property::Rect, QMetaType::QRectF }, - { QV4::CompiledData::Property::Point, QMetaType::QPointF }, - { QV4::CompiledData::Property::Size, QMetaType::QSizeF }, - { QV4::CompiledData::Property::Vector2D, QMetaType::QVector2D }, - { QV4::CompiledData::Property::Vector3D, QMetaType::QVector3D }, - { QV4::CompiledData::Property::Vector4D, QMetaType::QVector4D }, - { QV4::CompiledData::Property::Matrix4x4, QMetaType::QMatrix4x4 }, - { QV4::CompiledData::Property::Quaternion, QMetaType::QQuaternion } - }; - static const uint builtinTypeCount = sizeof(builtinTypes) / sizeof(TypeData); - - QByteArray newClassName; - - if (false /* ### compileState->root == obj && !compileState->nested*/) { -#if 0 // ### - 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)); - } -#endif - } - if (newClassName.isEmpty()) { - newClassName = QQmlMetaObject(baseTypeCache).className(); - newClassName.append("_QML_"); - newClassName.append(QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1))); - } - - cache->_dynamicClassName = newClassName; - - int aliasCount = 0; - int varPropCount = 0; - - const QV4::CompiledData::Property *p = obj->propertyTable(); - for (quint32 i = 0; i < obj->nProperties; ++i, ++p) { - - if (p->type == QV4::CompiledData::Property::Alias) - aliasCount++; - else if (p->type == QV4::CompiledData::Property::Var) - varPropCount++; - -#if 0 // ### Do this elsewhere - // 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")); -#endif - } - - typedef QQmlVMEMetaData VMD; - - QByteArray &dynamicData = *vmeMetaObjectData = QByteArray(sizeof(QQmlVMEMetaData) - + obj->nProperties * sizeof(VMD::PropertyData) - + obj->nFunctions * sizeof(VMD::MethodData) - + aliasCount * sizeof(VMD::AliasData), 0); - - int effectivePropertyIndex = cache->propertyIndexCacheStart; - int effectiveMethodIndex = cache->methodIndexCacheStart; - - // For property change signal override detection. - // We prepopulate a set of signal names which already exist in the object, - // and throw an error if there is a signal/method defined as an override. - QSet<QString> seenSignals; - seenSignals << QStringLiteral("destroyed") << QStringLiteral("parentChanged") << QStringLiteral("objectNameChanged"); - QQmlPropertyCache *parentCache = cache; - while ((parentCache = parentCache->parent())) { - if (int pSigCount = parentCache->signalCount()) { - int pSigOffset = parentCache->signalOffset(); - for (int i = pSigOffset; i < pSigCount; ++i) { - QQmlPropertyData *currPSig = parentCache->signal(i); - // XXX TODO: find a better way to get signal name from the property data :-/ - for (QQmlPropertyCache::StringCache::ConstIterator iter = parentCache->stringCache.begin(); - iter != parentCache->stringCache.end(); ++iter) { - if (currPSig == (*iter).second) { - seenSignals.insert(iter.key()); - break; - } - } - } - } - } - - // 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; - - const QV4::CompiledData::Property *p = obj->propertyTable(); - for (quint32 i = 0; i < obj->nProperties; ++i, ++p) { - if ((ii == NSS_Normal && (p->type == QV4::CompiledData::Property::Alias || - p->type == QV4::CompiledData::Property::Var)) || - ((ii == NSS_Var) && (p->type != QV4::CompiledData::Property::Var)) || - ((ii == NSS_Alias) && (p->type != QV4::CompiledData::Property::Alias))) - continue; - - quint32 flags = QQmlPropertyData::IsSignal | QQmlPropertyData::IsFunction | - QQmlPropertyData::IsVMESignal; - - QString changedSigName = stringAt(p->nameIndex) + QLatin1String("Changed"); - seenSignals.insert(changedSigName); - - cache->appendSignal(changedSigName, flags, effectiveMethodIndex++); - } - } - - // Dynamic signals - for (uint i = 0; i < obj->nSignals; ++i) { - const QV4::CompiledData::Signal *s = obj->signalAt(i); - const int paramCount = s->nParameters; - - QList<QByteArray> names; - QVarLengthArray<int, 10> paramTypes(paramCount?(paramCount + 1):0); - - if (paramCount) { - paramTypes[0] = paramCount; - - for (int i = 0; i < paramCount; ++i) { - const QV4::CompiledData::Parameter *param = s->parameterAt(i); - names.append(stringAt(param->nameIndex).toUtf8()); - if (param->type < builtinTypeCount) { - // built-in type - paramTypes[i + 1] = builtinTypes[param->type].metaType; - } else { - // lazily resolved type - Q_ASSERT(param->type == QV4::CompiledData::Property::Custom); - const QString customTypeName = stringAt(param->customTypeNameIndex); - QQmlType *qmltype = 0; - if (!imports->resolveType(customTypeName, &qmltype, 0, 0, 0)) - COMPILE_EXCEPTION(s, tr("Invalid signal parameter type: %1").arg(customTypeName)); - - if (qmltype->isComposite()) { - QQmlTypeData *tdata = enginePrivate->typeLoader.getType(qmltype->sourceUrl()); - Q_ASSERT(tdata); - Q_ASSERT(tdata->isComplete()); - - QQmlCompiledData *data = tdata->compiledData(); - - paramTypes[i + 1] = data->metaTypeId; - - tdata->release(); - } else { - paramTypes[i + 1] = qmltype->typeId(); - } - } - } - } - - ((QQmlVMEMetaData *)dynamicData.data())->signalCount++; - - quint32 flags = QQmlPropertyData::IsSignal | QQmlPropertyData::IsFunction | - QQmlPropertyData::IsVMESignal; - if (paramCount) - flags |= QQmlPropertyData::HasArguments; - - QString signalName = stringAt(s->nameIndex); - if (seenSignals.contains(signalName)) - COMPILE_EXCEPTION(s, tr("Duplicate signal name: invalid override of property change signal or superclass signal")); - seenSignals.insert(signalName); - - cache->appendSignal(signalName, flags, effectiveMethodIndex++, - paramCount?paramTypes.constData():0, names); - } - - - // Dynamic slots - const quint32 *functionIndex = obj->functionOffsetTable(); - for (quint32 i = 0; i < obj->nFunctions; ++i, ++functionIndex) { - const QV4::CompiledData::Function *s = qmlUnit->header.functionAt(*functionIndex); - int paramCount = s->nFormals; - - quint32 flags = QQmlPropertyData::IsFunction | QQmlPropertyData::IsVMEFunction; - - if (paramCount) - flags |= QQmlPropertyData::HasArguments; - - QString slotName = stringAt(s->nameIndex); - if (seenSignals.contains(slotName)) - COMPILE_EXCEPTION(s, tr("Duplicate method name: invalid override of property change signal or superclass signal")); - // Note: we don't append slotName to the seenSignals list, since we don't - // protect against overriding change signals or methods with properties. - - const quint32 *formalsIndices = s->formalsTable(); - QList<QByteArray> parameterNames; - parameterNames.reserve(paramCount); - for (int i = 0; i < paramCount; ++i) - parameterNames << stringAt(formalsIndices[i]).toUtf8(); - - cache->appendMethod(slotName, flags, effectiveMethodIndex++, parameterNames); - } - - - // Dynamic properties (except var and aliases) - int effectiveSignalIndex = cache->signalHandlerIndexCacheStart; - /* const QV4::CompiledData::Property* */ p = obj->propertyTable(); - for (quint32 i = 0; i < obj->nProperties; ++i, ++p) { - - if (p->type == QV4::CompiledData::Property::Alias || - p->type == QV4::CompiledData::Property::Var) - continue; - - int propertyType = 0; - int vmePropertyType = 0; - quint32 propertyFlags = 0; - - if (p->type < builtinTypeCount) { - propertyType = builtinTypes[p->type].metaType; - vmePropertyType = propertyType; - - if (p->type == QV4::CompiledData::Property::Variant) - propertyFlags |= QQmlPropertyData::IsQVariant; - } else { - Q_ASSERT(p->type == QV4::CompiledData::Property::CustomList || - p->type == QV4::CompiledData::Property::Custom); - - QQmlType *qmltype = 0; - if (!imports->resolveType(stringAt(p->customTypeNameIndex), &qmltype, 0, 0, 0)) { - COMPILE_EXCEPTION(p, tr("Invalid property type")); - } - - Q_ASSERT(qmltype); - if (qmltype->isComposite()) { - QQmlTypeData *tdata = enginePrivate->typeLoader.getType(qmltype->sourceUrl()); - Q_ASSERT(tdata); - Q_ASSERT(tdata->isComplete()); - - QQmlCompiledData *data = tdata->compiledData(); - - if (p->type == QV4::CompiledData::Property::Custom) { - propertyType = data->metaTypeId; - vmePropertyType = QMetaType::QObjectStar; - } else { - propertyType = data->listMetaTypeId; - vmePropertyType = qMetaTypeId<QQmlListProperty<QObject> >(); - } - - tdata->release(); - } else { - if (p->type == QV4::CompiledData::Property::Custom) { - propertyType = qmltype->typeId(); - vmePropertyType = QMetaType::QObjectStar; - } else { - propertyType = qmltype->qListTypeId(); - vmePropertyType = qMetaTypeId<QQmlListProperty<QObject> >(); - } - } - - if (p->type == QV4::CompiledData::Property::Custom) - propertyFlags |= QQmlPropertyData::IsQObjectDerived; - else - propertyFlags |= QQmlPropertyData::IsQList; - } - - if ((!p->flags & QV4::CompiledData::Property::IsReadOnly) && p->type != QV4::CompiledData::Property::CustomList) - propertyFlags |= QQmlPropertyData::IsWritable; - - - QString propertyName = stringAt(p->nameIndex); - if (i == obj->indexOfDefaultProperty) cache->_defaultPropertyName = propertyName; - cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++, - propertyType, effectiveSignalIndex); - - effectiveSignalIndex++; - - VMD *vmd = (QQmlVMEMetaData *)dynamicData.data(); - (vmd->propertyData() + vmd->propertyCount)->propertyType = vmePropertyType; - vmd->propertyCount++; - } - - // Now do var properties - /* const QV4::CompiledData::Property* */ p = obj->propertyTable(); - for (quint32 i = 0; i < obj->nProperties; ++i, ++p) { - - if (p->type != QV4::CompiledData::Property::Var) - continue; - - quint32 propertyFlags = QQmlPropertyData::IsVarProperty; - if (!p->flags & QV4::CompiledData::Property::IsReadOnly) - propertyFlags |= QQmlPropertyData::IsWritable; - - VMD *vmd = (QQmlVMEMetaData *)dynamicData.data(); - (vmd->propertyData() + vmd->propertyCount)->propertyType = QMetaType::QVariant; - vmd->propertyCount++; - ((QQmlVMEMetaData *)dynamicData.data())->varPropertyCount++; - - QString propertyName = stringAt(p->nameIndex); - if (i == obj->indexOfDefaultProperty) cache->_defaultPropertyName = propertyName; - cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++, - QMetaType::QVariant, effectiveSignalIndex); - - effectiveSignalIndex++; - } - - // Alias property count. Actual data is setup in buildDynamicMetaAliases - ((QQmlVMEMetaData *)dynamicData.data())->aliasCount = aliasCount; - - // Dynamic slot data - comes after the property data - /*const quint32* */functionIndex = obj->functionOffsetTable(); - for (quint32 i = 0; i < obj->nFunctions; ++i, ++functionIndex) { - const QV4::CompiledData::Function *s = qmlUnit->header.functionAt(*functionIndex); - - VMD::MethodData methodData = { /* runtimeFunctionIndex*/ 0, // ### - int(s->nFormals), - /* s->location.start.line */0 }; // ### - - VMD *vmd = (QQmlVMEMetaData *)dynamicData.data(); - VMD::MethodData &md = *(vmd->methodData() + vmd->methodCount); - vmd->methodCount++; - md = methodData; - } - - return true; -} - static void removeBindingOnProperty(QObject *o, int index) { int coreIndex = index & 0x0000FFFF; @@ -468,9 +80,10 @@ static void removeBindingOnProperty(QObject *o, int index) } QmlObjectCreator::QmlObjectCreator(QQmlContextData *parentContext, QQmlCompiledData *compiledData) - : QQmlCompilePass(compiledData->url, compiledData->qmlUnit) - , componentAttached(0) + : componentAttached(0) + , url(compiledData->url) , engine(parentContext->engine) + , qmlUnit(compiledData->qmlUnit) , jsUnit(compiledData->compilationUnit) , parentContext(parentContext) , context(0) @@ -478,8 +91,9 @@ QmlObjectCreator::QmlObjectCreator(QQmlContextData *parentContext, QQmlCompiledD , propertyCaches(compiledData->propertyCaches) , vmeMetaObjectData(compiledData->datas) , compiledData(compiledData) + , rootContext(0) , _qobject(0) - , _qobjectForBindings(0) + , _scopeObject(0) , _valueTypeProperty(0) , _compiledObject(0) , _ddata(0) @@ -512,6 +126,9 @@ QObject *QmlObjectCreator::create(int subComponentIndex, QObject *parent) context->imports->addref(); context->setParent(parentContext); + if (!rootContext) + rootContext = context; + QVector<QQmlContextData::ObjectIdMapping> mapping(objectIndexToId.count()); for (QHash<int, int>::ConstIterator it = objectIndexToId.constBegin(), end = objectIndexToId.constEnd(); it != end; ++it) { @@ -537,6 +154,10 @@ QObject *QmlObjectCreator::create(int subComponentIndex, QObject *parent) context->importedScripts = parentContext->importedScripts; } + QVector<QQmlParserStatus*> parserStatusCallbacks; + parserStatusCallbacks.resize(qmlUnit->nObjects); + qSwap(_parserStatusCallbacks, parserStatusCallbacks); + QObject *instance = createInstance(objectToCreate, parent); if (instance) { QQmlData *ddata = QQmlData::get(instance); @@ -546,6 +167,10 @@ QObject *QmlObjectCreator::create(int subComponentIndex, QObject *parent) context->contextObject = instance; } + + qSwap(_parserStatusCallbacks, parserStatusCallbacks); + allParserStatusCallbacks.prepend(parserStatusCallbacks); + return instance; } @@ -558,7 +183,13 @@ void QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, const QV4::C QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine); QV4::Scope scope(v4); - // ### enums + + // ### This should be resolved earlier at compile time and the binding value should be changed accordingly. + if (property->isEnum()) { + QVariant value = binding->valueAsString(&qmlUnit->header); + QQmlPropertyPrivate::write(_qobject, *property, value, context); + return; + } switch (property->propType) { case QMetaType::QVariant: { @@ -1015,14 +646,32 @@ bool QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, int bindingI const int id = attachedType->attachedPropertiesId(); QObject *qmlObject = qmlAttachedPropertiesObjectById(id, _qobject); QQmlRefPointer<QQmlPropertyCache> cache = QQmlEnginePrivate::get(engine)->cache(qmlObject); - if (!populateInstance(binding->value.objectIndex, qmlObject, cache, _qobject, /*value type property*/0)) + if (!populateInstance(binding->value.objectIndex, qmlObject, cache, qmlObject, /*value type property*/0)) return false; return true; } + // ### resolve this at compile time + if (property && property->propType == qMetaTypeId<QQmlScriptString>()) { + QQmlScriptString ss(binding->valueAsScriptString(&qmlUnit->header), context->asQQmlContext(), _scopeObject); + ss.d.data()->bindingId = QQmlBinding::Invalid; + ss.d.data()->lineNumber = binding->location.line; + ss.d.data()->columnNumber = binding->location.column; + ss.d.data()->isStringLiteral = binding->type == QV4::CompiledData::Binding::Type_String; + ss.d.data()->isNumberLiteral = binding->type == QV4::CompiledData::Binding::Type_Number; + ss.d.data()->numberValue = binding->valueAsNumber(); + + QQmlPropertyPrivate::WriteFlags propertyWriteFlags = QQmlPropertyPrivate::BypassInterceptor | + QQmlPropertyPrivate::RemoveBindingOnAliasWrite; + int propertyWriteStatus = -1; + void *argv[] = { &ss, 0, &propertyWriteStatus, &propertyWriteFlags }; + QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv); + return true; + } + QObject *createdSubObject = 0; if (binding->type == QV4::CompiledData::Binding::Type_Object) { - createdSubObject = createInstance(binding->value.objectIndex, _qobject); + createdSubObject = createInstance(binding->value.objectIndex, _bindingTarget); if (!createdSubObject) return false; } @@ -1035,11 +684,11 @@ bool QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, int bindingI if (stringAt(obj->inheritedTypeNameIndex).isEmpty()) { QQmlEnginePrivate *enginePrivate = QQmlEnginePrivate::get(engine); - QQmlRefPointer<QQmlPropertyCache> groupedObjCache; - QObject *groupedObjInstance = 0; - QObject *objForBindings = _qobjectForBindings; + QQmlRefPointer<QQmlPropertyCache> groupObjectPropertyCache; + QObject *groupObject = 0; QQmlValueType *valueType = 0; QQmlPropertyData *valueTypeProperty = 0; + QObject *bindingTarget = _bindingTarget; if (QQmlValueTypeFactory::isValueType(property->propType)) { valueType = QQmlValueTypeFactory::valueType(property->propType); @@ -1050,27 +699,27 @@ bool QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, int bindingI valueType->read(_qobject, property->coreIndex); - groupedObjCache = enginePrivate->cache(valueType); - groupedObjInstance = valueType; + groupObjectPropertyCache = enginePrivate->cache(valueType); + groupObject = valueType; valueTypeProperty = property; } else { - groupedObjCache = enginePrivate->propertyCacheForType(property->propType); - if (!groupedObjCache) { + groupObjectPropertyCache = enginePrivate->propertyCacheForType(property->propType); + if (!groupObjectPropertyCache) { recordError(binding->location, tr("Invalid grouped property access")); return false; } - void *argv[1] = { &groupedObjInstance }; + void *argv[1] = { &groupObject }; QMetaObject::metacall(_qobject, QMetaObject::ReadProperty, property->coreIndex, argv); - if (!groupedObjInstance) { + if (!groupObject) { recordError(binding->location, tr("Cannot set properties on %1 as it is null").arg(stringAt(binding->propertyNameIndex))); return false; } - objForBindings = groupedObjInstance; + bindingTarget = groupObject; } - if (!populateInstance(binding->value.objectIndex, groupedObjInstance, groupedObjCache, objForBindings, valueTypeProperty)) + if (!populateInstance(binding->value.objectIndex, groupObject, groupObjectPropertyCache, bindingTarget, valueTypeProperty)) return false; if (valueType) @@ -1080,8 +729,9 @@ bool QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, int bindingI } } - if (_ddata->hasBindingBit(property->coreIndex)) - removeBindingOnProperty(_qobject, property->coreIndex); + if (_ddata->hasBindingBit(property->coreIndex) && !(binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression) + && !(binding->flags & QV4::CompiledData::Binding::IsOnAssignment)) + removeBindingOnProperty(_bindingTarget, property->coreIndex); if (binding->type == QV4::CompiledData::Binding::Type_Script) { QV4::Function *runtimeFunction = jsUnit->runtimeFunctions[binding->value.compiledScriptIndex]; @@ -1091,14 +741,14 @@ bool QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, int bindingI if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression) { int signalIndex = _propertyCache->methodIndexToSignalIndex(property->coreIndex); - QQmlBoundSignal *bs = new QQmlBoundSignal(_qobject, signalIndex, _qobject, engine); - QQmlBoundSignalExpression *expr = new QQmlBoundSignalExpression(_qobject, signalIndex, - context, _qobject, function); + QQmlBoundSignal *bs = new QQmlBoundSignal(_bindingTarget, signalIndex, _scopeObject, engine); + QQmlBoundSignalExpression *expr = new QQmlBoundSignalExpression(_bindingTarget, signalIndex, + context, _scopeObject, function); bs->takeExpression(expr); } else { - QQmlBinding *qmlBinding = new QQmlBinding(function, _qobject, context, - QString(), 0, 0); // ### + QQmlBinding *qmlBinding = new QQmlBinding(function, _scopeObject, context, + context->urlString, binding->location.line, binding->location.column); // When writing bindings to grouped properties implemented as value types, // such as point.x: { someExpression; }, then the binding is installed on @@ -1109,7 +759,7 @@ bool QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, int bindingI if (_valueTypeProperty) targetCorePropertyData = QQmlPropertyPrivate::saveValueType(*_valueTypeProperty, _qobject->metaObject(), property->coreIndex, engine); - qmlBinding->setTarget(_qobjectForBindings, targetCorePropertyData, context); + qmlBinding->setTarget(_bindingTarget, targetCorePropertyData, context); qmlBinding->addToObject(); _createdBindings[bindingIndex] = qmlBinding; @@ -1119,6 +769,43 @@ bool QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, int bindingI } if (binding->type == QV4::CompiledData::Binding::Type_Object) { + if (binding->flags & QV4::CompiledData::Binding::IsOnAssignment) { + // ### determine value source and interceptor casts ahead of time. + QQmlType *type = 0; + const QMetaObject *mo = createdSubObject->metaObject(); + while (mo && !type) { + type = QQmlMetaType::qmlType(mo); + mo = mo->superClass(); + } + Q_ASSERT(type); + + QQmlPropertyData targetCorePropertyData = *property; + if (_valueTypeProperty) + targetCorePropertyData = QQmlPropertyPrivate::saveValueType(*_valueTypeProperty, _qobject->metaObject(), property->coreIndex, engine); + + int valueSourceCast = type->propertyValueSourceCast(); + if (valueSourceCast != -1) { + QQmlPropertyValueSource *vs = reinterpret_cast<QQmlPropertyValueSource *>(reinterpret_cast<char *>(createdSubObject) + valueSourceCast); + QObject *target = createdSubObject->parent(); + vs->setTarget(QQmlPropertyPrivate::restore(target, targetCorePropertyData, context)); + return true; + } + int valueInterceptorCast = type->propertyValueInterceptorCast(); + if (valueInterceptorCast != -1) { + QQmlPropertyValueInterceptor *vi = reinterpret_cast<QQmlPropertyValueInterceptor *>(reinterpret_cast<char *>(createdSubObject) + valueInterceptorCast); + QObject *target = createdSubObject->parent(); + + QQmlProperty prop = + QQmlPropertyPrivate::restore(target, targetCorePropertyData, context); + vi->setTarget(prop); + QQmlVMEMetaObject *mo = QQmlVMEMetaObject::get(target); + Q_ASSERT(mo); + mo->registerInterceptor(prop.index(), QQmlPropertyPrivate::valueTypeCoreIndex(prop), vi); + return true; + } + return false; + } + QQmlPropertyPrivate::WriteFlags propertyWriteFlags = QQmlPropertyPrivate::BypassInterceptor | QQmlPropertyPrivate::RemoveBindingOnAliasWrite; int propertyWriteStatus = -1; @@ -1203,7 +890,6 @@ void QmlObjectCreator::setupFunctions() { QV4::Scope scope(_qmlContext); QV4::ScopedValue function(scope); - QQmlVMEMetaObject *vme = QQmlVMEMetaObject::get(_qobject); const quint32 *functionIdx = _compiledObject->functionOffsetTable(); for (quint32 i = 0; i < _compiledObject->nFunctions; ++i, ++functionIdx) { @@ -1215,16 +901,27 @@ void QmlObjectCreator::setupFunctions() continue; function = QV4::FunctionObject::creatScriptFunction(_qmlContext, runtimeFunction); - vme->setVmeMethod(property->coreIndex, function); + _vmeMetaObject->setVmeMethod(property->coreIndex, function); } } +void QmlObjectCreator::recordError(const QV4::CompiledData::Location &location, const QString &description) +{ + QQmlError error; + error.setUrl(url); + error.setLine(location.line); + error.setColumn(location.column); + error.setDescription(description); + errors << error; +} + QObject *QmlObjectCreator::createInstance(int index, QObject *parent) { ActiveOCRestorer ocRestorer(this, QQmlEnginePrivate::get(engine)); bool isComponent = false; QObject *instance = 0; + QQmlCustomParser *customParser = 0; if (compiledData->isComponent(index)) { isComponent = true; @@ -1242,6 +939,16 @@ QObject *QmlObjectCreator::createInstance(int index, QObject *parent) recordError(obj->location, tr("Unable to create object of type %1").arg(stringAt(obj->inheritedTypeNameIndex))); return 0; } + + const int parserStatusCast = type->parserStatusCast(); + if (parserStatusCast != -1) { + QQmlParserStatus *parserStatus = reinterpret_cast<QQmlParserStatus*>(reinterpret_cast<char *>(instance) + parserStatusCast); + parserStatus->classBegin(); + _parserStatusCallbacks[index] = parserStatus; + parserStatus->d = &_parserStatusCallbacks[index]; + } + + customParser = type->customParser(); } else { Q_ASSERT(typeRef.component); if (typeRef.component->qmlUnit->isSingleton()) @@ -1258,6 +965,7 @@ QObject *QmlObjectCreator::createInstance(int index, QObject *parent) if (subCreator.componentAttached) subCreator.componentAttached->add(&componentAttached); allCreatedBindings << subCreator.allCreatedBindings; + allParserStatusCallbacks << subCreator.allParserStatusCallbacks; } // ### use no-event variant if (parent) @@ -1285,18 +993,37 @@ QObject *QmlObjectCreator::createInstance(int index, QObject *parent) if (idEntry != objectIndexToId.constEnd()) context->setIdProperty(idEntry.value(), instance); - if (!isComponent) { - QQmlRefPointer<QQmlPropertyCache> cache = propertyCaches.value(index); - Q_ASSERT(!cache.isNull()); - - if (!populateInstance(index, instance, cache, instance, /*value type property*/0)) - return 0; + if (customParser) { + QByteArray data = compiledData->customParserData.value(index); + customParser->setCustomData(instance, data); } - return instance; + if (isComponent) + return instance; + + QQmlRefPointer<QQmlPropertyCache> cache = propertyCaches.value(index); + Q_ASSERT(!cache.isNull()); + + QObject *scopeObject = instance; + qSwap(_scopeObject, scopeObject); + + QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine); + QV4::Scope valueScope(v4); + QV4::ScopedObject jsScopeObject(valueScope, QV4::QmlContextWrapper::qmlScope(QV8Engine::get(engine), context, _scopeObject)); + QV4::Scoped<QV4::QmlBindingWrapper> qmlBindingWrapper(valueScope, new (v4->memoryManager) QV4::QmlBindingWrapper(v4->rootContext, jsScopeObject)); + QV4::ExecutionContext *qmlContext = qmlBindingWrapper->context(); + + qSwap(_qmlContext, qmlContext); + + bool result = populateInstance(index, instance, cache, /*binding target*/instance, /*value type property*/0); + + qSwap(_qmlContext, qmlContext); + qSwap(_scopeObject, scopeObject); + + return result ? instance : 0; } -void QmlObjectCreator::finalize() +QQmlContextData *QmlObjectCreator::finalize() { { QQmlTrace trace("VME Binding Enable"); @@ -1321,6 +1048,45 @@ void QmlObjectCreator::finalize() } } + if (true /* ### componentCompleteEnabled()*/) { // the qml designer does the component complete later + QQmlTrace trace("VME Component Complete"); + for (QLinkedList<QVector<QQmlParserStatus*> >::ConstIterator it = allParserStatusCallbacks.constBegin(), end = allParserStatusCallbacks.constEnd(); + it != end; ++it) { + const QVector<QQmlParserStatus *> &parserStatusCallbacks = *it; + for (int i = parserStatusCallbacks.count() - 1; i >= 0; --i) { + QQmlParserStatus *status = parserStatusCallbacks.at(i); + + if (status && status->d) { + status->d = 0; + status->componentComplete(); + } + + #if 0 // ### + if (watcher.hasRecursed() || interrupt.shouldInterrupt()) + return 0; + #endif + } + } + allParserStatusCallbacks.clear(); + } + + { + QQmlTrace trace("VME Finalize Callbacks"); + for (int ii = 0; ii < finalizeCallbacks.count(); ++ii) { + QQmlEnginePrivate::FinalizeCallback callback = finalizeCallbacks.at(ii); + QObject *obj = callback.first; + if (obj) { + void *args[] = { 0 }; + QMetaObject::metacall(obj, QMetaObject::InvokeMetaMethod, callback.second, args); + } +#if 0 // ### + if (watcher.hasRecursed()) + return 0; +#endif + } + finalizeCallbacks.clear(); + } + { QQmlTrace trace("VME Component.onCompleted Callbacks"); while (componentAttached) { @@ -1339,35 +1105,34 @@ void QmlObjectCreator::finalize() #endif } } + + return rootContext; } -bool QmlObjectCreator::populateInstance(int index, QObject *instance, QQmlRefPointer<QQmlPropertyCache> cache, - QObject *scopeObjectForBindings, QQmlPropertyData *valueTypeProperty) +bool QmlObjectCreator::populateInstance(int index, QObject *instance, QQmlRefPointer<QQmlPropertyCache> cache, QObject *bindingTarget, QQmlPropertyData *valueTypeProperty) { const QV4::CompiledData::Object *obj = qmlUnit->objectAt(index); - Q_ASSERT(scopeObjectForBindings); - QQmlData *declarativeData = QQmlData::get(instance, /*create*/true); qSwap(_propertyCache, cache); qSwap(_qobject, instance); - qSwap(_qobjectForBindings, scopeObjectForBindings); qSwap(_valueTypeProperty, valueTypeProperty); qSwap(_compiledObject, obj); qSwap(_ddata, declarativeData); + qSwap(_bindingTarget, bindingTarget); QQmlVMEMetaObject *vmeMetaObject = 0; const QByteArray data = vmeMetaObjectData.value(index); if (!data.isEmpty()) { // install on _object - vmeMetaObject = new QQmlVMEMetaObject(_qobjectForBindings, _propertyCache, reinterpret_cast<const QQmlVMEMetaData*>(data.constData())); + vmeMetaObject = new QQmlVMEMetaObject(_qobject, _propertyCache, reinterpret_cast<const QQmlVMEMetaData*>(data.constData())); if (_ddata->propertyCache) _ddata->propertyCache->release(); _ddata->propertyCache = _propertyCache; _ddata->propertyCache->addref(); } else { - vmeMetaObject = QQmlVMEMetaObject::get(_qobjectForBindings); + vmeMetaObject = QQmlVMEMetaObject::get(_qobject); } _ddata->lineNumber = _compiledObject->location.line; @@ -1378,387 +1143,21 @@ bool QmlObjectCreator::populateInstance(int index, QObject *instance, QQmlRefPoi QVector<QQmlAbstractBinding*> createdBindings(_compiledObject->nBindings, 0); qSwap(_createdBindings, createdBindings); - QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine); - QV4::Scope valueScope(v4); - QV4::ScopedObject scopeObject(valueScope, QV4::QmlContextWrapper::qmlScope(QV8Engine::get(engine), context, _qobjectForBindings)); - QV4::Scoped<QV4::QmlBindingWrapper> qmlBindingWrapper(valueScope, new (v4->memoryManager) QV4::QmlBindingWrapper(v4->rootContext, scopeObject)); - QV4::ExecutionContext *qmlContext = qmlBindingWrapper->context(); - - qSwap(_qmlContext, qmlContext); - setupBindings(); setupFunctions(); allCreatedBindings.append(_createdBindings); - qSwap(_qmlContext, qmlContext); - qSwap(_createdBindings, createdBindings); qSwap(_vmeMetaObject, vmeMetaObject); - qSwap(_propertyCache, cache); + qSwap(_bindingTarget, bindingTarget); qSwap(_ddata, declarativeData); qSwap(_compiledObject, obj); qSwap(_valueTypeProperty, valueTypeProperty); - qSwap(_qobjectForBindings, scopeObjectForBindings); qSwap(_qobject, instance); + qSwap(_propertyCache, cache); return errors.isEmpty(); } -QQmlComponentAndAliasResolver::QQmlComponentAndAliasResolver(const QUrl &url, const QV4::CompiledData::QmlUnit *qmlUnit, - const QHash<int, QQmlCompiledData::TypeReference> &resolvedTypes, - const QList<QQmlPropertyCache *> &propertyCaches, QList<QByteArray> *vmeMetaObjectData, - QHash<int, int> *objectIndexToIdForRoot, - QHash<int, QHash<int, int> > *objectIndexToIdPerComponent) - : QQmlCompilePass(url, qmlUnit) - , _componentIndex(-1) - , _objectIndexToIdInScope(0) - , resolvedTypes(resolvedTypes) - , propertyCaches(propertyCaches) - , vmeMetaObjectData(vmeMetaObjectData) - , objectIndexToIdForRoot(objectIndexToIdForRoot) - , objectIndexToIdPerComponent(objectIndexToIdPerComponent) -{ -} - -bool QQmlComponentAndAliasResolver::resolve() -{ - Q_ASSERT(componentRoots.isEmpty()); - - // Find objects that are Components. This is missing an extra pass - // that finds implicitly defined components, i.e. - // someProperty: Item { ... } - // when someProperty _is_ a QQmlComponent. In that case the Item {} - // should be implicitly surrounded by Component {} - - for (quint32 i = 0; i < qmlUnit->nObjects; ++i) { - const QV4::CompiledData::Object *obj = qmlUnit->objectAt(i); - if (stringAt(obj->inheritedTypeNameIndex).isEmpty()) - continue; - - QQmlCompiledData::TypeReference tref = resolvedTypes.value(obj->inheritedTypeNameIndex); - if (!tref.type) - continue; - if (tref.type->metaObject() != &QQmlComponent::staticMetaObject) - continue; - - componentRoots.append(i); - // Sanity checks: There can be only an (optional) id property and - // a default property, that defines the component tree. - } - - std::sort(componentRoots.begin(), componentRoots.end()); - - // For each component's tree, remember to which component the children - // belong to - for (int i = 0; i < componentRoots.count(); ++i) { - const QV4::CompiledData::Object *component = qmlUnit->objectAt(componentRoots.at(i)); - - if (component->nFunctions > 0) - COMPILE_EXCEPTION(component, tr("Component objects cannot declare new functions.")); - if (component->nProperties > 0) - COMPILE_EXCEPTION(component, tr("Component objects cannot declare new properties.")); - if (component->nSignals > 0) - COMPILE_EXCEPTION(component, tr("Component objects cannot declare new signals.")); - - if (component->nBindings == 0) - COMPILE_EXCEPTION(component, tr("Cannot create empty component specification")); - - const QV4::CompiledData::Binding *rootBinding = component->bindingTable(); - if (component->nBindings > 1 || rootBinding->type != QV4::CompiledData::Binding::Type_Object) - COMPILE_EXCEPTION(rootBinding, tr("Component elements may not contain properties other than id")); - - _componentIndex = i; - _idToObjectIndex.clear(); - - _objectIndexToIdInScope = &(*objectIndexToIdPerComponent)[componentRoots.at(i)]; - - _objectsWithAliases.clear(); - - if (!collectIdsAndAliases(rootBinding->value.objectIndex)) - return false; - - if (!resolveAliases()) - return false; - } - - // Collect ids and aliases for root - _componentIndex = -1; - _idToObjectIndex.clear(); - _objectIndexToIdInScope = objectIndexToIdForRoot; - _objectsWithAliases.clear(); - - collectIdsAndAliases(qmlUnit->indexOfRootObject); - - resolveAliases(); - - return errors.isEmpty(); -} - -bool QQmlComponentAndAliasResolver::collectIdsAndAliases(int objectIndex) -{ - const QV4::CompiledData::Object *obj = qmlUnit->objectAt(objectIndex); - - // Only include creatable types. Everything else is synthetic, such as group property - // objects. - if (_componentIndex != -1 && !stringAt(obj->inheritedTypeNameIndex).isEmpty()) - objectIndexToComponentIndex.insert(objectIndex, _componentIndex); - - QString id = stringAt(obj->idIndex); - if (!id.isEmpty()) { - if (_idToObjectIndex.contains(obj->idIndex)) { - recordError(obj->locationOfIdProperty, tr("id is not unique")); - return false; - } - _idToObjectIndex.insert(obj->idIndex, objectIndex); - _objectIndexToIdInScope->insert(objectIndex, _objectIndexToIdInScope->count()); - } - - const QV4::CompiledData::Property *property = obj->propertyTable(); - for (quint32 i = 0; i < obj->nProperties; ++i, ++property) - if (property->type == QV4::CompiledData::Property::Alias) { - _objectsWithAliases.append(objectIndex); - break; - } - - const QV4::CompiledData::Binding *binding = obj->bindingTable(); - for (quint32 i = 0; i < obj->nBindings; ++i, ++binding) { - if (binding->type != QV4::CompiledData::Binding::Type_Object - && binding->type != QV4::CompiledData::Binding::Type_AttachedProperty - && binding->type != QV4::CompiledData::Binding::Type_GroupProperty) - continue; - - // Stop at Component boundary - if (std::binary_search(componentRoots.constBegin(), componentRoots.constEnd(), binding->value.objectIndex)) - continue; - - if (!collectIdsAndAliases(binding->value.objectIndex)) - return false; - } - - return true; -} - -bool QQmlComponentAndAliasResolver::resolveAliases() -{ - foreach (int objectIndex, _objectsWithAliases) { - const QV4::CompiledData::Object *obj = qmlUnit->objectAt(objectIndex); - - QQmlPropertyCache *propertyCache = propertyCaches.value(objectIndex); - Q_ASSERT(propertyCache); - - int effectiveSignalIndex = propertyCache->signalHandlerIndexCacheStart + propertyCache->propertyIndexCache.count(); - int effectivePropertyIndex = propertyCache->propertyIndexCacheStart + propertyCache->propertyIndexCache.count(); - int effectiveAliasIndex = 0; - - const QV4::CompiledData::Property *p = obj->propertyTable(); - for (quint32 propertyIndex = 0; propertyIndex < obj->nProperties; ++propertyIndex, ++p) { - if (p->type != QV4::CompiledData::Property::Alias) - continue; - - 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; - } - const int targetId = _objectIndexToIdInScope->value(targetObjectIndex, -1); - Q_ASSERT(targetId != -1); - - const QString aliasPropertyValue = stringAt(p->aliasPropertyValueIndex); - - 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()); - - int propIdx = -1; - int propType = 0; - int notifySignal = -1; - int flags = 0; - int type = 0; - bool writable = false; - bool resettable = false; - - quint32 propertyFlags = QQmlPropertyData::IsAlias; - - if (property.isEmpty()) { - const QV4::CompiledData::Object *targetObject = qmlUnit->objectAt(targetObjectIndex); - QQmlCompiledData::TypeReference typeRef = resolvedTypes.value(targetObject->inheritedTypeNameIndex); - - if (typeRef.type) - type = typeRef.type->typeId(); - else - type = typeRef.component->metaTypeId; - - flags |= QML_ALIAS_FLAG_PTR; - propertyFlags |= QQmlPropertyData::IsQObjectDerived; - } else { - QQmlPropertyCache *targetCache = propertyCaches.value(targetObjectIndex); - Q_ASSERT(targetCache); - QtQml::PropertyResolver resolver(targetCache); - - QQmlPropertyData *targetProperty = resolver.property(property.toString()); - if (!targetProperty || targetProperty->coreIndex > 0x0000FFFF) { - recordError(p->aliasLocation, tr("Invalid alias location")); - 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) { - recordError(p->aliasLocation, tr("Invalid alias location")); - return false; - } - - propType = type; - - int valueTypeIndex = - valueType->metaObject()->indexOfProperty(subProperty.toString().toUtf8().constData()); - if (valueTypeIndex == -1) { - recordError(p->aliasLocation, tr("Invalid alias location")); - 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 (targetProperty->isQObject()) - flags |= QML_ALIAS_FLAG_PTR; - } - } - } - - QQmlVMEMetaData::AliasData aliasData = { targetId, propIdx, propType, flags, notifySignal }; - - typedef QQmlVMEMetaData VMD; - QByteArray &dynamicData = (*vmeMetaObjectData)[objectIndex]; - Q_ASSERT(!dynamicData.isEmpty()); - VMD *vmd = (QQmlVMEMetaData *)dynamicData.data(); - *(vmd->aliasData() + effectiveAliasIndex++) = aliasData; - - Q_ASSERT(dynamicData.isDetached()); - - if (!(p->flags & QV4::CompiledData::Property::IsReadOnly) && writable) - propertyFlags |= QQmlPropertyData::IsWritable; - else - propertyFlags &= ~QQmlPropertyData::IsWritable; - - if (resettable) - propertyFlags |= QQmlPropertyData::IsResettable; - else - propertyFlags &= ~QQmlPropertyData::IsResettable; - - QString propertyName = stringAt(p->nameIndex); - if (propertyIndex == obj->indexOfDefaultProperty) propertyCache->_defaultPropertyName = propertyName; - propertyCache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++, - type, effectiveSignalIndex++); - - } - } - return true; -} - - -QQmlPropertyValidator::QQmlPropertyValidator(const QUrl &url, const QV4::CompiledData::QmlUnit *qmlUnit, - const QHash<int, QQmlCompiledData::TypeReference> &resolvedTypes, - const QList<QQmlPropertyCache *> &propertyCaches, const QHash<int, QHash<int, int> > &objectIndexToIdPerComponent) - : QQmlCompilePass(url, qmlUnit) - , resolvedTypes(resolvedTypes) - , propertyCaches(propertyCaches) - , objectIndexToIdPerComponent(objectIndexToIdPerComponent) -{ -} - -bool QQmlPropertyValidator::validate() -{ - for (quint32 i = 0; i < qmlUnit->nObjects; ++i) { - const QV4::CompiledData::Object *obj = qmlUnit->objectAt(i); - if (stringAt(obj->inheritedTypeNameIndex).isEmpty()) - continue; - - if (isComponent(i)) - continue; - - QQmlPropertyCache *propertyCache = propertyCaches.value(i); - Q_ASSERT(propertyCache); - - if (!validateObject(obj, i, propertyCache)) - return false; - } - return true; -} - -bool QQmlPropertyValidator::validateObject(const QV4::CompiledData::Object *obj, int objectIndex, QQmlPropertyCache *propertyCache) -{ - PropertyResolver propertyResolver(propertyCache); - - QQmlPropertyData *defaultProperty = propertyCache->defaultProperty(); - - const QV4::CompiledData::Binding *binding = obj->bindingTable(); - for (quint32 i = 0; i < obj->nBindings; ++i, ++binding) { - if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty - || binding->type == QV4::CompiledData::Binding::Type_GroupProperty) - continue; - - const QString name = stringAt(binding->propertyNameIndex); - - bool bindingToDefaultProperty = false; - - bool notInRevision = false; - QQmlPropertyData *pd = 0; - if (!name.isEmpty()) { - pd = propertyResolver.property(name, ¬InRevision); - - if (notInRevision) { - QString typeName = stringAt(obj->inheritedTypeNameIndex); - QQmlCompiledData::TypeReference type = resolvedTypes.value(objectIndex); - if (type.type) { - COMPILE_EXCEPTION(binding, tr("\"%1.%2\" is not available in %3 %4.%5.").arg(typeName).arg(name).arg(type.type->module()).arg(type.majorVersion).arg(type.minorVersion)); - } else { - COMPILE_EXCEPTION(binding, tr("\"%1.%2\" is not available due to component versioning.").arg(typeName).arg(name)); - } - } - } else { - pd = defaultProperty; - bindingToDefaultProperty = true; - } - - if (!pd) { - if (bindingToDefaultProperty) { - COMPILE_EXCEPTION(binding, tr("Cannot assign to non-existent default property")); - } else { - COMPILE_EXCEPTION(binding, tr("Cannot assign to non-existent property \"%1\"").arg(name)); - } - } - } - - return true; -} |