diff options
author | Ulf Hermann <ulf.hermann@qt.io> | 2022-11-24 15:15:13 +0100 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@qt.io> | 2022-11-28 14:11:44 +0100 |
commit | b6ba7e9c9023d1d5c6ba543c1c551344b7a9e5b5 (patch) | |
tree | 19ab013570976ea1191134f85f8115944a2e9866 | |
parent | 6acf343acb532ad0579f8261ea281af3eb59da28 (diff) |
Key required properties by object and property data
Property data alone is not enough as the same property can be required
in multiple objects.
Fixes: QTBUG-108291
Change-Id: I3b1c899e24bb2967d05372701f9b5d0927b3c711
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
-rw-r--r-- | src/qml/qml/qqmlcomponent.cpp | 4 | ||||
-rw-r--r-- | src/qml/qml/qqmlcomponent_p.h | 9 | ||||
-rw-r--r-- | src/qml/qml/qqmlobjectcreator.cpp | 11 | ||||
-rw-r--r-- | src/qml/qml/qqmlobjectcreator_p.h | 25 | ||||
-rw-r--r-- | tests/auto/qml/qqmllanguage/data/multiRequired.qml | 12 | ||||
-rw-r--r-- | tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp | 13 |
6 files changed, 63 insertions, 11 deletions
diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp index 0ee74cdd19..657c978c23 100644 --- a/src/qml/qml/qqmlcomponent.cpp +++ b/src/qml/qml/qqmlcomponent.cpp @@ -1036,7 +1036,7 @@ QObject *QQmlComponentPrivate::beginCreate(QQmlRefPointer<QQmlContextData> conte state.ensureRequiredPropertyStorage(); RequiredPropertyInfo info; info.propertyName = propertyData->name(rv); - state.addPendingRequiredProperty(propertyData, info); + state.addPendingRequiredProperty(rv, propertyData, info); } } } @@ -1147,7 +1147,7 @@ QQmlProperty QQmlComponentPrivate::removePropertyFromRequired( Q_ASSERT(data && data->propertyCache); targetProp = data->propertyCache->property(targetProp->coreIndex()); } - auto it = requiredProperties->find(targetProp); + auto it = requiredProperties->find({createdComponent, targetProp}); if (it != requiredProperties->end()) { if (wasInRequiredProperties) *wasInRequiredProperties = true; diff --git a/src/qml/qml/qqmlcomponent_p.h b/src/qml/qml/qqmlcomponent_p.h index 2cebd54232..d76e1c24a3 100644 --- a/src/qml/qml/qqmlcomponent_p.h +++ b/src/qml/qml/qqmlcomponent_p.h @@ -110,7 +110,9 @@ public: inline void ensureRequiredPropertyStorage(); inline RequiredProperties *requiredProperties(); - inline void addPendingRequiredProperty(const QQmlPropertyData *propData, const RequiredPropertyInfo &info); + inline void addPendingRequiredProperty( + const QObject *object, const QQmlPropertyData *propData, + const RequiredPropertyInfo &info); inline bool hasUnsetRequiredProperties() const; inline void clearRequiredProperties(); @@ -193,10 +195,11 @@ inline RequiredProperties *QQmlComponentPrivate::ConstructionState::requiredProp return m_creatorOrRequiredProperties.asT2(); } -inline void QQmlComponentPrivate::ConstructionState::addPendingRequiredProperty(const QQmlPropertyData *propData, const RequiredPropertyInfo &info) +inline void QQmlComponentPrivate::ConstructionState::addPendingRequiredProperty( + const QObject *object, const QQmlPropertyData *propData, const RequiredPropertyInfo &info) { Q_ASSERT(requiredProperties()); - requiredProperties()->insert(propData, info); + requiredProperties()->insert({object, propData}, info); } inline bool QQmlComponentPrivate::ConstructionState::hasUnsetRequiredProperties() const { diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp index b85a6c1220..b000a10b13 100644 --- a/src/qml/qml/qqmlobjectcreator.cpp +++ b/src/qml/qml/qqmlobjectcreator.cpp @@ -694,8 +694,9 @@ void QQmlObjectCreator::setupBindings(BindingSetupFlags mode) QQmlData *data = QQmlData::get(targetObject); Q_ASSERT(data && data->propertyCache); targetProperty = data->propertyCache->property(targetIndex.coreIndex()); + sharedState->requiredProperties.remove({targetObject, targetProperty}); } - sharedState->requiredProperties.remove(targetProperty); + sharedState->requiredProperties.remove({_bindingTarget, property}); } @@ -1563,7 +1564,7 @@ bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject * postHocRequired.erase(postHocIt); if (isContextObject) sharedState->hadTopLevelRequiredProperties = true; - sharedState->requiredProperties.insert(propertyData, + sharedState->requiredProperties.insert({_qobject, propertyData}, RequiredPropertyInfo {compilationUnit->stringAt(property->nameIndex), compilationUnit->finalUrl(), property->location, {}}); } @@ -1623,7 +1624,7 @@ bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject * if (isContextObject) sharedState->hadTopLevelRequiredProperties = true; sharedState->requiredProperties.insert( - propertyData, + {_qobject, propertyData}, RequiredPropertyInfo { name, compilationUnit->finalUrl(), _compiledObject->location, {} }); } @@ -1654,7 +1655,7 @@ bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject * if (isContextObject) sharedState->hadTopLevelRequiredProperties = true; sharedState->requiredProperties.insert( - propertyData, + {_qobject, propertyData}, RequiredPropertyInfo { name, compilationUnit->finalUrl(), _compiledObject->location, {} }); } @@ -1687,7 +1688,7 @@ bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject * const QQmlPropertyData *const targetProperty = targetDData->propertyCache->property(coreIndex); if (!targetProperty) continue; - auto it = sharedState->requiredProperties.find(targetProperty); + auto it = sharedState->requiredProperties.find({target, targetProperty}); if (it != sharedState->requiredProperties.end()) it->aliasesToRequired.push_back( AliasToRequiredInfo { diff --git a/src/qml/qml/qqmlobjectcreator_p.h b/src/qml/qml/qqmlobjectcreator_p.h index 2371facc0a..c951072dd5 100644 --- a/src/qml/qml/qqmlobjectcreator_p.h +++ b/src/qml/qml/qqmlobjectcreator_p.h @@ -53,7 +53,30 @@ struct RequiredPropertyInfo QVector<AliasToRequiredInfo> aliasesToRequired; }; -class RequiredProperties : public QHash<const QQmlPropertyData *, RequiredPropertyInfo> {}; +struct RequiredPropertyKey +{ + RequiredPropertyKey() = default; + RequiredPropertyKey(const QObject *object, const QQmlPropertyData *data) + : object(object) + , data(data) + {} + + const QObject *object = nullptr; + const QQmlPropertyData *data = nullptr; + +private: + friend size_t qHash(const RequiredPropertyKey &key, size_t seed = 0) + { + return qHashMulti(seed, key.object, key.data); + } + + friend bool operator==(const RequiredPropertyKey &a, const RequiredPropertyKey &b) + { + return a.object == b.object && a.data == b.data; + } +}; + +class RequiredProperties : public QHash<RequiredPropertyKey, RequiredPropertyInfo> {}; struct DeferredQPropertyBinding { QObject *target = nullptr; diff --git a/tests/auto/qml/qqmllanguage/data/multiRequired.qml b/tests/auto/qml/qqmllanguage/data/multiRequired.qml new file mode 100644 index 0000000000..442a4d226a --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/multiRequired.qml @@ -0,0 +1,12 @@ +import QtQml + +QtObject { + component AccessibleButton : QtObject { + required property string description + objectName: description + } + property AccessibleButton a: AccessibleButton {} + property AccessibleButton b: AccessibleButton { + description: "b" + } +} diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp index 6884826894..948b3b1bc3 100644 --- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp +++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp @@ -401,6 +401,7 @@ private slots: void functionSignatureEnforcement(); void importPrecedence(); void nullIsNull(); + void multiRequired(); private: QQmlEngine engine; @@ -7740,6 +7741,18 @@ void tst_qqmllanguage::nullIsNull() QTRY_COMPARE(o->property("someProperty").value<QObject*>(), nullptr); } +void tst_qqmllanguage::multiRequired() +{ + QQmlEngine engine; + const QUrl url = testFileUrl("multiRequired.qml"); + QQmlComponent c(&engine, url); + QVERIFY2(c.isReady(), qPrintable(c.errorString())); + QScopedPointer<QObject> o(c.create()); + QVERIFY(o.isNull()); + QCOMPARE(c.errorString(), + qPrintable(url.toString() + ":5 Required property description was not initialized\n")); +} + QTEST_MAIN(tst_qqmllanguage) #include "tst_qqmllanguage.moc" |