aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2022-03-23 10:04:22 +0100
committerUlf Hermann <ulf.hermann@qt.io>2022-03-25 07:28:57 +0000
commit8a70e8df0030e962aabcb2322cccb09070c2311c (patch)
tree03ecfce99c16975c4335e10cb9f1c20d996e6f86
parentd52e1d609516d0573bea1acf2d73d811ff25f0e9 (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.h2
-rw-r--r--src/qml/jsruntime/qv4qmlcontext.cpp4
-rw-r--r--src/qml/qml/qqml.cpp2
-rw-r--r--src/qmlcompiler/qqmljscodegenerator.cpp15
-rw-r--r--tests/auto/qml/qmlcppcodegen/data/CMakeLists.txt3
-rw-r--r--tests/auto/qml/qmlcppcodegen/data/WindowDerived.qml3
-rw-r--r--tests/auto/qml/qmlcppcodegen/data/prefixedMetaType.qml18
-rw-r--r--tests/auto/qml/qmlcppcodegen/data/state.h28
-rw-r--r--tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp26
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"))