diff options
author | Andrei Golubev <andrei.golubev@qt.io> | 2022-05-18 14:37:01 +0200 |
---|---|---|
committer | Andrei Golubev <andrei.golubev@qt.io> | 2022-05-24 10:30:44 +0200 |
commit | c02dd17a4f648ec18c6ff2ae7bfe468bd9c42732 (patch) | |
tree | 2975f030e9cbbcffa3ecb79d835507e86298ef8b | |
parent | ce441f819389d729dea63a7d1ae02fae35b35bfc (diff) |
Support extension property revisions
Previously the extension's property revision would make
the property unusable since extensions would've been skipped
from property cache construction w.r.t. revisions
This is due to the meta object cloning that we do for
extension types (since we put the cloned meta object on top
of the meta object hierarchy for the QQmlProxyMetaObject).
Once cloned, the meta object has no associated QQmlType
anymore and we need one to deal with revisions. Overcome this
by registering the cloned meta object in the QQmlMetaTypeData
From now on, the cloned extension meta object has an
associated QQmlType, which is the *extended* type, NOT the
*extension* type
Change-Id: I4a6a4380278b80e49e1b9874dd458183667e5cb5
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
-rw-r--r-- | src/qml/qml/qqmlmetatype.cpp | 16 | ||||
-rw-r--r-- | src/qml/qml/qqmlmetatype_p.h | 2 | ||||
-rw-r--r-- | src/qml/qml/qqmltype.cpp | 1 | ||||
-rw-r--r-- | tests/auto/qml/qqmllanguage/testtypes.h | 32 | ||||
-rw-r--r-- | tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp | 23 |
5 files changed, 71 insertions, 3 deletions
diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp index db4ecc6397..110363ae3b 100644 --- a/src/qml/qml/qqmlmetatype.cpp +++ b/src/qml/qml/qqmlmetatype.cpp @@ -1430,6 +1430,14 @@ void QQmlMetaType::unregisterType(int typeIndex) } } +void QQmlMetaType::registerMetaObjectForType(const QMetaObject *metaobject, QQmlTypePrivate *type) +{ + Q_ASSERT(type); + + QQmlMetaTypeDataPtr data; + data->metaObjectToType.insert(metaobject, type); +} + static bool hasActiveInlineComponents(const QQmlTypePrivate *d) { for (const QQmlType &ic : qAsConst(d->objectIdToICType)) { @@ -1635,7 +1643,8 @@ QList<QQmlProxyMetaObject::ProxyData> QQmlMetaType::proxyData(const QMetaObject const QQmlMetaTypeDataPtr data; - auto createProxyMetaObject = [&](const QMetaObject *superdataBaseMetaObject, + auto createProxyMetaObject = [&](QQmlTypePrivate *This, + const QMetaObject *superdataBaseMetaObject, const QMetaObject *extMetaObject, QObject *(*extFunc)(QObject *)) { if (!extMetaObject) @@ -1652,16 +1661,17 @@ QList<QQmlProxyMetaObject::ProxyData> QQmlMetaType::proxyData(const QMetaObject lastMetaObject->d.superdata = mmo; QQmlProxyMetaObject::ProxyData data = { mmo, extFunc, 0, 0 }; metaObjects << data; + registerMetaObjectForType(mmo, This); }; while (mo) { QQmlTypePrivate *t = data->metaObjectToType.value(mo); if (t) { if (t->regType == QQmlType::CppType) { - createProxyMetaObject(t->baseMetaObject, t->extraData.cd->extMetaObject, + createProxyMetaObject(t, t->baseMetaObject, t->extraData.cd->extMetaObject, t->extraData.cd->extFunc); } else if (t->regType == QQmlType::SingletonType) { - createProxyMetaObject(t->baseMetaObject, t->extraData.sd->extMetaObject, + createProxyMetaObject(t, t->baseMetaObject, t->extraData.sd->extMetaObject, t->extraData.sd->extFunc); } } diff --git a/src/qml/qml/qqmlmetatype_p.h b/src/qml/qml/qqmlmetatype_p.h index 2c010f516d..b9bf78b0a7 100644 --- a/src/qml/qml/qqmlmetatype_p.h +++ b/src/qml/qml/qqmlmetatype_p.h @@ -148,6 +148,8 @@ public: static void unregisterType(int type); + static void registerMetaObjectForType(const QMetaObject *metaobject, QQmlTypePrivate *type); + static void registerModule(const char *uri, QTypeRevision version); static bool protectModule(const QString &uri, QTypeRevision version, bool weakProtectAllVersions = false); diff --git a/src/qml/qml/qqmltype.cpp b/src/qml/qml/qqmltype.cpp index 1d34b57fed..0bc817845d 100644 --- a/src/qml/qml/qqmltype.cpp +++ b/src/qml/qml/qqmltype.cpp @@ -232,6 +232,7 @@ void QQmlTypePrivate::init() const mmo->d.superdata = mo; QQmlProxyMetaObject::ProxyData data = { mmo, extFunc, 0, 0 }; metaObjects << data; + QQmlMetaType::registerMetaObjectForType(mmo, const_cast<QQmlTypePrivate *>(this)); }; if (regType == QQmlType::SingletonType) diff --git a/tests/auto/qml/qqmllanguage/testtypes.h b/tests/auto/qml/qqmllanguage/testtypes.h index 54022b268f..bcc6a9d9eb 100644 --- a/tests/auto/qml/qqmllanguage/testtypes.h +++ b/tests/auto/qml/qqmllanguage/testtypes.h @@ -1888,6 +1888,38 @@ public: } }; +class RevisionedExtension : public QObject +{ + Q_OBJECT + Q_PROPERTY(int extension READ extension WRITE setExtension REVISION(1, 0)) +public: + RevisionedExtension(QObject *parent = nullptr) : QObject(parent) {} + int extension() const { return m_ext; } + void setExtension(int e) { m_ext = e; } +private: + int m_ext = 42; +}; + +class ExtendedWithRevisionOld : public QObject +{ + Q_OBJECT + QML_ELEMENT + QML_EXTENDED(RevisionedExtension) + QML_ADDED_IN_VERSION(0, 5) +public: + ExtendedWithRevisionOld(QObject *parent = nullptr) : QObject(parent) { } +}; + +class ExtendedWithRevisionNew : public QObject +{ + Q_OBJECT + QML_ELEMENT + QML_EXTENDED(RevisionedExtension) + QML_ADDED_IN_VERSION(1, 0) +public: + ExtendedWithRevisionNew(QObject *parent = nullptr) : QObject(parent) { } +}; + class StringSignaler : public QObject { Q_OBJECT diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp index 81d6e6f6a0..73f886e217 100644 --- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp +++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp @@ -369,6 +369,7 @@ private slots: void multiExtensionIndirect(); void multiExtensionQmlTypes(); void extensionSpecial(); + void extensionRevision(); void invalidInlineComponent(); void warnOnInjectedParameters(); #if QT_CONFIG(wheelevent) @@ -6540,6 +6541,28 @@ void tst_qqmllanguage::extensionSpecial() } } +void tst_qqmllanguage::extensionRevision() +{ + QQmlEngine engine; + { + QQmlComponent c(&engine); + c.setData("import StaticTest 0.5\nExtendedWithRevisionOld { extension: 40\n}", QUrl()); + QVERIFY(!c.isReady()); + QRegularExpression error( + ".*\"ExtendedWithRevisionOld.extension\" is not available in StaticTest 0.5.*"); + QVERIFY2(error.match(c.errorString()).hasMatch(), + qPrintable(u"Unmatched error: "_s + c.errorString())); + } + + { + QQmlComponent c(&engine); + c.setData("import StaticTest 1.0\nExtendedWithRevisionNew { extension: 40\n}", QUrl()); + QVERIFY2(c.isReady(), qPrintable(c.errorString())); + QScopedPointer<QObject> o(c.create()); + QVERIFY(o); + } +} + void tst_qqmllanguage::invalidInlineComponent() { QQmlEngine e; |