1// Copyright (C) 2022 The Qt Company Ltd.
2// Copyright (C) 2019 Intel Corporation.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
5#ifndef QOBJECTDEFS_H
6#define QOBJECTDEFS_H
7
8#if defined(__OBJC__) && !defined(__cplusplus)
9# warning "File built in Objective-C mode (.m), but using Qt requires Objective-C++ (.mm)"
10#endif
11
12#include <QtCore/qnamespace.h>
13#include <QtCore/qobjectdefs_impl.h>
14#include <QtCore/qtmetamacros.h>
15
16QT_BEGIN_NAMESPACE
17
18class QByteArray;
19struct QArrayData;
20
21class QString;
22
23#ifndef QT_NO_META_MACROS
24// macro for onaming members
25#ifdef METHOD
26#undef METHOD
27#endif
28#ifdef SLOT
29#undef SLOT
30#endif
31#ifdef SIGNAL
32#undef SIGNAL
33#endif
34#endif // QT_NO_META_MACROS
35
36Q_CORE_EXPORT const char *qFlagLocation(const char *method);
37
38#ifndef QT_NO_META_MACROS
39# define QMETHOD_CODE 0 // member type codes
40# define QSLOT_CODE 1
41# define QSIGNAL_CODE 2
42# define QT_PREFIX_CODE(code, a) QT_STRINGIFY(code) #a
43# define QT_STRINGIFY_METHOD(a) QT_PREFIX_CODE(QMETHOD_CODE, a)
44# define QT_STRINGIFY_SLOT(a) QT_PREFIX_CODE(QSLOT_CODE, a)
45# define QT_STRINGIFY_SIGNAL(a) QT_PREFIX_CODE(QSIGNAL_CODE, a)
46# ifndef QT_NO_DEBUG
47# define QLOCATION "\0" __FILE__ ":" QT_STRINGIFY(__LINE__)
48# ifndef QT_NO_KEYWORDS
49# define METHOD(a) qFlagLocation(QT_STRINGIFY_METHOD(a) QLOCATION)
50# endif
51# define SLOT(a) qFlagLocation(QT_STRINGIFY_SLOT(a) QLOCATION)
52# define SIGNAL(a) qFlagLocation(QT_STRINGIFY_SIGNAL(a) QLOCATION)
53# else
54# ifndef QT_NO_KEYWORDS
55# define METHOD(a) QT_STRINGIFY_METHOD(a)
56# endif
57# define SLOT(a) QT_STRINGIFY_SLOT(a)
58# define SIGNAL(a) QT_STRINGIFY_SIGNAL(a)
59# endif
60#endif // QT_NO_META_MACROS
61
62#define Q_ARG(Type, data) QtPrivate::Invoke::argument<Type>(QT_STRINGIFY(Type), data)
63#define Q_RETURN_ARG(Type, data) QtPrivate::Invoke::returnArgument<Type>(QT_STRINGIFY(Type), data)
64
65class QObject;
66class QMetaMethod;
67class QMetaEnum;
68class QMetaProperty;
69class QMetaClassInfo;
70
71namespace QtPrivate {
72class QMetaTypeInterface;
73template<typename T> constexpr const QMetaTypeInterface *qMetaTypeInterfaceForType();
74}
75
76struct QMethodRawArguments
77{
78 void **arguments;
79};
80
81#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
82class Q_CORE_EXPORT QGenericArgument
83{
84public:
85 inline QGenericArgument(const char *aName = nullptr, const void *aData = nullptr)
86 : _data(aData), _name(aName) {}
87 inline void *data() const { return const_cast<void *>(_data); }
88 inline const char *name() const { return _name; }
89
90private:
91 const void *_data;
92 const char *_name;
93};
94
95class Q_CORE_EXPORT QGenericReturnArgument: public QGenericArgument
96{
97public:
98 inline QGenericReturnArgument(const char *aName = nullptr, void *aData = nullptr)
99 : QGenericArgument(aName, aData)
100 {}
101};
102
103template <class T>
104class QArgument: public QGenericArgument
105{
106public:
107 inline QArgument(const char *aName, const T &aData)
108 : QGenericArgument(aName, static_cast<const void *>(&aData))
109 {}
110};
111template <class T>
112class QArgument<T &>: public QGenericArgument
113{
114public:
115 inline QArgument(const char *aName, T &aData)
116 : QGenericArgument(aName, static_cast<const void *>(&aData))
117 {}
118};
119
120
121template <typename T>
122class QReturnArgument: public QGenericReturnArgument
123{
124public:
125 inline QReturnArgument(const char *aName, T &aData)
126 : QGenericReturnArgument(aName, static_cast<void *>(&aData))
127 {}
128};
129#endif
130
131struct QMetaMethodArgument
132{
133 const QtPrivate::QMetaTypeInterface *metaType;
134 const char *name;
135 const void *data;
136};
137
138struct QMetaMethodReturnArgument
139{
140 const QtPrivate::QMetaTypeInterface *metaType;
141 const char *name;
142 void *data;
143};
144
145namespace QtPrivate {
146namespace Invoke {
147#if QT_VERSION <= QT_VERSION_CHECK(7, 0, 0)
148template <typename... Args>
149using AreOldStyleArgs = std::disjunction<std::is_base_of<QGenericArgument, Args>...>;
150
151template <typename T, typename... Args> using IfNotOldStyleArgs =
152 std::enable_if_t<!AreOldStyleArgs<Args...>::value, T>;
153#else
154template <typename T, typename... Args> using IfNotOldStyleArgs = T;
155#endif
156
157template <typename T> inline QMetaMethodArgument argument(const char *name, const T &t)
158{
159 if constexpr ((std::is_lvalue_reference_v<T> && std::is_const_v<std::remove_reference_t<T>>) ||
160 !std::is_reference_v<T>) {
161 return { qMetaTypeInterfaceForType<T>(), name, std::addressof(t) };
162 } else {
163 return { nullptr, name, std::addressof(t) };
164 }
165}
166
167template <typename T> inline QMetaMethodReturnArgument returnArgument(const char *name, T &t)
168{
169 return { qMetaTypeInterfaceForType<T>(), name, std::addressof(t) };
170}
171
172template <typename T> inline const char *typenameHelper(const T &)
173{
174 return nullptr;
175}
176template <typename T> inline const void *dataHelper(const T &t)
177{
178 return std::addressof(t);
179}
180template <typename T> inline const QMetaTypeInterface *metaTypeHelper(const T &)
181{
182 return qMetaTypeInterfaceForType<T>();
183}
184
185inline const char *typenameHelper(QMetaMethodArgument a)
186{ return a.name; }
187inline const void *dataHelper(QMetaMethodArgument a)
188{ return a.data; }
189inline const QMetaTypeInterface *metaTypeHelper(QMetaMethodArgument a)
190{ return a.metaType; }
191
192inline const char *typenameHelper(const char *) = delete;
193template <typename T> inline const void *dataHelper(const char *) = delete;
194inline const QMetaTypeInterface *metaTypeHelper(const char *) = delete;
195inline const char *typenameHelper(const char16_t *) = delete;
196template <typename T> inline const void *dataHelper(const char16_t *) = delete;
197inline const QMetaTypeInterface *metaTypeHelper(const char16_t *) = delete;
198
199} // namespace QtPrivate::Invoke
200
201template <typename... Args> inline auto invokeMethodHelper(QMetaMethodReturnArgument r, const Args &... arguments)
202{
203 std::array params = { const_cast<const void *>(r.data), Invoke::dataHelper(arguments)... };
204 std::array names = { r.name, Invoke::typenameHelper(arguments)... };
205 std::array types = { r.metaType, Invoke::metaTypeHelper(arguments)... };
206 static_assert(params.size() == types.size());
207 static_assert(params.size() == names.size());
208
209 struct R {
210 decltype(params) parameters;
211 decltype(names) typeNames;
212 decltype(types) metaTypes;
213 constexpr qsizetype parameterCount() const { return qsizetype(parameters.size()); }
214 };
215 return R { params, names, types };
216}
217} // namespace QtPrivate
218
219template <typename T> void qReturnArg(const T &&) = delete;
220template <typename T> inline QMetaMethodReturnArgument qReturnArg(T &data)
221{
222 return QtPrivate::Invoke::returnArgument(nullptr, data);
223}
224
225struct Q_CORE_EXPORT QMetaObject
226{
227 class Connection;
228 const char *className() const;
229 const QMetaObject *superClass() const;
230
231 bool inherits(const QMetaObject *metaObject) const noexcept;
232 QObject *cast(QObject *obj) const
233 { return const_cast<QObject *>(cast(obj: const_cast<const QObject *>(obj))); }
234 const QObject *cast(const QObject *obj) const;
235
236#if !defined(QT_NO_TRANSLATION) || defined(Q_QDOC)
237 QString tr(const char *s, const char *c, int n = -1) const;
238#endif // QT_NO_TRANSLATION
239
240 QMetaType metaType() const;
241
242 int methodOffset() const;
243 int enumeratorOffset() const;
244 int propertyOffset() const;
245 int classInfoOffset() const;
246
247 int constructorCount() const;
248 int methodCount() const;
249 int enumeratorCount() const;
250 int propertyCount() const;
251 int classInfoCount() const;
252
253 int indexOfConstructor(const char *constructor) const;
254 int indexOfMethod(const char *method) const;
255 int indexOfSignal(const char *signal) const;
256 int indexOfSlot(const char *slot) const;
257 int indexOfEnumerator(const char *name) const;
258 int indexOfProperty(const char *name) const;
259 int indexOfClassInfo(const char *name) const;
260
261 QMetaMethod constructor(int index) const;
262 QMetaMethod method(int index) const;
263 QMetaEnum enumerator(int index) const;
264 QMetaProperty property(int index) const;
265 QMetaClassInfo classInfo(int index) const;
266 QMetaProperty userProperty() const;
267
268 static bool checkConnectArgs(const char *signal, const char *method);
269 static bool checkConnectArgs(const QMetaMethod &signal,
270 const QMetaMethod &method);
271 static QByteArray normalizedSignature(const char *method);
272 static QByteArray normalizedType(const char *type);
273
274 // internal index-based connect
275 static Connection connect(const QObject *sender, int signal_index,
276 const QObject *receiver, int method_index,
277 int type = 0, int *types = nullptr);
278 // internal index-based disconnect
279 static bool disconnect(const QObject *sender, int signal_index,
280 const QObject *receiver, int method_index);
281 static bool disconnectOne(const QObject *sender, int signal_index,
282 const QObject *receiver, int method_index);
283 // internal slot-name based connect
284 static void connectSlotsByName(QObject *o);
285
286 // internal index-based signal activation
287 static void activate(QObject *sender, int signal_index, void **argv);
288 static void activate(QObject *sender, const QMetaObject *, int local_signal_index, void **argv);
289 static void activate(QObject *sender, int signal_offset, int local_signal_index, void **argv);
290
291#if QT_VERSION <= QT_VERSION_CHECK(7, 0, 0)
292 static bool invokeMethod(QObject *obj, const char *member,
293 Qt::ConnectionType,
294 QGenericReturnArgument ret,
295 QGenericArgument val0 = QGenericArgument(nullptr),
296 QGenericArgument val1 = QGenericArgument(),
297 QGenericArgument val2 = QGenericArgument(),
298 QGenericArgument val3 = QGenericArgument(),
299 QGenericArgument val4 = QGenericArgument(),
300 QGenericArgument val5 = QGenericArgument(),
301 QGenericArgument val6 = QGenericArgument(),
302 QGenericArgument val7 = QGenericArgument(),
303 QGenericArgument val8 = QGenericArgument(),
304 QGenericArgument val9 = QGenericArgument());
305
306 static inline bool invokeMethod(QObject *obj, const char *member,
307 QGenericReturnArgument ret,
308 QGenericArgument val0 = QGenericArgument(nullptr),
309 QGenericArgument val1 = QGenericArgument(),
310 QGenericArgument val2 = QGenericArgument(),
311 QGenericArgument val3 = QGenericArgument(),
312 QGenericArgument val4 = QGenericArgument(),
313 QGenericArgument val5 = QGenericArgument(),
314 QGenericArgument val6 = QGenericArgument(),
315 QGenericArgument val7 = QGenericArgument(),
316 QGenericArgument val8 = QGenericArgument(),
317 QGenericArgument val9 = QGenericArgument())
318 {
319 return invokeMethod(obj, member, Qt::AutoConnection, ret, val0, val1, val2, val3,
320 val4, val5, val6, val7, val8, val9);
321 }
322
323 static inline bool invokeMethod(QObject *obj, const char *member,
324 Qt::ConnectionType type,
325 QGenericArgument val0,
326 QGenericArgument val1 = QGenericArgument(),
327 QGenericArgument val2 = QGenericArgument(),
328 QGenericArgument val3 = QGenericArgument(),
329 QGenericArgument val4 = QGenericArgument(),
330 QGenericArgument val5 = QGenericArgument(),
331 QGenericArgument val6 = QGenericArgument(),
332 QGenericArgument val7 = QGenericArgument(),
333 QGenericArgument val8 = QGenericArgument(),
334 QGenericArgument val9 = QGenericArgument())
335 {
336 return invokeMethod(obj, member, type, ret: QGenericReturnArgument(), val0, val1, val2,
337 val3, val4, val5, val6, val7, val8, val9);
338 }
339
340 static inline bool invokeMethod(QObject *obj, const char *member,
341 QGenericArgument val0,
342 QGenericArgument val1 = QGenericArgument(),
343 QGenericArgument val2 = QGenericArgument(),
344 QGenericArgument val3 = QGenericArgument(),
345 QGenericArgument val4 = QGenericArgument(),
346 QGenericArgument val5 = QGenericArgument(),
347 QGenericArgument val6 = QGenericArgument(),
348 QGenericArgument val7 = QGenericArgument(),
349 QGenericArgument val8 = QGenericArgument(),
350 QGenericArgument val9 = QGenericArgument())
351 {
352 return invokeMethod(obj, member, Qt::AutoConnection, ret: QGenericReturnArgument(), val0,
353 val1, val2, val3, val4, val5, val6, val7, val8, val9);
354 }
355#endif // Qt < 7.0
356
357 template <typename... Args> static
358#ifdef Q_QDOC
359 bool
360#else
361 QtPrivate::Invoke::IfNotOldStyleArgs<bool, Args...>
362#endif
363 invokeMethod(QObject *obj, const char *member, Qt::ConnectionType c,
364 QMetaMethodReturnArgument r, Args &&... arguments)
365 {
366 auto h = QtPrivate::invokeMethodHelper(r, std::forward<Args>(arguments)...);
367 return invokeMethodImpl(obj, member, c, h.parameterCount(), h.parameters.data(),
368 h.typeNames.data(), h.metaTypes.data());
369 }
370
371 template <typename... Args> static
372#ifdef Q_QDOC
373 bool
374#else
375 QtPrivate::Invoke::IfNotOldStyleArgs<bool, Args...>
376#endif
377 invokeMethod(QObject *obj, const char *member, Qt::ConnectionType c, Args &&... arguments)
378 {
379 QMetaMethodReturnArgument r = {};
380 return invokeMethod(obj, member, c, r, std::forward<Args>(arguments)...);
381 }
382
383 template <typename... Args> static
384#ifdef Q_QDOC
385 bool
386#else
387 QtPrivate::Invoke::IfNotOldStyleArgs<bool, Args...>
388#endif
389 invokeMethod(QObject *obj, const char *member, QMetaMethodReturnArgument r,
390 Args &&... arguments)
391 {
392 return invokeMethod(obj, member, Qt::AutoConnection, r, std::forward<Args>(arguments)...);
393 }
394
395 template <typename... Args> static
396#ifdef Q_QDOC
397 bool
398#else
399 QtPrivate::Invoke::IfNotOldStyleArgs<bool, Args...>
400#endif
401 invokeMethod(QObject *obj, const char *member, Args &&... arguments)
402 {
403 QMetaMethodReturnArgument r = {};
404 return invokeMethod(obj, member, Qt::AutoConnection, r, std::forward<Args>(arguments)...);
405 }
406
407#ifdef Q_QDOC
408 template<typename Functor, typename FunctorReturnType>
409 static bool invokeMethod(QObject *context, Functor &&function, Qt::ConnectionType type = Qt::AutoConnection, FunctorReturnType *ret = nullptr);
410 template<typename Functor, typename FunctorReturnType>
411 static bool invokeMethod(QObject *context, Functor &&function, FunctorReturnType *ret);
412#else
413 template <typename Func>
414 static std::enable_if_t<!std::disjunction_v<std::is_convertible<Func, const char *>,
415 QtPrivate::Invoke::AreOldStyleArgs<Func>>,
416 bool>
417 invokeMethod(typename QtPrivate::ContextTypeForFunctor<Func>::ContextType *object,
418 Func &&function,
419 Qt::ConnectionType type = Qt::AutoConnection,
420 typename QtPrivate::Callable<Func>::ReturnType *ret = nullptr)
421 {
422 static_assert(QtPrivate::Callable<Func>::ArgumentCount <= 0,
423 "QMetaObject::invokeMethod cannot call functions with arguments!");
424 using Prototype = typename QtPrivate::Callable<Func>::Function;
425 return invokeMethodImpl(object, QtPrivate::makeCallableObject<Prototype>(std::forward<Func>(function)), type, ret);
426 }
427
428 template <typename Func>
429 static std::enable_if_t<!std::disjunction_v<std::is_convertible<Func, const char *>,
430 QtPrivate::Invoke::AreOldStyleArgs<Func>>,
431 bool>
432 invokeMethod(typename QtPrivate::ContextTypeForFunctor<Func>::ContextType *object,
433 Func &&function,
434 typename QtPrivate::Callable<Func>::ReturnType *ret)
435 {
436 return invokeMethod(object, std::forward<Func>(function), Qt::AutoConnection, ret);
437 }
438
439#endif
440
441#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
442 QObject *newInstance(QGenericArgument val0,
443 QGenericArgument val1 = QGenericArgument(),
444 QGenericArgument val2 = QGenericArgument(),
445 QGenericArgument val3 = QGenericArgument(),
446 QGenericArgument val4 = QGenericArgument(),
447 QGenericArgument val5 = QGenericArgument(),
448 QGenericArgument val6 = QGenericArgument(),
449 QGenericArgument val7 = QGenericArgument(),
450 QGenericArgument val8 = QGenericArgument(),
451 QGenericArgument val9 = QGenericArgument()) const;
452#endif
453
454 template <typename... Args>
455#ifdef Q_QDOC
456 QObject *
457#else
458 QtPrivate::Invoke::IfNotOldStyleArgs<QObject *, Args...>
459#endif
460 newInstance(Args &&... arguments) const
461 {
462 auto h = QtPrivate::invokeMethodHelper(QMetaMethodReturnArgument{}, std::forward<Args>(arguments)...);
463 return newInstanceImpl(mobj: this, parameterCount: h.parameterCount(), parameters: h.parameters.data(),
464 typeNames: h.typeNames.data(), metaTypes: h.metaTypes.data());
465 }
466
467 enum Call {
468 InvokeMetaMethod,
469 ReadProperty,
470 WriteProperty,
471 ResetProperty,
472 CreateInstance,
473 IndexOfMethod,
474 RegisterPropertyMetaType,
475 RegisterMethodArgumentMetaType,
476 BindableProperty,
477 CustomCall,
478 ConstructInPlace,
479 };
480
481 int static_metacall(Call, int, void **) const;
482 static int metacall(QObject *, Call, int, void **);
483
484 template <const QMetaObject &MO> static constexpr const QMetaObject *staticMetaObject()
485 {
486 return &MO;
487 }
488
489 struct SuperData {
490 using Getter = const QMetaObject *(*)();
491 const QMetaObject *direct;
492 SuperData() = default;
493 constexpr SuperData(std::nullptr_t) : direct(nullptr) {}
494 constexpr SuperData(const QMetaObject *mo) : direct(mo) {}
495
496 constexpr const QMetaObject *operator->() const { return operator const QMetaObject *(); }
497
498#ifdef QT_NO_DATA_RELOCATION
499 Getter indirect = nullptr;
500 constexpr SuperData(Getter g) : direct(nullptr), indirect(g) {}
501 constexpr operator const QMetaObject *() const
502 { return indirect ? indirect() : direct; }
503 template <const QMetaObject &MO> static constexpr SuperData link()
504 { return SuperData(QMetaObject::staticMetaObject<MO>); }
505#else
506 constexpr SuperData(Getter g) : direct(g()) {}
507 constexpr operator const QMetaObject *() const
508 { return direct; }
509 template <const QMetaObject &MO> static constexpr SuperData link()
510 { return SuperData(QMetaObject::staticMetaObject<MO>()); }
511#endif
512 };
513
514 struct Data { // private data
515 SuperData superdata;
516 const uint *stringdata;
517 const uint *data;
518 typedef void (*StaticMetacallFunction)(QObject *, QMetaObject::Call, int, void **);
519 StaticMetacallFunction static_metacall;
520 const SuperData *relatedMetaObjects;
521 const QtPrivate::QMetaTypeInterface *const *metaTypes;
522 void *extradata; //reserved for future use
523 } d;
524
525private:
526 static bool invokeMethodImpl(QObject *object, const char *member, Qt::ConnectionType type,
527 qsizetype parameterCount, const void *const *parameters, const char *const *names,
528 const QtPrivate::QMetaTypeInterface * const *metaTypes);
529 static bool invokeMethodImpl(QObject *object, QtPrivate::QSlotObjectBase *slot, Qt::ConnectionType type, void *ret);
530 static QObject *newInstanceImpl(const QMetaObject *mobj, qsizetype parameterCount,
531 const void **parameters, const char **typeNames,
532 const QtPrivate::QMetaTypeInterface **metaTypes);
533 friend class QTimer;
534};
535
536class Q_CORE_EXPORT QMetaObject::Connection {
537 void *d_ptr; //QObjectPrivate::Connection*
538 explicit Connection(void *data) : d_ptr(data) { }
539 friend class QObject;
540 friend class QObjectPrivate;
541 friend struct QMetaObject;
542 bool isConnected_helper() const;
543public:
544 ~Connection();
545 Connection();
546 Connection(const Connection &other);
547 Connection &operator=(const Connection &other);
548#ifdef Q_QDOC
549 operator bool() const;
550#else
551 // still using the restricted bool trick here, in order to support
552 // code using copy-init (e.g. `bool ok = connect(...)`)
553 typedef void *Connection::*RestrictedBool;
554 operator RestrictedBool() const { return d_ptr && isConnected_helper() ? &Connection::d_ptr : nullptr; }
555#endif
556
557 Connection(Connection &&other) noexcept : d_ptr(std::exchange(obj&: other.d_ptr, new_val: nullptr)) {}
558 QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(Connection)
559 void swap(Connection &other) noexcept { qt_ptr_swap(lhs&: d_ptr, rhs&: other.d_ptr); }
560};
561
562inline void swap(QMetaObject::Connection &lhs, QMetaObject::Connection &rhs) noexcept
563{
564 lhs.swap(other&: rhs);
565}
566
567inline const QMetaObject *QMetaObject::superClass() const
568{ return d.superdata; }
569
570namespace QtPrivate {
571 // Trait that tells if a QObject has a Q_OBJECT macro
572 template <typename Object> struct HasQ_OBJECT_Macro {
573 template <typename T>
574 static char test(int (T::*)(QMetaObject::Call, int, void **));
575 static int test(int (Object::*)(QMetaObject::Call, int, void **));
576 enum { Value = sizeof(test(&Object::qt_metacall)) == sizeof(int) };
577 };
578}
579
580QT_END_NAMESPACE
581
582#endif // QOBJECTDEFS_H
583

source code of qtbase/src/corelib/kernel/qobjectdefs.h