From 6b36e783521993df8de6477c789aa26c38803656 Mon Sep 17 00:00:00 2001 From: Fabian Kosmale Date: Thu, 17 Jun 2021 12:33:54 +0200 Subject: QBindable: Use setter in setValue for QObjectCompatProperty Directly writing to the underlying property storage has the potential of breaking all kinds of internal invariants. As we return QBindable in the public interface, we should not grant callers access to the internals of the object. Pick-to: 6.2 6.1 Change-Id: I737ff293b9d921b7de861da5ae23356c17690b78 Reviewed-by: Ulf Hermann Reviewed-by: Andreas Buhr --- src/corelib/kernel/qproperty_p.h | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'src') diff --git a/src/corelib/kernel/qproperty_p.h b/src/corelib/kernel/qproperty_p.h index e92c8f878a..2883308299 100644 --- a/src/corelib/kernel/qproperty_p.h +++ b/src/corelib/kernel/qproperty_p.h @@ -396,6 +396,9 @@ namespace QtPrivate { template class QObjectCompatProperty : public QPropertyData { + template + friend class QtPrivate::QBindableInterfaceForProperty; + using ThisType = QObjectCompatProperty; using SignalTakesValue = std::is_invocable; Class *owner() @@ -408,6 +411,7 @@ class QObjectCompatProperty : public QPropertyData char *that = const_cast(reinterpret_cast(this)); return reinterpret_cast(that - QtPrivate::detail::getOffset(Offset)); } + static bool bindingWrapper(QMetaType type, QUntypedPropertyData *dataPtr, QtPrivate::QPropertyBindingFunction binding) { auto *thisData = static_cast(dataPtr); @@ -591,6 +595,33 @@ private: } }; +namespace QtPrivate { +template +class QBindableInterfaceForProperty, std::void_t> +{ + using Property = QObjectCompatProperty; + using T = typename Property::value_type; +public: + static constexpr QBindableInterface iface = { + [](const QUntypedPropertyData *d, void *value) -> void + { *static_cast(value) = static_cast(d)->value(); }, + [](QUntypedPropertyData *d, const void *value) -> void + { + (static_cast(d)->owner()->*Setter)(*static_cast(value)); + }, + [](const QUntypedPropertyData *d) -> QUntypedPropertyBinding + { return static_cast(d)->binding(); }, + [](QUntypedPropertyData *d, const QUntypedPropertyBinding &binding) -> QUntypedPropertyBinding + { return static_cast(d)->setBinding(static_cast &>(binding)); }, + [](const QUntypedPropertyData *d, const QPropertyBindingSourceLocation &location) -> QUntypedPropertyBinding + { return Qt::makePropertyBinding([d]() -> T { return static_cast(d)->value(); }, location); }, + [](const QUntypedPropertyData *d, QPropertyObserver *observer) -> void + { observer->setSource(static_cast(d)->bindingData()); }, + []() { return QMetaType::fromType(); } + }; +}; +} + #define QT_OBJECT_COMPAT_PROPERTY_4(Class, Type, name, setter) \ static constexpr size_t _qt_property_##name##_offset() { \ QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF \ -- cgit v1.2.3