diff options
| author | Ulf Hermann <ulf.hermann@qt.io> | 2024-09-11 10:37:59 +0200 |
|---|---|---|
| committer | Ulf Hermann <ulf.hermann@qt.io> | 2024-09-24 10:40:52 +0200 |
| commit | 4278f024612cc54402192ba332f4c97b2a8a9195 (patch) | |
| tree | cd5371ef4ee43da34bc0ca48dbccfcdee427bc2a | |
| parent | 322e0ad320f69ed0f4168958dbb85de946ae2ab4 (diff) | |
QmlCompiler: Fix enum scoping rules
You can always access a scoped enum in a scoped way in QML, no matter if
the type it belongs to enforces scoped enum access. Read the respective
flag separately and don't mix it in with the scopedness of the actual
enums.
Amends commit 7da544e862a92cc0a9d97cbed68a35c532699116
Pick-to: 6.5 6.2
Fixes: QTBUG-127308
Change-Id: I167602d44c8cea874dc39614fc6726a72e66c007
Reviewed-by: Sami Shalayel <sami.shalayel@qt.io>
(cherry picked from commit 96b29e720c81eef176d49d9fc74f04c87ecd9abd)
(cherry picked from commit 290336814f5e57f3ec5c8e9cfc414fbdae0802c7)
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
19 files changed, 263 insertions, 31 deletions
diff --git a/src/imports/tooling/Component.qml b/src/imports/tooling/Component.qml index 30644e3ac2..41e0a44aee 100644 --- a/src/imports/tooling/Component.qml +++ b/src/imports/tooling/Component.qml @@ -24,6 +24,7 @@ QtObject { property bool hasCustomParser: false property bool extensionIsJavaScript: false property bool extensionIsNamespace: false + property bool enforcesScopedEnums: false property string accessSemantics: "reference" property string defaultProperty property string parentProperty diff --git a/src/qmlcompiler/qqmljsscope.cpp b/src/qmlcompiler/qqmljsscope.cpp index 0935690d46..8ea28672d5 100644 --- a/src/qmlcompiler/qqmljsscope.cpp +++ b/src/qmlcompiler/qqmljsscope.cpp @@ -1247,6 +1247,22 @@ QVector<QQmlJSScope::ConstPtr> QQmlJSScope::childScopes() const } /*! + \internal + + Returns true if this type or any base type of it has the "EnforcesScopedEnums" flag. + The rationale is that you can turn on enforcement of scoped enums, but you cannot turn + it off explicitly. + */ +bool QQmlJSScope::enforcesScopedEnums() const +{ + for (const QQmlJSScope *scope = this; scope; scope = scope->baseType().get()) { + if (scope->hasEnforcesScopedEnumsFlag()) + return true; + } + return false; +} + +/*! \internal Returns true if the current type is creatable by checking all the required base classes. "Uncreatability" is only inherited from base types for composite types (in qml) and not for non-composite types (c++). diff --git a/src/qmlcompiler/qqmljsscope_p.h b/src/qmlcompiler/qqmljsscope_p.h index cf70bc0691..677594c057 100644 --- a/src/qmlcompiler/qqmljsscope_p.h +++ b/src/qmlcompiler/qqmljsscope_p.h @@ -166,6 +166,7 @@ public: IsListProperty = 0x400, Structured = 0x800, ExtensionIsJavaScript = 0x1000, + EnforcesScopedEnums = 0x2000, }; Q_DECLARE_FLAGS(Flags, Flag) Q_FLAGS(Flags); @@ -377,6 +378,10 @@ public: bool isListProperty() const { return m_flags.testFlag(IsListProperty); } void setIsListProperty(bool v) { m_flags.setFlag(IsListProperty, v); } bool isSingleton() const { return m_flags & Singleton; } + + bool enforcesScopedEnums() const; + void setEnforcesScopedEnumsFlag(bool v) { m_flags.setFlag(EnforcesScopedEnums, v); } + bool isCreatable() const; bool isStructured() const; bool isReferenceType() const { return m_semantics == QQmlJSScope::AccessSemantics::Reference; } @@ -483,6 +488,7 @@ private: void addOwnPropertyBindingInQmlIROrder(const QQmlJSMetaPropertyBinding &binding, BindingTargetSpecifier specifier); + bool hasEnforcesScopedEnumsFlag() const { return m_flags & EnforcesScopedEnums; } bool hasCreatableFlag() const { return m_flags & Creatable; } bool hasStructuredFlag() const { return m_flags & Structured; } diff --git a/src/qmlcompiler/qqmljstypedescriptionreader.cpp b/src/qmlcompiler/qqmljstypedescriptionreader.cpp index 34e46d4256..f88c4b988c 100644 --- a/src/qmlcompiler/qqmljstypedescriptionreader.cpp +++ b/src/qmlcompiler/qqmljstypedescriptionreader.cpp @@ -219,6 +219,8 @@ void QQmlJSTypeDescriptionReader::readComponent(UiObjectDefinition *ast) scope->setIsComposite(readBoolBinding(script)); } else if (name == QLatin1String("hasCustomParser")) { scope->setHasCustomParser(readBoolBinding(script)); + } else if (name == QLatin1String("enforcesScopedEnums")) { + scope->setEnforcesScopedEnumsFlag(readBoolBinding(script)); } else if (name == QLatin1String("accessSemantics")) { const QString semantics = readStringBinding(script); if (semantics == QLatin1String("reference")) { @@ -247,7 +249,7 @@ void QQmlJSTypeDescriptionReader::readComponent(UiObjectDefinition *ast) addWarning(script->firstSourceLocation(), tr("Expected only name, prototype, defaultProperty, attachedType, " "valueType, exports, interfaces, isSingleton, isCreatable, " - "isStructured, isComposite, hasCustomParser, " + "isStructured, isComposite, hasCustomParser, enforcesScopedEnums, " "exportMetaObjectRevisions, deferredNames, and immediateNames " "in script bindings, not \"%1\".") .arg(name)); diff --git a/src/qmlcompiler/qqmljstyperesolver.cpp b/src/qmlcompiler/qqmljstyperesolver.cpp index bbdd7a8a1e..2d96cc71e7 100644 --- a/src/qmlcompiler/qqmljstyperesolver.cpp +++ b/src/qmlcompiler/qqmljstyperesolver.cpp @@ -1115,7 +1115,8 @@ bool QQmlJSTypeResolver::checkEnums(const QQmlJSScope::ConstPtr &scope, const QS return true; } - if (!enumeration.isScoped() && enumeration.hasKey(name)) { + if ((!enumeration.isScoped() || enumeration.isQml() || !scope->enforcesScopedEnums()) + && enumeration.hasKey(name)) { *result = QQmlJSRegisterContent::create( storedType(enumeration.type()), enumeration, name, inExtension ? QQmlJSRegisterContent::ExtensionObjectEnum diff --git a/src/qmltyperegistrar/qqmltyperegistrarconstants_p.h b/src/qmltyperegistrar/qqmltyperegistrarconstants_p.h index b43defe598..acd1eb2025 100644 --- a/src/qmltyperegistrar/qqmltyperegistrarconstants_p.h +++ b/src/qmltyperegistrar/qqmltyperegistrarconstants_p.h @@ -31,6 +31,7 @@ static constexpr QLatin1StringView S_BINDABLE { "bindable" } static constexpr QLatin1StringView S_COMPONENT { "Component" }; static constexpr QLatin1StringView S_DEFAULT_PROPERTY { "defaultProperty" }; static constexpr QLatin1StringView S_DEFERRED_NAMES { "deferredNames" }; +static constexpr QLatin1StringView S_ENFORCES_SCOPED_ENUMS { "enforcesScopedEnums" }; static constexpr QLatin1StringView S_ENUM { "Enum" }; static constexpr QLatin1StringView S_EXPORTS { "exports" }; static constexpr QLatin1StringView S_EXPORT_META_OBJECT_REVISIONS { "exportMetaObjectRevisions" }; diff --git a/src/qmltyperegistrar/qqmltypesclassdescription.cpp b/src/qmltyperegistrar/qqmltypesclassdescription.cpp index 3a8fb80cb9..6d32b97fb1 100644 --- a/src/qmltyperegistrar/qqmltypesclassdescription.cpp +++ b/src/qmltyperegistrar/qqmltypesclassdescription.cpp @@ -165,6 +165,17 @@ void QmlTypesClassDescription::collectInterfaces(const QCborMap &classDef) } } +void QmlTypesClassDescription::handleRegisterEnumClassesUnscoped( + const QCborMap &classDef, QAnyStringView value) +{ + if (value == S_FALSE) + enforcesScopedEnums = true; + else if (value == S_TRUE) + warning(classDef) << "Setting RegisterEnumClassesUnscoped to true has no effect."; + else + warning(classDef) << "Unrecognized value for RegisterEnumClassesUnscoped:" << value; +} + void QmlTypesClassDescription::collectLocalAnonymous( const QCborMap &classDef, const QVector<QCborMap> &types, const QVector<QCborMap> &foreign, QTypeRevision defaultRevision) @@ -189,8 +200,8 @@ void QmlTypesClassDescription::collectLocalAnonymous( defaultProp = toStringView(obj, S_VALUE); else if (name == S_PARENT_PROPERTY) parentProp = toStringView(obj, S_VALUE); - else if (name == S_REGISTER_ENUM_CLASSES_UNSCOPED && toStringView(obj, S_VALUE) == S_FALSE) - registerEnumClassesScoped = true; + else if (name == S_REGISTER_ENUM_CLASSES_UNSCOPED) + handleRegisterEnumClassesUnscoped(classDef, toStringView(obj, S_VALUE)); } collectInterfaces(classDef); @@ -229,8 +240,8 @@ void QmlTypesClassDescription::collect( } if (name == S_REGISTER_ENUM_CLASSES_UNSCOPED) { - if (mode != RelatedType && value == S_FALSE) - registerEnumClassesScoped = true; + if (mode != RelatedType) + handleRegisterEnumClassesUnscoped(classDef, value); continue; } @@ -328,7 +339,7 @@ void QmlTypesClassDescription::collect( // Default properties and enum classes are always local. defaultProp = {}; - registerEnumClassesScoped = false; + enforcesScopedEnums = false; // Foreign type can have a default property or an attached type, // or RegisterEnumClassesUnscoped classinfo. @@ -342,8 +353,7 @@ void QmlTypesClassDescription::collect( } else if (parentProp.isEmpty() && foreignName == S_PARENT_PROPERTY) { parentProp = foreignValue; } else if (foreignName == S_REGISTER_ENUM_CLASSES_UNSCOPED) { - if (foreignValue == S_FALSE) - registerEnumClassesScoped = true; + handleRegisterEnumClassesUnscoped(resolved, foreignValue); } else if (foreignName == S_ATTACHED) { if (const FoundType attached = collectRelated( foreignValue, types, foreign, defaultRevision, namespaces)) { diff --git a/src/qmltyperegistrar/qqmltypesclassdescription_p.h b/src/qmltyperegistrar/qqmltypesclassdescription_p.h index 2132c37e0f..2dc94055da 100644 --- a/src/qmltyperegistrar/qqmltypesclassdescription_p.h +++ b/src/qmltyperegistrar/qqmltypesclassdescription_p.h @@ -73,7 +73,7 @@ struct QmlTypesClassDescription bool isRootClass = false; bool extensionIsJavaScript = false; bool extensionIsNamespace = false; - bool registerEnumClassesScoped = false; + bool enforcesScopedEnums = false; QList<QAnyStringView> implementsInterfaces; QList<QAnyStringView> deferredNames; QList<QAnyStringView> immediateNames; @@ -105,6 +105,8 @@ private: const QCborMap &classDef, const QVector<QCborMap> &types, const QVector<QCborMap> &foreign, CollectMode mode, QTypeRevision defaultRevision); void collectInterfaces(const QCborMap &classDef); + + void handleRegisterEnumClassesUnscoped(const QCborMap &classDef, QAnyStringView value); }; QT_END_NAMESPACE diff --git a/src/qmltyperegistrar/qqmltypescreator.cpp b/src/qmltyperegistrar/qqmltypescreator.cpp index afd3cf61bb..11a81e834b 100644 --- a/src/qmltyperegistrar/qqmltypescreator.cpp +++ b/src/qmltyperegistrar/qqmltypescreator.cpp @@ -154,6 +154,9 @@ void QmlTypesCreator::writeClassProperties(const QmlTypesClassDescription &colle if (collector.hasCustomParser) m_qml.writeBooleanBinding(S_HAS_CUSTOM_PARSER, true); + if (collector.enforcesScopedEnums) + m_qml.writeBooleanBinding(S_ENFORCES_SCOPED_ENUMS, true); + m_qml.writeArrayBinding(S_EXPORT_META_OBJECT_REVISIONS, metaObjects); if (!collector.attachedType.isEmpty()) @@ -341,8 +344,7 @@ void QmlTypesCreator::writeMethods(const QCborArray &methods, QLatin1StringView } } -void QmlTypesCreator::writeEnums( - const QCborArray &enums, QmlTypesCreator::EnumClassesMode enumClassesMode) +void QmlTypesCreator::writeEnums(const QCborArray &enums) { for (const QCborValue &item : enums) { const QCborMap obj = item.toMap(); @@ -361,11 +363,9 @@ void QmlTypesCreator::writeEnums( if (isFlag != obj.end() && isFlag->toBool()) m_qml.writeBooleanBinding(S_IS_FLAG, true); - if (enumClassesMode == EnumClassesMode::Scoped) { - const auto isClass = obj.find(MetatypesDotJson::S_IS_CLASS); - if (isClass != obj.end() && isClass->toBool()) - m_qml.writeBooleanBinding(S_IS_SCOPED, true); - } + const auto isClass = obj.find(MetatypesDotJson::S_IS_CLASS); + if (isClass != obj.end() && isClass->toBool()) + m_qml.writeBooleanBinding(S_IS_SCOPED, true); writeType(obj, MetatypesDotJson::S_TYPE); m_qml.writeStringListBinding(S_VALUES, valueList); @@ -480,11 +480,7 @@ void QmlTypesCreator::writeComponents() writeClassProperties(collector); if (const QCborMap &classDef = collector.resolvedClass; !classDef.isEmpty()) { - writeEnums( - members(classDef, MetatypesDotJson::S_ENUMS, m_version), - collector.registerEnumClassesScoped - ? EnumClassesMode::Scoped - : EnumClassesMode::Unscoped); + writeEnums(members(classDef, MetatypesDotJson::S_ENUMS, m_version)); writeProperties(members(classDef, MetatypesDotJson::S_PROPERTIES, m_version)); @@ -516,11 +512,7 @@ void QmlTypesCreator::writeComponents() collector.collectLocalAnonymous(component, m_ownTypes, m_foreignTypes, m_version); writeClassProperties(collector); - writeEnums( - members(component, MetatypesDotJson::S_ENUMS, m_version), - collector.registerEnumClassesScoped - ? EnumClassesMode::Scoped - : EnumClassesMode::Unscoped); + writeEnums(members(component, MetatypesDotJson::S_ENUMS, m_version)); writeProperties(members(component, MetatypesDotJson::S_PROPERTIES, m_version)); diff --git a/src/qmltyperegistrar/qqmltypescreator_p.h b/src/qmltyperegistrar/qqmltypescreator_p.h index a5636d6910..11cfe83257 100644 --- a/src/qmltyperegistrar/qqmltypescreator_p.h +++ b/src/qmltyperegistrar/qqmltypescreator_p.h @@ -41,10 +41,7 @@ private: void writeType(const QCborMap &property, QLatin1StringView key); void writeProperties(const QCborArray &properties); void writeMethods(const QCborArray &methods, QLatin1StringView type); - - enum class EnumClassesMode { Scoped, Unscoped }; - void writeEnums(const QCborArray &enums, EnumClassesMode enumClassesMode); - + void writeEnums(const QCborArray &enums); void writeComponents(); void writeRootMethods(const QCborMap &classDef); diff --git a/tests/auto/qml/qmllint/data/Enumerei/Main.qml b/tests/auto/qml/qmllint/data/Enumerei/Main.qml new file mode 100644 index 0000000000..61c27e4670 --- /dev/null +++ b/tests/auto/qml/qmllint/data/Enumerei/Main.qml @@ -0,0 +1,22 @@ +import QtQml 2.15 +import qtbug127308 + +QtObject { + Component.onCompleted: { + console.log("Unscoped access:") + try { console.log("EnumTester::Scoped", EnumTester.S1, EnumTester.S2 ); } catch (a) { console.log("EnumTester::Scoped", a) } + try { console.log("EnumTester::Unscoped", EnumTester.U1, EnumTester.U2 ); } catch (b) { console.log("EnumTester::Unscoped", b) } + try { console.log("EnumTesterScoped::Scoped", EnumTesterScoped.S1, EnumTesterScoped.S2 ); } catch (c) { console.log("EnumTesterScoped::Scoped", c) } + try { console.log("EnumTesterScoped::Unscoped", EnumTesterScoped.U1, EnumTesterScoped.U2 ); } catch (d) { console.log("EnumTesterScoped::Unscoped", d) } + try { console.log("EnumTesterUnscoped::Scoped", EnumTesterUnscoped.S1, EnumTesterUnscoped.S2 ); } catch (e) { console.log("EnumTesterUnscoped::Scoped", e) } + try { console.log("EnumTesterUnscoped::Unscoped", EnumTesterUnscoped.U1, EnumTesterUnscoped.U2 ); } catch (f) { console.log("EnumTesterUnscoped::Unscoped", f) } + console.log() + console.log("Scoped access:") + try { console.log("EnumTester::Scoped", EnumTester.Scoped.S1, EnumTester.Scoped.S2 ); } catch (g) { console.log("EnumTester::Scoped", g) } + try { console.log("EnumTester::Unscoped", EnumTester.Unscoped.U1, EnumTester.Unscoped.U2 ); } catch (h) { console.log("EnumTester::Unscoped", h) } + try { console.log("EnumTesterScoped::Scoped", EnumTesterScoped.Scoped.S1, EnumTesterScoped.Scoped.S2 ); } catch (i) { console.log("EnumTesterScoped::Scoped", i) } + try { console.log("EnumTesterScoped::Unscoped", EnumTesterScoped.Unscoped.U1, EnumTesterScoped.Unscoped.U2 ); } catch (j) { console.log("EnumTesterScoped::Unscoped", j) } + try { console.log("EnumTesterUnscoped::Scoped", EnumTesterUnscoped.Scoped.S1, EnumTesterUnscoped.Scoped.S2 ); } catch (k) { console.log("EnumTesterUnscoped::Scoped", k) } + try { console.log("EnumTesterUnscoped::Unscoped", EnumTesterUnscoped.Unscoped.U1, EnumTesterUnscoped.Unscoped.U2 ); } catch (l) { console.log("EnumTesterUnscoped::Unscoped", l) } + } +} diff --git a/tests/auto/qml/qmllint/data/Enumerei/plugins.qmltypes b/tests/auto/qml/qmllint/data/Enumerei/plugins.qmltypes new file mode 100644 index 0000000000..212215362a --- /dev/null +++ b/tests/auto/qml/qmllint/data/Enumerei/plugins.qmltypes @@ -0,0 +1,44 @@ +import QtQuick.tooling 1.2 + +// This file describes the plugin-supplied types contained in the library. +// It is used for QML tooling purposes only. +// +// This file was auto-generated by qmltyperegistrar. + +Module { + Component { + file: "main.h" + name: "EnumTester" + accessSemantics: "reference" + prototype: "QObject" + exports: ["Enumerei/EnumTester 1.0"] + exportMetaObjectRevisions: [256] + Enum { + name: "Unscoped" + values: ["U1", "U2"] + } + Enum { + name: "Scoped" + isScoped: true + values: ["S1", "S2"] + } + } + Component { + file: "main.h" + name: "EnumTesterScoped" + accessSemantics: "reference" + prototype: "QObject" + exports: ["Enumerei/EnumTesterScoped 1.0"] + enforcesScopedEnums: true + exportMetaObjectRevisions: [256] + Enum { + name: "Unscoped" + values: ["U1", "U2"] + } + Enum { + name: "Scoped" + isScoped: true + values: ["S1", "S2"] + } + } +} diff --git a/tests/auto/qml/qmllint/data/Enumerei/qmldir b/tests/auto/qml/qmllint/data/Enumerei/qmldir new file mode 100644 index 0000000000..aa031dd7e8 --- /dev/null +++ b/tests/auto/qml/qmllint/data/Enumerei/qmldir @@ -0,0 +1,3 @@ +module Enumerei +typeinfo plugins.qmltypes + diff --git a/tests/auto/qml/qmllint/data/enumValid.qml b/tests/auto/qml/qmllint/data/enumValid.qml new file mode 100644 index 0000000000..32971df070 --- /dev/null +++ b/tests/auto/qml/qmllint/data/enumValid.qml @@ -0,0 +1,11 @@ +import QtQml +import Enumerei + +QtObject { + property int a: EnumTester.S2 + property int b: EnumTester.U2 + property int c: EnumTesterScoped.U2 + + property int d: EnumTester.Scoped.S2 + property int e: EnumTesterScoped.Scoped.S2 +} diff --git a/tests/auto/qml/qmllint/tst_qmllint.cpp b/tests/auto/qml/qmllint/tst_qmllint.cpp index bd175dc6ca..67f5f464d5 100644 --- a/tests/auto/qml/qmllint/tst_qmllint.cpp +++ b/tests/auto/qml/qmllint/tst_qmllint.cpp @@ -1363,6 +1363,7 @@ void TestQmllint::cleanQmlCode_data() QTest::newRow("QEventPoint") << QStringLiteral("qEventPoint.qml"); QTest::newRow("locale") << QStringLiteral("locale.qml"); QTest::newRow("constInvokable") << QStringLiteral("useConstInvokable.qml"); + QTest::newRow("scopedAndUnscopedEnums") << QStringLiteral("enumValid.qml"); } void TestQmllint::cleanQmlCode() diff --git a/tests/auto/qml/qmltyperegistrar/CMakeLists.txt b/tests/auto/qml/qmltyperegistrar/CMakeLists.txt index b8c57b499d..ef533eb5d6 100644 --- a/tests/auto/qml/qmltyperegistrar/CMakeLists.txt +++ b/tests/auto/qml/qmltyperegistrar/CMakeLists.txt @@ -97,6 +97,7 @@ qt_internal_add_resource(tst_qmltyperegistrar "resources" PREFIX "/" FILES + brokenEnums.json duplicatedExports.json missingTypes.json ) diff --git a/tests/auto/qml/qmltyperegistrar/brokenEnums.json b/tests/auto/qml/qmltyperegistrar/brokenEnums.json new file mode 100644 index 0000000000..e54a58f9b7 --- /dev/null +++ b/tests/auto/qml/qmltyperegistrar/brokenEnums.json @@ -0,0 +1,57 @@ +[ + { + "classes": [ + { + "className": "QObject", + "object": true, + "qualifiedClassName": "QObject" + }, + { + "classInfos": [ + { + "name": "QML.Element", + "value": "auto" + }, + { + "name": "RegisterEnumClassesUnscoped", + "value": "true" + } + ], + "className": "EnumsExplicitlyUnscoped", + "lineNumber": 878, + "object": true, + "qualifiedClassName": "EnumsExplicitlyUnscoped", + "superClasses": [ + { + "access": "public", + "name": "QObject" + } + ] + }, + { + "classInfos": [ + { + "name": "QML.Element", + "value": "auto" + }, + { + "name": "RegisterEnumClassesUnscoped", + "value": "horst" + } + ], + "className": "EnumScopingConfused", + "lineNumber": 885, + "object": true, + "qualifiedClassName": "EnumScopingConfused", + "superClasses": [ + { + "access": "public", + "name": "QObject" + } + ] + } + ], + "inputFile": "tst_qmltyperegistrar.h", + "outputRevision": 68 + } +] diff --git a/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.cpp b/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.cpp index 33108fec88..1ac3fadf55 100644 --- a/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.cpp +++ b/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.cpp @@ -472,6 +472,47 @@ void tst_qmltyperegistrar::consistencyWarnings() r.generatePluginTypes(pluginTypes.fileName()); } +void tst_qmltyperegistrar::enumWarnings() +{ + QmlTypeRegistrar r; + r.setModuleVersions(QTypeRevision::fromVersion(1, 1), {}, false); + QString moduleName = "tstmodule"; + QString targetNamespace = "tstnamespace"; + r.setModuleNameAndNamespace(moduleName, targetNamespace); + + const auto expectWarning = [](const char *message) { + QTest::ignoreMessage(QtWarningMsg, message); + }; + + expectWarning("Warning: tst_qmltyperegistrar.h:: " + "Unrecognized value for RegisterEnumClassesUnscoped: horst"); + expectWarning("Warning: tst_qmltyperegistrar.h:: " + "Setting RegisterEnumClassesUnscoped to true has no effect."); + + QTest::failOnWarning(QRegularExpression(".*")); + + + MetaTypesJsonProcessor processor(true); + + QVERIFY(processor.processTypes({ ":/brokenEnums.json" })); + processor.postProcessTypes(); + processor.postProcessForeignTypes(); + + QVector<QCborMap> types = processor.types(); + QVector<QCborMap> typesforeign = processor.foreignTypes(); + r.setTypes(types, typesforeign); + + QString outputData; + QTextStream output(&outputData, QIODeviceBase::ReadWrite); + + r.write(output, "tst_qmltyperegistrar_qmltyperegistrations.cpp"); + + QTemporaryFile pluginTypes; + QVERIFY(pluginTypes.open()); + + r.generatePluginTypes(pluginTypes.fileName()); +} + void tst_qmltyperegistrar::clonedSignal() { QVERIFY(qmltypesData.contains(R"(Signal { @@ -989,4 +1030,17 @@ void tst_qmltyperegistrar::constReturnType() })")); } +void tst_qmltyperegistrar::enumsExplicitlyScoped() +{ + QVERIFY(qmltypesData.contains(R"(Component { + file: "tst_qmltyperegistrar.h" + name: "EnumsExplicitlyScoped" + accessSemantics: "reference" + prototype: "QObject" + exports: ["QmlTypeRegistrarTest/EnumsExplicitlyScoped 1.0"] + enforcesScopedEnums: true + exportMetaObjectRevisions: [256] + })")); +} + QTEST_MAIN(tst_qmltyperegistrar) diff --git a/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.h b/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.h index fea73b7695..350f7f5847 100644 --- a/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.h +++ b/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.h @@ -785,6 +785,13 @@ public: Q_INVOKABLE const QObject *getObject() { return nullptr; } }; +class EnumsExplicitlyScoped : public QObject +{ + Q_OBJECT + QML_ELEMENT + Q_CLASSINFO("RegisterEnumClassesUnscoped", "false") +}; + class tst_qmltyperegistrar : public QObject { Q_OBJECT @@ -852,11 +859,15 @@ private slots: void javaScriptExtension(); void consistencyWarnings(); + void enumWarnings(); + void relatedAddedInVersion(); void longNumberTypes(); void enumList(); void constReturnType(); + void enumsExplicitlyScoped(); + private: QByteArray qmltypesData; }; |
