aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/qml/qqmlobjectcreator.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/qml/qqmlobjectcreator.cpp')
-rw-r--r--src/qml/qml/qqmlobjectcreator.cpp1001
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, &notInRevision);
-
- 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;
-}