aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2024-09-11 10:37:59 +0200
committerUlf Hermann <ulf.hermann@qt.io>2024-09-24 10:40:52 +0200
commit4278f024612cc54402192ba332f4c97b2a8a9195 (patch)
treecd5371ef4ee43da34bc0ca48dbccfcdee427bc2a
parent322e0ad320f69ed0f4168958dbb85de946ae2ab4 (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>
-rw-r--r--src/imports/tooling/Component.qml1
-rw-r--r--src/qmlcompiler/qqmljsscope.cpp16
-rw-r--r--src/qmlcompiler/qqmljsscope_p.h6
-rw-r--r--src/qmlcompiler/qqmljstypedescriptionreader.cpp4
-rw-r--r--src/qmlcompiler/qqmljstyperesolver.cpp3
-rw-r--r--src/qmltyperegistrar/qqmltyperegistrarconstants_p.h1
-rw-r--r--src/qmltyperegistrar/qqmltypesclassdescription.cpp24
-rw-r--r--src/qmltyperegistrar/qqmltypesclassdescription_p.h4
-rw-r--r--src/qmltyperegistrar/qqmltypescreator.cpp26
-rw-r--r--src/qmltyperegistrar/qqmltypescreator_p.h5
-rw-r--r--tests/auto/qml/qmllint/data/Enumerei/Main.qml22
-rw-r--r--tests/auto/qml/qmllint/data/Enumerei/plugins.qmltypes44
-rw-r--r--tests/auto/qml/qmllint/data/Enumerei/qmldir3
-rw-r--r--tests/auto/qml/qmllint/data/enumValid.qml11
-rw-r--r--tests/auto/qml/qmllint/tst_qmllint.cpp1
-rw-r--r--tests/auto/qml/qmltyperegistrar/CMakeLists.txt1
-rw-r--r--tests/auto/qml/qmltyperegistrar/brokenEnums.json57
-rw-r--r--tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.cpp54
-rw-r--r--tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.h11
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;
};