From b386b6491d3486a78aee88e432f0d33f8ae39d06 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Tue, 1 Mar 2022 11:37:53 +0100 Subject: QML: Handle dynamic meta objects in AOT lookups If we are dealing with dynamic metaobjects, the QML engine may not create property caches. We cannot see this at compile time. Therefore, we need to establish a fallback infrastructure that does the same operations on plain QMetaObject. Fixes: QTBUG-101349 Change-Id: I8c936fc077b0018df71196620b6987825253cb39 Reviewed-by: Fabian Kosmale (cherry picked from commit 1e722f5e8e6510f3a1bc10436f8262c918ca9599) --- tests/auto/qml/qmlcppcodegen/data/CMakeLists.txt | 2 + tests/auto/qml/qmlcppcodegen/data/dynamicmeta.h | 78 ++++++++++++++++++++++ .../qml/qmlcppcodegen/data/fallbacklookups.qml | 34 ++++++++++ tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp | 34 ++++++++++ 4 files changed, 148 insertions(+) create mode 100644 tests/auto/qml/qmlcppcodegen/data/dynamicmeta.h create mode 100644 tests/auto/qml/qmlcppcodegen/data/fallbacklookups.qml (limited to 'tests') diff --git a/tests/auto/qml/qmlcppcodegen/data/CMakeLists.txt b/tests/auto/qml/qmlcppcodegen/data/CMakeLists.txt index 3d05ffcf1d..4d585b62f0 100644 --- a/tests/auto/qml/qmlcppcodegen/data/CMakeLists.txt +++ b/tests/auto/qml/qmlcppcodegen/data/CMakeLists.txt @@ -1,6 +1,7 @@ set(cpp_sources birthdayparty.cpp birthdayparty.h cppbaseclass.h + dynamicmeta.h objectwithmethod.h person.cpp person.h theme.cpp theme.h @@ -61,6 +62,7 @@ set(qml_files excessiveParameters.qml extendedTypes.qml failures.qml + fallbacklookups.qml fileDialog.qml functionLookup.qml funcWithParams.qml diff --git a/tests/auto/qml/qmlcppcodegen/data/dynamicmeta.h b/tests/auto/qml/qmlcppcodegen/data/dynamicmeta.h new file mode 100644 index 0000000000..3f02e460e7 --- /dev/null +++ b/tests/auto/qml/qmlcppcodegen/data/dynamicmeta.h @@ -0,0 +1,78 @@ +#ifndef DYNAMICMETA_H +#define DYNAMICMETA_H + +#include +#include + +struct FreeDeleter { + void operator()(QMetaObject *meta) { free(meta); } +}; + +template +class MetaObjectData : public QDynamicMetaObjectData +{ + Q_DISABLE_COPY_MOVE(MetaObjectData) +public: + MetaObjectData() = default; + ~MetaObjectData() = default; + + QMetaObject *toDynamicMetaObject(QObject *) override + { + return const_cast(&T::staticMetaObject); + } + int metaCall(QObject *o, QMetaObject::Call call, int idx, void **argv) override + { + return o->qt_metacall(call, idx, argv); + } +}; + +class DynamicMeta : public QObject +{ + Q_OBJECT + Q_PROPERTY(int foo READ foo WRITE setFoo NOTIFY fooChanged FINAL) + QML_ELEMENT +public: + + DynamicMeta(QObject *parent = nullptr) + : QObject(parent) + { + // deletes itself + QObjectPrivate::get(this)->metaObject = new MetaObjectData; + } + + int foo() const { return m_foo; } + void setFoo(int newFoo) + { + if (m_foo != newFoo) { + m_foo = newFoo; + emit fooChanged(); + } + } + + Q_INVOKABLE int bar(int baz) { return baz + 12; } + +Q_SIGNALS: + void fooChanged(); + +private: + int m_foo = 0; +}; + +class DynamicMetaSingleton : public DynamicMeta +{ + Q_OBJECT + QML_ELEMENT + QML_SINGLETON + Q_PROPERTY(DynamicMetaSingleton *itself READ itself CONSTANT FINAL) +public: + DynamicMetaSingleton(QObject *parent = nullptr) : DynamicMeta(parent) + { + QObjectPrivate *d = QObjectPrivate::get(this); + delete d->metaObject; + d->metaObject = new MetaObjectData; + } + + DynamicMetaSingleton *itself() { return this; } +}; + +#endif // DYNAMICMETA_H diff --git a/tests/auto/qml/qmlcppcodegen/data/fallbacklookups.qml b/tests/auto/qml/qmlcppcodegen/data/fallbacklookups.qml new file mode 100644 index 0000000000..4b58cd344d --- /dev/null +++ b/tests/auto/qml/qmlcppcodegen/data/fallbacklookups.qml @@ -0,0 +1,34 @@ +import TestTypes +import QtQml + +DynamicMeta { + id: self + + function getSingleton(): QtObject { + return DynamicMetaSingleton.itself + } + + function withContext(): int { + foo = 93; + objectName = "aa" + foo; + return bar(4); + } + + function withId(): int { + self.foo = 94; + self.objectName = "bb" + foo; + return self.bar(5); + } + + function withSingleton(): int { + DynamicMetaSingleton.foo = 95; + DynamicMetaSingleton.objectName = "cc" + DynamicMetaSingleton.foo; + return DynamicMetaSingleton.bar(6); + } + + function withProperty(): int { + DynamicMetaSingleton.itself.foo = 96; + DynamicMetaSingleton.itself.objectName = "dd" + DynamicMetaSingleton.itself.foo; + return DynamicMetaSingleton.itself.bar(7); + } +} diff --git a/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp b/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp index d1b8565afc..acc117d967 100644 --- a/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp +++ b/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp @@ -124,6 +124,7 @@ private slots: void functionLookup(); void objectInVar(); void testIsnan(); + void fallbackLookups(); }; void tst_QmlCppCodegen::simpleBinding() @@ -1846,6 +1847,39 @@ void tst_QmlCppCodegen::testIsnan() QVERIFY(b.toBool()); } +void tst_QmlCppCodegen::fallbackLookups() +{ + QQmlEngine engine; + const QUrl document(u"qrc:/TestTypes/fallbacklookups.qml"_qs); + QQmlComponent c(&engine, document); + QVERIFY2(c.isReady(), qPrintable(c.errorString())); + QScopedPointer o(c.create()); + QVERIFY(o); + + QCOMPARE(o->objectName(), QString()); + int result = 0; + + QMetaObject::invokeMethod(o.data(), "withContext", Q_RETURN_ARG(int, result)); + QCOMPARE(result, 16); + QCOMPARE(o->objectName(), QStringLiteral("aa93")); + + QMetaObject::invokeMethod(o.data(), "withId", Q_RETURN_ARG(int, result)); + QCOMPARE(result, 17); + QCOMPARE(o->objectName(), QStringLiteral("bb94")); + + QObject *singleton = nullptr; + QMetaObject::invokeMethod(o.data(), "getSingleton", Q_RETURN_ARG(QObject*, singleton)); + QVERIFY(singleton); + + QMetaObject::invokeMethod(o.data(), "withSingleton", Q_RETURN_ARG(int, result)); + QCOMPARE(result, 18); + QCOMPARE(singleton->objectName(), QStringLiteral("cc95")); + + QMetaObject::invokeMethod(o.data(), "withProperty", Q_RETURN_ARG(int, result)); + QCOMPARE(result, 19); + QCOMPARE(singleton->objectName(), QStringLiteral("dd96")); +} + void tst_QmlCppCodegen::runInterpreted() { if (qEnvironmentVariableIsSet("QV4_FORCE_INTERPRETER")) -- cgit v1.2.3