summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVolker Hilsheimer <volker.hilsheimer@qt.io>2023-03-06 18:32:40 +0100
committerQt Cherry-pick Bot <cherrypick_bot@qt-project.org>2023-03-10 16:40:50 +0000
commitf4b1a9b8bdfc50166c0773ccfee0f6f2c0e4a16f (patch)
treed02edd4210935b0fd6ef7feaf0ed4ca80d482bf3
parentae3046258521dd0bb0580afa9ed1c50794a49009 (diff)
downloadqtbase-f4b1a9b8bdfc50166c0773ccfee0f6f2c0e4a16f.tar.gz
Make it possible to use QObjectPrivate::connect in private code
In most QObjectPrivate-subclasses, the Q_DECLARE_PUBLIC macro is used in the private segment of the class declaration. In that case, the q_ptr becomes a private member of the private class, and then the QObjectPrivate::connect function can no longer be used, as it needs to access the d_ptr. Fix this by declaring QObjectPrivate, and the static-assert-helper, as friends of the class using the Q_DECLARE_PUBLIC macro. Adapt the QObject test by moving the Q_DECLARE_PUBLIC macro into the private section of the test-private, and add a compile test. Change-Id: Ifc04be3b305221e138b1e08bb3a3838d871f4fcb Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Axel Spoerl <axel.spoerl@qt.io> Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io> (cherry picked from commit 4f02973e2f447dfc92234ec247d7157ea0e1e807) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
-rw-r--r--src/corelib/global/qtclasshelpermacros.h11
-rw-r--r--src/corelib/kernel/qobject_p.h3
-rw-r--r--tests/auto/corelib/kernel/qobject/tst_qobject.cpp14
3 files changed, 24 insertions, 4 deletions
diff --git a/src/corelib/global/qtclasshelpermacros.h b/src/corelib/global/qtclasshelpermacros.h
index e6b66ed5f2..8839e80fb9 100644
--- a/src/corelib/global/qtclasshelpermacros.h
+++ b/src/corelib/global/qtclasshelpermacros.h
@@ -78,6 +78,13 @@ template <typename T> inline T *qGetPtrHelper(T *ptr) noexcept { return ptr; }
template <typename Ptr> inline auto qGetPtrHelper(Ptr &ptr) noexcept -> decltype(ptr.get())
{ static_assert(noexcept(ptr.get()), "Smart d pointers for Q_DECLARE_PRIVATE must have noexcept get()"); return ptr.get(); }
+class QObject;
+class QObjectPrivate;
+namespace QtPrivate {
+ template <typename ObjPrivate> void assertObjectType(QObjectPrivate *d);
+ inline const QObject *getQObject(const QObjectPrivate *d);
+}
+
#define Q_DECLARE_PRIVATE(Class) \
inline Class##Private* d_func() noexcept \
{ Q_CAST_IGNORE_ALIGN(return reinterpret_cast<Class##Private *>(qGetPtrHelper(d_ptr));) } \
@@ -95,7 +102,9 @@ template <typename Ptr> inline auto qGetPtrHelper(Ptr &ptr) noexcept -> decltype
#define Q_DECLARE_PUBLIC(Class) \
inline Class* q_func() noexcept { return static_cast<Class *>(q_ptr); } \
inline const Class* q_func() const noexcept { return static_cast<const Class *>(q_ptr); } \
- friend class Class;
+ friend class Class; \
+ friend const QObject *QtPrivate::getQObject(const QObjectPrivate *d); \
+ template <typename ObjPrivate> friend void QtPrivate::assertObjectType(QObjectPrivate *d);
#define Q_D(Class) Class##Private * const d = d_func()
#define Q_Q(Class) Class * const q = q_func()
diff --git a/src/corelib/kernel/qobject_p.h b/src/corelib/kernel/qobject_p.h
index dbb4eb2326..ccd807da99 100644
--- a/src/corelib/kernel/qobject_p.h
+++ b/src/corelib/kernel/qobject_p.h
@@ -243,6 +243,7 @@ inline void QObjectPrivate::disconnectNotify(const QMetaMethod &signal)
}
namespace QtPrivate {
+inline const QObject *getQObject(const QObjectPrivate *d) { return d->q_func(); }
template <typename Func>
struct FunctionStorageByValue
@@ -322,7 +323,7 @@ inline QMetaObject::Connection QObjectPrivate::connect(const typename QtPrivate:
types = QtPrivate::ConnectionTypes<typename SignalType::Arguments>::types();
return QObject::connectImpl(sender, reinterpret_cast<void **>(&signal),
- receiverPrivate->q_ptr, reinterpret_cast<void **>(&slot),
+ QtPrivate::getQObject(receiverPrivate), reinterpret_cast<void **>(&slot),
new QtPrivate::QPrivateSlotObject<Func2, typename QtPrivate::List_Left<typename SignalType::Arguments, SlotType::ArgumentCount>::Value,
typename SignalType::ReturnType>(slot),
type, types, &SignalType::Object::staticMetaObject);
diff --git a/tests/auto/corelib/kernel/qobject/tst_qobject.cpp b/tests/auto/corelib/kernel/qobject/tst_qobject.cpp
index 1b678d8851..0877637a50 100644
--- a/tests/auto/corelib/kernel/qobject/tst_qobject.cpp
+++ b/tests/auto/corelib/kernel/qobject/tst_qobject.cpp
@@ -5982,15 +5982,15 @@ class ConnectToPrivateSlotPrivate;
class ConnectToPrivateSlot :public QObject {
Q_OBJECT
+ Q_DECLARE_PRIVATE(ConnectToPrivateSlot)
public:
ConnectToPrivateSlot();
void test(SenderObject *obj1) ;
- Q_DECLARE_PRIVATE(ConnectToPrivateSlot)
};
class ConnectToPrivateSlotPrivate : public QObjectPrivate {
-public:
Q_DECLARE_PUBLIC(ConnectToPrivateSlot)
+public:
int receivedCount;
QVariant receivedValue;
@@ -6002,6 +6002,8 @@ public:
receivedCount++;
receivedValue = v;
};
+
+ void testFromPrivate(SenderObject *obj);
};
ConnectToPrivateSlot::ConnectToPrivateSlot(): QObject(*new ConnectToPrivateSlotPrivate) {}
@@ -6028,6 +6030,14 @@ void ConnectToPrivateSlot::test(SenderObject* obj1) {
QVERIFY(!QObjectPrivate::disconnect(obj1, &SenderObject::signal2, d, &ConnectToPrivateSlotPrivate::thisIsAPrivateSlot));
}
+// Compile test to verify that we can use QObjectPrivate::connect in
+// the code of the private class, even if Q_DECLARE_PUBLIC is used in the
+// private section of the private class.
+void ConnectToPrivateSlotPrivate::testFromPrivate(SenderObject *obj)
+{
+ QVERIFY(QObjectPrivate::connect(obj, &SenderObject::signal1, this, &ConnectToPrivateSlotPrivate::thisIsAPrivateSlot));
+}
+
void tst_QObject::connectPrivateSlots()
{
SenderObject sender;