From 464abaec05e0aa0ab699243412c50a5d5ac30742 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Thu, 3 Mar 2022 12:05:18 +0100 Subject: QML: Unify treatment of invalid revisions on registration Revisions before QML_ADDED_IN_VERSION and revisions after QML_REMOVED_IN_VERSION should both result in anonymous types. This way, you can then derive from the type in question and expose the derived type in a different set of versions. Pick-to: 6.3 Change-Id: Ia59258047fc242c809c27525bb75fd2797fe5aab Reviewed-by: Qt CI Bot Reviewed-by: Fabian Kosmale --- src/qml/qml/qqml.cpp | 22 ++++++------ .../qml/qmltyperegistrar/tst_qmltyperegistrar.cpp | 40 ++++++++++++++++++++++ .../qml/qmltyperegistrar/tst_qmltyperegistrar.h | 25 ++++++++++++++ 3 files changed, 77 insertions(+), 10 deletions(-) diff --git a/src/qml/qml/qqml.cpp b/src/qml/qml/qqml.cpp index ff19bc4165..43cb973691 100644 --- a/src/qml/qml/qqml.cpp +++ b/src/qml/qml/qqml.cpp @@ -528,21 +528,23 @@ int QQmlPrivate::qmlregister(RegistrationType type, void *data) uniqueRevisions(&revisions, type.version, added); for (QTypeRevision revision : revisions) { - if (revision < added) - continue; if (revision.hasMajorVersion() && revision.majorVersion() > type.version.majorVersion()) break; - // When removed, we still add revisions, but anonymous ones - if (removed.isValid() && !(revision < removed)) { + + assignVersions(&typeRevision, revision, type.version); + + // When removed or before added, we still add revisions, but anonymous ones + if (typeRevision.version < added + || (removed.isValid() && !(typeRevision.version < removed))) { typeRevision.elementName = nullptr; typeRevision.create = nullptr; + typeRevision.userdata = nullptr; } else { typeRevision.elementName = elementName; typeRevision.create = creatable ? type.create : nullptr; typeRevision.userdata = type.userdata; } - assignVersions(&typeRevision, revision, type.version); typeRevision.customParser = type.customParserFactory(); const int id = qmlregister(TypeRegistration, &typeRevision); if (type.qmlTypeIds) @@ -589,13 +591,14 @@ int QQmlPrivate::qmlregister(RegistrationType type, void *data) uniqueRevisions(&revisions, type.version, added); for (QTypeRevision revision : qAsConst(revisions)) { - if (revision < added) - continue; if (revision.hasMajorVersion() && revision.majorVersion() > type.version.majorVersion()) break; - // When removed, we still add revisions, but anonymous ones - if (removed.isValid() && !(revision < removed)) { + assignVersions(&revisionRegistration, revision, type.version); + + // When removed or before added, we still add revisions, but anonymous ones + if (revisionRegistration.version < added + || (removed.isValid() && !(revisionRegistration.version < removed))) { revisionRegistration.typeName = nullptr; revisionRegistration.qObjectApi = nullptr; } else { @@ -603,7 +606,6 @@ int QQmlPrivate::qmlregister(RegistrationType type, void *data) revisionRegistration.qObjectApi = type.qObjectApi; } - assignVersions(&revisionRegistration, revision, type.version); const int id = qmlregister(SingletonRegistration, &revisionRegistration); if (type.qmlTypeIds) type.qmlTypeIds->append(id); diff --git a/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.cpp b/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.cpp index 5619c2aa0f..3fc746552e 100644 --- a/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.cpp +++ b/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.cpp @@ -339,6 +339,46 @@ void tst_qmltyperegistrar::methodReturnType() QVERIFY(qmltypesData.contains("type: \"QQmlComponent\"")); } +void tst_qmltyperegistrar::addRemoveVersion_data() +{ + QTest::addColumn("importVersion"); + for (int i = 0; i < 20; ++i) + QTest::addRow("v1.%d.qml", i) << QTypeRevision::fromVersion(1, i); +} + +void tst_qmltyperegistrar::addRemoveVersion() +{ + QFETCH(QTypeRevision, importVersion); + + const bool creatable + = importVersion > QTypeRevision::fromVersion(1, 2) + && importVersion < QTypeRevision::fromVersion(1, 18); + const bool thingAccessible = importVersion > QTypeRevision::fromVersion(1, 3); + + QQmlEngine engine; + QQmlComponent c(&engine); + c.setData(QStringLiteral("import QmlTypeRegistrarTest %1.%2\n" + "Versioned {\n" + " property int thing: revisioned\n" + "}") + .arg(importVersion.majorVersion()).arg(importVersion.minorVersion()).toUtf8(), + QUrl(QTest::currentDataTag())); + if (!creatable) { + QVERIFY(c.isError()); + return; + } + QVERIFY2(c.isReady(), qPrintable(c.errorString())); + if (!thingAccessible) { + QTest::ignoreMessage( + QtWarningMsg, + qPrintable(QStringLiteral("%1:3: ReferenceError: revisioned is not defined") + .arg(QTest::currentDataTag()))); + } + QScopedPointer o(c.create()); + QVERIFY(!o.isNull()); + QCOMPARE(o->property("thing").toInt(), thingAccessible ? 24 : 0); +} + #ifdef QT_QUICK_LIB void tst_qmltyperegistrar::foreignRevisionedProperty() { diff --git a/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.h b/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.h index d57053a051..385d3b6666 100644 --- a/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.h +++ b/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.h @@ -469,6 +469,28 @@ public: }; #endif +class AddedInLateVersion : public QObject +{ + Q_OBJECT + QML_NAMED_ELEMENT(Versioned) + QML_ADDED_IN_VERSION(1, 8) + Q_PROPERTY(int revisioned READ revisioned CONSTANT REVISION(1, 4)) + Q_PROPERTY(int insane READ revisioned CONSTANT REVISION 17) +public: + AddedInLateVersion(QObject *parent = nullptr) : QObject(parent) {} + int revisioned() const { return 24; } +}; + +class RemovedInEarlyVersion : public AddedInLateVersion +{ + Q_OBJECT + QML_NAMED_ELEMENT(Versioned) + QML_ADDED_IN_VERSION(1, 3) + QML_REMOVED_IN_VERSION(1, 8) +public: + RemovedInEarlyVersion(QObject *parent = nullptr) : AddedInLateVersion(parent) {} +}; + class tst_qmltyperegistrar : public QObject { Q_OBJECT @@ -508,6 +530,9 @@ private slots: void foreignRevisionedProperty(); #endif + void addRemoveVersion_data(); + void addRemoveVersion(); + private: QByteArray qmltypesData; }; -- cgit v1.2.3