diff --git a/src/imports/tooling/Component.qml b/src/imports/tooling/Component.qml index 773fcfecda..3f2435cee7 100644 --- a/src/imports/tooling/Component.qml +++ b/src/imports/tooling/Component.qml @@ -18,7 +18,8 @@ QtObject { property string valueType property string extension property bool isSingleton: false - property bool isCreatable: name.length > 0 + property bool isCreatable: accessSemantics === "reference" && name.length > 0 + property bool isStructured: false property bool isComposite: false property bool hasCustomParser: false property bool extensionIsNamespace: false diff --git a/src/qmlcompiler/qqmljsscope.cpp b/src/qmlcompiler/qqmljsscope.cpp index 02819913ac..9e70f1fd38 100644 --- a/src/qmlcompiler/qqmljsscope.cpp +++ b/src/qmlcompiler/qqmljsscope.cpp @@ -1286,6 +1286,15 @@ bool QQmlJSScope::isCreatable() const return false; } +bool QQmlJSScope::isStructured() const +{ + for (const QQmlJSScope *scope = this; scope; scope = scope->baseType().get()) { + if (!scope->isComposite()) + return scope->hasStructuredFlag(); + } + return false; +} + QQmlSA::Element QQmlJSScope::createQQmlSAElement(const ConstPtr &ptr) { QQmlSA::Element element; diff --git a/src/qmlcompiler/qqmljsscope_p.h b/src/qmlcompiler/qqmljsscope_p.h index 053ba4127f..cc0d554409 100644 --- a/src/qmlcompiler/qqmljsscope_p.h +++ b/src/qmlcompiler/qqmljsscope_p.h @@ -131,6 +131,7 @@ public: HasBaseTypeError = 0x100, HasExtensionNamespace = 0x200, IsListProperty = 0x400, + Structured = 0x800, }; Q_DECLARE_FLAGS(Flags, Flag) Q_FLAGS(Flags); @@ -531,8 +532,13 @@ QT_WARNING_POP } bool isSingleton() const { return m_flags & Singleton; } + bool isCreatable() const; bool hasCreatableFlag() const { return m_flags & Creatable; } + + bool isStructured() const; + bool hasStructuredFlag() const { return m_flags & Structured; } + /*! * \internal * @@ -547,6 +553,7 @@ QT_WARNING_POP bool extensionIsNamespace() const { return m_flags & HasExtensionNamespace; } void setIsSingleton(bool v) { m_flags.setFlag(Singleton, v); } void setCreatableFlag(bool v) { m_flags.setFlag(Creatable, v); } + void setStructuredFlag(bool v) { m_flags.setFlag(Structured, v); } void setIsComposite(bool v) { m_flags.setFlag(Composite, v); } void setIsScript(bool v) { m_flags.setFlag(Script, v); } void setHasCustomParser(bool v) diff --git a/src/qmlcompiler/qqmljstypedescriptionreader.cpp b/src/qmlcompiler/qqmljstypedescriptionreader.cpp index 7a14970714..7c9de07779 100644 --- a/src/qmlcompiler/qqmljstypedescriptionreader.cpp +++ b/src/qmlcompiler/qqmljstypedescriptionreader.cpp @@ -213,6 +213,8 @@ void QQmlJSTypeDescriptionReader::readComponent(UiObjectDefinition *ast) scope->setIsSingleton(readBoolBinding(script)); } else if (name == QLatin1String("isCreatable")) { scope->setCreatableFlag(readBoolBinding(script)); + } else if (name == QLatin1String("isStructured")) { + scope->setStructuredFlag(readBoolBinding(script)); } else if (name == QLatin1String("isComposite")) { scope->setIsComposite(readBoolBinding(script)); } else if (name == QLatin1String("hasCustomParser")) { @@ -243,8 +245,9 @@ void QQmlJSTypeDescriptionReader::readComponent(UiObjectDefinition *ast) addWarning(script->firstSourceLocation(), tr("Expected only name, prototype, defaultProperty, attachedType, " "valueType, exports, interfaces, isSingleton, isCreatable, " - "isComposite, hasCustomParser, exportMetaObjectRevisions, " - "deferredNames, and immediateNames in script bindings, not \"%1\".") + "isStructured, isComposite, hasCustomParser, " + "exportMetaObjectRevisions, deferredNames, and immediateNames " + "in script bindings, not \"%1\".") .arg(name)); } } else { diff --git a/src/qmltyperegistrar/qqmltyperegistrarconstants_p.h b/src/qmltyperegistrar/qqmltyperegistrarconstants_p.h index 4cb2195534..8170e30e53 100644 --- a/src/qmltyperegistrar/qqmltyperegistrarconstants_p.h +++ b/src/qmltyperegistrar/qqmltyperegistrarconstants_p.h @@ -88,6 +88,7 @@ static constexpr QLatin1StringView S_CLASSES { "classes" }; static constexpr QLatin1StringView S_CLASS_INFOS { "classInfos" }; static constexpr QLatin1StringView S_CLASS_NAME { "className" }; static constexpr QLatin1StringView S_CONSTANT { "constant" }; +static constexpr QLatin1StringView S_CONSTRUCT { "construct" }; static constexpr QLatin1StringView S_CONSTRUCTORS { "constructors" }; static constexpr QLatin1StringView S_DEFAULT_PROPERTY { "DefaultProperty" }; static constexpr QLatin1StringView S_DEFERRED_PROPERTY_NAMES { "DeferredPropertyNames" }; @@ -123,6 +124,7 @@ static constexpr QLatin1StringView S_RETURN_TYPE { "returnType" static constexpr QLatin1StringView S_REVISION { "revision" }; static constexpr QLatin1StringView S_SIGNALS { "signals" }; static constexpr QLatin1StringView S_SLOTS { "slots" }; +static constexpr QLatin1StringView S_STRUCTURED { "structured" }; static constexpr QLatin1StringView S_SUPER_CLASSES { "superClasses" }; static constexpr QLatin1StringView S_TRUE { "true" }; static constexpr QLatin1StringView S_TYPE { "type" }; @@ -135,6 +137,7 @@ namespace Qml { static constexpr QLatin1StringView S_ADDED_IN_VERSION { "QML.AddedInVersion" }; static constexpr QLatin1StringView S_ATTACHED { "QML.Attached" }; static constexpr QLatin1StringView S_CREATABLE { "QML.Creatable" }; +static constexpr QLatin1StringView S_CREATION_METHOD { "QML.CreationMethod" }; static constexpr QLatin1StringView S_ELEMENT { "QML.Element" }; static constexpr QLatin1StringView S_EXTENDED { "QML.Extended" }; static constexpr QLatin1StringView S_EXTENSION_IS_NAMESPACE { "QML.ExtensionIsNamespace" }; diff --git a/src/qmltyperegistrar/qqmltypesclassdescription.cpp b/src/qmltyperegistrar/qqmltypesclassdescription.cpp index 73766c7d50..dbc18f0c81 100644 --- a/src/qmltyperegistrar/qqmltypesclassdescription.cpp +++ b/src/qmltyperegistrar/qqmltypesclassdescription.cpp @@ -116,7 +116,7 @@ void QmlTypesClassDescription::collect( const auto classInfos = classDef->value(S_CLASS_INFOS).toArray(); const QAnyStringView classDefName = toStringView(*classDef, S_CLASS_NAME); QAnyStringView foreignTypeName; - bool explicitCreatable = false; + bool isConstructible = false; for (const QCborValue classInfo : classInfos) { const QCborMap obj = classInfo.toMap(); const QAnyStringView name = toStringView(obj, S_NAME); @@ -151,7 +151,9 @@ void QmlTypesClassDescription::collect( removedInRevision = QTypeRevision::fromEncodedVersion(toInt(value)); } else if (name == S_CREATABLE) { isCreatable = (value != S_FALSE); - explicitCreatable = true; + } else if (name == S_CREATION_METHOD) { + isStructured = (value == S_STRUCTURED); + isConstructible = isStructured || (value == S_CONSTRUCT); } else if (name == S_ATTACHED) { attachedType = value; collectRelated(value, types, foreign, defaultRevision); @@ -270,8 +272,7 @@ void QmlTypesClassDescription::collect( } else if (classDef && classDef->value(S_OBJECT).toBool()) { accessSemantics = DotQmltypes::S_REFERENCE; } else { - if (!explicitCreatable) - isCreatable = false; + isCreatable = isConstructible; if (!classDef) { if (elementName.isEmpty() || elementName.front().isLower()) { diff --git a/src/qmltyperegistrar/qqmltypesclassdescription_p.h b/src/qmltyperegistrar/qqmltypesclassdescription_p.h index 8789ec6f6b..96265821ce 100644 --- a/src/qmltyperegistrar/qqmltypesclassdescription_p.h +++ b/src/qmltyperegistrar/qqmltypesclassdescription_p.h @@ -43,6 +43,7 @@ struct QmlTypesClassDescription QTypeRevision addedInRevision; QTypeRevision removedInRevision; bool isCreatable = true; + bool isStructured = false; bool isSingleton = false; bool hasCustomParser = false; bool omitFromQmlTypes = false; diff --git a/src/qmltyperegistrar/qqmltypescreator.cpp b/src/qmltyperegistrar/qqmltypescreator.cpp index d2e6adf2eb..8dc5dc5ac7 100644 --- a/src/qmltyperegistrar/qqmltypescreator.cpp +++ b/src/qmltyperegistrar/qqmltypescreator.cpp @@ -115,6 +115,9 @@ void QmlTypesCreator::writeClassProperties(const QmlTypesClassDescription &colle if (!collector.isCreatable || collector.isSingleton) m_qml.writeBooleanBinding(S_IS_CREATABLE, false); + if (collector.isStructured) + m_qml.writeScriptBinding(QLatin1String("isStructured"), QLatin1String("true")); + if (collector.isSingleton) m_qml.writeBooleanBinding(S_IS_SINGLETON, true); diff --git a/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.cpp b/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.cpp index c9d41bdb78..13308f4ae0 100644 --- a/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.cpp +++ b/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.cpp @@ -593,6 +593,20 @@ void tst_qmltyperegistrar::constructibleValueType() })")); } +void tst_qmltyperegistrar::structuredValueType() +{ + QVERIFY(qmltypesData.contains( + R"(Component { + file: "tst_qmltyperegistrar.h" + name: "Structured" + accessSemantics: "value" + exports: ["QmlTypeRegistrarTest/structured 1.0"] + isStructured: true + exportMetaObjectRevisions: [256] + Property { name: "i"; type: "int"; index: 0; isFinal: true } + })")); +} + void tst_qmltyperegistrar::anonymousAndUncreatable() { QVERIFY(qmltypesData.contains( diff --git a/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.h b/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.h index 4d69922a86..59893f74c9 100644 --- a/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.h +++ b/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.h @@ -513,6 +513,17 @@ private: int m_i; }; +class Structured +{ + Q_GADGET + QML_VALUE_TYPE(structured) + QML_STRUCTURED_VALUE + Q_PROPERTY(int i MEMBER m_i FINAL) + +private: + int m_i; +}; + class AnonymousAndUncreatable : public QObject { Q_OBJECT @@ -615,6 +626,7 @@ private slots: void clonedSignal(); void baseVersionInQmltypes(); void constructibleValueType(); + void structuredValueType(); void anonymousAndUncreatable(); void omitInvisible(); void typedEnum();