aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFabian Kosmale <fabian.kosmale@qt.io>2020-04-24 15:55:23 +0200
committerFabian Kosmale <fabian.kosmale@qt.io>2020-06-22 09:14:36 +0200
commit121b8a6ae42d9423250ab1121c15c49ab064307a (patch)
treeb092dd6514e88ac4d5aff5eed1399142a57384db
parent8a3f8595569a920cf2fa811704dec97ae31be15d (diff)
qqmltypecompiler: Be more careful when resolving enums
Task-number: QTBUG-83703 Pick-to: 5.15 Change-Id: I60c0811e47e0cd3b63b3ddfebb9bb6e9ab7f4f40 Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
-rw-r--r--src/qml/qml/qqmltypecompiler.cpp18
-rw-r--r--tests/auto/qml/qqmllanguage/data/enumScopeLeak.qml6
-rw-r--r--tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp57
3 files changed, 77 insertions, 4 deletions
diff --git a/src/qml/qml/qqmltypecompiler.cpp b/src/qml/qml/qqmltypecompiler.cpp
index a9f5cdbf8d..a49722f57e 100644
--- a/src/qml/qml/qqmltypecompiler.cpp
+++ b/src/qml/qml/qqmltypecompiler.cpp
@@ -616,10 +616,20 @@ bool QQmlEnumTypeResolver::tryQualifiedEnumAssignment(const QmlIR::Object *obj,
bool ok = false;
auto *tr = resolvedType(obj->inheritedTypeNameIndex);
- if (type.isValid() && tr && tr->type() == type) {
- // When these two match, we can short cut the search
- QMetaProperty mprop = propertyCache->firstCppMetaObject()->property(prop->coreIndex());
- QMetaEnum menum = mprop.enumerator();
+
+ // When these two match, we can short cut the search, unless...
+ bool useFastPath = type.isValid() && tr && tr->type() == type;
+ QMetaProperty mprop;
+ QMetaEnum menum;
+ if (useFastPath) {
+ mprop = propertyCache->firstCppMetaObject()->property(prop->coreIndex());
+ menum = mprop.enumerator();
+ // ...the enumerator merely comes from a related metaobject, but the enum scope does not match
+ // the typename we resolved
+ if (!menum.isScoped() && scopedEnumName.isEmpty() && typeName != QString::fromUtf8(menum.scope()))
+ useFastPath = false;;
+ }
+ if (useFastPath) {
QByteArray enumName = enumValue.toUtf8();
if (menum.isScoped() && !scopedEnumName.isEmpty() && enumName != scopedEnumName.toUtf8())
return true;
diff --git a/tests/auto/qml/qqmllanguage/data/enumScopeLeak.qml b/tests/auto/qml/qqmllanguage/data/enumScopeLeak.qml
new file mode 100644
index 0000000000..b4bdc54f86
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/enumScopeLeak.qml
@@ -0,0 +1,6 @@
+import QtQml 2.0
+import test 1.0
+
+ObjectC {
+ testEnum: ObjectC.TestValue1
+}
diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
index 77e545722a..411ff7df56 100644
--- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
+++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
@@ -228,6 +228,7 @@ private slots:
void scopedEnum();
void scopedEnumsWithNameClash();
void scopedEnumsWithResolvedNameClash();
+ void enumNoScopeLeak();
void qmlEnums();
void literals_data();
void literals();
@@ -4155,6 +4156,62 @@ void tst_qqmllanguage::scopedEnumsWithResolvedNameClash()
QVERIFY(obj->property("success").toBool());
}
+class ObjectA : public QObject
+{
+ Q_OBJECT
+
+public:
+
+ enum TestEnum {
+ Default = 42,
+ TestValue1,
+ TestValue2
+ };
+ Q_ENUM(TestEnum)
+
+ ObjectA() = default;
+};
+
+class ObjectB : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(ObjectA::TestEnum testEnum READ testEnum WRITE setTestEnum NOTIFY testEnumChanged)
+
+public:
+ ObjectB() = default;
+ ObjectA::TestEnum testEnum() const {return m_testEnum;}
+
+public slots:
+ void setTestEnum(ObjectA::TestEnum testEnum) {auto old = m_testEnum; m_testEnum = testEnum; if (old != m_testEnum) testEnumChanged(m_testEnum);}
+signals:
+ void testEnumChanged(ObjectA::TestEnum testEnum);
+private:
+ ObjectA::TestEnum m_testEnum = ObjectA::Default;
+};
+
+class ObjectC : public ObjectB
+{
+ Q_OBJECT
+
+public:
+ ObjectC() = default;
+};
+
+void tst_qqmllanguage::enumNoScopeLeak()
+{
+ qmlRegisterType<ObjectA>("test", 1, 0, "ObjectA");
+ qmlRegisterType<ObjectB>("test", 1, 0, "ObjectB");
+ qmlRegisterType<ObjectC>("test", 1, 0, "ObjectC");
+ QQmlEngine engine;
+ auto url = testFileUrl("enumScopeLeak.qml");
+ QQmlComponent component(&engine, url);
+ const auto msg = url.toString() + ":5:5: Unable to assign [undefined] to ObjectA::TestEnum";
+ QTest::ignoreMessage(QtMsgType::QtWarningMsg, msg.toUtf8().constData());
+ QScopedPointer<QObject> root(component.create());
+ QVERIFY(root);
+ QCOMPARE(root->property("testEnum").toInt(), ObjectA::Default);
+}
+
void tst_qqmllanguage::qmlEnums()
{
QQmlEngine engine;