diff options
author | Ulf Hermann <ulf.hermann@qt.io> | 2021-02-02 14:11:24 +0100 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@qt.io> | 2021-02-02 14:32:35 +0100 |
commit | 1b93a1d86549347566e1a7645c0501e5c9f6aa0a (patch) | |
tree | 25bab0d6ef18650576864ed245ba95a628169816 | |
parent | ecd54e68b90ad7022d1bdb71f1c1640ab392adae (diff) |
qmltyperegistrar: Fix handling of default properties
Default properties are always local. There is no way to declare a
default property for a foreign type as the default property is queried
directly from the classinfo at runtime.
Change-Id: I30efb6fba190957ac2a4ad86da437f209cd1f3ad
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
-rw-r--r-- | src/qmltyperegistrar/qmltypesclassdescription.cpp | 61 | ||||
-rw-r--r-- | tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.cpp | 34 | ||||
-rw-r--r-- | tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.h | 51 |
3 files changed, 120 insertions, 26 deletions
diff --git a/src/qmltyperegistrar/qmltypesclassdescription.cpp b/src/qmltyperegistrar/qmltypesclassdescription.cpp index 82c1c31ec2..90f7565e5e 100644 --- a/src/qmltyperegistrar/qmltypesclassdescription.cpp +++ b/src/qmltyperegistrar/qmltypesclassdescription.cpp @@ -113,7 +113,7 @@ void QmlTypesClassDescription::collectLocalAnonymous( for (const QJsonValue &classInfo : classInfos) { const QJsonObject obj = classInfo.toObject(); if (obj[QStringLiteral("name")].toString() == QStringLiteral("DefaultProperty")) - defaultProp = obj[obj[QStringLiteral("value")].toString()].toString(); + defaultProp = obj[QStringLiteral("value")].toString(); } collectInterfaces(classDef); @@ -129,6 +129,7 @@ void QmlTypesClassDescription::collect( const auto classInfos = classDef->value(QLatin1String("classInfos")).toArray(); const QString classDefName = classDef->value(QLatin1String("className")).toString(); + QString foreignTypeName; for (const QJsonValue &classInfo : classInfos) { const QJsonObject obj = classInfo.toObject(); const QString name = obj[QLatin1String("name")].toString(); @@ -173,36 +174,44 @@ void QmlTypesClassDescription::collect( if (value == QLatin1String("true")) isSingleton = true; } else if (name == QLatin1String("QML.Foreign")) { - if (const QJsonObject *other = findType(foreign, value)) { - classDef = other; - // Foreign type can have a default property or an attached types - const auto classInfos = classDef->value(QLatin1String("classInfos")).toArray(); - for (const QJsonValue &classInfo : classInfos) { - const QJsonObject obj = classInfo.toObject(); - const QString foreignName = obj[QLatin1String("name")].toString(); - const QString foreignValue = obj[QLatin1String("value")].toString(); - if (defaultProp.isEmpty() && foreignName == QLatin1String("DefaultProperty")) { - defaultProp = foreignValue; - } else if (foreignName == QLatin1String("QML.Attached")) { - attachedType = foreignValue; - collectRelated(foreignValue, types, foreign, defaultRevision); - } else if (foreignName == QLatin1String("QML.Extended")) { - extensionType = foreignValue; - collectRelated(foreignValue, types, foreign, defaultRevision); - } else if (foreignName == QLatin1String("QML.Sequence")) { - sequenceValueType = foreignValue; - collectRelated(foreignValue, types, foreign, defaultRevision); - } - } - } else { - className = value; - classDef = nullptr; - } + foreignTypeName = value; } else if (name == QLatin1String("QML.Root")) { isRootClass = true; } } + if (!foreignTypeName.isEmpty()) { + if (const QJsonObject *other = findType(foreign, foreignTypeName)) { + classDef = other; + + // Default properties are always local. + defaultProp.clear(); + + // Foreign type can have a default property or an attached types + const auto classInfos = classDef->value(QLatin1String("classInfos")).toArray(); + for (const QJsonValue &classInfo : classInfos) { + const QJsonObject obj = classInfo.toObject(); + const QString foreignName = obj[QLatin1String("name")].toString(); + const QString foreignValue = obj[QLatin1String("value")].toString(); + if (defaultProp.isEmpty() && foreignName == QLatin1String("DefaultProperty")) { + defaultProp = foreignValue; + } else if (foreignName == QLatin1String("QML.Attached")) { + attachedType = foreignValue; + collectRelated(foreignValue, types, foreign, defaultRevision); + } else if (foreignName == QLatin1String("QML.Extended")) { + extensionType = foreignValue; + collectRelated(foreignValue, types, foreign, defaultRevision); + } else if (foreignName == QLatin1String("QML.Sequence")) { + sequenceValueType = foreignValue; + collectRelated(foreignValue, types, foreign, defaultRevision); + } + } + } else { + className = foreignTypeName; + classDef = nullptr; + } + } + if (classDef) { if (mode == RelatedType || !elementName.isEmpty()) { collectExtraVersions(classDef, QString::fromLatin1("properties"), revisions); diff --git a/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.cpp b/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.cpp index cd3596e142..34d8007ede 100644 --- a/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.cpp +++ b/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.cpp @@ -171,4 +171,38 @@ void tst_qmltyperegistrar::multiExtensions() QVERIFY(qmltypesData.contains("interfaces: [\"Interface3\"]")); } +void tst_qmltyperegistrar::localDefault() +{ + QQmlEngine engine; + { + QQmlComponent c(&engine); + c.setData("import QmlTypeRegistrarTest\n" + "import QtQml\n" + "ForeignWithoutDefault { QtObject {} }", QUrl()); + QVERIFY(c.isError()); + QVERIFY(c.errorString().contains( + QStringLiteral("Cannot assign to non-existent default property"))); + } + { + QQmlComponent c(&engine); + c.setData("import QmlTypeRegistrarTest\n" + "import QtQml\n" + "Local { QtObject {} }", QUrl()); + QVERIFY(c.isReady()); + } + + QCOMPARE(qmltypesData.count("name: \"LocalWithDefault\""), 1); + QCOMPARE(qmltypesData.count("name: \"ForeignWithoutDefault\""), 1); + QCOMPARE(qmltypesData.count("defaultProperty: \"d\""), 1); + + const int local = qmltypesData.indexOf("name: \"LocalWithDefault\""); + const int foreign = qmltypesData.indexOf("name: \"ForeignWithoutDefault\""); + const int defaultProp = qmltypesData.indexOf("defaultProperty: \"d\""); + + // We assume that name is emitted before defaultProperty. + // Then this proves that the default property does not belong to ForeignWithoutDefault. + QVERIFY(local < defaultProp); + QVERIFY(foreign > defaultProp || foreign < local); +} + QTEST_MAIN(tst_qmltyperegistrar) diff --git a/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.h b/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.h index 40569879ec..eb3b680e82 100644 --- a/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.h +++ b/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.h @@ -116,11 +116,61 @@ public: void setWidth(int width) { v.setWidth(width); } }; +class ForeignWithoutDefault : public QObject +{ + Q_OBJECT + Q_PROPERTY(QObject *d READ d WRITE setD NOTIFY dChanged) +public: + QObject *d() const { return m_d; } + + void setD(QObject *d) + { + if (m_d != d) { + m_d = d; + emit dChanged(); + } + } + +signals: + void dChanged(); + +private: + QObject *m_d = nullptr; +}; + +class LocalWithDefault : public QObject +{ + Q_OBJECT + Q_PROPERTY(QObject *d READ d WRITE setD NOTIFY dChanged) + QML_NAMED_ELEMENT(ForeignWithoutDefault) + QML_FOREIGN(ForeignWithoutDefault) + Q_CLASSINFO("DefaultProperty", "d") + +public: + LocalWithDefault(QObject *parent = nullptr) : QObject(parent) {} + QObject *d() const { return m_d; } + + void setD(QObject *d) + { + if (m_d != d) { + m_d = d; + emit dChanged(); + } + } + +signals: + void dChanged(); + +private: + QObject *m_d = nullptr; +}; + class Local : public Foreign { Q_OBJECT QML_ELEMENT Q_PROPERTY(int someProperty MEMBER someProperty BINDABLE bindableSomeProperty) + QML_EXTENDED(LocalWithDefault) public: enum Flag { Flag1 = 0x1, @@ -216,6 +266,7 @@ private slots: void derivedFromForeign(); void metaTypesRegistered(); void multiExtensions(); + void localDefault(); private: QByteArray qmltypesData; |