diff options
author | Ulf Hermann <ulf.hermann@qt.io> | 2022-11-30 10:48:21 +0100 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@qt.io> | 2022-12-02 13:35:42 +0100 |
commit | 8bc748e7e52d19a078b0281c5b8265a42015ffdb (patch) | |
tree | a823402ed7c48272ae5310387f0cd708048d3b30 | |
parent | b7bc1874a5cf1738ce7885b8bef0e16d0f83f56f (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.h | 28 | ||||
-rw-r--r-- | src/qmlcompiler/qqmljsshadowcheck.cpp | 6 | ||||
-rw-r--r-- | src/qmlcompiler/qqmljstyperesolver.cpp | 4 | ||||
-rw-r--r-- | tests/auto/qml/qmlcppcodegen/data/CMakeLists.txt | 2 | ||||
-rw-r--r-- | tests/auto/qml/qmlcppcodegen/data/enumProblems.qml | 14 | ||||
-rw-r--r-- | tests/auto/qml/qmlcppcodegen/data/enumproblems.h | 53 | ||||
-rw-r--r-- | tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp | 21 |
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" |