From 16cbcc606d431456ef5ab6783705a37d27776207 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Fri, 18 Oct 2019 10:03:18 +0200 Subject: Add support for primitive self-references in composite types This has been long missing and will also help with the implementation of inline components and the referenced bugs. Done-with: Fabian Kosmale Task-number: QTBUG-41087 Task-number: QTBUG-35910 Change-Id: Ia42a8f9808ece543f8ce2314b3352507fab22c62 Reviewed-by: Ulf Hermann --- src/qml/jsruntime/qv4executablecompilationunit.cpp | 10 +++-- src/qml/jsruntime/qv4executablecompilationunit_p.h | 5 ++- src/qml/qml/qqmlimport.cpp | 42 +++++++++++-------- src/qml/qml/qqmlimport_p.h | 5 +-- src/qml/qml/qqmlmetatype.cpp | 24 ++++------- src/qml/qml/qqmlmetatype_p.h | 13 +++++- src/qml/qml/qqmlpropertycachecreator.cpp | 16 ++++++++ src/qml/qml/qqmlpropertycachecreator_p.h | 48 ++++++++++++++-------- src/qml/qml/qqmltypecompiler.cpp | 7 +++- src/qml/qml/qqmltypecompiler_p.h | 2 + src/qml/qml/qqmltypedata.cpp | 34 +++++++++++---- src/qml/qml/qqmltypedata_p.h | 12 +++++- src/qml/qml/qqmltypenamecache.cpp | 4 +- 13 files changed, 151 insertions(+), 71 deletions(-) (limited to 'src') diff --git a/src/qml/jsruntime/qv4executablecompilationunit.cpp b/src/qml/jsruntime/qv4executablecompilationunit.cpp index 79e2ec2a5d..9c7609ee8d 100644 --- a/src/qml/jsruntime/qv4executablecompilationunit.cpp +++ b/src/qml/jsruntime/qv4executablecompilationunit.cpp @@ -283,7 +283,7 @@ void ExecutableCompilationUnit::unlink() Q_ASSERT(data && propertyCaches.count() > 0 && propertyCaches.at(/*root object*/0)); if (qmlEngine) qmlEngine->unregisterInternalCompositeType(this); - QQmlMetaType::unregisterInternalCompositeType(this); + QQmlMetaType::unregisterInternalCompositeType({metaTypeId, listMetaTypeId}); isRegisteredWithEngine = false; } @@ -383,13 +383,17 @@ IdentifierHash ExecutableCompilationUnit::createNamedObjectsPerComponent(int com return *namedObjectsPerComponentCache.insert(componentObjectIndex, namedObjectCache); } -void ExecutableCompilationUnit::finalizeCompositeType(QQmlEnginePrivate *qmlEngine) +void ExecutableCompilationUnit::finalizeCompositeType(QQmlEnginePrivate *qmlEngine, QQmlMetaType::CompositeMetaTypeIds typeIds) { this->qmlEngine = qmlEngine; // Add to type registry of composites if (propertyCaches.needsVMEMetaObject(/*root object*/0)) { - QQmlMetaType::registerInternalCompositeType(this); + // typeIds is only valid for types that have references to themselves. + if (!typeIds.isValid()) + typeIds = QQmlMetaType::registerInternalCompositeType(rootPropertyCache()->className()); + metaTypeId = typeIds.id; + listMetaTypeId = typeIds.listId; qmlEngine->registerInternalCompositeType(this); } else { const QV4::CompiledData::Object *obj = objectAt(/*root object*/0); diff --git a/src/qml/jsruntime/qv4executablecompilationunit_p.h b/src/qml/jsruntime/qv4executablecompilationunit_p.h index 6eef3b12c3..1272e7a2c3 100644 --- a/src/qml/jsruntime/qv4executablecompilationunit_p.h +++ b/src/qml/jsruntime/qv4executablecompilationunit_p.h @@ -58,6 +58,7 @@ #include #include #include +#include QT_BEGIN_NAMESPACE @@ -142,7 +143,7 @@ public: QHash namedObjectsPerComponentCache; inline IdentifierHash namedObjectsPerComponent(int componentObjectIndex); - void finalizeCompositeType(QQmlEnginePrivate *qmlEngine); + void finalizeCompositeType(QQmlEnginePrivate *qmlEngine, QQmlMetaType::CompositeMetaTypeIds typeIds); int totalBindingsCount = 0; // Number of bindings used in this type int totalParserStatusCount = 0; // Number of instantiated types that are QQmlParserStatus subclasses @@ -154,6 +155,8 @@ public: bool verifyChecksum(const CompiledData::DependentTypesHasher &dependencyHasher) const; + QQmlMetaType::CompositeMetaTypeIds typeIds() const { return {metaTypeId, listMetaTypeId}; } + int metaTypeId = -1; int listMetaTypeId = -1; bool isRegisteredWithEngine = false; diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp index af6d067fbb..73546bd795 100644 --- a/src/qml/qml/qqmlimport.cpp +++ b/src/qml/qml/qqmlimport.cpp @@ -229,8 +229,7 @@ public: bool resolveType(const QHashedStringRef &type, int *vmajor, int *vminor, QQmlType *type_return, QList *errors, QQmlType::RegistrationType registrationType, - QQmlImport::RecursionRestriction recursionRestriction - = QQmlImport::PreventRecursion); + bool *typeRecursionDetected = nullptr); QUrl baseUrl; QString base; @@ -594,7 +593,7 @@ bool QQmlImports::resolveType(const QHashedStringRef &type, QQmlType *type_return, int *vmaj, int *vmin, QQmlImportNamespace** ns_return, QList *errors, QQmlType::RegistrationType registrationType, - QQmlImport::RecursionRestriction recursionRestriction) const + bool *typeRecursionDetected) const { QQmlImportNamespace* ns = d->findQualifiedNamespace(type); if (ns) { @@ -604,7 +603,7 @@ bool QQmlImports::resolveType(const QHashedStringRef &type, } if (type_return) { if (d->resolveType(type, vmaj, vmin, type_return, errors, registrationType, - recursionRestriction)) { + typeRecursionDetected)) { if (qmlImportTrace()) { #define RESOLVE_TYPE_DEBUG qDebug().nospace() << "QQmlImports(" << qPrintable(baseUrl().toString()) \ << ')' << "::resolveType: " << type.toString() << " => " @@ -744,9 +743,12 @@ bool QQmlImportInstance::resolveType(QQmlTypeLoader *typeLoader, const QHashedSt if (resolveLocalUrl(*base, c.fileName) != componentUrl) continue; // failed attempt to access an internal type } - if (recursionRestriction == QQmlImport::PreventRecursion && *base == componentUrl) { - if (typeRecursionDetected) - *typeRecursionDetected = true; + + const bool recursion = *base == componentUrl; + if (typeRecursionDetected) + *typeRecursionDetected = recursion; + + if (recursionRestriction == QQmlImport::PreventRecursion && recursion) { continue; // no recursion } } @@ -803,10 +805,10 @@ bool QQmlImportInstance::resolveType(QQmlTypeLoader *typeLoader, const QHashedSt } if (exists) { - if (recursionRestriction == QQmlImport::PreventRecursion && base && (*base == qmlUrl)) { // no recursion - if (typeRecursionDetected) - *typeRecursionDetected = true; - } else { + const bool recursion = base && *base == qmlUrl; + if (typeRecursionDetected) + *typeRecursionDetected = recursion; + if (recursionRestriction == QQmlImport::AllowRecursion || !recursion) { QQmlType returnType = QQmlMetaType::typeForUrl( qmlUrl, type, registrationType == QQmlType::CompositeSingletonType, errors); if (type_return) @@ -822,7 +824,7 @@ bool QQmlImportInstance::resolveType(QQmlTypeLoader *typeLoader, const QHashedSt bool QQmlImportsPrivate::resolveType(const QHashedStringRef& type, int *vmajor, int *vminor, QQmlType *type_return, QList *errors, QQmlType::RegistrationType registrationType, - QQmlImport::RecursionRestriction recursionRestriction) + bool *typeRecursionDetected) { QQmlImportNamespace *s = nullptr; int dot = type.indexOf(Dot); @@ -852,7 +854,7 @@ bool QQmlImportsPrivate::resolveType(const QHashedStringRef& type, int *vmajor, QHashedStringRef unqualifiedtype = dot < 0 ? type : QHashedStringRef(type.constData()+dot+1, type.length()-dot-1); if (s) { if (s->resolveType(typeLoader, unqualifiedtype, vmajor, vminor, type_return, &base, errors, - registrationType, recursionRestriction)) + registrationType, typeRecursionDetected)) return true; if (s->imports.count() == 1 && !s->imports.at(0)->isLibrary && type_return && s != &unqualifiedset) { // qualified, and only 1 url @@ -880,13 +882,19 @@ bool QQmlImportNamespace::resolveType(QQmlTypeLoader *typeLoader, const QHashedS int *vmajor, int *vminor, QQmlType *type_return, QString *base, QList *errors, QQmlType::RegistrationType registrationType, - QQmlImport::RecursionRestriction recursionRestriction) + bool *typeRecursionDetected) { - bool typeRecursionDetected = false; + QQmlImport::RecursionRestriction recursionRestriction = + typeRecursionDetected ? QQmlImport::AllowRecursion : QQmlImport::PreventRecursion; + + bool localTypeRecursionDetected = false; + if (!typeRecursionDetected) + typeRecursionDetected = &localTypeRecursionDetected; + for (int i=0; iresolveType(typeLoader, type, vmajor, vminor, type_return, base, - &typeRecursionDetected, registrationType, recursionRestriction, errors)) { + typeRecursionDetected, registrationType, recursionRestriction, errors)) { if (qmlCheckTypes()) { // check for type clashes for (int j = i+1; j *errors = nullptr, QQmlType::RegistrationType registrationType = QQmlType::AnyRegistrationType, - QQmlImport::RecursionRestriction recursionRestriction = QQmlImport::PreventRecursion); + bool *typeRecursionDeteced = nullptr); // Prefix when used as a qualified import. Otherwise empty. QHashedString prefix; @@ -142,8 +142,7 @@ public: QQmlImportNamespace **ns_return, QList *errors = nullptr, QQmlType::RegistrationType registrationType = QQmlType::AnyRegistrationType, - QQmlImport::RecursionRestriction recursionRestriction - = QQmlImport::PreventRecursion) const; + bool *typeRecursionDetected = nullptr) const; bool resolveType(QQmlImportNamespace *, const QHashedStringRef& type, QQmlType *type_return, int *version_major, int *version_minor, diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp index c21247bb95..af43bfc921 100644 --- a/src/qml/qml/qqmlmetatype.cpp +++ b/src/qml/qml/qqmlmetatype.cpp @@ -518,12 +518,10 @@ QQmlType QQmlMetaType::registerCompositeType(const QQmlPrivate::RegisterComposit return QQmlType(priv); } -void QQmlMetaType::registerInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit) +QQmlMetaType::CompositeMetaTypeIds QQmlMetaType::registerInternalCompositeType(const QByteArray &className) { - QByteArray name = compilationUnit->rootPropertyCache()->className(); - - QByteArray ptr = name + '*'; - QByteArray lst = "QQmlListProperty<" + name + '>'; + QByteArray ptr = className + '*'; + QByteArray lst = "QQmlListProperty<" + className + '>'; int ptr_type = QMetaType::registerNormalizedType(ptr, QtMetaTypePrivate::QMetaTypeFunctionHelper::Destruct, @@ -538,23 +536,19 @@ void QQmlMetaType::registerInternalCompositeType(QV4::ExecutableCompilationUnit static_cast >(QtPrivate::QMetaTypeTypeFlags >::Flags), static_cast(nullptr)); - compilationUnit->metaTypeId = ptr_type; - compilationUnit->listMetaTypeId = lst_type; - QQmlMetaTypeDataPtr data; data->qmlLists.insert(lst_type, ptr_type); + + return {ptr_type, lst_type}; } -void QQmlMetaType::unregisterInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit) +void QQmlMetaType::unregisterInternalCompositeType(const QQmlMetaType::CompositeMetaTypeIds &typeIds) { - int ptr_type = compilationUnit->metaTypeId; - int lst_type = compilationUnit->listMetaTypeId; - QQmlMetaTypeDataPtr data; - data->qmlLists.remove(lst_type); + data->qmlLists.remove(typeIds.listId); - QMetaType::unregisterType(ptr_type); - QMetaType::unregisterType(lst_type); + QMetaType::unregisterType(typeIds.id); + QMetaType::unregisterType(typeIds.listId); } int QQmlMetaType::registerUnitCacheHook( diff --git a/src/qml/qml/qqmlmetatype_p.h b/src/qml/qml/qqmlmetatype_p.h index 13ba4d809b..146a5ab136 100644 --- a/src/qml/qml/qqmlmetatype_p.h +++ b/src/qml/qml/qqmlmetatype_p.h @@ -80,8 +80,17 @@ public: static void unregisterType(int type); - static void registerInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit); - static void unregisterInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit); + struct CompositeMetaTypeIds + { + int id = -1; + int listId = -1; + CompositeMetaTypeIds() = default; + CompositeMetaTypeIds(int id, int listId) : id(id), listId(listId) {} + bool isValid() const { return id != -1 && listId != -1; } + }; + + static CompositeMetaTypeIds registerInternalCompositeType(const QByteArray &className); + static void unregisterInternalCompositeType(const QQmlMetaType::CompositeMetaTypeIds &typeIds); static void registerModule(const char *uri, int versionMajor, int versionMinor); static bool protectModule(const QString &uri, int majVersion); diff --git a/src/qml/qml/qqmlpropertycachecreator.cpp b/src/qml/qml/qqmlpropertycachecreator.cpp index 034ebfc743..36581bda4e 100644 --- a/src/qml/qml/qqmlpropertycachecreator.cpp +++ b/src/qml/qml/qqmlpropertycachecreator.cpp @@ -74,6 +74,22 @@ int QQmlPropertyCacheCreatorBase::metaTypeForPropertyType(QV4::CompiledData::Bui return QMetaType::UnknownType; } +QByteArray QQmlPropertyCacheCreatorBase::createClassNameTypeByUrl(const QUrl &url) +{ + const QString path = url.path(); + int lastSlash = path.lastIndexOf(QLatin1Char('/')); + // Not a reusable type if we don't have an absolute Url + if (lastSlash <= -1) + return QByteArray(); + // ### this might not be correct for .ui.qml files + const QStringRef nameBase = path.midRef(lastSlash + 1, path.length() - lastSlash - 5); + // Not a reusable type if it doesn't start with a upper case letter. + if (nameBase.isEmpty() || !nameBase.at(0).isUpper()) + return QByteArray(); + return nameBase.toUtf8() + "_QMLTYPE_" + + QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1)); +} + QQmlBindingInstantiationContext::QQmlBindingInstantiationContext(int referencingObjectIndex, const QV4::CompiledData::Binding *instantiatingBinding, const QString &instantiatingPropertyName, QQmlPropertyCache *referencingObjectPropertyCache) : referencingObjectIndex(referencingObjectIndex) diff --git a/src/qml/qml/qqmlpropertycachecreator_p.h b/src/qml/qml/qqmlpropertycachecreator_p.h index 39778aa328..8571b0c9b3 100644 --- a/src/qml/qml/qqmlpropertycachecreator_p.h +++ b/src/qml/qml/qqmlpropertycachecreator_p.h @@ -97,6 +97,8 @@ public: static QAtomicInt classIndexCounter; static int metaTypeForPropertyType(QV4::CompiledData::BuiltinType type); + + static QByteArray createClassNameTypeByUrl(const QUrl &url); }; template @@ -108,7 +110,8 @@ public: QQmlPropertyCacheCreator(QQmlPropertyCacheVector *propertyCaches, QQmlPendingGroupPropertyBindings *pendingGroupPropertyBindings, QQmlEnginePrivate *enginePrivate, - const ObjectContainer *objectContainer, const QQmlImports *imports); + const ObjectContainer *objectContainer, const QQmlImports *imports, + const QByteArray &typeClassName); QQmlJS::DiagnosticMessage buildMetaObjects(); @@ -126,18 +129,21 @@ protected: const QQmlImports * const imports; QQmlPropertyCacheVector *propertyCaches; QQmlPendingGroupPropertyBindings *pendingGroupPropertyBindings; + const QByteArray typeClassName; }; template inline QQmlPropertyCacheCreator::QQmlPropertyCacheCreator(QQmlPropertyCacheVector *propertyCaches, QQmlPendingGroupPropertyBindings *pendingGroupPropertyBindings, QQmlEnginePrivate *enginePrivate, - const ObjectContainer *objectContainer, const QQmlImports *imports) + const ObjectContainer *objectContainer, const QQmlImports *imports, + const QByteArray &typeClassName) : enginePrivate(enginePrivate) , objectContainer(objectContainer) , imports(imports) , propertyCaches(propertyCaches) , pendingGroupPropertyBindings(pendingGroupPropertyBindings) + , typeClassName(typeClassName) { propertyCaches->resize(objectContainer->objectCount()); } @@ -293,14 +299,7 @@ inline QQmlJS::DiagnosticMessage QQmlPropertyCacheCreator::crea QByteArray newClassName; if (objectIndex == /*root object*/0) { - const QString path = objectContainer->url().path(); - int lastSlash = path.lastIndexOf(QLatin1Char('/')); - if (lastSlash > -1) { - const QStringRef nameBase = path.midRef(lastSlash + 1, path.length() - lastSlash - 5); - if (!nameBase.isEmpty() && nameBase.at(0).isUpper()) - newClassName = nameBase.toUtf8() + "_QMLTYPE_" + - QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1)); - } + newClassName = typeClassName; } if (newClassName.isEmpty()) { newClassName = QQmlMetaObject(baseTypeCache.data()).className(); @@ -499,22 +498,30 @@ inline QQmlJS::DiagnosticMessage QQmlPropertyCacheCreator::crea Q_ASSERT(!p->isBuiltinType); QQmlType qmltype; - if (!imports->resolveType(stringAt(p->builtinTypeOrTypeNameIndex), &qmltype, nullptr, nullptr, nullptr)) { + bool selfReference = false; + if (!imports->resolveType(stringAt(p->builtinTypeOrTypeNameIndex), &qmltype, nullptr, nullptr, nullptr, + nullptr, QQmlType::AnyRegistrationType, &selfReference)) { return qQmlCompileError(p->location, QQmlPropertyCacheCreatorBase::tr("Invalid property type")); } Q_ASSERT(qmltype.isValid()); if (qmltype.isComposite()) { - QQmlRefPointer tdata = enginePrivate->typeLoader.getType(qmltype.sourceUrl()); - Q_ASSERT(tdata); - Q_ASSERT(tdata->isComplete()); + QQmlMetaType::CompositeMetaTypeIds typeIds; + if (selfReference) { + typeIds = objectContainer->typeIds(); + } else { + QQmlRefPointer tdata = enginePrivate->typeLoader.getType(qmltype.sourceUrl()); + Q_ASSERT(tdata); + Q_ASSERT(tdata->isComplete()); - auto compilationUnit = tdata->compilationUnit(); + auto compilationUnit = tdata->compilationUnit(); + typeIds = compilationUnit->typeIds(); + } if (p->isList) { - propertyType = compilationUnit->listMetaTypeId; + propertyType = typeIds.listId; } else { - propertyType = compilationUnit->metaTypeId; + propertyType = typeIds.id; } } else { if (p->isList) { @@ -562,12 +569,17 @@ inline int QQmlPropertyCacheCreator::metaTypeForParameter(const if (customTypeName) *customTypeName = typeName; QQmlType qmltype; - if (!imports->resolveType(typeName, &qmltype, nullptr, nullptr, nullptr)) + bool selfReference = false; + if (!imports->resolveType(typeName, &qmltype, nullptr, nullptr, nullptr, nullptr, QQmlType::AnyRegistrationType, + &selfReference)) return QMetaType::UnknownType; if (!qmltype.isComposite()) return qmltype.typeId(); + if (selfReference) + return objectContainer->typeIds().id; + QQmlRefPointer tdata = enginePrivate->typeLoader.getType(qmltype.sourceUrl()); Q_ASSERT(tdata); Q_ASSERT(tdata->isComplete()); diff --git a/src/qml/qml/qqmltypecompiler.cpp b/src/qml/qml/qqmltypecompiler.cpp index 9ff0e3fb9e..7b4cf1a580 100644 --- a/src/qml/qml/qqmltypecompiler.cpp +++ b/src/qml/qml/qqmltypecompiler.cpp @@ -81,7 +81,7 @@ QQmlRefPointer QQmlTypeCompiler::compile() { QQmlPropertyCacheCreator propertyCacheBuilder(&m_propertyCaches, &pendingGroupPropertyBindings, - engine, this, imports()); + engine, this, imports(), typeData->typeClassName()); QQmlJS::DiagnosticMessage error = propertyCacheBuilder.buildMetaObjects(); if (error.isValid()) { recordError(error); @@ -279,6 +279,11 @@ void QQmlTypeCompiler::addImport(const QString &module, const QString &qualifier document->imports.append(import); } +QQmlMetaType::CompositeMetaTypeIds QQmlTypeCompiler::typeIds() const +{ + return typeData->typeIds(); +} + QQmlCompilePass::QQmlCompilePass(QQmlTypeCompiler *typeCompiler) : compiler(typeCompiler) { diff --git a/src/qml/qml/qqmltypecompiler_p.h b/src/qml/qml/qqmltypecompiler_p.h index 40b0337848..b43089dc06 100644 --- a/src/qml/qml/qqmltypecompiler_p.h +++ b/src/qml/qml/qqmltypecompiler_p.h @@ -129,6 +129,8 @@ public: return resolvedTypes->value(id); } + QQmlMetaType::CompositeMetaTypeIds typeIds() const; + private: QList errors; QQmlEnginePrivate *engine; diff --git a/src/qml/qml/qqmltypedata.cpp b/src/qml/qml/qqmltypedata.cpp index cfdcf6aad5..fac96a2d02 100644 --- a/src/qml/qml/qqmltypedata.cpp +++ b/src/qml/qml/qqmltypedata.cpp @@ -105,6 +105,11 @@ void QQmlTypeData::unregisterCallback(TypeDataCallback *callback) Q_ASSERT(!m_callbacks.contains(callback)); } +QQmlMetaType::CompositeMetaTypeIds QQmlTypeData::typeIds() const +{ + return m_typeIds; +} + bool QQmlTypeData::tryLoadFromDiskCache() { if (diskCacheDisabled() && !diskCacheForced()) @@ -199,7 +204,7 @@ void QQmlTypeData::createTypeAndPropertyCaches( { QQmlPropertyCacheCreator propertyCacheCreator( &m_compiledData->propertyCaches, &pendingGroupPropertyBindings, engine, - m_compiledData.data(), &m_importCache); + m_compiledData.data(), &m_importCache, typeClassName()); QQmlJS::DiagnosticMessage error = propertyCacheCreator.buildMetaObjects(); if (error.isValid()) { setError(error); @@ -299,6 +304,14 @@ void QQmlTypeData::done() } } + m_typeClassName = QQmlPropertyCacheCreatorBase::createClassNameTypeByUrl(finalUrl()); + if (!m_typeClassName.isEmpty()) + m_typeIds = QQmlMetaType::registerInternalCompositeType(m_typeClassName); + auto typeCleanupGuard = qScopeGuard([&]() { + if (isError() && m_typeIds.isValid()) + QQmlMetaType::unregisterInternalCompositeType(m_typeIds); + }); + QQmlRefPointer typeNameCache; QV4::ResolvedTypeReferenceMap resolvedTypeCache; { @@ -351,7 +364,7 @@ void QQmlTypeData::done() } } - m_compiledData->finalizeCompositeType(enginePrivate); + m_compiledData->finalizeCompositeType(enginePrivate, typeIds()); } { @@ -704,12 +717,14 @@ void QQmlTypeData::resolveTypes() const QString name = stringAt(unresolvedRef.key()); + bool *selfReferenceDetection = unresolvedRef->needsCreation ? nullptr : &ref.selfReference; + if (!resolveType(name, majorVersion, minorVersion, ref, unresolvedRef->location.line, unresolvedRef->location.column, reportErrors, - QQmlType::AnyRegistrationType) && reportErrors) + QQmlType::AnyRegistrationType, selfReferenceDetection) && reportErrors) return; - if (ref.type.isComposite()) { + if (ref.type.isComposite() && !ref.selfReference) { ref.typeData = typeLoader()->getType(ref.type.sourceUrl()); addDependency(ref.typeData.data()); } @@ -755,7 +770,7 @@ QQmlJS::DiagnosticMessage QQmlTypeData::buildTypeResolutionCaches( return qQmlCompileError(resolvedType->location, tr("Composite Singleton Type %1 is not creatable.").arg(qmlType.qmlTypeName())); } ref->compilationUnit = resolvedType->typeData->compilationUnit(); - } else if (qmlType.isValid()) { + } else if (qmlType.isValid() && !resolvedType->selfReference) { ref->type = qmlType; Q_ASSERT(ref->type.isValid()); @@ -782,20 +797,23 @@ QQmlJS::DiagnosticMessage QQmlTypeData::buildTypeResolutionCaches( bool QQmlTypeData::resolveType(const QString &typeName, int &majorVersion, int &minorVersion, TypeReference &ref, int lineNumber, int columnNumber, - bool reportErrors, QQmlType::RegistrationType registrationType) + bool reportErrors, QQmlType::RegistrationType registrationType, + bool *typeRecursionDetected) { QQmlImportNamespace *typeNamespace = nullptr; QList errors; bool typeFound = m_importCache.resolveType(typeName, &ref.type, &majorVersion, &minorVersion, - &typeNamespace, &errors, registrationType); + &typeNamespace, &errors, registrationType, + typeRecursionDetected); if (!typeNamespace && !typeFound && !m_implicitImportLoaded) { // Lazy loading of implicit import if (loadImplicitImport()) { // Try again to find the type errors.clear(); typeFound = m_importCache.resolveType(typeName, &ref.type, &majorVersion, &minorVersion, - &typeNamespace, &errors, registrationType); + &typeNamespace, &errors, registrationType, + typeRecursionDetected); } else { return false; //loadImplicitImport() hit an error, and called setError already } diff --git a/src/qml/qml/qqmltypedata_p.h b/src/qml/qml/qqmltypedata_p.h index e1d0c900ea..53e78e06d7 100644 --- a/src/qml/qml/qqmltypedata_p.h +++ b/src/qml/qml/qqmltypedata_p.h @@ -69,6 +69,7 @@ public: int majorVersion; int minorVersion; QQmlRefPointer typeData; + bool selfReference = false; QString prefix; // used by CompositeSingleton types QString qualifiedName() const; bool needsCreation; @@ -102,6 +103,9 @@ public: void registerCallback(TypeDataCallback *); void unregisterCallback(TypeDataCallback *); + QQmlMetaType::CompositeMetaTypeIds typeIds() const; + QByteArray typeClassName() const { return m_typeClassName; } + protected: void done() override; void completed() override; @@ -130,11 +134,11 @@ private: bool resolveType(const QString &typeName, int &majorVersion, int &minorVersion, TypeReference &ref, int lineNumber = -1, int columnNumber = -1, bool reportErrors = true, - QQmlType::RegistrationType registrationType = QQmlType::AnyRegistrationType); + QQmlType::RegistrationType registrationType = QQmlType::AnyRegistrationType, + bool *typeRecursionDetected = nullptr); void scriptImported(const QQmlRefPointer &blob, const QV4::CompiledData::Location &location, const QString &qualifier, const QString &nameSpace) override; - SourceCodeData m_backupSourceCode; // used when cache verification fails. QScopedPointer m_document; QV4::CompiledData::TypeReferenceMap m_typeReferences; @@ -150,6 +154,10 @@ private: QMap m_resolvedTypes; bool m_typesResolved:1; + // Used for self-referencing types, otherwise -1. + QQmlMetaType::CompositeMetaTypeIds m_typeIds; + QByteArray m_typeClassName; // used for meta-object later + QQmlRefPointer m_compiledData; QList m_callbacks; diff --git a/src/qml/qml/qqmltypenamecache.cpp b/src/qml/qml/qqmltypenamecache.cpp index 8f1a61e6ad..1015403226 100644 --- a/src/qml/qml/qqmltypenamecache.cpp +++ b/src/qml/qml/qqmltypenamecache.cpp @@ -154,8 +154,10 @@ QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QV4::String *name, QQml QQmlImportNamespace *typeNamespace = nullptr; QList errors; QQmlType t; + bool typeRecursionDetected = false; bool typeFound = m_imports.resolveType(typeName, &t, nullptr, nullptr, &typeNamespace, &errors, - QQmlType::AnyRegistrationType, recursionRestriction); + QQmlType::AnyRegistrationType, + recursionRestriction == QQmlImport::AllowRecursion ? &typeRecursionDetected : nullptr); if (typeFound) { return Result(t); } -- cgit v1.2.3