From bdb2b66f3d7d027e3022aabd63fe73d305ed058f Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Mon, 18 Jan 2021 11:24:02 +0100 Subject: Add support for extended types to qmltyperegistrar We generate the extensions as separate types. This also covers the case of value types being extended by "themselves". We can properly express this now, so we don't need the hackery of generating the local members of a type with QML_FOREIGN into the foreign type anymore. This also fixes interfaces from local types being written for foreign types. Fixes: QTBUG-89501 Change-Id: Ic76acd7eef09a92c1e36bd7a649c7a2deb24597b Reviewed-by: Ulf Hermann Reviewed-by: Fabian Kosmale --- src/imports/tooling/Component.qml | 1 + src/qmltyperegistrar/metatypesjsonprocessor.cpp | 35 ++--- src/qmltyperegistrar/metatypesjsonprocessor.h | 5 +- src/qmltyperegistrar/qmltyperegistrar.cpp | 1 + src/qmltyperegistrar/qmltypesclassdescription.cpp | 130 +++++++++++------ src/qmltyperegistrar/qmltypesclassdescription.h | 13 +- src/qmltyperegistrar/qmltypescreator.cpp | 159 ++++++++++++--------- src/qmltyperegistrar/qmltypescreator.h | 2 + .../qml/qmltyperegistrar/tst_qmltyperegistrar.cpp | 1 + .../qml/qmltyperegistrar/tst_qmltyperegistrar.h | 5 +- 10 files changed, 221 insertions(+), 131 deletions(-) diff --git a/src/imports/tooling/Component.qml b/src/imports/tooling/Component.qml index 0045a75a6d..786e4a99df 100644 --- a/src/imports/tooling/Component.qml +++ b/src/imports/tooling/Component.qml @@ -50,6 +50,7 @@ QtObject { property var interfaces: [] property string attachedType property string valueType + property string extension property bool isSingleton: false property bool isCreatable: name.length > 0 property bool isComposite: false diff --git a/src/qmltyperegistrar/metatypesjsonprocessor.cpp b/src/qmltyperegistrar/metatypesjsonprocessor.cpp index a9c3128350..0e0723d072 100644 --- a/src/qmltyperegistrar/metatypesjsonprocessor.cpp +++ b/src/qmltyperegistrar/metatypesjsonprocessor.cpp @@ -110,16 +110,24 @@ bool MetaTypesJsonProcessor::processForeignTypes(const QStringList &foreignTypes return success; } +static void sortStringList(QStringList *list) +{ + std::sort(list->begin(), list->end()); + const auto newEnd = std::unique(list->begin(), list->end()); + list->erase(QStringList::const_iterator(newEnd), list->constEnd()); +} + void MetaTypesJsonProcessor::postProcessTypes() { sortTypes(m_types); - sortIncludes(); + sortStringList(&m_includes); } void MetaTypesJsonProcessor::postProcessForeignTypes() { sortTypes(m_foreignTypes); - m_types += foreignRelatedTypes(); + addRelatedTypes(); + sortStringList(&m_referencedTypes); sortTypes(m_types); } @@ -145,13 +153,14 @@ MetaTypesJsonProcessor::RegistrationMode MetaTypesJsonProcessor::qmlTypeRegistra return NoRegistration; } -QVector MetaTypesJsonProcessor::foreignRelatedTypes() const +void MetaTypesJsonProcessor::addRelatedTypes() { const QLatin1String classInfosKey("classInfos"); const QLatin1String nameKey("name"); const QLatin1String qualifiedClassNameKey("qualifiedClassName"); const QLatin1String qmlNamePrefix("QML."); const QLatin1String qmlForeignName("QML.Foreign"); + const QLatin1String qmlExtendedName("QML.Extended"); const QLatin1String qmlAttachedName("QML.Attached"); const QLatin1String qmlSequenceName("QML.Sequence"); const QLatin1String valueKey("value"); @@ -162,7 +171,6 @@ QVector MetaTypesJsonProcessor::foreignRelatedTypes() const QSet processedRelatedNames; QQueue typeQueue; typeQueue.append(m_types); - QVector relatedTypes; // First mark all classes registered from this module as already processed. for (const QJsonObject &type : m_types) { @@ -197,12 +205,13 @@ QVector MetaTypesJsonProcessor::foreignRelatedTypes() const } auto addType = [&](const QString &typeName) { + m_referencedTypes.append(typeName); if (processedRelatedNames.contains(typeName)) return; processedRelatedNames.insert(typeName); if (const QJsonObject *other = QmlTypesClassDescription::findType(m_foreignTypes, typeName)) { - relatedTypes.append(*other); + m_types.append(*other); typeQueue.enqueue(*other); } }; @@ -216,7 +225,8 @@ QVector MetaTypesJsonProcessor::foreignRelatedTypes() const for (const QJsonValue &classInfo : classInfos) { const QJsonObject obj = classInfo.toObject(); const QString objNameValue = obj.value(nameKey).toString(); - if (objNameValue == qmlAttachedName || objNameValue == qmlSequenceName) { + if (objNameValue == qmlAttachedName || objNameValue == qmlSequenceName + || objNameValue == qmlExtendedName) { addType(obj.value(valueKey).toString()); } else if (objNameValue == qmlForeignName) { const QString foreignClassName = obj.value(valueKey).toString(); @@ -233,13 +243,13 @@ QVector MetaTypesJsonProcessor::foreignRelatedTypes() const for (const QJsonValue &otherClassInfo : otherClassInfos) { const QJsonObject obj = otherClassInfo.toObject(); const QString objNameValue = obj.value(nameKey).toString(); - if (objNameValue == qmlAttachedName || objNameValue == qmlSequenceName) { + if (objNameValue == qmlAttachedName || objNameValue == qmlSequenceName + || objNameValue == qmlExtendedName) { addType(obj.value(valueKey).toString()); break; } // No, you cannot chain QML_FOREIGN declarations. Sorry. } - break; } } } @@ -251,8 +261,6 @@ QVector MetaTypesJsonProcessor::foreignRelatedTypes() const addType(superObject.value(nameKey).toString()); } } - - return relatedTypes; } void MetaTypesJsonProcessor::sortTypes(QVector &types) @@ -264,13 +272,6 @@ void MetaTypesJsonProcessor::sortTypes(QVector &types) }); } -void MetaTypesJsonProcessor::sortIncludes() -{ - std::sort(m_includes.begin(), m_includes.end()); - const auto newEnd = std::unique(m_includes.begin(), m_includes.end()); - m_includes.erase(QList::const_iterator(newEnd), m_includes.constEnd()); -} - QString MetaTypesJsonProcessor::resolvedInclude(const QString &include) { return (m_privateIncludes && include.endsWith(QLatin1String("_p.h"))) diff --git a/src/qmltyperegistrar/metatypesjsonprocessor.h b/src/qmltyperegistrar/metatypesjsonprocessor.h index 341a64a98b..94016e3bc0 100644 --- a/src/qmltyperegistrar/metatypesjsonprocessor.h +++ b/src/qmltyperegistrar/metatypesjsonprocessor.h @@ -48,6 +48,7 @@ public: QVector types() const { return m_types; } QVector foreignTypes() const { return m_foreignTypes; } + QStringList referencedTypes() const { return m_referencedTypes; } QStringList includes() const { return m_includes; } private: @@ -59,15 +60,15 @@ private: }; static RegistrationMode qmlTypeRegistrationMode(const QJsonObject &classDef); - QVector foreignRelatedTypes() const; + void addRelatedTypes(); void sortTypes(QVector &types); - void sortIncludes(); QString resolvedInclude(const QString &include);; void processTypes(const QJsonObject &types); void processForeignTypes(const QJsonObject &types); QStringList m_includes; + QStringList m_referencedTypes; QVector m_types; QVector m_foreignTypes; bool m_privateIncludes = false; diff --git a/src/qmltyperegistrar/qmltyperegistrar.cpp b/src/qmltyperegistrar/qmltyperegistrar.cpp index 4e010a3252..7ae59b3e37 100644 --- a/src/qmltyperegistrar/qmltyperegistrar.cpp +++ b/src/qmltyperegistrar/qmltyperegistrar.cpp @@ -245,6 +245,7 @@ int main(int argc, char **argv) QmlTypesCreator creator; creator.setOwnTypes(processor.types()); creator.setForeignTypes(processor.foreignTypes()); + creator.setReferencedTypes(processor.referencedTypes()); creator.setModule(module); creator.setVersion(QTypeRevision::fromVersion(parser.value(majorVersionOption).toInt(), 0)); diff --git a/src/qmltyperegistrar/qmltypesclassdescription.cpp b/src/qmltyperegistrar/qmltypesclassdescription.cpp index 4d7e4ac072..5af8ea5be6 100644 --- a/src/qmltyperegistrar/qmltypesclassdescription.cpp +++ b/src/qmltyperegistrar/qmltypesclassdescription.cpp @@ -58,15 +58,32 @@ const QJsonObject *QmlTypesClassDescription::findType(const QVector return (it != types.end() && it->value(qualifiedClassNameKey) == name) ? &(*it) : nullptr; } -void QmlTypesClassDescription::collect(const QJsonObject *classDef, - const QVector &types, - const QVector &foreign, - CollectMode mode, QTypeRevision defaultRevision) +void QmlTypesClassDescription::collectSuperClasses( + const QJsonObject *classDef, const QVector &types, + const QVector &foreign, CollectMode mode, QTypeRevision defaultRevision) { - const QJsonObject *origClassDef = classDef; // if we find QML.Foreign, classDef changes. - if (file.isEmpty() && classDef->value(QLatin1String("registerable")).toBool()) - file = classDef->value(QLatin1String("inputFile")).toString(); + const auto supers = classDef->value(QLatin1String("superClasses")).toArray(); + for (const QJsonValue &superValue : supers) { + const QJsonObject superObject = superValue.toObject(); + if (superObject[QLatin1String("access")].toString() == QLatin1String("public")) { + const QString superName = superObject[QLatin1String("name")].toString(); + const CollectMode superMode = (mode == TopLevel) ? SuperClass : RelatedType; + if (const QJsonObject *other = findType(types, superName)) + collect(other, types, foreign, superMode, defaultRevision); + else if (const QJsonObject *other = findType(foreign, superName)) + collect(other, types, foreign, superMode, defaultRevision); + else // If we cannot locate a type for it, there is no point in recording the superClass + continue; + + if (mode == TopLevel && superClass.isEmpty()) + superClass = superName; + } + } +} + +void QmlTypesClassDescription::collectInterfaces(const QJsonObject *classDef) +{ if (classDef->contains(QLatin1String("interfaces"))) { const QJsonArray array = classDef->value(QLatin1String("interfaces")).toArray(); for (const QJsonValue &value : array) { @@ -74,6 +91,43 @@ void QmlTypesClassDescription::collect(const QJsonObject *classDef, implementsInterfaces << object[QLatin1String("className")].toString(); } } +} + +void QmlTypesClassDescription::collectLocalAnonymous( + const QJsonObject *classDef, const QVector &types, + const QVector &foreign, QTypeRevision defaultRevision) +{ + file = classDef->value(QLatin1String("inputFile")).toString(); + + resolvedClass = classDef; + className = classDef->value(QLatin1String("qualifiedClassName")).toString(); + + if (classDef->value(QStringLiteral("object")).toBool()) + accessSemantics = QStringLiteral("reference"); + else if (classDef->value(QStringLiteral("gadget")).toBool()) + accessSemantics = QStringLiteral("value"); + else + accessSemantics = QStringLiteral("none"); + + const auto classInfos = classDef->value(QLatin1String("classInfos")).toArray(); + for (const QJsonValue &classInfo : classInfos) { + const QJsonObject obj = classInfo.toObject(); + if (obj[QLatin1String("name")].toString() == QLatin1String("DefaultProperty")) { + defaultProp = obj[QLatin1String("value")].toString(); + break; + } + } + + collectInterfaces(classDef); + collectSuperClasses(classDef, types, foreign, TopLevel, defaultRevision); +} + +void QmlTypesClassDescription::collect( + const QJsonObject *classDef, const QVector &types, + const QVector &foreign, CollectMode mode, QTypeRevision defaultRevision) +{ + if (file.isEmpty() && classDef->value(QLatin1String("registerable")).toBool()) + file = classDef->value(QLatin1String("inputFile")).toString(); const auto classInfos = classDef->value(QLatin1String("classInfos")).toArray(); const QString classDefName = classDef->value(QLatin1String("className")).toString(); @@ -83,7 +137,7 @@ void QmlTypesClassDescription::collect(const QJsonObject *classDef, const QString value = obj[QLatin1String("value")].toString(); if (name == QLatin1String("DefaultProperty")) { - if (mode != AttachedType && defaultProp.isEmpty()) + if (mode != RelatedType && defaultProp.isEmpty()) defaultProp = value; } else if (name == QLatin1String("QML.AddedInVersion")) { const QTypeRevision revision = QTypeRevision::fromEncodedVersion(value.toInt()); @@ -111,6 +165,9 @@ void QmlTypesClassDescription::collect(const QJsonObject *classDef, } else if (name == QLatin1String("QML.Attached")) { attachedType = value; collectRelated(value, types, foreign, defaultRevision); + } else if (name == QLatin1String("QML.Extended")) { + extensionType = value; + collectRelated(value, types, foreign, defaultRevision); } else if (name == QLatin1String("QML.Sequence")) { sequenceValueType = value; collectRelated(value, types, foreign, defaultRevision); @@ -131,55 +188,40 @@ void QmlTypesClassDescription::collect(const QJsonObject *classDef, } else if (foreignName == QLatin1String("QML.Attached")) { attachedType = foreignValue; collectRelated(foreignValue, types, foreign, defaultRevision); + } else if (foreignName == QLatin1String("QML.Extended")) { + extensionType = foreignValue; + collectRelated(foreignValue, types, foreign, defaultRevision); } else if (foreignName == QLatin1String("QML.Sequence")) { sequenceValueType = foreignValue; collectRelated(foreignValue, types, foreign, defaultRevision); } } } else { - // The foreign type does not have a meta object: We only override the name. className = value; + classDef = nullptr; } } else if (name == QLatin1String("QML.Root")) { isRootClass = true; } } - if (mode == AttachedType || !elementName.isEmpty()) { - collectExtraVersions(classDef, QString::fromLatin1("properties"), revisions); - collectExtraVersions(classDef, QString::fromLatin1("slots"), revisions); - collectExtraVersions(classDef, QString::fromLatin1("methods"), revisions); - collectExtraVersions(classDef, QString::fromLatin1("signals"), revisions); - } - - auto supers = classDef->value(QLatin1String("superClasses")).toArray(); - if (classDef != origClassDef) { - const QJsonArray origSupers = origClassDef->value(QLatin1String("superClasses")).toArray(); - for (const QJsonValue origSuper : origSupers) - supers.append(origSuper); - } - - for (const QJsonValue &superValue : qAsConst(supers)) { - const QJsonObject superObject = superValue.toObject(); - if (superObject[QLatin1String("access")].toString() == QLatin1String("public")) { - const QString superName = superObject[QLatin1String("name")].toString(); - - const CollectMode superMode = (mode == TopLevel) ? SuperClass : AttachedType; - if (const QJsonObject *other = findType(types, superName)) - collect(other, types, foreign, superMode, defaultRevision); - else if (const QJsonObject *other = findType(foreign, superName)) - collect(other, types, foreign, superMode, defaultRevision); - else // If we cannot locate a type for it, there is no point in recording the superClass - continue; - - if (mode == TopLevel && superClass.isEmpty()) - superClass = superName; + if (classDef) { + if (mode == RelatedType || !elementName.isEmpty()) { + collectExtraVersions(classDef, QString::fromLatin1("properties"), revisions); + collectExtraVersions(classDef, QString::fromLatin1("slots"), revisions); + collectExtraVersions(classDef, QString::fromLatin1("methods"), revisions); + collectExtraVersions(classDef, QString::fromLatin1("signals"), revisions); } + + collectSuperClasses(classDef, types, foreign, mode, defaultRevision); } if (mode != TopLevel) return; + if (classDef) + collectInterfaces(classDef); + if (!addedInRevision.isValid()) { revisions.append(defaultRevision); addedInRevision = defaultRevision; @@ -192,17 +234,19 @@ void QmlTypesClassDescription::collect(const QJsonObject *classDef, revisions.erase(QList::const_iterator(end), revisions.constEnd()); resolvedClass = classDef; - if (className.isEmpty() && mode == TopLevel) + if (className.isEmpty() && classDef) className = classDef->value(QLatin1String("qualifiedClassName")).toString(); if (!sequenceValueType.isEmpty()) { isCreatable = false; accessSemantics = QLatin1String("sequence"); - } else if (classDef->value(QLatin1String("object")).toBool()) { + } else if (classDef && classDef->value(QLatin1String("object")).toBool()) { accessSemantics = QLatin1String("reference"); } else { isCreatable = false; - accessSemantics = classDef->value(QLatin1String("gadget")).toBool() + // If no classDef, we assume it's a value type defined by the foreign/extended trick. + // Objects and namespaces always have metaobjects and therefore classDefs. + accessSemantics = (!classDef || classDef->value(QLatin1String("gadget")).toBool()) ? QLatin1String("value") : QLatin1String("none"); } @@ -214,7 +258,7 @@ void QmlTypesClassDescription::collectRelated(const QString &related, QTypeRevision defaultRevision) { if (const QJsonObject *other = findType(types, related)) - collect(other, types, foreign, AttachedType, defaultRevision); + collect(other, types, foreign, RelatedType, defaultRevision); else if (const QJsonObject *other = findType(foreign, related)) - collect(other, types, foreign, AttachedType, defaultRevision); + collect(other, types, foreign, RelatedType, defaultRevision); } diff --git a/src/qmltyperegistrar/qmltypesclassdescription.h b/src/qmltyperegistrar/qmltypesclassdescription.h index fd172d1922..04d3adac77 100644 --- a/src/qmltyperegistrar/qmltypesclassdescription.h +++ b/src/qmltyperegistrar/qmltypesclassdescription.h @@ -44,6 +44,7 @@ struct QmlTypesClassDescription QString defaultProp; QString superClass; QString attachedType; + QString extensionType; QString sequenceValueType; QString accessSemantics; QList revisions; @@ -57,7 +58,7 @@ struct QmlTypesClassDescription enum CollectMode { TopLevel, SuperClass, - AttachedType + RelatedType }; void collect(const QJsonObject *classDef, const QVector &types, @@ -67,6 +68,16 @@ struct QmlTypesClassDescription const QVector &foreign, QTypeRevision defaultRevision); static const QJsonObject *findType(const QVector &types, const QString &name); + + void collectLocalAnonymous(const QJsonObject *classDef,const QVector &types, + const QVector &foreign, QTypeRevision defaultRevision); + + +private: + void collectSuperClasses( + const QJsonObject *classDef, const QVector &types, + const QVector &foreign, CollectMode mode, QTypeRevision defaultRevision); + void collectInterfaces(const QJsonObject *classDef); }; #endif // QMLTYPESCLASSDESCRIPTION_H diff --git a/src/qmltyperegistrar/qmltypescreator.cpp b/src/qmltyperegistrar/qmltypescreator.cpp index 62996ff90b..b5a3cd749c 100644 --- a/src/qmltyperegistrar/qmltypescreator.cpp +++ b/src/qmltyperegistrar/qmltypescreator.cpp @@ -97,6 +97,9 @@ void QmlTypesCreator::writeClassProperties(const QmlTypesClassDescription &colle if (!collector.attachedType.isEmpty()) m_qml.writeScriptBinding(QLatin1String("attachedType"), enquote(collector.attachedType)); + if (!collector.extensionType.isEmpty()) + m_qml.writeScriptBinding(QLatin1String("extension"), enquote(collector.extensionType)); + if (!collector.implementsInterfaces.isEmpty()) { QStringList interfaces; for (const QString &interface : collector.implementsInterfaces) @@ -249,7 +252,7 @@ static bool isAllowedInMajorVersion(const QJsonValue &member, QTypeRevision maxM || memberRevision.majorVersion() <= maxMajorVersion.majorVersion(); } -static QJsonArray members(const QJsonObject *classDef, const QJsonObject *origClassDef, +static QJsonArray members(const QJsonObject *classDef, const QString &key, QTypeRevision maxMajorVersion) { QJsonArray classDefMembers; @@ -260,14 +263,6 @@ static QJsonArray members(const QJsonObject *classDef, const QJsonObject *origCl classDefMembers.append(member); } - if (classDef != origClassDef) { - const QJsonArray origClassDefMembers = origClassDef->value(key).toArray(); - for (const QJsonValue member : origClassDefMembers) { - if (isAllowedInMajorVersion(member, maxMajorVersion)) - classDefMembers.append(member); - } - } - return classDefMembers; } @@ -298,6 +293,57 @@ void QmlTypesCreator::writeComponents() const QLatin1String intType("int"); const QLatin1String stringType("string"); + auto writeRootClass = [&](const QJsonObject *classDef, const QSet ¬ifySignals) { + // Hide destroyed() signals + QJsonArray componentSignals = members(classDef, signalsKey, m_version); + for (auto it = componentSignals.begin(); it != componentSignals.end();) { + if (it->toObject().value(nameKey).toString() == destroyedName) + it = componentSignals.erase(it); + else + ++it; + } + writeMethods(componentSignals, signalElement, notifySignals); + + // Hide deleteLater() methods + QJsonArray componentMethods = members(classDef, methodsKey, m_version); + const QJsonArray componentSlots = members(classDef, slotsKey, m_version); + for (const QJsonValue &componentSlot : componentSlots) + componentMethods.append(componentSlot); + for (auto it = componentMethods.begin(); it != componentMethods.end();) { + if (it->toObject().value(nameKey).toString() == deleteLaterName) + it = componentMethods.erase(it); + else + ++it; + } + + // Add toString() + QJsonObject toStringMethod; + toStringMethod.insert(nameKey, toStringName); + toStringMethod.insert(accessKey, publicAccess); + toStringMethod.insert(returnTypeKey, stringType); + componentMethods.append(toStringMethod); + + // Add destroy() + QJsonObject destroyMethod; + destroyMethod.insert(nameKey, destroyName); + destroyMethod.insert(accessKey, publicAccess); + componentMethods.append(destroyMethod); + + // Add destroy(int) + QJsonObject destroyMethodWithArgument; + destroyMethodWithArgument.insert(nameKey, destroyName); + destroyMethodWithArgument.insert(accessKey, publicAccess); + QJsonObject delayArgument; + delayArgument.insert(nameKey, delayName); + delayArgument.insert(typeKey, intType); + QJsonArray destroyArguments; + destroyArguments.append(delayArgument); + destroyMethodWithArgument.insert(argumentsKey, destroyArguments); + componentMethods.append(destroyMethodWithArgument); + + writeMethods(componentMethods, methodElement); + }; + for (const QJsonObject &component : m_ownTypes) { m_qml.writeStartObject(componentElement); @@ -307,69 +353,50 @@ void QmlTypesCreator::writeComponents() writeClassProperties(collector); - const QJsonObject *classDef = collector.resolvedClass; - writeEnums(members(classDef, &component, enumsKey, m_version)); - - QSet notifySignals; - writeProperties(members(classDef, &component, propertiesKey, m_version), notifySignals); + if (const QJsonObject *classDef = collector.resolvedClass) { + writeEnums(members(classDef, enumsKey, m_version)); - if (collector.isRootClass) { + QSet notifySignals; + writeProperties(members(classDef, propertiesKey, m_version), notifySignals); - // Hide destroyed() signals - QJsonArray componentSignals = members(classDef, &component, signalsKey, m_version); - for (auto it = componentSignals.begin(); it != componentSignals.end();) { - if (it->toObject().value(nameKey).toString() == destroyedName) - it = componentSignals.erase(it); - else - ++it; - } - writeMethods(componentSignals, signalElement, notifySignals); - - // Hide deleteLater() methods - QJsonArray componentMethods = members(classDef, &component, methodsKey, m_version); - const QJsonArray componentSlots = members(classDef, &component, slotsKey, m_version); - for (const QJsonValue componentSlot : componentSlots) - componentMethods.append(componentSlot); - for (auto it = componentMethods.begin(); it != componentMethods.end();) { - if (it->toObject().value(nameKey).toString() == deleteLaterName) - it = componentMethods.erase(it); - else - ++it; + if (collector.isRootClass) { + writeRootClass(classDef, notifySignals); + } else { + writeMethods(members(classDef, signalsKey, m_version), signalElement, + notifySignals); + writeMethods(members(classDef, slotsKey, m_version), methodElement); + writeMethods(members(classDef, methodsKey, m_version), methodElement); } + } + m_qml.writeEndObject(); + + if (collector.resolvedClass != &component + && std::binary_search( + m_referencedTypes.begin(), m_referencedTypes.end(), + component.value(QStringLiteral("qualifiedClassName")).toString())) { + + // This type is referenced from elsewhere and has a QML_FOREIGN of its own. We need to + // also generate a description of the local type then. All the QML_* macros are + // ignored, and the result is an anonymous type. + + m_qml.writeStartObject(componentElement); + + QmlTypesClassDescription collector; + collector.collectLocalAnonymous(&component, m_ownTypes, m_foreignTypes, m_version); - // Add toString() - QJsonObject toStringMethod; - toStringMethod.insert(nameKey, toStringName); - toStringMethod.insert(accessKey, publicAccess); - toStringMethod.insert(returnTypeKey, stringType); - componentMethods.append(toStringMethod); - - // Add destroy() - QJsonObject destroyMethod; - destroyMethod.insert(nameKey, destroyName); - destroyMethod.insert(accessKey, publicAccess); - componentMethods.append(destroyMethod); - - // Add destroy(int) - QJsonObject destroyMethodWithArgument; - destroyMethodWithArgument.insert(nameKey, destroyName); - destroyMethodWithArgument.insert(accessKey, publicAccess); - QJsonObject delayArgument; - delayArgument.insert(nameKey, delayName); - delayArgument.insert(typeKey, intType); - QJsonArray destroyArguments; - destroyArguments.append(delayArgument); - destroyMethodWithArgument.insert(argumentsKey, destroyArguments); - componentMethods.append(destroyMethodWithArgument); - - writeMethods(componentMethods, methodElement); - } else { - writeMethods(members(classDef, &component, signalsKey, m_version), signalElement, + writeClassProperties(collector); + writeEnums(members(&component, enumsKey, m_version)); + + QSet notifySignals; + writeProperties(members(&component, propertiesKey, m_version), notifySignals); + + writeMethods(members(&component, signalsKey, m_version), signalElement, notifySignals); - writeMethods(members(classDef, &component, slotsKey, m_version), methodElement); - writeMethods(members(classDef, &component, methodsKey, m_version), methodElement); + writeMethods(members(&component, slotsKey, m_version), methodElement); + writeMethods(members(&component, methodsKey, m_version), methodElement); + + m_qml.writeEndObject(); } - m_qml.writeEndObject(); } } diff --git a/src/qmltyperegistrar/qmltypescreator.h b/src/qmltyperegistrar/qmltypescreator.h index 2216a8a967..208cc19952 100644 --- a/src/qmltyperegistrar/qmltypescreator.h +++ b/src/qmltyperegistrar/qmltypescreator.h @@ -44,6 +44,7 @@ public: void setOwnTypes(QVector ownTypes) { m_ownTypes = std::move(ownTypes); } void setForeignTypes(QVector foreignTypes) { m_foreignTypes = std::move(foreignTypes); } + void setReferencedTypes(QStringList referencedTypes) { m_referencedTypes = std::move(referencedTypes); } void setModule(QString module) { m_module = std::move(module); } void setVersion(QTypeRevision version) { m_version = version; } @@ -61,6 +62,7 @@ private: QQmlJSStreamWriter m_qml; QVector m_ownTypes; QVector m_foreignTypes; + QStringList m_referencedTypes; QString m_module; QTypeRevision m_version = QTypeRevision::zero(); }; diff --git a/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.cpp b/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.cpp index ae160e0d33..7b82be20f7 100644 --- a/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.cpp +++ b/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.cpp @@ -82,6 +82,7 @@ void tst_qmltyperegistrar::superAndForeignTypes() QVERIFY(qmltypesData.contains("Property { name: \"height\"; type: \"int\" }")); QVERIFY(qmltypesData.contains("Property { name: \"width\"; type: \"int\" }")); QVERIFY(qmltypesData.contains("Method { name: \"sizeToString\"; type: \"QString\" }")); + QVERIFY(qmltypesData.contains("extension: \"SizeValueType\"")); } void tst_qmltyperegistrar::accessSemantics() diff --git a/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.h b/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.h index 211119a654..509816f62c 100644 --- a/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.h +++ b/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.h @@ -86,7 +86,7 @@ private: class SizeEnums { Q_GADGET - QML_NAMED_ELEMENT(SizeEnums) + QML_NAMED_ELEMENT(sizeEnums) QML_UNCREATABLE("Element is not creatable.") public: @@ -99,8 +99,9 @@ class SizeValueType : public SizeEnums QSize v; Q_GADGET Q_PROPERTY(int width READ width WRITE setWidth FINAL) - QML_NAMED_ELEMENT(MySize) + QML_NAMED_ELEMENT(mySize) QML_FOREIGN(SizeGadget) + QML_EXTENDED(SizeValueType) public: Q_INVOKABLE QString sizeToString() const -- cgit v1.2.3