aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/qml/compiler/qqmlcodegenerator.cpp56
-rw-r--r--src/qml/compiler/qqmlcodegenerator_p.h3
-rw-r--r--src/qml/compiler/qv4compileddata_p.h6
-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
7 files changed, 260 insertions, 44 deletions
diff --git a/src/qml/compiler/qqmlcodegenerator.cpp b/src/qml/compiler/qqmlcodegenerator.cpp
index 669cdfbf3e..381f5bfec9 100644
--- a/src/qml/compiler/qqmlcodegenerator.cpp
+++ b/src/qml/compiler/qqmlcodegenerator.cpp
@@ -124,6 +124,8 @@ bool QQmlCodeGenerator::generateFromQml(const QString &code, const QUrl &url, co
this->pool = output->jsParserEngine.pool();
this->jsGenerator = &output->jsGenerator;
+ emptyStringIndex = registerString(QString());
+
sourceCode = code;
accept(program->imports);
@@ -195,7 +197,7 @@ bool QQmlCodeGenerator::visit(AST::UiObjectDefinition *node)
bool isType = lastId->name.unicode()->isUpper();
if (isType) {
int idx = defineQMLObject(node);
- appendBinding(AST::SourceLocation(), registerString(QString()), idx);
+ appendBinding(AST::SourceLocation(), emptyStringIndex, idx);
} else {
int idx = defineQMLObject(/*qualfied type name id*/0, node->initializer);
appendBinding(node->qualifiedTypeNameId, idx);
@@ -307,7 +309,7 @@ int QQmlCodeGenerator::defineQMLObject(AST::UiQualifiedId *qualifiedTypeNameId,
_object->location.line = loc.startLine;
_object->location.column = loc.startColumn;
- _object->idIndex = registerString(QString());
+ _object->idIndex = emptyStringIndex;
_object->indexOfDefaultProperty = -1;
_object->properties = New<PoolList<QmlProperty> >();
_object->qmlSignals = New<PoolList<Signal> >();
@@ -347,7 +349,7 @@ bool QQmlCodeGenerator::visit(AST::UiImport *node)
uri = asString(node->importUri);
}
- import->qualifierIndex = registerString(QString());
+ import->qualifierIndex = emptyStringIndex;
// Qualifier
if (!node->importId.isNull()) {
@@ -416,6 +418,24 @@ bool QQmlCodeGenerator::visit(AST::UiImport *node)
return false;
}
+static QStringList astNodeToStringList(QQmlJS::AST::Node *node)
+{
+ if (node->kind == QQmlJS::AST::Node::Kind_IdentifierExpression) {
+ QString name =
+ static_cast<QQmlJS::AST::IdentifierExpression *>(node)->name.toString();
+ return QStringList() << name;
+ } else if (node->kind == QQmlJS::AST::Node::Kind_FieldMemberExpression) {
+ QQmlJS::AST::FieldMemberExpression *expr = static_cast<QQmlJS::AST::FieldMemberExpression *>(node);
+
+ QStringList rv = astNodeToStringList(expr->base);
+ if (rv.isEmpty())
+ return rv;
+ rv.append(expr->name.toString());
+ return rv;
+ }
+ return QStringList();
+}
+
bool QQmlCodeGenerator::visit(AST::UiPublicMember *node)
{
static const struct TypeNameToType {
@@ -507,7 +527,7 @@ bool QQmlCodeGenerator::visit(AST::UiPublicMember *node)
} else {
// the parameter is a known basic type
param->type = type->type;
- param->customTypeNameIndex = registerString(QString());
+ param->customTypeNameIndex = emptyStringIndex;
}
param->nameIndex = registerString(p->name.toString());
@@ -595,7 +615,7 @@ bool QQmlCodeGenerator::visit(AST::UiPublicMember *node)
if (type >= QV4::CompiledData::Property::Custom)
property->customTypeNameIndex = registerString(memberType.toString());
else
- property->customTypeNameIndex = registerString(QString());
+ property->customTypeNameIndex = emptyStringIndex;
property->nameIndex = registerString(name.toString());
@@ -603,7 +623,31 @@ bool QQmlCodeGenerator::visit(AST::UiPublicMember *node)
property->location.line = loc.startLine;
property->location.column = loc.startColumn;
- if (node->statement)
+ property->aliasPropertyValueIndex = emptyStringIndex;
+
+ if (type == QV4::CompiledData::Property::Alias) {
+ if (!node->statement && !node->binding)
+ COMPILE_EXCEPTION(loc, tr("No property alias location"));
+
+ QStringList alias;
+ if (AST::ExpressionStatement *stmt = AST::cast<AST::ExpressionStatement*>(node->statement))
+ alias = astNodeToStringList(stmt->expression);
+
+ if (node->binding || alias.isEmpty())
+ COMPILE_EXCEPTION(loc, tr("Invalid alias location"));
+
+ if (alias.count() < 1 || alias.count() > 3)
+ COMPILE_EXCEPTION(loc, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>"));
+
+ property->aliasIdValueIndex = registerString(alias.first());
+
+ QString propertyValue = alias.value(1);
+ if (alias.count() == 3) {
+ propertyValue += QLatin1Char('.');
+ propertyValue += alias.at(2);
+ }
+ property->aliasPropertyValueIndex = registerString(propertyValue);
+ } else if (node->statement)
appendBinding(node->identifierToken, property->nameIndex, node->statement);
_object->properties->append(property);
diff --git a/src/qml/compiler/qqmlcodegenerator_p.h b/src/qml/compiler/qqmlcodegenerator_p.h
index 981ac0a9a7..c3a3a8e4c3 100644
--- a/src/qml/compiler/qqmlcodegenerator_p.h
+++ b/src/qml/compiler/qqmlcodegenerator_p.h
@@ -262,6 +262,7 @@ public:
QString sourceCode;
QUrl url;
QV4::Compiler::JSUnitGenerator *jsGenerator;
+ int emptyStringIndex;
bool sanityCheckFunctionNames();
};
@@ -291,7 +292,7 @@ struct PropertyResolver
return cache->property(index);
}
- QQmlPropertyData *property(const QString &name, bool *notInRevision);
+ QQmlPropertyData *property(const QString &name, bool *notInRevision = 0);
// This code must match the semantics of QQmlPropertyPrivate::findSignalByName
QQmlPropertyData *signal(const QString &name, bool *notInRevision);
diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h
index 774cd70608..8481e17857 100644
--- a/src/qml/compiler/qv4compileddata_p.h
+++ b/src/qml/compiler/qv4compileddata_p.h
@@ -329,7 +329,11 @@ struct Property
quint32 nameIndex;
quint32 type;
- quint32 customTypeNameIndex;
+ union {
+ quint32 customTypeNameIndex; // If type >= Custom
+ quint32 aliasIdValueIndex; // If type == Alias
+ };
+ quint32 aliasPropertyValueIndex;
quint32 flags; // readonly
Location location;
};
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()) {