aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2022-11-30 10:48:21 +0100
committerUlf Hermann <ulf.hermann@qt.io>2022-12-02 13:35:42 +0100
commit8bc748e7e52d19a078b0281c5b8265a42015ffdb (patch)
treea823402ed7c48272ae5310387f0cd708048d3b30
parentb7bc1874a5cf1738ce7885b8bef0e16d0f83f56f (diff)
QmlCompiler: Fix various kinds of enum lookup
* If we got an object type exposed as namespace, we still need to add the "*" to get its augmentedInternalName(). Otherwise we cannot get its metaobject, needed to look up enums. * Enums cannot be shadowed. The shadow check will produce garbage if we try to check because an enum lookup also does not use the accumulator, which then contains some artifact from a previous operation. * If we find a property lookup on a plain QMetaObject* we have to immediately return in order to not confuse it with attached properties. Pick-to: 6.4 6.2 Fixes: QTBUG-109048 Change-Id: If9e3b4806e4d773de9cf48f1b3750b684a8c8f69 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
-rw-r--r--src/qmlcompiler/qqmljsscope_p.h28
-rw-r--r--src/qmlcompiler/qqmljsshadowcheck.cpp6
-rw-r--r--src/qmlcompiler/qqmljstyperesolver.cpp4
-rw-r--r--tests/auto/qml/qmlcppcodegen/data/CMakeLists.txt2
-rw-r--r--tests/auto/qml/qmlcppcodegen/data/enumProblems.qml14
-rw-r--r--tests/auto/qml/qmlcppcodegen/data/enumproblems.h53
-rw-r--r--tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp21
7 files changed, 124 insertions, 4 deletions
diff --git a/src/qmlcompiler/qqmljsscope_p.h b/src/qmlcompiler/qqmljsscope_p.h
index 70b51fec5f..9586d1c333 100644
--- a/src/qmlcompiler/qqmljsscope_p.h
+++ b/src/qmlcompiler/qqmljsscope_p.h
@@ -352,10 +352,30 @@ public:
{
using namespace Qt::StringLiterals;
- QString suffix;
- if (m_semantics == AccessSemantics::Reference)
- suffix = u" *"_s;
- return m_internalName + suffix;
+ switch (m_semantics) {
+ case AccessSemantics::Reference:
+ return m_internalName + " *"_L1;
+ case AccessSemantics::Value:
+ case AccessSemantics::Sequence:
+ break;
+ case AccessSemantics::None:
+ // If we got a namespace, it might still be a regular type, exposed as namespace.
+ // We may need to travel the inheritance chain all the way up to QObject to
+ // figure this out, since all other types may be exposed the same way.
+ for (QQmlJSScope::ConstPtr base = baseType(); base; base = base->baseType()) {
+ switch (base->accessSemantics()) {
+ case AccessSemantics::Reference:
+ return m_internalName + " *"_L1;
+ case AccessSemantics::Value:
+ case AccessSemantics::Sequence:
+ return m_internalName;
+ case AccessSemantics::None:
+ break;
+ }
+ }
+ break;
+ }
+ return m_internalName;
}
// This returns a more user readable version of internalName / baseTypeName
diff --git a/src/qmlcompiler/qqmljsshadowcheck.cpp b/src/qmlcompiler/qqmljsshadowcheck.cpp
index f8252b1faa..086b778263 100644
--- a/src/qmlcompiler/qqmljsshadowcheck.cpp
+++ b/src/qmlcompiler/qqmljsshadowcheck.cpp
@@ -41,6 +41,9 @@ void QQmlJSShadowCheck::run(
void QQmlJSShadowCheck::generate_LoadProperty(int nameIndex)
{
+ if (!m_state.readsRegister(Accumulator))
+ return; // enum lookup cannot be shadowed.
+
auto accumulatorIn = m_state.registers.find(Accumulator);
if (accumulatorIn != m_state.registers.end())
checkShadowing(accumulatorIn.value(), m_jsUnitGenerator->stringForIndex(nameIndex));
@@ -48,6 +51,9 @@ void QQmlJSShadowCheck::generate_LoadProperty(int nameIndex)
void QQmlJSShadowCheck::generate_GetLookup(int index)
{
+ if (!m_state.readsRegister(Accumulator))
+ return; // enum lookup cannot be shadowed.
+
auto accumulatorIn = m_state.registers.find(Accumulator);
if (accumulatorIn != m_state.registers.end())
checkShadowing(accumulatorIn.value(), m_jsUnitGenerator->lookupName(index));
diff --git a/src/qmlcompiler/qqmljstyperesolver.cpp b/src/qmlcompiler/qqmljstyperesolver.cpp
index 948f24db59..6999a1e2a3 100644
--- a/src/qmlcompiler/qqmljstyperesolver.cpp
+++ b/src/qmlcompiler/qqmljstyperesolver.cpp
@@ -996,6 +996,10 @@ QQmlJSRegisterContent QQmlJSTypeResolver::memberType(const QQmlJSScope::ConstPtr
{
QQmlJSRegisterContent result;
+ // If we got a plain type reference we have to check the enums of the _scope_.
+ if (equals(type, metaObjectType()))
+ return {};
+
if (equals(type, jsValueType())) {
QQmlJSMetaProperty prop;
prop.setPropertyName(name);
diff --git a/tests/auto/qml/qmlcppcodegen/data/CMakeLists.txt b/tests/auto/qml/qmlcppcodegen/data/CMakeLists.txt
index 372f38cffe..f97ae2c781 100644
--- a/tests/auto/qml/qmlcppcodegen/data/CMakeLists.txt
+++ b/tests/auto/qml/qmlcppcodegen/data/CMakeLists.txt
@@ -6,6 +6,7 @@ set(cpp_sources
birthdayparty.cpp birthdayparty.h
cppbaseclass.h
dynamicmeta.h
+ enumproblems.h
gadgetwithenum.h
invisible.h
multiforeign.h
@@ -76,6 +77,7 @@ set(qml_files
dynamicscene.qml
enumInvalid.qml
enumLookup.qml
+ enumProblems.qml
enumScope.qml
enumsInOtherObject.qml
enumsUser.qml
diff --git a/tests/auto/qml/qmlcppcodegen/data/enumProblems.qml b/tests/auto/qml/qmlcppcodegen/data/enumProblems.qml
new file mode 100644
index 0000000000..f9a4eb144b
--- /dev/null
+++ b/tests/auto/qml/qmlcppcodegen/data/enumProblems.qml
@@ -0,0 +1,14 @@
+pragma Strict
+import TestTypes
+import QtQml
+
+QtObject {
+ id: root
+
+ readonly property FooFactory f: FooFactory {}
+
+ property QtObject o: QtObject {
+ readonly property FooThing fighter: root.f.get(Foo.Fighter)
+ readonly property FooThing bar: root.f.get(Foo.Component)
+ }
+}
diff --git a/tests/auto/qml/qmlcppcodegen/data/enumproblems.h b/tests/auto/qml/qmlcppcodegen/data/enumproblems.h
new file mode 100644
index 0000000000..08a00acf7e
--- /dev/null
+++ b/tests/auto/qml/qmlcppcodegen/data/enumproblems.h
@@ -0,0 +1,53 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef ENUMPROBLEMS_H
+#define ENUMPROBLEMS_H
+
+#include <QObject>
+#include <QtQml/qqml.h>
+#include <QtQml/qqmlregistration.h>
+
+class Foo : public QObject {
+ Q_OBJECT
+
+public:
+ enum Type {
+ Unknown,
+ Fighter,
+ Component
+ };
+ Q_ENUM(Type)
+
+ explicit Foo(Foo::Type type, QObject *parent = nullptr) : QObject(parent), m_type(type) {}
+
+ Type type() const { return m_type; }
+
+private:
+ Type m_type = Type::Unknown;
+};
+
+namespace FooWrapper {
+ Q_NAMESPACE
+ QML_FOREIGN_NAMESPACE(Foo)
+ QML_NAMED_ELEMENT(Foo)
+};
+
+
+class FooThingWrapper {
+ Q_GADGET
+ QML_FOREIGN(Foo)
+ QML_NAMED_ELEMENT(FooThing)
+ QML_UNCREATABLE("nope")
+};
+
+
+class FooFactory : public QObject {
+ Q_OBJECT
+ QML_ELEMENT
+
+public:
+ Q_INVOKABLE Foo* get(Foo::Type type) const { return new Foo(type); }
+};
+
+#endif // ENUMPROBLEMS_H
diff --git a/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp b/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp
index d2868e023a..3f76090e6f 100644
--- a/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp
+++ b/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp
@@ -2,6 +2,7 @@
#include <data/birthdayparty.h>
#include <data/cppbaseclass.h>
+#include <data/enumproblems.h>
#include <data/objectwithmethod.h>
#include <QtQml/private/qqmlengine_p.h>
@@ -149,6 +150,7 @@ private slots:
void consoleObject();
void multiForeign();
void namespaceWithEnum();
+ void enumProblems();
};
void tst_QmlCppCodegen::initTestCase()
@@ -2881,6 +2883,25 @@ void tst_QmlCppCodegen::namespaceWithEnum()
QCOMPARE(o->property("i").toInt(), 2);
}
+void tst_QmlCppCodegen::enumProblems()
+{
+ QQmlEngine engine;
+ QQmlComponent c(&engine, QUrl(u"qrc:/qt/qml/TestTypes/enumProblems.qml"_s));
+ QVERIFY2(c.isReady(), qPrintable(c.errorString()));
+ QScopedPointer<QObject> outer(c.create());
+ QVERIFY(!outer.isNull());
+ QObject *inner = outer->property("o").value<QObject *>();
+ QVERIFY(inner);
+
+ Foo *bar = inner->property("bar").value<Foo *>();
+ QVERIFY(bar);
+ QCOMPARE(bar->type(), Foo::Component);
+
+ Foo *fighter = inner->property("fighter").value<Foo *>();
+ QVERIFY(fighter);
+ QCOMPARE(fighter->type(), Foo::Fighter);
+}
+
QTEST_MAIN(tst_QmlCppCodegen)
#include "tst_qmlcppcodegen.moc"