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();
|
state.ensureRequiredPropertyStorage();
|
||||||
RequiredPropertyInfo info;
|
RequiredPropertyInfo info;
|
||||||
info.propertyName = propertyData->name(rv);
|
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);
|
Q_ASSERT(data && data->propertyCache);
|
||||||
targetProp = data->propertyCache->property(targetProp->coreIndex());
|
targetProp = data->propertyCache->property(targetProp->coreIndex());
|
||||||
}
|
}
|
||||||
auto it = requiredProperties->find(targetProp);
|
auto it = requiredProperties->find({createdComponent, targetProp});
|
||||||
if (it != requiredProperties->end()) {
|
if (it != requiredProperties->end()) {
|
||||||
if (wasInRequiredProperties)
|
if (wasInRequiredProperties)
|
||||||
*wasInRequiredProperties = true;
|
*wasInRequiredProperties = true;
|
||||||
|
|
|
@ -110,7 +110,9 @@ public:
|
||||||
|
|
||||||
inline void ensureRequiredPropertyStorage();
|
inline void ensureRequiredPropertyStorage();
|
||||||
inline RequiredProperties *requiredProperties();
|
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 bool hasUnsetRequiredProperties() const;
|
||||||
inline void clearRequiredProperties();
|
inline void clearRequiredProperties();
|
||||||
|
|
||||||
|
@ -193,10 +195,11 @@ inline RequiredProperties *QQmlComponentPrivate::ConstructionState::requiredProp
|
||||||
return m_creatorOrRequiredProperties.asT2();
|
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());
|
Q_ASSERT(requiredProperties());
|
||||||
requiredProperties()->insert(propData, info);
|
requiredProperties()->insert({object, propData}, info);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool QQmlComponentPrivate::ConstructionState::hasUnsetRequiredProperties() const {
|
inline bool QQmlComponentPrivate::ConstructionState::hasUnsetRequiredProperties() const {
|
||||||
|
|
|
@ -694,8 +694,9 @@ void QQmlObjectCreator::setupBindings(BindingSetupFlags mode)
|
||||||
QQmlData *data = QQmlData::get(targetObject);
|
QQmlData *data = QQmlData::get(targetObject);
|
||||||
Q_ASSERT(data && data->propertyCache);
|
Q_ASSERT(data && data->propertyCache);
|
||||||
targetProperty = data->propertyCache->property(targetIndex.coreIndex());
|
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);
|
postHocRequired.erase(postHocIt);
|
||||||
if (isContextObject)
|
if (isContextObject)
|
||||||
sharedState->hadTopLevelRequiredProperties = true;
|
sharedState->hadTopLevelRequiredProperties = true;
|
||||||
sharedState->requiredProperties.insert(propertyData,
|
sharedState->requiredProperties.insert({_qobject, propertyData},
|
||||||
RequiredPropertyInfo {compilationUnit->stringAt(property->nameIndex), compilationUnit->finalUrl(), property->location, {}});
|
RequiredPropertyInfo {compilationUnit->stringAt(property->nameIndex), compilationUnit->finalUrl(), property->location, {}});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1623,7 +1624,7 @@ bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject *
|
||||||
if (isContextObject)
|
if (isContextObject)
|
||||||
sharedState->hadTopLevelRequiredProperties = true;
|
sharedState->hadTopLevelRequiredProperties = true;
|
||||||
sharedState->requiredProperties.insert(
|
sharedState->requiredProperties.insert(
|
||||||
propertyData,
|
{_qobject, propertyData},
|
||||||
RequiredPropertyInfo {
|
RequiredPropertyInfo {
|
||||||
name, compilationUnit->finalUrl(), _compiledObject->location, {} });
|
name, compilationUnit->finalUrl(), _compiledObject->location, {} });
|
||||||
}
|
}
|
||||||
|
@ -1654,7 +1655,7 @@ bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject *
|
||||||
if (isContextObject)
|
if (isContextObject)
|
||||||
sharedState->hadTopLevelRequiredProperties = true;
|
sharedState->hadTopLevelRequiredProperties = true;
|
||||||
sharedState->requiredProperties.insert(
|
sharedState->requiredProperties.insert(
|
||||||
propertyData,
|
{_qobject, propertyData},
|
||||||
RequiredPropertyInfo {
|
RequiredPropertyInfo {
|
||||||
name, compilationUnit->finalUrl(), _compiledObject->location, {} });
|
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);
|
const QQmlPropertyData *const targetProperty = targetDData->propertyCache->property(coreIndex);
|
||||||
if (!targetProperty)
|
if (!targetProperty)
|
||||||
continue;
|
continue;
|
||||||
auto it = sharedState->requiredProperties.find(targetProperty);
|
auto it = sharedState->requiredProperties.find({target, targetProperty});
|
||||||
if (it != sharedState->requiredProperties.end())
|
if (it != sharedState->requiredProperties.end())
|
||||||
it->aliasesToRequired.push_back(
|
it->aliasesToRequired.push_back(
|
||||||
AliasToRequiredInfo {
|
AliasToRequiredInfo {
|
||||||
|
|
|
@ -53,7 +53,30 @@ struct RequiredPropertyInfo
|
||||||
QVector<AliasToRequiredInfo> aliasesToRequired;
|
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 {
|
struct DeferredQPropertyBinding {
|
||||||
QObject *target = nullptr;
|
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 functionSignatureEnforcement();
|
||||||
void importPrecedence();
|
void importPrecedence();
|
||||||
void nullIsNull();
|
void nullIsNull();
|
||||||
|
void multiRequired();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QQmlEngine engine;
|
QQmlEngine engine;
|
||||||
|
@ -7740,6 +7741,18 @@ void tst_qqmllanguage::nullIsNull()
|
||||||
QTRY_COMPARE(o->property("someProperty").value<QObject*>(), nullptr);
|
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)
|
QTEST_MAIN(tst_qqmllanguage)
|
||||||
|
|
||||||
#include "tst_qqmllanguage.moc"
|
#include "tst_qqmllanguage.moc"
|
||||||
|
|
Loading…
Reference in New Issue