aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/qml
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@digia.com>2013-09-19 13:32:13 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-09-20 14:27:49 +0200
commit3123a22ae66016a0d9cd600dbb6f636fd29fc312 (patch)
treede483a714d4ac3234de4b13e3c6bb00d437d0a32 /src/qml/qml
parent4c953b1592956b712eca60eec070868a567c04c1 (diff)
[new compiler] Initial support for alias properties
Aliases are resolved at "compile time", not rough JS expressions. This is done right after we determined the scope of components in the QML file, which is also where we collect object ids (that aliases use). Change-Id: If5702337f2cca08d17f196c3b2fde3bbdfea5b3c Reviewed-by: Lars Knoll <lars.knoll@digia.com>
Diffstat (limited to 'src/qml/qml')
-rw-r--r--src/qml/qml/qqmlobjectcreator.cpp195
-rw-r--r--src/qml/qml/qqmlobjectcreator_p.h19
-rw-r--r--src/qml/qml/qqmlpropertycache_p.h1
-rw-r--r--src/qml/qml/qqmltypeloader.cpp24
4 files changed, 203 insertions, 36 deletions
diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp
index 4e6c82c198..b4201fd10a 100644
--- a/src/qml/qml/qqmlobjectcreator.cpp
+++ b/src/qml/qml/qqmlobjectcreator.cpp
@@ -54,6 +54,7 @@
#include <private/qqmlcomponentattached_p.h>
#include <QQmlComponent>
#include <private/qqmlcomponent_p.h>
+#include <private/qqmlcodegenerator_p.h>
QT_USE_NAMESPACE
@@ -526,6 +527,8 @@ QObject *QmlObjectCreator::create(int subComponentIndex, QObject *parent)
Q_ASSERT(ddata);
ddata->compiledData = compiledData;
ddata->compiledData->addref();
+
+ QQmlEnginePrivate::get(engine)->registerInternalCompositeType(compiledData);
}
return instance;
}
@@ -1301,17 +1304,23 @@ bool QmlObjectCreator::populateInstance(int index, QObject *instance, QQmlRefPoi
}
-QQmlAnonymousComponentResolver::QQmlAnonymousComponentResolver(const QUrl &url, const QV4::CompiledData::QmlUnit *qmlUnit,
+QQmlComponentAndAliasResolver::QQmlComponentAndAliasResolver(const QUrl &url, const QV4::CompiledData::QmlUnit *qmlUnit,
const QHash<int, QQmlCompiledData::TypeReference> &resolvedTypes,
- const QList<QQmlPropertyCache *> &propertyCaches)
+ 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 QQmlAnonymousComponentResolver::resolve()
+bool QQmlComponentAndAliasResolver::resolve()
{
Q_ASSERT(componentRoots.isEmpty());
@@ -1357,32 +1366,58 @@ bool QQmlAnonymousComponentResolver::resolve()
COMPILE_EXCEPTION(rootBinding, tr("Component elements may not contain properties other than id"));
_componentIndex = i;
- _ids.clear();
- if (!recordComponentSubTree(rootBinding->value.objectIndex))
- break;
+ _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 QQmlAnonymousComponentResolver::recordComponentSubTree(int objectIndex)
+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 (!stringAt(obj->inheritedTypeNameIndex).isEmpty())
+ if (_componentIndex != -1 && !stringAt(obj->inheritedTypeNameIndex).isEmpty())
objectIndexToComponentIndex.insert(objectIndex, _componentIndex);
QString id = stringAt(obj->idIndex);
if (!id.isEmpty()) {
- if (_ids.contains(obj->idIndex)) {
+ if (_idToObjectIndex.contains(obj->idIndex)) {
recordError(obj->locationOfIdProperty, tr("id is not unique"));
return false;
}
- _ids.insert(obj->idIndex);
+ _idToObjectIndex.insert(obj->idIndex, objectIndex);
+ _objectIndexToIdInScope->insert(objectIndex, _objectIndexToIdInScope->count());
}
+ const QV4::CompiledData::Property *property = obj->propertyTable();
+ for (int 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 (int i = 0; i < obj->nBindings; ++i, ++binding) {
if (binding->type != QV4::CompiledData::Binding::Type_Object
@@ -1394,9 +1429,147 @@ bool QQmlAnonymousComponentResolver::recordComponentSubTree(int objectIndex)
if (std::binary_search(componentRoots.constBegin(), componentRoots.constEnd(), binding->value.objectIndex))
continue;
- if (!recordComponentSubTree(binding->value.objectIndex))
+ 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)
+ COMPILE_EXCEPTION(p, tr("Invalid alias reference. Unable to find id \"%1\"").arg(stringAt(idIndex)));
+ 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)
+ COMPILE_EXCEPTION(p, tr("Invalid alias location"));
+
+ 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)
+ COMPILE_EXCEPTION(p, tr("Invalid alias location"));
+
+ propType = type;
+
+ int valueTypeIndex =
+ valueType->metaObject()->indexOfProperty(subProperty.toString().toUtf8().constData());
+ if (valueTypeIndex == -1)
+ COMPILE_EXCEPTION(p, tr("Invalid alias location"));
+ 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;
+}
diff --git a/src/qml/qml/qqmlobjectcreator_p.h b/src/qml/qml/qqmlobjectcreator_p.h
index 4b29295f0a..fe3a4bb00a 100644
--- a/src/qml/qml/qqmlobjectcreator_p.h
+++ b/src/qml/qml/qqmlobjectcreator_p.h
@@ -80,13 +80,16 @@ protected:
QHash<int, QQmlCompiledData::TypeReference> *resolvedTypes;
};
-class QQmlAnonymousComponentResolver : public QQmlCompilePass
+class QQmlComponentAndAliasResolver : public QQmlCompilePass
{
Q_DECLARE_TR_FUNCTIONS(QQmlAnonymousComponentResolver)
public:
- QQmlAnonymousComponentResolver(const QUrl &url, const QV4::CompiledData::QmlUnit *qmlUnit,
+ QQmlComponentAndAliasResolver(const QUrl &url, const QV4::CompiledData::QmlUnit *qmlUnit,
const QHash<int, QQmlCompiledData::TypeReference> &resolvedTypes,
- const QList<QQmlPropertyCache *> &propertyCaches);
+ const QList<QQmlPropertyCache *> &propertyCaches,
+ QList<QByteArray> *vmeMetaObjectData,
+ QHash<int, int> *objectIndexToIdForRoot,
+ QHash<int, QHash<int, int> > *objectIndexToIdPerComponent);
bool resolve();
@@ -94,13 +97,19 @@ public:
QHash<int, int> objectIndexToComponentIndex;
protected:
- bool recordComponentSubTree(int objectIndex);
+ bool collectIdsAndAliases(int objectIndex);
+ bool resolveAliases();
int _componentIndex;
- QSet<int> _ids;
+ QHash<int, int> _idToObjectIndex;
+ QHash<int, int> *_objectIndexToIdInScope;
+ QList<int> _objectsWithAliases;
const QHash<int, QQmlCompiledData::TypeReference> resolvedTypes;
const QList<QQmlPropertyCache *> propertyCaches;
+ QList<QByteArray> *vmeMetaObjectData;
+ QHash<int, int> *objectIndexToIdForRoot;
+ QHash<int, QHash<int, int> > *objectIndexToIdPerComponent;
};
class QmlObjectCreator : public QQmlCompilePass
diff --git a/src/qml/qml/qqmlpropertycache_p.h b/src/qml/qml/qqmlpropertycache_p.h
index 32c0018819..bc0cef9f4c 100644
--- a/src/qml/qml/qqmlpropertycache_p.h
+++ b/src/qml/qml/qqmlpropertycache_p.h
@@ -341,6 +341,7 @@ private:
friend class QQmlEnginePrivate;
friend class QQmlCompiler;
friend class QQmlPropertyCacheCreator;
+ friend class QQmlComponentAndAliasResolver;
inline QQmlPropertyCache *copy(int reserve);
diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp
index 096356126d..7b1935a447 100644
--- a/src/qml/qml/qqmltypeloader.cpp
+++ b/src/qml/qml/qqmltypeloader.cpp
@@ -2281,28 +2281,12 @@ void QQmlTypeData::compile()
}
}
- {
- // Scan for anonymous components and determine their scopes.
- QQmlAnonymousComponentResolver resolver(m_compiledData->url, m_compiledData->qmlUnit, m_compiledData->resolvedTypes, m_compiledData->propertyCaches);
+ if (errors.isEmpty()) {
+ // Scan for components, determine their scopes and resolve aliases within the scope.
+ QQmlComponentAndAliasResolver resolver(m_compiledData->url, m_compiledData->qmlUnit, m_compiledData->resolvedTypes, m_compiledData->propertyCaches,
+ &m_compiledData->datas, &m_compiledData->objectIndexToIdForRoot, &m_compiledData->objectIndexToIdPerComponent);
if (!resolver.resolve())
errors << resolver.errors;
-
- for (quint32 i = 0; i < qmlUnit->nObjects; ++i) {
- const QV4::CompiledData::Object *obj = qmlUnit->objectAt(i);
-
- QHash<int, int> *objectIndexToId = 0;
- QHash<int, int>::ConstIterator componentIt = resolver.objectIndexToComponentIndex.find(i);
- if (componentIt != resolver.objectIndexToComponentIndex.constEnd()) {
- int indexOfComponent = resolver.componentRoots[*componentIt];
- objectIndexToId = &m_compiledData->objectIndexToIdPerComponent[indexOfComponent];
- } else
- objectIndexToId = &m_compiledData->objectIndexToIdForRoot;
-
- const QString &id = qmlUnit->header.stringAt(obj->idIndex);
- if (id.isEmpty())
- continue;
- objectIndexToId->insert(i, objectIndexToId->count());
- }
}
if (!errors.isEmpty()) {