From 5c40193f8223a8bdefcf694c719396807a83f0ea Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Tue, 7 Jan 2014 15:35:20 +0100 Subject: [new compiler] Add support for implicitly defined components Use-cases like itemDelegate: Item { ... } implicitly define a component without the item-surrounding Component {}, base on the fact that the property itself is of type QQmlComponent (or derived). This means we have to synthesize a Component {} object and insert it into the data structure. Change-Id: I8992451a5a6732c7fd898eaf83c276dc6a8b7d19 Reviewed-by: Lars Knoll --- src/qml/compiler/qqmlcodegenerator.cpp | 27 +++++---- src/qml/compiler/qqmlcodegenerator_p.h | 4 +- src/qml/compiler/qqmltypecompiler.cpp | 10 ++++ src/qml/compiler/qqmltypecompiler_p.h | 2 + src/qml/parser/qqmljsmemorypool_p.h | 2 + src/qml/qml/qqmlobjectcreator.cpp | 100 +++++++++++++++++++++++++++------ src/qml/qml/qqmlobjectcreator_p.h | 14 +++-- 7 files changed, 124 insertions(+), 35 deletions(-) (limited to 'src/qml') diff --git a/src/qml/compiler/qqmlcodegenerator.cpp b/src/qml/compiler/qqmlcodegenerator.cpp index a4da07ab66..f0dfc9b7ea 100644 --- a/src/qml/compiler/qqmlcodegenerator.cpp +++ b/src/qml/compiler/qqmlcodegenerator.cpp @@ -64,6 +64,21 @@ using namespace QtQml; return false; \ } +void QmlObject::init(MemoryPool *pool, int typeNameIndex, int id, const AST::SourceLocation &loc) +{ + inheritedTypeNameIndex = typeNameIndex; + + location.line = loc.startLine; + location.column = loc.startColumn; + + idIndex = id; + indexOfDefaultProperty = -1; + properties = pool->New >(); + qmlSignals = pool->New >(); + bindings = pool->New >(); + functions = pool->New >(); +} + void QmlObject::dump(DebugStream &out) { out << inheritedTypeNameIndex << " {" << endl; @@ -306,20 +321,10 @@ int QQmlCodeGenerator::defineQMLObject(AST::UiQualifiedId *qualifiedTypeNameId, const int objectIndex = _objects.size() - 1; qSwap(_object, obj); - _object->inheritedTypeNameIndex = registerString(asString(qualifiedTypeNameId)); - AST::SourceLocation loc; if (qualifiedTypeNameId) loc = qualifiedTypeNameId->firstSourceLocation(); - _object->location.line = loc.startLine; - _object->location.column = loc.startColumn; - - _object->idIndex = emptyStringIndex; - _object->indexOfDefaultProperty = -1; - _object->properties = New >(); - _object->qmlSignals = New >(); - _object->bindings = New >(); - _object->functions = New >(); + _object->init(pool, registerString(asString(qualifiedTypeNameId)), emptyStringIndex, loc); QSet propertyNames; qSwap(_propertyNames, propertyNames); diff --git a/src/qml/compiler/qqmlcodegenerator_p.h b/src/qml/compiler/qqmlcodegenerator_p.h index 18193eea2b..4b126ef5ea 100644 --- a/src/qml/compiler/qqmlcodegenerator_p.h +++ b/src/qml/compiler/qqmlcodegenerator_p.h @@ -155,6 +155,8 @@ struct QmlObject PoolList *bindings; PoolList *functions; + void init(QQmlJS::MemoryPool *pool, int typeNameIndex, int id, const AST::SourceLocation &location = AST::SourceLocation()); + void dump(DebugStream &out); }; @@ -274,7 +276,7 @@ public: static QQmlScript::LocationSpan location(AST::SourceLocation start, AST::SourceLocation end); int registerString(const QString &str) const { return jsGenerator->registerString(str); } - template _Tp *New() { return new (pool->allocate(sizeof(_Tp))) _Tp(); } + template _Tp *New() { return pool->New<_Tp>(); } QString stringAt(int index) const { return jsGenerator->strings.at(index); } diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp index b5a48f3611..f39ea2f3c7 100644 --- a/src/qml/compiler/qqmltypecompiler.cpp +++ b/src/qml/compiler/qqmltypecompiler.cpp @@ -224,6 +224,11 @@ QString QQmlTypeCompiler::stringAt(int idx) const return parsedQML->stringAt(idx); } +int QQmlTypeCompiler::registerString(const QString &str) +{ + return parsedQML->jsGenerator.registerString(str); +} + const QV4::CompiledData::QmlUnit *QQmlTypeCompiler::qmlUnit() const { return compiledData->qmlUnit; @@ -274,4 +279,9 @@ QHash *QQmlTypeCompiler::customParserData() return &compiledData->customParserData; } +MemoryPool *QQmlTypeCompiler::memoryPool() +{ + return parsedQML->jsParserEngine.pool(); +} + QT_END_NAMESPACE diff --git a/src/qml/compiler/qqmltypecompiler_p.h b/src/qml/compiler/qqmltypecompiler_p.h index 9ce8313d8d..442911093c 100644 --- a/src/qml/compiler/qqmltypecompiler_p.h +++ b/src/qml/compiler/qqmltypecompiler_p.h @@ -75,6 +75,7 @@ struct QQmlTypeCompiler void recordError(const QQmlError &error); QString stringAt(int idx) const; + int registerString(const QString &str); const QV4::CompiledData::QmlUnit *qmlUnit() const; @@ -88,6 +89,7 @@ struct QQmlTypeCompiler QHash *objectIndexToIdForRoot(); QHash > *objectIndexToIdPerComponent(); QHash *customParserData(); + QQmlJS::MemoryPool *memoryPool(); private: QList errors; diff --git a/src/qml/parser/qqmljsmemorypool_p.h b/src/qml/parser/qqmljsmemorypool_p.h index 820ae8ed71..29103930ad 100644 --- a/src/qml/parser/qqmljsmemorypool_p.h +++ b/src/qml/parser/qqmljsmemorypool_p.h @@ -108,6 +108,8 @@ public: _ptr = _end = 0; } + template _Tp *New() { return new (this->allocate(sizeof(_Tp))) _Tp(); } + private: void *allocate_helper(size_t size) { diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp index 1067a8dd0a..4e6f354214 100644 --- a/src/qml/qml/qqmlobjectcreator.cpp +++ b/src/qml/qml/qqmlobjectcreator.cpp @@ -1470,11 +1470,13 @@ bool QmlObjectCreator::populateInstance(int index, QObject *instance, QQmlRefPoi QQmlComponentAndAliasResolver::QQmlComponentAndAliasResolver(QQmlTypeCompiler *typeCompiler) : QQmlCompilePass(typeCompiler) - , qmlObjects(*typeCompiler->qmlObjects()) + , enginePrivate(typeCompiler->enginePrivate()) + , pool(typeCompiler->memoryPool()) + , qmlObjects(typeCompiler->qmlObjects()) , indexOfRootObject(typeCompiler->rootObjectIndex()) , _componentIndex(-1) , _objectIndexToIdInScope(0) - , resolvedTypes(*typeCompiler->resolvedTypes()) + , resolvedTypes(typeCompiler->resolvedTypes()) , propertyCaches(typeCompiler->propertyCaches()) , vmeMetaObjectData(typeCompiler->vmeMetaObjects()) , objectIndexToIdForRoot(typeCompiler->objectIndexToIdForRoot()) @@ -1482,26 +1484,88 @@ QQmlComponentAndAliasResolver::QQmlComponentAndAliasResolver(QQmlTypeCompiler *t { } -bool QQmlComponentAndAliasResolver::resolve() +void QQmlComponentAndAliasResolver::findAndRegisterImplicitComponents(const QtQml::QmlObject *obj, int objectIndex) { - QVector componentRoots; + QQmlPropertyCache *propertyCache = propertyCaches.value(objectIndex); + Q_ASSERT(propertyCache); + + PropertyResolver propertyResolver(propertyCache); + + for (QtQml::Binding *binding = obj->bindings->first; binding; binding = binding->next) { + if (binding->type != QV4::CompiledData::Binding::Type_Object) + continue; + if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression) + continue; + + const QtQml::QmlObject *targetObject = qmlObjects->at(binding->value.objectIndex); + QQmlType *targetType = resolvedTypes->value(targetObject->inheritedTypeNameIndex).type; + if (targetType && targetType->metaObject() == &QQmlComponent::staticMetaObject) + continue; + + QString propertyName = stringAt(binding->propertyNameIndex); + bool notInRevision = false; + QQmlPropertyData *pd = propertyResolver.property(propertyName, ¬InRevision); + if (!pd || !pd->isQObject()) + continue; + + QQmlPropertyCache *pc = enginePrivate->rawPropertyCacheForType(pd->propType); + const QMetaObject *mo = pc->firstCppMetaObject(); + while (mo) { + if (mo == &QQmlComponent::staticMetaObject) + break; + mo = mo->superClass(); + } + + if (!mo) + continue; + + static QQmlType *componentType = QQmlMetaType::qmlType(&QQmlComponent::staticMetaObject); + Q_ASSERT(componentType); + + QtQml::QmlObject *syntheticComponent = pool->New(); + syntheticComponent->init(pool, compiler->registerString(QString::fromUtf8(componentType->typeName())), compiler->registerString(QString())); + + if (!resolvedTypes->contains(syntheticComponent->inheritedTypeNameIndex)) { + QQmlCompiledData::TypeReference typeRef; + typeRef.type = componentType; + typeRef.majorVersion = componentType->majorVersion(); + typeRef.minorVersion = componentType->minorVersion(); + resolvedTypes->insert(syntheticComponent->inheritedTypeNameIndex, typeRef); + } - // 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 {} + qmlObjects->append(syntheticComponent); + const int componentIndex = qmlObjects->count() - 1; - for (int i = 0; i < qmlObjects.count(); ++i) { - const QtQml::QmlObject *obj = qmlObjects.at(i); + QtQml::Binding *syntheticBinding = pool->New(); + *syntheticBinding = *binding; + syntheticBinding->type = QV4::CompiledData::Binding::Type_Object; + syntheticComponent->bindings->append(syntheticBinding); + + binding->value.objectIndex = componentIndex; + + componentRoots.append(componentIndex); + componentBoundaries.append(syntheticBinding->value.objectIndex); + } +} + +bool QQmlComponentAndAliasResolver::resolve() +{ + // Detect real Component {} objects as well as implicitly defined components, such as + // someItemDelegate: Item {} + // In the implicit case Item is surrounded by a synthetic Component {} because the property + // on the left hand side is of QQmlComponent type. + for (int i = 0; i < qmlObjects->count(); ++i) { + const QtQml::QmlObject *obj = qmlObjects->at(i); if (stringAt(obj->inheritedTypeNameIndex).isEmpty()) continue; - QQmlCompiledData::TypeReference tref = resolvedTypes.value(obj->inheritedTypeNameIndex); + QQmlCompiledData::TypeReference tref = resolvedTypes->value(obj->inheritedTypeNameIndex); if (!tref.type) continue; - if (tref.type->metaObject() != &QQmlComponent::staticMetaObject) + if (tref.type->metaObject() != &QQmlComponent::staticMetaObject) { + findAndRegisterImplicitComponents(obj, i); continue; + } componentRoots.append(i); @@ -1525,7 +1589,7 @@ bool QQmlComponentAndAliasResolver::resolve() std::sort(componentBoundaries.begin(), componentBoundaries.end()); for (int i = 0; i < componentRoots.count(); ++i) { - const QtQml::QmlObject *component = qmlObjects.at(componentRoots.at(i)); + const QtQml::QmlObject *component = qmlObjects->at(componentRoots.at(i)); const QtQml::Binding *rootBinding = component->bindings->first; _componentIndex = i; @@ -1557,7 +1621,7 @@ bool QQmlComponentAndAliasResolver::resolve() bool QQmlComponentAndAliasResolver::collectIdsAndAliases(int objectIndex) { - const QtQml::QmlObject *obj = qmlObjects.at(objectIndex); + const QtQml::QmlObject *obj = qmlObjects->at(objectIndex); QString id = stringAt(obj->idIndex); if (!id.isEmpty()) { @@ -1596,7 +1660,7 @@ bool QQmlComponentAndAliasResolver::collectIdsAndAliases(int objectIndex) bool QQmlComponentAndAliasResolver::resolveAliases() { foreach (int objectIndex, _objectsWithAliases) { - const QtQml::QmlObject *obj = qmlObjects.at(objectIndex); + const QtQml::QmlObject *obj = qmlObjects->at(objectIndex); QQmlPropertyCache *propertyCache = propertyCaches.value(objectIndex); Q_ASSERT(propertyCache); @@ -1642,8 +1706,8 @@ bool QQmlComponentAndAliasResolver::resolveAliases() quint32 propertyFlags = QQmlPropertyData::IsAlias; if (property.isEmpty()) { - const QtQml::QmlObject *targetObject = qmlObjects.at(targetObjectIndex); - QQmlCompiledData::TypeReference typeRef = resolvedTypes.value(targetObject->inheritedTypeNameIndex); + const QtQml::QmlObject *targetObject = qmlObjects->at(targetObjectIndex); + QQmlCompiledData::TypeReference typeRef = resolvedTypes->value(targetObject->inheritedTypeNameIndex); if (typeRef.type) type = typeRef.type->typeId(); diff --git a/src/qml/qml/qqmlobjectcreator_p.h b/src/qml/qml/qqmlobjectcreator_p.h index 92f40648d3..2d776058ca 100644 --- a/src/qml/qml/qqmlobjectcreator_p.h +++ b/src/qml/qml/qqmlobjectcreator_p.h @@ -76,16 +76,20 @@ public: bool resolve(); protected: + void findAndRegisterImplicitComponents(const QtQml::QmlObject *obj, int objectIndex); bool collectIdsAndAliases(int objectIndex); bool resolveAliases(); - bool isComponentType(int typeNameIndex) const - { return resolvedTypes.value(typeNameIndex).type == 0; } + QQmlEnginePrivate *enginePrivate; + QQmlJS::MemoryPool *pool; - const QList &qmlObjects; + QList *qmlObjects; const int indexOfRootObject; - // indices of objects that are of type QQmlComponent + // indices of the objects that are actually Component {} + QVector componentRoots; + // indices of objects that are the beginning of a new component + // scope. This is sorted and used for binary search. QVector componentBoundaries; int _componentIndex; @@ -93,7 +97,7 @@ protected: QHash *_objectIndexToIdInScope; QList _objectsWithAliases; - const QHash resolvedTypes; + QHash *resolvedTypes; const QList propertyCaches; QList *vmeMetaObjectData; QHash *objectIndexToIdForRoot; -- cgit v1.2.3