From 7d7e8ae3fa79b06c916de1a7a10eed63611c5d25 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Sat, 14 Sep 2013 13:18:15 +0200 Subject: [PATCH] Use Q_STATIC_ASSERT to report error about missing Q_OBJECT Q_STATIC_ASSERT gives better error with C++11 enabled. Aslo the qt_check_for_QOBJECT_macro had warning on some compiler since it used null reference Change-Id: Ic6115da800064b00c50a5762f0b79f5f656bf750 Reviewed-by: Thiago Macieira --- src/corelib/kernel/qmetaobject.h | 4 +-- src/corelib/kernel/qobject.h | 26 +++++++++++++------ src/corelib/kernel/qobject_impl.h | 1 - src/corelib/kernel/qobject_p.h | 6 +++-- src/corelib/kernel/qobjectdefs.h | 10 +++++++ .../corelib/kernel/qobject/tst_qobject.cpp | 4 +++ 6 files changed, 38 insertions(+), 13 deletions(-) diff --git a/src/corelib/kernel/qmetaobject.h b/src/corelib/kernel/qmetaobject.h index 0c8ad8591f..818613195d 100644 --- a/src/corelib/kernel/qmetaobject.h +++ b/src/corelib/kernel/qmetaobject.h @@ -148,8 +148,8 @@ public: static inline QMetaMethod fromSignal(Func signal) { typedef QtPrivate::FunctionPointer SignalType; - reinterpret_cast(0)->qt_check_for_QOBJECT_macro( - *reinterpret_cast(0)); + Q_STATIC_ASSERT_X(QtPrivate::HasQ_OBJECT_Macro::Value, + "No Q_OBJECT in the class with the signal"); return fromSignalImpl(&SignalType::Object::staticMetaObject, reinterpret_cast(&signal)); } diff --git a/src/corelib/kernel/qobject.h b/src/corelib/kernel/qobject.h index aaa09fac50..9d49bf26d2 100644 --- a/src/corelib/kernel/qobject.h +++ b/src/corelib/kernel/qobject.h @@ -217,7 +217,9 @@ public: { typedef QtPrivate::FunctionPointer SignalType; typedef QtPrivate::FunctionPointer SlotType; - reinterpret_cast(0)->qt_check_for_QOBJECT_macro(*reinterpret_cast(0)); + + Q_STATIC_ASSERT_X(QtPrivate::HasQ_OBJECT_Macro::Value, + "No Q_OBJECT in the class with the signal"); //compilation error if the arguments does not match. Q_STATIC_ASSERT_X(int(SignalType::ArgumentCount) >= int(SlotType::ArgumentCount), @@ -246,6 +248,9 @@ public: typedef QtPrivate::FunctionPointer SignalType; typedef QtPrivate::FunctionPointer SlotType; + Q_STATIC_ASSERT_X(QtPrivate::HasQ_OBJECT_Macro::Value, + "No Q_OBJECT in the class with the signal"); + //compilation error if the arguments does not match. Q_STATIC_ASSERT_X(int(SignalType::ArgumentCount) >= int(SlotType::ArgumentCount), "The slot requires more arguments than the signal provides."); @@ -307,6 +312,9 @@ public: Q_STATIC_ASSERT_X((QtPrivate::AreArgumentsCompatible::value), "Return type of the slot is not compatible with the return type of the signal."); + Q_STATIC_ASSERT_X(QtPrivate::HasQ_OBJECT_Macro::Value, + "No Q_OBJECT in the class with the signal"); + return connectImpl(sender, reinterpret_cast(&signal), sender, 0, new QtPrivate::QFunctorSlotObject::Value, @@ -335,7 +343,9 @@ public: { typedef QtPrivate::FunctionPointer SignalType; typedef QtPrivate::FunctionPointer SlotType; - reinterpret_cast(0)->qt_check_for_QOBJECT_macro(*reinterpret_cast(0)); + + Q_STATIC_ASSERT_X(QtPrivate::HasQ_OBJECT_Macro::Value, + "No Q_OBJECT in the class with the signal"); //compilation error if the arguments does not match. Q_STATIC_ASSERT_X((QtPrivate::CheckCompatibleArguments::value), @@ -477,18 +487,18 @@ inline QT_DEPRECATED QList qFindChildren(const QObject *o, const QRegExp &re) template inline T qobject_cast(QObject *object) { -#if !defined(QT_NO_QOBJECT_CHECK) - reinterpret_cast(object)->qt_check_for_QOBJECT_macro(*reinterpret_cast(object)); -#endif + typedef typename QtPrivate::remove_cv::type>::type ObjType; + Q_STATIC_ASSERT_X(QtPrivate::HasQ_OBJECT_Macro::Value, + "qobject_cast require the type to have a Q_OBJECT macro"); return static_cast(reinterpret_cast(object)->staticMetaObject.cast(object)); } template inline T qobject_cast(const QObject *object) { -#if !defined(QT_NO_QOBJECT_CHECK) - reinterpret_cast(object)->qt_check_for_QOBJECT_macro(*reinterpret_cast(const_cast(object))); -#endif + typedef typename QtPrivate::remove_cv::type>::type ObjType; + Q_STATIC_ASSERT_X(QtPrivate::HasQ_OBJECT_Macro::Value, + "qobject_cast require the type to have a Q_OBJECT macro"); return static_cast(reinterpret_cast(object)->staticMetaObject.cast(object)); } diff --git a/src/corelib/kernel/qobject_impl.h b/src/corelib/kernel/qobject_impl.h index 0b5631f2a6..1bbd548be6 100644 --- a/src/corelib/kernel/qobject_impl.h +++ b/src/corelib/kernel/qobject_impl.h @@ -204,7 +204,6 @@ namespace QtPrivate { public: explicit QFunctorSlotObject(const Func &f) : QSlotObjectBase(&impl), function(f) {} }; - } diff --git a/src/corelib/kernel/qobject_p.h b/src/corelib/kernel/qobject_p.h index 3c43972ac9..562b0d24c7 100644 --- a/src/corelib/kernel/qobject_p.h +++ b/src/corelib/kernel/qobject_p.h @@ -316,7 +316,8 @@ inline QMetaObject::Connection QObjectPrivate::connect(const typename QtPrivate: { typedef QtPrivate::FunctionPointer SignalType; typedef QtPrivate::FunctionPointer SlotType; - reinterpret_cast(0)->qt_check_for_QOBJECT_macro(*reinterpret_cast(0)); + Q_STATIC_ASSERT_X(QtPrivate::HasQ_OBJECT_Macro::Value, + "No Q_OBJECT in the class with the signal"); //compilation error if the arguments does not match. Q_STATIC_ASSERT_X(int(SignalType::ArgumentCount) >= int(SlotType::ArgumentCount), @@ -343,7 +344,8 @@ bool QObjectPrivate::disconnect(const typename QtPrivate::FunctionPointer< Func1 { typedef QtPrivate::FunctionPointer SignalType; typedef QtPrivate::FunctionPointer SlotType; - reinterpret_cast(0)->qt_check_for_QOBJECT_macro(*reinterpret_cast(0)); + Q_STATIC_ASSERT_X(QtPrivate::HasQ_OBJECT_Macro::Value, + "No Q_OBJECT in the class with the signal"); //compilation error if the arguments does not match. Q_STATIC_ASSERT_X((QtPrivate::CheckCompatibleArguments::value), "Signal and slot arguments are not compatible."); diff --git a/src/corelib/kernel/qobjectdefs.h b/src/corelib/kernel/qobjectdefs.h index dd10e70609..7354c3f0d0 100644 --- a/src/corelib/kernel/qobjectdefs.h +++ b/src/corelib/kernel/qobjectdefs.h @@ -480,6 +480,16 @@ public: inline const QMetaObject *QMetaObject::superClass() const { return d.superdata; } +namespace QtPrivate { + /* Trait that tells is a the Object has a Q_OBJECT macro */ + template struct HasQ_OBJECT_Macro { + template + static char test(int (T::*)(QMetaObject::Call, int, void **)); + static int test(int (Object::*)(QMetaObject::Call, int, void **)); + enum { Value = sizeof(test(&Object::qt_metacall)) == sizeof(int) }; + }; +} + QT_END_NAMESPACE #endif // QOBJECTDEFS_H diff --git a/tests/auto/corelib/kernel/qobject/tst_qobject.cpp b/tests/auto/corelib/kernel/qobject/tst_qobject.cpp index ff453d767b..081dc8a857 100644 --- a/tests/auto/corelib/kernel/qobject/tst_qobject.cpp +++ b/tests/auto/corelib/kernel/qobject/tst_qobject.cpp @@ -5931,5 +5931,9 @@ void tst_QObject::qmlConnect() #endif } +// Test for QtPrivate::HasQ_OBJECT_Macro +Q_STATIC_ASSERT(QtPrivate::HasQ_OBJECT_Macro::Value); +Q_STATIC_ASSERT(!QtPrivate::HasQ_OBJECT_Macro::Value); + QTEST_MAIN(tst_QObject) #include "tst_qobject.moc"