diff options
author | Ulf Hermann <ulf.hermann@qt.io> | 2022-03-23 10:04:22 +0100 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@qt.io> | 2022-03-25 07:28:57 +0000 |
commit | 8a70e8df0030e962aabcb2322cccb09070c2311c (patch) | |
tree | 03ecfce99c16975c4335e10cb9f1c20d996e6f86 | |
parent | d52e1d609516d0573bea1acf2d73d811ff25f0e9 (diff) |
QmlCompiler: Fix a number of warts regarding type lookup
There was a condition missing in qqml.cpp making most type lookups crash
right away. Furthermore, we need to generate code for type lookups we do
need.
Fixes: QTBUG-102019
Change-Id: I34e9de7686528b39a35e59c616e4e28b32a6e031
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
(cherry picked from commit 5901fba81195ed725ffd7ad6c278e44f41b6df6f)
-rw-r--r-- | src/qml/jsruntime/qv4lookup_p.h | 2 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4qmlcontext.cpp | 4 | ||||
-rw-r--r-- | src/qml/qml/qqml.cpp | 2 | ||||
-rw-r--r-- | src/qmlcompiler/qqmljscodegenerator.cpp | 15 | ||||
-rw-r--r-- | tests/auto/qml/qmlcppcodegen/data/CMakeLists.txt | 3 | ||||
-rw-r--r-- | tests/auto/qml/qmlcppcodegen/data/WindowDerived.qml | 3 | ||||
-rw-r--r-- | tests/auto/qml/qmlcppcodegen/data/prefixedMetaType.qml | 18 | ||||
-rw-r--r-- | tests/auto/qml/qmlcppcodegen/data/state.h | 28 | ||||
-rw-r--r-- | tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp | 26 |
9 files changed, 96 insertions, 5 deletions
diff --git a/src/qml/jsruntime/qv4lookup_p.h b/src/qml/jsruntime/qv4lookup_p.h index d964fadd18..cd7c5e10d9 100644 --- a/src/qml/jsruntime/qv4lookup_p.h +++ b/src/qml/jsruntime/qv4lookup_p.h @@ -167,7 +167,7 @@ struct Q_QML_PRIVATE_EXPORT Lookup { ReturnedValue (*getterTrampoline)(Lookup *l, ExecutionEngine *engine); } qmlContextGlobalLookup; struct { - Heap::Object *qmlTypeWrapper; + Heap::Base *qmlTypeWrapper; quintptr unused2; } qmlTypeLookup; struct { diff --git a/src/qml/jsruntime/qv4qmlcontext.cpp b/src/qml/jsruntime/qv4qmlcontext.cpp index f7a5f897c8..edcccdd1b8 100644 --- a/src/qml/jsruntime/qv4qmlcontext.cpp +++ b/src/qml/jsruntime/qv4qmlcontext.cpp @@ -268,7 +268,7 @@ ReturnedValue QQmlContextWrapper::getPropertyAndBase(const QQmlContextWrapper *r result = QQmlTypeWrapper::create(v4, scopeObject, context->imports(), r.importNamespace); } if (lookup) { - lookup->qmlTypeLookup.qmlTypeWrapper = static_cast<Heap::Object*>(result->heapObject()); + lookup->qmlTypeLookup.qmlTypeWrapper = result->heapObject(); lookup->qmlContextPropertyGetter = QQmlContextWrapper::lookupType; } return result->asReturnedValue(); @@ -718,7 +718,7 @@ ReturnedValue QQmlContextWrapper::lookupType(Lookup *l, ExecutionEngine *engine, if (scopeObject && QQmlData::wasDeleted(scopeObject)) return QV4::Encode::undefined(); - Heap::Object *heapObject = l->qmlTypeLookup.qmlTypeWrapper; + Heap::Base *heapObject = l->qmlTypeLookup.qmlTypeWrapper; if (static_cast<Heap::QQmlTypeWrapper *>(heapObject)->object != scopeObject) { l->qmlTypeLookup.qmlTypeWrapper = nullptr; l->qmlContextPropertyGetter = QQmlContextWrapper::resolveQmlContextPropertyLookupGetter; diff --git a/src/qml/qml/qqml.cpp b/src/qml/qml/qqml.cpp index b5ba3d778f..8781e4bf50 100644 --- a/src/qml/qml/qqml.cpp +++ b/src/qml/qml/qqml.cpp @@ -1398,6 +1398,8 @@ static void initTypeWrapperLookup( l->qmlContextPropertyGetter = qmlContextPropertyGetter; if (qmlContextPropertyGetter == QV4::QQmlContextWrapper::lookupSingleton) l->qmlContextSingletonLookup.singletonObject = wrapper->heapObject(); + else if (qmlContextPropertyGetter == QV4::QQmlContextWrapper::lookupType) + l->qmlTypeLookup.qmlTypeWrapper = wrapper->heapObject(); return; } scope.engine->throwTypeError(); diff --git a/src/qmlcompiler/qqmljscodegenerator.cpp b/src/qmlcompiler/qqmljscodegenerator.cpp index addda79063..34bb402f7e 100644 --- a/src/qmlcompiler/qqmljscodegenerator.cpp +++ b/src/qmlcompiler/qqmljscodegenerator.cpp @@ -992,6 +992,13 @@ void QQmlJSCodeGenerator::generate_GetLookup(int index) + indexString + u", "_qs + namespaceString + u')'; generateLookup(lookup, initialization); return; + } else if (m_state.accumulatorOut.variant() == QQmlJSRegisterContent::MetaType) { + const QString lookup = u"aotContext->loadTypeLookup("_qs + indexString + + u", &"_qs + m_state.accumulatorVariableOut + u')'; + const QString initialization = u"aotContext->initLoadTypeLookup("_qs + indexString + + u", "_qs + namespaceString + u")"_qs; + generateLookup(lookup, initialization); + return; } Q_ASSERT(m_state.accumulatorOut.isProperty()); @@ -2528,13 +2535,17 @@ QString QQmlJSCodeGenerator::conversion(const QQmlJSScope::ConstPtr &from, if (from->accessSemantics() == QQmlJSScope::AccessSemantics::Reference) { if (to->accessSemantics() == QQmlJSScope::AccessSemantics::Reference) { + // Compare internalName here. The same C++ type can be exposed muliple times in + // different QML types. However, the C++ names have to be unique. We can always + // static_cast to those. + for (QQmlJSScope::ConstPtr base = from; base; base = base->baseType()) { // We still have to cast as other execution paths may result in different types. - if (base == to) + if (base->internalName() == to->internalName()) return u"static_cast<"_qs + to->internalName() + u" *>("_qs + variable + u')'; } for (QQmlJSScope::ConstPtr base = to; base; base = base->baseType()) { - if (base == from) + if (base->internalName() == from->internalName()) return u"static_cast<"_qs + to->internalName() + u" *>("_qs + variable + u')'; } } else if (to == m_typeResolver->boolType()) { diff --git a/tests/auto/qml/qmlcppcodegen/data/CMakeLists.txt b/tests/auto/qml/qmlcppcodegen/data/CMakeLists.txt index 4d585b62f0..36741105af 100644 --- a/tests/auto/qml/qmlcppcodegen/data/CMakeLists.txt +++ b/tests/auto/qml/qmlcppcodegen/data/CMakeLists.txt @@ -4,6 +4,7 @@ set(cpp_sources dynamicmeta.h objectwithmethod.h person.cpp person.h + state.h theme.cpp theme.h timelinetheme.cpp timelinetheme.h ) @@ -30,6 +31,7 @@ set(qml_files SelectionRectangle.qml Test.qml TestCase.qml + WindowDerived.qml aliasLookup.qml anchorsFill.qml array.qml @@ -103,6 +105,7 @@ set(qml_files page.qml parentProp.qml popContextAfterRet.qml + prefixedMetaType.qml pressAndHoldButton.qml registerelimination.qml revisions.qml diff --git a/tests/auto/qml/qmlcppcodegen/data/WindowDerived.qml b/tests/auto/qml/qmlcppcodegen/data/WindowDerived.qml new file mode 100644 index 0000000000..5e35d425e3 --- /dev/null +++ b/tests/auto/qml/qmlcppcodegen/data/WindowDerived.qml @@ -0,0 +1,3 @@ +import TestTypes as Test + +Test.WindowInstance {} diff --git a/tests/auto/qml/qmlcppcodegen/data/prefixedMetaType.qml b/tests/auto/qml/qmlcppcodegen/data/prefixedMetaType.qml new file mode 100644 index 0000000000..0039d7a4c7 --- /dev/null +++ b/tests/auto/qml/qmlcppcodegen/data/prefixedMetaType.qml @@ -0,0 +1,18 @@ +import QtQml +import TestTypes as Test + +QtObject { + id: self + property int state + property QtObject a: Test.WindowInstance {} + property QtObject b: a as Test.WindowInstance + property QtObject c: self as Test.WindowInstance + + property QtObject d: Test.WindowDerived {} + property QtObject e: d as Test.WindowDerived + property QtObject f: self as Test.WindowDerived + + Component.onCompleted: { + self.state = Test.WindowState.UNCALIBRATED + } +} diff --git a/tests/auto/qml/qmlcppcodegen/data/state.h b/tests/auto/qml/qmlcppcodegen/data/state.h new file mode 100644 index 0000000000..287b774c88 --- /dev/null +++ b/tests/auto/qml/qmlcppcodegen/data/state.h @@ -0,0 +1,28 @@ +#ifndef STATE_H +#define STATE_H + +#include <QObject> +#include <QtQml/qqmlregistration.h> + +namespace model { +namespace Window { +Q_NAMESPACE +QML_NAMED_ELEMENT(WindowState) +enum State { + OPEN, + TILT, + UNCALIBRATED, + CLOSE +}; +Q_ENUM_NS(State) +} + +class WindowInstance : public QObject +{ + Q_OBJECT + QML_ELEMENT +}; + +} + +#endif // STATE_H diff --git a/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp b/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp index acc117d967..bc6fa5a106 100644 --- a/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp +++ b/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp @@ -125,6 +125,7 @@ private slots: void objectInVar(); void testIsnan(); void fallbackLookups(); + void prefixedMetaType(); }; void tst_QmlCppCodegen::simpleBinding() @@ -1880,6 +1881,31 @@ void tst_QmlCppCodegen::fallbackLookups() QCOMPARE(singleton->objectName(), QStringLiteral("dd96")); } +void tst_QmlCppCodegen::prefixedMetaType() +{ + QQmlEngine engine; + + // We need to add an import path here because we cannot namespace the implicit import. + // The implicit import is what we use for all the other tests, even if we explicitly + // import TestTypes. That is because the TestTypes module is in a subdirectory "data". + engine.addImportPath(u":/"_qs); + + const QUrl document(u"qrc:/TestTypes/prefixedMetaType.qml"_qs); + QQmlComponent c(&engine, document); + QVERIFY2(c.isReady(), qPrintable(c.errorString())); + QScopedPointer<QObject> o(c.create()); + QVERIFY(o); + + QCOMPARE(o->property("state").toInt(), 2); + QVERIFY(qvariant_cast<QObject *>(o->property("a")) != nullptr); + QVERIFY(qvariant_cast<QObject *>(o->property("b")) != nullptr); + QVERIFY(qvariant_cast<QObject *>(o->property("c")) == nullptr); + + QVERIFY(qvariant_cast<QObject *>(o->property("d")) != nullptr); + QVERIFY(qvariant_cast<QObject *>(o->property("e")) != nullptr); + QVERIFY(qvariant_cast<QObject *>(o->property("f")) == nullptr); +} + void tst_QmlCppCodegen::runInterpreted() { if (qEnvironmentVariableIsSet("QV4_FORCE_INTERPRETER")) |