From e850416fcffe48cc19cdbf6a01f759964815681c Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Wed, 25 May 2016 14:55:44 +0200 Subject: Optimize named object handling By storing the object indices of named objects in the CompiledData::Object of a component, we can achieve two things: (1) We can eliminate the hash of vectors in QQmlCompiledData for the object-to-id mapping (2) We can store the mapping from object name to integer object id in the CompilationUnit and share it across different QQmlContextData instances (as long as it is not modified). Also added a new test that verifies the functionality of a .qml file starting with Component{} itself with object names, something that was previously only implicitly tested through some of the examples (corkboards.qml for example). Change-Id: I28c70217222dc0e5252bf5247b7e3fc4def47446 Reviewed-by: Lars Knoll --- src/qml/compiler/qqmlirbuilder.cpp | 20 +++++++--- src/qml/compiler/qqmlirbuilder_p.h | 4 +- src/qml/compiler/qqmltypecompiler.cpp | 20 +++++++--- src/qml/compiler/qqmltypecompiler_p.h | 4 ++ src/qml/compiler/qv4compileddata.cpp | 16 ++++++++ src/qml/compiler/qv4compileddata_p.h | 16 +++++++- src/qml/jsruntime/qv4identifier.cpp | 21 +++++++++++ src/qml/jsruntime/qv4identifier_p.h | 12 +++++- src/qml/qml/qqmlcompiler_p.h | 3 -- src/qml/qml/qqmlcontext.cpp | 44 ++++++++++++---------- src/qml/qml/qqmlcontext_p.h | 11 ++++-- src/qml/qml/qqmlobjectcreator.cpp | 6 +-- src/qml/qml/qqmlobjectcreator_p.h | 1 - .../qml/qqmllanguage/data/rootItemIsComponent.qml | 6 +++ tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp | 14 +++++++ 15 files changed, 153 insertions(+), 45 deletions(-) create mode 100644 tests/auto/qml/qqmllanguage/data/rootItemIsComponent.qml diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp index 0338240699..c9a4e21ddd 100644 --- a/src/qml/compiler/qqmlirbuilder.cpp +++ b/src/qml/compiler/qqmlirbuilder.cpp @@ -1369,12 +1369,12 @@ QV4::CompiledData::Unit *QmlUnitGenerator::generate(Document &output) const int importSize = sizeof(QV4::CompiledData::Import) * output.imports.count(); const int objectOffsetTableSize = output.objects.count() * sizeof(quint32); - QHash objectOffsets; + QHash objectOffsets; int objectsSize = 0; foreach (Object *o, output.objects) { objectOffsets.insert(o, unitSize + importSize + objectOffsetTableSize + objectsSize); - objectsSize += QV4::CompiledData::Object::calculateSizeExcludingSignals(o->functionCount(), o->propertyCount(), o->aliasCount(), o->signalCount(), o->bindingCount()); + objectsSize += QV4::CompiledData::Object::calculateSizeExcludingSignals(o->functionCount(), o->propertyCount(), o->aliasCount(), o->signalCount(), o->bindingCount(), o->namedObjectsInComponent.count); int signalTableSize = 0; for (const Signal *s = o->firstSignal(); s; s = s->next) @@ -1414,7 +1414,8 @@ QV4::CompiledData::Unit *QmlUnitGenerator::generate(Document &output) // write objects quint32 *objectTable = reinterpret_cast(data + qmlUnit->offsetToObjects); char *objectPtr = data + qmlUnit->offsetToObjects + objectOffsetTableSize; - foreach (Object *o, output.objects) { + for (int i = 0; i < output.objects.count(); ++i) { + const Object *o = output.objects.at(i); *objectTable++ = objectOffsets.value(o); QV4::CompiledData::Object *objectToWrite = reinterpret_cast(objectPtr); @@ -1449,6 +1450,10 @@ QV4::CompiledData::Unit *QmlUnitGenerator::generate(Document &output) objectToWrite->offsetToBindings = nextOffset; nextOffset += objectToWrite->nBindings * sizeof(QV4::CompiledData::Binding); + objectToWrite->nNamedObjectsInComponent = o->namedObjectsInComponent.count; + objectToWrite->offsetToNamedObjectsInComponent = nextOffset; + nextOffset += objectToWrite->nNamedObjectsInComponent * sizeof(quint32); + quint32 *functionsTable = reinterpret_cast(objectPtr + objectToWrite->offsetToFunctions); for (const Function *f = o->firstFunction(); f; f = f->next) *functionsTable++ = o->runtimeFunctionIndices.at(f->index); @@ -1495,7 +1500,12 @@ QV4::CompiledData::Unit *QmlUnitGenerator::generate(Document &output) signalPtr += size; } - objectPtr += QV4::CompiledData::Object::calculateSizeExcludingSignals(o->functionCount(), o->propertyCount(), o->aliasCount(), o->signalCount(), o->bindingCount()); + quint32 *namedObjectInComponentPtr = reinterpret_cast(objectPtr + objectToWrite->offsetToNamedObjectsInComponent); + for (int i = 0; i < o->namedObjectsInComponent.count; ++i) { + *namedObjectInComponentPtr++ = o->namedObjectsInComponent.at(i); + } + + objectPtr += QV4::CompiledData::Object::calculateSizeExcludingSignals(o->functionCount(), o->propertyCount(), o->aliasCount(), o->signalCount(), o->bindingCount(), o->namedObjectsInComponent.count); objectPtr += signalTableSize; } @@ -1512,7 +1522,7 @@ QV4::CompiledData::Unit *QmlUnitGenerator::generate(Document &output) return qmlUnit; } -char *QmlUnitGenerator::writeBindings(char *bindingPtr, Object *o, BindingFilter filter) const +char *QmlUnitGenerator::writeBindings(char *bindingPtr, const Object *o, BindingFilter filter) const { for (const Binding *b = o->firstBinding(); b; b = b->next) { if (!(b->*(filter))()) diff --git a/src/qml/compiler/qqmlirbuilder_p.h b/src/qml/compiler/qqmlirbuilder_p.h index 38fe23b150..16dcd70554 100644 --- a/src/qml/compiler/qqmlirbuilder_p.h +++ b/src/qml/compiler/qqmlirbuilder_p.h @@ -321,6 +321,8 @@ public: PoolList *functionsAndExpressions; FixedPoolArray runtimeFunctionIndices; + FixedPoolArray namedObjectsInComponent; + private: friend struct IRLoader; @@ -474,7 +476,7 @@ struct Q_QML_PRIVATE_EXPORT QmlUnitGenerator private: typedef bool (Binding::*BindingFilter)() const; - char *writeBindings(char *bindingPtr, Object *o, BindingFilter filter) const; + char *writeBindings(char *bindingPtr, const Object *o, BindingFilter filter) const; }; #ifndef V4_BOOTSTRAP diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp index f5b1ce5951..f26a38adf0 100644 --- a/src/qml/compiler/qqmltypecompiler.cpp +++ b/src/qml/compiler/qqmltypecompiler.cpp @@ -348,12 +348,12 @@ const QQmlPropertyCacheVector &QQmlTypeCompiler::propertyCaches() const QVector *QQmlTypeCompiler::namedObjectsInRootScope() { - return &compiledData->namedObjectsInRootScope; + return &m_namedObjectsInRootScope; } QHash> *QQmlTypeCompiler::namedObjectsPerComponent() { - return &compiledData->namedObjectsPerComponent; + return &m_namedObjectsPerComponent; } QHash *QQmlTypeCompiler::customParserBindings() @@ -1441,7 +1441,6 @@ bool QQmlComponentAndAliasResolver::resolve() } obj->flags |= QV4::CompiledData::Object::IsComponent; - componentRoots.append(i); if (obj->functionCount() > 0) COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new functions.")); @@ -1463,13 +1462,19 @@ bool QQmlComponentAndAliasResolver::resolve() if (rootBinding->next || rootBinding->type != QV4::CompiledData::Binding::Type_Object) COMPILE_EXCEPTION(obj, tr("Invalid component body specification")); - componentBoundaries.append(rootBinding->value.objectIndex); + // We are going to collect ids/aliases and resolve them for the root object as a separate + // last pass. + if (i != indexOfRootObject) { + componentRoots.append(i); + componentBoundaries.append(rootBinding->value.objectIndex); + } + } std::sort(componentBoundaries.begin(), componentBoundaries.end()); for (int i = 0; i < componentRoots.count(); ++i) { - const QmlIR::Object *component = qmlObjects->at(componentRoots.at(i)); + QmlIR::Object *component = qmlObjects->at(componentRoots.at(i)); const QmlIR::Binding *rootBinding = component->firstBinding(); _componentIndex = i; @@ -1484,6 +1489,8 @@ bool QQmlComponentAndAliasResolver::resolve() if (!resolveAliases()) return false; + + component->namedObjectsInComponent.allocate(pool, *_namedObjectsInScope); } // Collect ids and aliases for root @@ -1496,6 +1503,9 @@ bool QQmlComponentAndAliasResolver::resolve() resolveAliases(); + QmlIR::Object *rootComponent = qmlObjects->at(indexOfRootObject); + rootComponent->namedObjectsInComponent.allocate(pool, *_namedObjectsInScope); + // Implicit component insertion may have added objects and thus we also need // to extend the symmetric propertyCaches. compiler->setPropertyCaches(propertyCaches); diff --git a/src/qml/compiler/qqmltypecompiler_p.h b/src/qml/compiler/qqmltypecompiler_p.h index 2650d07a32..48dffb59c4 100644 --- a/src/qml/compiler/qqmltypecompiler_p.h +++ b/src/qml/compiler/qqmltypecompiler_p.h @@ -122,6 +122,10 @@ private: QmlIR::Document *document; // index is string index of type name (use obj->inheritedTypeNameIndex) QHash customParsers; + + // index in first hash is component index, vector inside contains object indices of objects with id property + QHash> m_namedObjectsPerComponent; + QVector m_namedObjectsInRootScope; }; struct QQmlCompilePass diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp index ded2c1a9f8..e9955ffb04 100644 --- a/src/qml/compiler/qv4compileddata.cpp +++ b/src/qml/compiler/qv4compileddata.cpp @@ -189,6 +189,22 @@ void CompilationUnit::markObjects(QV4::ExecutionEngine *e) } } +IdentifierHash CompilationUnit::namedObjectsPerComponent(int componentObjectIndex) +{ + auto it = namedObjectsPerComponentCache.find(componentObjectIndex); + if (it == namedObjectsPerComponentCache.end()) { + IdentifierHash namedObjectCache(engine); + const CompiledData::Object *component = data->objectAt(componentObjectIndex); + const quint32 *namedObjectIndexPtr = component->namedObjectsInComponentTable(); + for (quint32 i = 0; i < component->nNamedObjectsInComponent; ++i, ++namedObjectIndexPtr) { + const CompiledData::Object *namedObject = data->objectAt(*namedObjectIndexPtr); + namedObjectCache.add(runtimeStrings[namedObject->idNameIndex], namedObject->id); + } + it = namedObjectsPerComponentCache.insert(componentObjectIndex, namedObjectCache); + } + return *it; +} + #endif // V4_BOOTSTRAP Unit *CompilationUnit::createUnitData(QmlIR::Document *irDocument) diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h index 3b413e2215..863708d23e 100644 --- a/src/qml/compiler/qv4compileddata_p.h +++ b/src/qml/compiler/qv4compileddata_p.h @@ -60,6 +60,7 @@ #include #include #include +#include QT_BEGIN_NAMESPACE @@ -415,6 +416,8 @@ struct Object quint32 offsetToSignals; // which in turn will be a table with offsets to variable-sized Signal objects quint32 nBindings; quint32 offsetToBindings; + quint32 nNamedObjectsInComponent; + quint32 offsetToNamedObjectsInComponent; Location location; Location locationOfIdProperty; // Function[] @@ -422,7 +425,7 @@ struct Object // Signal[] // Binding[] - static int calculateSizeExcludingSignals(int nFunctions, int nProperties, int nAliases, int nSignals, int nBindings) + static int calculateSizeExcludingSignals(int nFunctions, int nProperties, int nAliases, int nSignals, int nBindings, int nNamedObjectsInComponent) { return ( sizeof(Object) + nFunctions * sizeof(quint32) @@ -430,6 +433,7 @@ struct Object + nAliases * sizeof(Alias) + nSignals * sizeof(quint32) + nBindings * sizeof(Binding) + + nNamedObjectsInComponent * sizeof(int) + 0x7 ) & ~0x7; } @@ -460,6 +464,11 @@ struct Object const uint offset = offsetTable[idx]; return reinterpret_cast(reinterpret_cast(this) + offset); } + + const quint32 *namedObjectsInComponentTable() const + { + return reinterpret_cast(reinterpret_cast(this) + offsetToNamedObjectsInComponent); + } }; struct Import @@ -653,6 +662,11 @@ struct Q_QML_PRIVATE_EXPORT CompilationUnit : public QQmlRefCount // lookups by string (property name). QVector bindingPropertyDataPerObject; + // mapping from component object index (CompiledData::Unit object index that points to component) to identifier hash of named objects + // this is initialized on-demand by QQmlContextData + QHash> namedObjectsPerComponentCache; + IdentifierHash namedObjectsPerComponent(int componentObjectIndex); + QV4::Function *linkToEngine(QV4::ExecutionEngine *engine); void unlink(); diff --git a/src/qml/jsruntime/qv4identifier.cpp b/src/qml/jsruntime/qv4identifier.cpp index 626648067f..6260fd0cc8 100644 --- a/src/qml/jsruntime/qv4identifier.cpp +++ b/src/qml/jsruntime/qv4identifier.cpp @@ -64,12 +64,33 @@ IdentifierHashData::IdentifierHashData(int numBits) memset(entries, 0, alloc*sizeof(IdentifierHashEntry)); } +IdentifierHashData::IdentifierHashData(IdentifierHashData *other) + : size(other->size) + , numBits(other->numBits) + , identifierTable(other->identifierTable) +{ + refCount.store(1); + alloc = other->alloc; + entries = (IdentifierHashEntry *)malloc(alloc*sizeof(IdentifierHashEntry)); + memcpy(entries, other->entries, alloc*sizeof(IdentifierHashEntry)); +} + IdentifierHashBase::IdentifierHashBase(ExecutionEngine *engine) { d = new IdentifierHashData(3); d->identifierTable = engine->identifierTable; } +void IdentifierHashBase::detach() +{ + if (!d || d->refCount == 1) + return; + IdentifierHashData *newData = new IdentifierHashData(d); + if (d && !d->refCount.deref()) + delete d; + d = newData; +} + IdentifierHashEntry *IdentifierHashBase::addEntry(const Identifier *identifier) { diff --git a/src/qml/jsruntime/qv4identifier_p.h b/src/qml/jsruntime/qv4identifier_p.h index a3abfd8e13..2695bbc875 100644 --- a/src/qml/jsruntime/qv4identifier_p.h +++ b/src/qml/jsruntime/qv4identifier_p.h @@ -85,6 +85,7 @@ struct IdentifierHashEntry { struct IdentifierHashData { IdentifierHashData(int numBits); + explicit IdentifierHashData(IdentifierHashData *other); ~IdentifierHashData() { free(entries); } @@ -115,6 +116,8 @@ struct IdentifierHashBase bool contains(const QString &str) const; bool contains(String *str) const; + void detach(); + protected: IdentifierHashEntry *addEntry(const Identifier *i); const IdentifierHashEntry *lookup(const Identifier *identifier) const; @@ -141,6 +144,7 @@ struct IdentifierHash : public IdentifierHashBase } void add(const QString &str, const T &value); + void add(Heap::String *str, const T &value); inline T value(const QString &str) const; inline T value(String *str) const; @@ -197,6 +201,13 @@ void IdentifierHash::add(const QString &str, const T &value) e->value = value; } +template +void IdentifierHash::add(Heap::String *str, const T &value) +{ + IdentifierHashEntry *e = addEntry(toIdentifier(str)); + e->value = value; +} + template inline T IdentifierHash::value(const QString &str) const { @@ -223,7 +234,6 @@ QString IdentifierHash::findId(T value) const return QString(); } - } QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlcompiler_p.h b/src/qml/qml/qqmlcompiler_p.h index e953673a4d..cd2c533150 100644 --- a/src/qml/qml/qqmlcompiler_p.h +++ b/src/qml/qml/qqmlcompiler_p.h @@ -131,9 +131,6 @@ public: QList scripts; QQmlRefPointer compilationUnit; - // index in first hash is component index, vector inside contains object indices of objects with id property - QHash> namedObjectsPerComponent; - QVector namedObjectsInRootScope; // hash key is object index, value is indicies of bindings covered by custom parser QHash customParserBindings; QHash deferredBindingsPerObject; // index is object index diff --git a/src/qml/qml/qqmlcontext.cpp b/src/qml/qml/qqmlcontext.cpp index 11a8e81d8f..b3081ddbe6 100644 --- a/src/qml/qml/qqmlcontext.cpp +++ b/src/qml/qml/qqmlcontext.cpp @@ -310,7 +310,7 @@ void QQmlContext::setContextProperty(const QString &name, const QVariant &value) } } - QV4::IdentifierHash &properties = data->propertyNames(); + QV4::IdentifierHash &properties = data->detachedPropertyNames(); int idx = properties.value(name); if (idx == -1) { properties.add(name, data->idValueCount + d->propertyValues.count()); @@ -346,7 +346,7 @@ void QQmlContext::setContextProperty(const QString &name, QObject *value) return; } - QV4::IdentifierHash &properties = data->propertyNames(); + QV4::IdentifierHash &properties = data->detachedPropertyNames(); int idx = properties.value(name); if (idx == -1) { @@ -523,7 +523,7 @@ QQmlContextData::QQmlContextData() QQmlContextData::QQmlContextData(QQmlContext *ctxt) : parent(0), engine(0), isInternal(false), ownedByParent(false), isJSContext(false), isPragmaLibraryContext(false), unresolvedNames(false), hasEmittedDestruction(false), isRootObjectInCreation(false), - publicContext(ctxt), activeVMEData(0), + publicContext(ctxt), activeVMEData(0), componentObjectIndex(-1), contextObject(0), imports(0), childContexts(0), nextChild(0), prevChild(0), expressions(0), contextObjects(0), contextGuards(0), idValues(0), idValueCount(0), linkedContext(0), componentAttached(0) @@ -760,15 +760,6 @@ void QQmlContextData::setIdProperty(int idx, QObject *obj) idValues[idx].context = this; } -void QQmlContextData::setNamedObjects(const QVector &objects) -{ - Q_ASSERT(namedObjects.isEmpty()); - namedObjects = objects; - Q_ASSERT(propertyNameCache.isEmpty()); - idValueCount = objects.count(); - idValues = new ContextGuard[idValueCount]; -} - QString QQmlContextData::findObjectId(const QObject *obj) const { const QV4::IdentifierHash &properties = propertyNames(); @@ -804,20 +795,33 @@ QQmlContextPrivate *QQmlContextData::asQQmlContextPrivate() return QQmlContextPrivate::get(asQQmlContext()); } -QV4::IdentifierHash &QQmlContextData::propertyNames() const +void QQmlContextData::initFromTypeCompilationUnit(const QQmlRefPointer &unit, int subComponentIndex) +{ + typeCompilationUnit = unit; + componentObjectIndex = subComponentIndex == -1 ? typeCompilationUnit->data->indexOfRootObject : subComponentIndex; + Q_ASSERT(!idValues); + idValueCount = typeCompilationUnit->data->objectAt(componentObjectIndex)->nNamedObjectsInComponent; + idValues = new ContextGuard[idValueCount]; +} + +const QV4::IdentifierHash &QQmlContextData::propertyNames() const { if (propertyNameCache.isEmpty()) { - propertyNameCache = QV4::IdentifierHash(QV8Engine::getV4(engine->handle())); - for (int i = 0; i < namedObjects.count(); ++i) { - const QV4::CompiledData::Object *obj = typeCompilationUnit->data->objectAt(namedObjects.at(i)); - const QString name = typeCompilationUnit->data->stringAt(obj->idNameIndex); - propertyNameCache.add(name, obj->id); - } - namedObjects.clear(); + if (typeCompilationUnit) + propertyNameCache = typeCompilationUnit->namedObjectsPerComponent(componentObjectIndex); + else + propertyNameCache = QV4::IdentifierHash(QV8Engine::getV4(engine)); } return propertyNameCache; } +QV4::IdentifierHash &QQmlContextData::detachedPropertyNames() +{ + propertyNames(); + propertyNameCache.detach(); + return propertyNameCache; +} + QUrl QQmlContextData::url() const { if (typeCompilationUnit) diff --git a/src/qml/qml/qqmlcontext_p.h b/src/qml/qml/qqmlcontext_p.h index e455c1f07b..05ce39401e 100644 --- a/src/qml/qml/qqmlcontext_p.h +++ b/src/qml/qml/qqmlcontext_p.h @@ -151,9 +151,15 @@ public: // Compilation unit for contexts that belong to a compiled type. QQmlRefPointer typeCompilationUnit; - mutable QVector namedObjects; + // object index in CompiledData::Unit to component that created this context + int componentObjectIndex; + + void initFromTypeCompilationUnit(const QQmlRefPointer &unit, int subComponentIndex); + + // flag indicates whether the context owns the cache (after mutation) or not. mutable QV4::IdentifierHash propertyNameCache; - QV4::IdentifierHash &propertyNames() const; + const QV4::IdentifierHash &propertyNames() const; + QV4::IdentifierHash &detachedPropertyNames(); // Context object QObject *contextObject; @@ -201,7 +207,6 @@ public: ContextGuard *idValues; int idValueCount; void setIdProperty(int, QObject *); - void setNamedObjects(const QVector &objects); // Linked contexts. this owns linkedContext. QQmlContextData *linkedContext; diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp index 215423cb6d..a6b24c4f16 100644 --- a/src/qml/qml/qqmlobjectcreator.cpp +++ b/src/qml/qml/qqmlobjectcreator.cpp @@ -158,10 +158,8 @@ QObject *QQmlObjectCreator::create(int subComponentIndex, QObject *parent, QQmlI int objectToCreate; if (subComponentIndex == -1) { - namedObjects = compiledData->namedObjectsInRootScope; objectToCreate = qmlUnit->indexOfRootObject; } else { - namedObjects = compiledData->namedObjectsPerComponent[subComponentIndex]; const QV4::CompiledData::Object *compObj = qmlUnit->objectAt(subComponentIndex); objectToCreate = compObj->bindingTable()->value.objectIndex; } @@ -170,7 +168,7 @@ QObject *QQmlObjectCreator::create(int subComponentIndex, QObject *parent, QQmlI context->isInternal = true; context->imports = compiledData->importCache; context->imports->addref(); - context->typeCompilationUnit = compiledData->compilationUnit; + context->initFromTypeCompilationUnit(compiledData->compilationUnit, subComponentIndex); context->setParent(parentContext); if (!sharedState->rootContext) { @@ -185,8 +183,6 @@ QObject *QQmlObjectCreator::create(int subComponentIndex, QObject *parent, QQmlI if (topLevelCreator) sharedState->allJavaScriptObjects = scope.alloc(compiledData->totalObjectCount); - context->setNamedObjects(namedObjects); - if (subComponentIndex == -1 && compiledData->scripts.count()) { QV4::ScopedObject scripts(scope, v4->newArrayObject(compiledData->scripts.count())); context->importedScripts.set(v4, scripts); diff --git a/src/qml/qml/qqmlobjectcreator_p.h b/src/qml/qml/qqmlobjectcreator_p.h index e2e17bcf6c..730237acfe 100644 --- a/src/qml/qml/qqmlobjectcreator_p.h +++ b/src/qml/qml/qqmlobjectcreator_p.h @@ -143,7 +143,6 @@ private: QQmlContextData *context; const QHash &resolvedTypes; const QQmlPropertyCacheVector &propertyCaches; - QVector namedObjects; QExplicitlySharedDataPointer sharedState; bool topLevelCreator; void *activeVMEDataForRootContext; diff --git a/tests/auto/qml/qqmllanguage/data/rootItemIsComponent.qml b/tests/auto/qml/qqmllanguage/data/rootItemIsComponent.qml new file mode 100644 index 0000000000..dd653352d9 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/rootItemIsComponent.qml @@ -0,0 +1,6 @@ +import QtQml 2.0 +Component { + QtObject { + id: blah + } +} diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp index 5bb129fbb8..58a7c39760 100644 --- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp +++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp @@ -108,6 +108,7 @@ private slots: void bindTypeToJSValue(); void customParserTypes(); void rootAsQmlComponent(); + void rootItemIsComponent(); void inlineQmlComponents(); void idProperty(); void autoNotifyConnection(); @@ -1195,6 +1196,19 @@ void tst_qqmllanguage::rootAsQmlComponent() QCOMPARE(object->getChildren()->count(), 2); } +void tst_qqmllanguage::rootItemIsComponent() +{ + QQmlComponent component(&engine, testFileUrl("rootItemIsComponent.qml")); + VERIFY_ERRORS(0); + QScopedPointer root(component.create()); + QVERIFY(qobject_cast(root.data())); + QScopedPointer other(qobject_cast(root.data())->create()); + QVERIFY(!other.isNull()); + QQmlContext *context = qmlContext(other.data()); + QVERIFY(context); + QCOMPARE(context->nameForObject(other.data()), QStringLiteral("blah")); +} + // Tests that components can be specified inline void tst_qqmllanguage::inlineQmlComponents() { -- cgit v1.2.3