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>
This commit is contained in:
parent
6acf343acb
commit
b6ba7e9c90
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
|
@ -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"
|
||||
|
|
Loading…
Reference in New Issue