summaryrefslogtreecommitdiffstats
path: root/src/corelib
diff options
context:
space:
mode:
authorFabian Kosmale <fabian.kosmale@qt.io>2021-06-17 12:33:54 +0200
committerFabian Kosmale <fabian.kosmale@qt.io>2021-06-17 19:32:56 +0200
commit6b36e783521993df8de6477c789aa26c38803656 (patch)
tree72a0e60c5e65742271c564d1cb4d11d54910daca /src/corelib
parent8aee7c6b29be5a0ee7d5e7cfcb5f2db762b2e28b (diff)
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 <ulf.hermann@qt.io> Reviewed-by: Andreas Buhr <andreas.buhr@qt.io>
Diffstat (limited to 'src/corelib')
-rw-r--r--src/corelib/kernel/qproperty_p.h31
1 files changed, 31 insertions, 0 deletions
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<typename Class, typename T, auto Offset, auto Setter, auto Signal=nullptr>
class QObjectCompatProperty : public QPropertyData<T>
{
+ template<typename Property, typename>
+ friend class QtPrivate::QBindableInterfaceForProperty;
+
using ThisType = QObjectCompatProperty<Class, T, Offset, Setter, Signal>;
using SignalTakesValue = std::is_invocable<decltype(Signal), Class, T>;
Class *owner()
@@ -408,6 +411,7 @@ class QObjectCompatProperty : public QPropertyData<T>
char *that = const_cast<char *>(reinterpret_cast<const char *>(this));
return reinterpret_cast<Class *>(that - QtPrivate::detail::getOffset(Offset));
}
+
static bool bindingWrapper(QMetaType type, QUntypedPropertyData *dataPtr, QtPrivate::QPropertyBindingFunction binding)
{
auto *thisData = static_cast<ThisType *>(dataPtr);
@@ -591,6 +595,33 @@ private:
}
};
+namespace QtPrivate {
+template<typename Class, typename Ty, auto Offset, auto Setter, auto Signal>
+class QBindableInterfaceForProperty<QObjectCompatProperty<Class, Ty, Offset, Setter, Signal>, std::void_t<Class>>
+{
+ using Property = QObjectCompatProperty<Class, Ty, Offset, Setter, Signal>;
+ using T = typename Property::value_type;
+public:
+ static constexpr QBindableInterface iface = {
+ [](const QUntypedPropertyData *d, void *value) -> void
+ { *static_cast<T*>(value) = static_cast<const Property *>(d)->value(); },
+ [](QUntypedPropertyData *d, const void *value) -> void
+ {
+ (static_cast<Property *>(d)->owner()->*Setter)(*static_cast<const T*>(value));
+ },
+ [](const QUntypedPropertyData *d) -> QUntypedPropertyBinding
+ { return static_cast<const Property *>(d)->binding(); },
+ [](QUntypedPropertyData *d, const QUntypedPropertyBinding &binding) -> QUntypedPropertyBinding
+ { return static_cast<Property *>(d)->setBinding(static_cast<const QPropertyBinding<T> &>(binding)); },
+ [](const QUntypedPropertyData *d, const QPropertyBindingSourceLocation &location) -> QUntypedPropertyBinding
+ { return Qt::makePropertyBinding([d]() -> T { return static_cast<const Property *>(d)->value(); }, location); },
+ [](const QUntypedPropertyData *d, QPropertyObserver *observer) -> void
+ { observer->setSource(static_cast<const Property *>(d)->bindingData()); },
+ []() { return QMetaType::fromType<T>(); }
+ };
+};
+}
+
#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 \