1// Copyright (C) 2020 The Qt Company Ltd.
2// Copyright (C) 2015 Olivier Goffart <ogoffart@woboq.com>
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
5#include "qmetaobject.h"
6#include "qmetatype.h"
7#include "qobject.h"
8#include "qmetaobject_p.h"
9#include "qmetatype_p.h"
10
11#include <qcoreapplication.h>
12#include <qcoreevent.h>
13#include <qdatastream.h>
14#include <qstringlist.h>
15#include <qthread.h>
16#include <qvariant.h>
17#include <qdebug.h>
18#if QT_CONFIG(thread)
19#include <qsemaphore.h>
20#endif
21
22#include "private/qobject_p.h"
23#include "private/qmetaobject_p.h"
24#include "private/qthread_p.h"
25
26// for normalizeTypeInternal
27#include "private/qmetaobject_moc_p.h"
28
29#include <ctype.h>
30#include <memory>
31
32QT_BEGIN_NAMESPACE
33
34using namespace Qt::StringLiterals;
35
36/*!
37 \class QMetaObject
38 \inmodule QtCore
39
40 \brief The QMetaObject class contains meta-information about Qt
41 objects.
42
43 \ingroup objectmodel
44
45 The Qt \l{Meta-Object System} in Qt is responsible for the
46 signals and slots inter-object communication mechanism, runtime
47 type information, and the Qt property system. A single
48 QMetaObject instance is created for each QObject subclass that is
49 used in an application, and this instance stores all the
50 meta-information for the QObject subclass. This object is
51 available as QObject::metaObject().
52
53 This class is not normally required for application programming,
54 but it is useful if you write meta-applications, such as scripting
55 engines or GUI builders.
56
57 The functions you are most likely to find useful are these:
58 \list
59 \li className() returns the name of a class.
60 \li superClass() returns the superclass's meta-object.
61 \li method() and methodCount() provide information
62 about a class's meta-methods (signals, slots and other
63 \l{Q_INVOKABLE}{invokable} member functions).
64 \li enumerator() and enumeratorCount() and provide information about
65 a class's enumerators.
66 \li propertyCount() and property() provide information about a
67 class's properties.
68 \li constructor() and constructorCount() provide information
69 about a class's meta-constructors.
70 \endlist
71
72 The index functions indexOfConstructor(), indexOfMethod(),
73 indexOfEnumerator(), and indexOfProperty() map names of constructors,
74 member functions, enumerators, or properties to indexes in the
75 meta-object. For example, Qt uses indexOfMethod() internally when you
76 connect a signal to a slot.
77
78 Classes can also have a list of \e{name}--\e{value} pairs of
79 additional class information, stored in QMetaClassInfo objects.
80 The number of pairs is returned by classInfoCount(), single pairs
81 are returned by classInfo(), and you can search for pairs with
82 indexOfClassInfo().
83
84 \note Operations that use the meta object system are generally thread-
85 safe, as QMetaObjects are typically static read-only instances
86 generated at compile time. However, if meta objects are dynamically
87 modified by the application (for instance, when using QQmlPropertyMap),
88 then the application has to explicitly synchronize access to the
89 respective meta object.
90
91 \sa QMetaClassInfo, QMetaEnum, QMetaMethod, QMetaProperty, QMetaType,
92 {Meta-Object System}
93*/
94
95/*!
96 \enum QMetaObject::Call
97
98 \internal
99
100 \value InvokeMetaMethod
101 \value ReadProperty
102 \value WriteProperty
103 \value ResetProperty
104 \value CreateInstance
105 \value IndexOfMethod
106 \value RegisterPropertyMetaType
107 \value RegisterMethodArgumentMetaType
108 \value BindableProperty
109 \value CustomCall
110 \value ConstructInPlace
111*/
112
113/*!
114 \enum QMetaMethod::Access
115
116 This enum describes the access level of a method, following the conventions used in C++.
117
118 \value Private
119 \value Protected
120 \value Public
121*/
122
123static inline const QMetaObjectPrivate *priv(const uint* data)
124{ return reinterpret_cast<const QMetaObjectPrivate*>(data); }
125
126static inline const char *rawStringData(const QMetaObject *mo, int index)
127{
128 Q_ASSERT(priv(mo->d.data)->revision >= 7);
129 uint offset = mo->d.stringdata[2*index];
130 return reinterpret_cast<const char *>(mo->d.stringdata) + offset;
131}
132
133static inline QLatin1StringView stringDataView(const QMetaObject *mo, int index)
134{
135 Q_ASSERT(priv(mo->d.data)->revision >= 7);
136 uint offset = mo->d.stringdata[2*index];
137 uint length = mo->d.stringdata[2*index + 1];
138 const char *string = reinterpret_cast<const char *>(mo->d.stringdata) + offset;
139 return {string, qsizetype(length)};
140}
141
142static inline QByteArray stringData(const QMetaObject *mo, int index)
143{
144 const auto view = stringDataView(mo, index);
145 return QByteArray::fromRawData(data: view.data(), size: view.size());
146}
147
148static inline const char *rawTypeNameFromTypeInfo(const QMetaObject *mo, uint typeInfo)
149{
150 if (typeInfo & IsUnresolvedType) {
151 return rawStringData(mo, index: typeInfo & TypeNameIndexMask);
152 } else {
153 return QMetaType(typeInfo).name();
154 }
155}
156
157static inline QByteArray typeNameFromTypeInfo(const QMetaObject *mo, uint typeInfo)
158{
159 if (typeInfo & IsUnresolvedType) {
160 return stringData(mo, index: typeInfo & TypeNameIndexMask);
161 } else {
162 return QMetaType(typeInfo).name();
163 }
164}
165
166static inline int typeFromTypeInfo(const QMetaObject *mo, uint typeInfo)
167{
168 if (!(typeInfo & IsUnresolvedType))
169 return typeInfo;
170 return QMetaType::fromName(name: rawStringData(mo, index: typeInfo & TypeNameIndexMask)).id();
171}
172
173namespace {
174class QMetaMethodPrivate : public QMetaMethodInvoker
175{
176public:
177 static const QMetaMethodPrivate *get(const QMetaMethod *q)
178 { return static_cast<const QMetaMethodPrivate *>(q); }
179
180 inline QByteArray signature() const;
181 inline QByteArray name() const;
182 inline int typesDataIndex() const;
183 inline const char *rawReturnTypeName() const;
184 inline int returnType() const;
185 inline int parameterCount() const;
186 inline int parametersDataIndex() const;
187 inline uint parameterTypeInfo(int index) const;
188 inline int parameterType(int index) const;
189 inline void getParameterTypes(int *types) const;
190 inline const QtPrivate::QMetaTypeInterface *returnMetaTypeInterface() const;
191 inline const QtPrivate::QMetaTypeInterface *const *parameterMetaTypeInterfaces() const;
192 inline QByteArray parameterTypeName(int index) const;
193 inline QList<QByteArray> parameterTypes() const;
194 inline QList<QByteArray> parameterNames() const;
195 inline QByteArray tag() const;
196 inline int ownMethodIndex() const;
197 inline int ownConstructorMethodIndex() const;
198
199private:
200 void checkMethodMetaTypeConsistency(const QtPrivate::QMetaTypeInterface *iface, int index) const;
201 QMetaMethodPrivate();
202};
203} // unnamed namespace
204
205enum { MaximumParamCount = 11 }; // up to 10 arguments + 1 return value
206
207#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
208/*!
209 \since 4.5
210 \obsolete [6.5] Please use the variadic overload of this function
211
212 Constructs a new instance of this class. You can pass up to ten arguments
213 (\a val0, \a val1, \a val2, \a val3, \a val4, \a val5, \a val6, \a val7,
214 \a val8, and \a val9) to the constructor. Returns the new object, or
215 \nullptr if no suitable constructor is available.
216
217 Note that only constructors that are declared with the Q_INVOKABLE
218 modifier are made available through the meta-object system.
219
220 \sa Q_ARG(), constructor()
221*/
222QObject *QMetaObject::newInstance(QGenericArgument val0,
223 QGenericArgument val1,
224 QGenericArgument val2,
225 QGenericArgument val3,
226 QGenericArgument val4,
227 QGenericArgument val5,
228 QGenericArgument val6,
229 QGenericArgument val7,
230 QGenericArgument val8,
231 QGenericArgument val9) const
232{
233 const char *typeNames[] = {
234 nullptr,
235 val0.name(), val1.name(), val2.name(), val3.name(), val4.name(),
236 val5.name(), val6.name(), val7.name(), val8.name(), val9.name()
237 };
238 const void *parameters[] = {
239 nullptr,
240 val0.data(), val1.data(), val2.data(), val3.data(), val4.data(),
241 val5.data(), val6.data(), val7.data(), val8.data(), val9.data()
242 };
243
244 int paramCount;
245 for (paramCount = 1; paramCount < MaximumParamCount; ++paramCount) {
246 int len = int(qstrlen(str: typeNames[paramCount]));
247 if (len <= 0)
248 break;
249 }
250
251 return newInstanceImpl(mobj: this, parameterCount: paramCount, parameters, typeNames, metaTypes: nullptr);
252}
253#endif
254
255/*!
256 \fn template <typename... Args> QObject *QMetaObject::newInstance(Args &&... arguments) const
257 \since 6.5
258
259 Constructs a new instance of this class and returns the new object, or
260 \nullptr if no suitable constructor is available. The types of the
261 arguments \a arguments will be used to find a matching constructor, and then
262 forwarded to it the same way signal-slot connections do.
263
264 Note that only constructors that are declared with the Q_INVOKABLE
265 modifier are made available through the meta-object system.
266
267 \sa constructor()
268*/
269
270QObject *QMetaObject::newInstanceImpl(const QMetaObject *mobj, qsizetype paramCount,
271 const void **parameters, const char **typeNames,
272 const QtPrivate::QMetaTypeInterface **metaTypes)
273{
274 if (!mobj->inherits(metaObject: &QObject::staticMetaObject)) {
275 qWarning(msg: "QMetaObject::newInstance: type %s does not inherit QObject", mobj->className());
276 return nullptr;
277 }
278
279QT_WARNING_PUSH
280#if Q_CC_GNU >= 1200
281QT_WARNING_DISABLE_GCC("-Wdangling-pointer")
282#endif
283
284 // set the return type
285 QObject *returnValue = nullptr;
286 QMetaType returnValueMetaType = QMetaType::fromType<decltype(returnValue)>();
287 parameters[0] = &returnValue;
288 typeNames[0] = returnValueMetaType.name();
289 if (metaTypes)
290 metaTypes[0] = returnValueMetaType.iface();
291
292QT_WARNING_POP
293
294 // find the constructor
295 auto priv = QMetaObjectPrivate::get(metaobject: mobj);
296 for (int i = 0; i < priv->constructorCount; ++i) {
297 QMetaMethod m = QMetaMethod::fromRelativeConstructorIndex(mobj, index: i);
298 if (m.parameterCount() != (paramCount - 1))
299 continue;
300
301 // attempt to call
302 QMetaMethodPrivate::InvokeFailReason r =
303 QMetaMethodPrivate::invokeImpl(self: m, target: nullptr, Qt::DirectConnection, paramCount,
304 parameters, typeNames, metaTypes);
305 if (r == QMetaMethodPrivate::InvokeFailReason::None)
306 return returnValue;
307 if (int(r) < 0)
308 return nullptr;
309 }
310
311 return returnValue;
312}
313
314/*!
315 \internal
316*/
317int QMetaObject::static_metacall(Call cl, int idx, void **argv) const
318{
319 Q_ASSERT(priv(d.data)->revision >= 6);
320 if (!d.static_metacall)
321 return 0;
322 d.static_metacall(nullptr, cl, idx, argv);
323 return -1;
324}
325
326/*!
327 \internal
328*/
329int QMetaObject::metacall(QObject *object, Call cl, int idx, void **argv)
330{
331 if (object->d_ptr->metaObject)
332 return object->d_ptr->metaObject->metaCall(object, cl, id: idx, argv);
333 else
334 return object->qt_metacall(cl, idx, argv);
335}
336
337static inline const char *objectClassName(const QMetaObject *m)
338{
339 return rawStringData(mo: m, index: priv(data: m->d.data)->className);
340}
341
342/*!
343 Returns the class name.
344
345 \sa superClass()
346*/
347const char *QMetaObject::className() const
348{
349 return objectClassName(m: this);
350}
351
352/*!
353 \fn QMetaObject *QMetaObject::superClass() const
354
355 Returns the meta-object of the superclass, or \nullptr if there is
356 no such object.
357
358 \sa className()
359*/
360
361/*!
362 Returns \c true if the class described by this QMetaObject inherits
363 the type described by \a metaObject; otherwise returns false.
364
365 A type is considered to inherit itself.
366
367 \since 5.7
368*/
369bool QMetaObject::inherits(const QMetaObject *metaObject) const noexcept
370{
371 const QMetaObject *m = this;
372 do {
373 if (metaObject == m)
374 return true;
375 } while ((m = m->d.superdata));
376 return false;
377}
378
379/*!
380 \fn QObject *QMetaObject::cast(QObject *obj) const
381 \internal
382
383 Returns \a obj if object \a obj inherits from this
384 meta-object; otherwise returns \nullptr.
385*/
386
387/*!
388 \internal
389
390 Returns \a obj if object \a obj inherits from this
391 meta-object; otherwise returns \nullptr.
392*/
393const QObject *QMetaObject::cast(const QObject *obj) const
394{
395 return (obj && obj->metaObject()->inherits(metaObject: this)) ? obj : nullptr;
396}
397
398#ifndef QT_NO_TRANSLATION
399/*!
400 \internal
401*/
402QString QMetaObject::tr(const char *s, const char *c, int n) const
403{
404 return QCoreApplication::translate(context: objectClassName(m: this), key: s, disambiguation: c, n);
405}
406#endif // QT_NO_TRANSLATION
407
408/*!
409 \since 6.2
410 Returns the metatype corresponding to this metaobject.
411 If the metaobject originates from a namespace, an invalid metatype is returned.
412 */
413QMetaType QMetaObject::metaType() const
414{
415
416 const QMetaObjectPrivate *d = priv(data: this->d.data);
417 if (d->revision < 10) {
418 // before revision 10, we did not store the metatype in the metatype array
419 return QMetaType::fromName(name: className());
420 } else {
421 /* in the metatype array, we store
422
423 | index | data |
424 |----------------------------------------------------------------------|
425 | 0 | QMetaType(property0) |
426 | ... | ... |
427 | propertyCount - 1 | QMetaType(propertyCount - 1) |
428 | propertyCount | QMetaType(enumerator0) |
429 | ... | ... |
430 | propertyCount + enumeratorCount - 1 | QMetaType(enumeratorCount - 1) |
431 | propertyCount + enumeratorCount | QMetaType(class) |
432
433 */
434#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
435 // Before revision 12 we only stored metatypes for enums if they showed
436 // up as types of properties or method arguments or return values.
437 // From revision 12 on, we always store them in a predictable place.
438 const qsizetype offset = d->revision < 12
439 ? d->propertyCount
440 : d->propertyCount + d->enumeratorCount;
441#else
442 const qsizetype offset = d->propertyCount + d->enumeratorCount;
443#endif
444
445 auto iface = this->d.metaTypes[offset];
446 if (iface && QtMetaTypePrivate::isInterfaceFor<void>(iface))
447 return QMetaType(); // return invalid meta-type for namespaces
448 if (iface)
449 return QMetaType(iface);
450 else // in case of a dynamic metaobject, we might have no metatype stored
451 return QMetaType::fromName(name: className()); // try lookup by name in that case
452 }
453}
454
455/*!
456 Returns the method offset for this class; i.e. the index position
457 of this class's first member function.
458
459 The offset is the sum of all the methods in the class's
460 superclasses (which is always positive since QObject has the
461 deleteLater() slot and a destroyed() signal).
462
463 \sa method(), methodCount(), indexOfMethod()
464*/
465int QMetaObject::methodOffset() const
466{
467 int offset = 0;
468 const QMetaObject *m = d.superdata;
469 while (m) {
470 offset += priv(data: m->d.data)->methodCount;
471 m = m->d.superdata;
472 }
473 return offset;
474}
475
476
477/*!
478 Returns the enumerator offset for this class; i.e. the index
479 position of this class's first enumerator.
480
481 If the class has no superclasses with enumerators, the offset is
482 0; otherwise the offset is the sum of all the enumerators in the
483 class's superclasses.
484
485 \sa enumerator(), enumeratorCount(), indexOfEnumerator()
486*/
487int QMetaObject::enumeratorOffset() const
488{
489 int offset = 0;
490 const QMetaObject *m = d.superdata;
491 while (m) {
492 offset += priv(data: m->d.data)->enumeratorCount;
493 m = m->d.superdata;
494 }
495 return offset;
496}
497
498/*!
499 Returns the property offset for this class; i.e. the index
500 position of this class's first property.
501
502 The offset is the sum of all the properties in the class's
503 superclasses (which is always positive since QObject has the
504 name() property).
505
506 \sa property(), propertyCount(), indexOfProperty()
507*/
508int QMetaObject::propertyOffset() const
509{
510 int offset = 0;
511 const QMetaObject *m = d.superdata;
512 while (m) {
513 offset += priv(data: m->d.data)->propertyCount;
514 m = m->d.superdata;
515 }
516 return offset;
517}
518
519/*!
520 Returns the class information offset for this class; i.e. the
521 index position of this class's first class information item.
522
523 If the class has no superclasses with class information, the
524 offset is 0; otherwise the offset is the sum of all the class
525 information items in the class's superclasses.
526
527 \sa classInfo(), classInfoCount(), indexOfClassInfo()
528*/
529int QMetaObject::classInfoOffset() const
530{
531 int offset = 0;
532 const QMetaObject *m = d.superdata;
533 while (m) {
534 offset += priv(data: m->d.data)->classInfoCount;
535 m = m->d.superdata;
536 }
537 return offset;
538}
539
540/*!
541 \since 4.5
542
543 Returns the number of constructors in this class.
544
545 \sa constructor(), indexOfConstructor()
546*/
547int QMetaObject::constructorCount() const
548{
549 Q_ASSERT(priv(d.data)->revision >= 2);
550 return priv(data: d.data)->constructorCount;
551}
552
553/*!
554 Returns the number of methods in this class, including the number of
555 methods provided by each base class. These include signals and slots
556 as well as normal member functions.
557
558 Use code like the following to obtain a QStringList containing the methods
559 specific to a given class:
560
561 \snippet code/src_corelib_kernel_qmetaobject.cpp methodCount
562
563 \sa method(), methodOffset(), indexOfMethod()
564*/
565int QMetaObject::methodCount() const
566{
567 int n = priv(data: d.data)->methodCount;
568 const QMetaObject *m = d.superdata;
569 while (m) {
570 n += priv(data: m->d.data)->methodCount;
571 m = m->d.superdata;
572 }
573 return n;
574}
575
576/*!
577 Returns the number of enumerators in this class.
578
579 \sa enumerator(), enumeratorOffset(), indexOfEnumerator()
580*/
581int QMetaObject::enumeratorCount() const
582{
583 int n = priv(data: d.data)->enumeratorCount;
584 const QMetaObject *m = d.superdata;
585 while (m) {
586 n += priv(data: m->d.data)->enumeratorCount;
587 m = m->d.superdata;
588 }
589 return n;
590}
591
592/*!
593 Returns the number of properties in this class, including the number of
594 properties provided by each base class.
595
596 Use code like the following to obtain a QStringList containing the properties
597 specific to a given class:
598
599 \snippet code/src_corelib_kernel_qmetaobject.cpp propertyCount
600
601 \sa property(), propertyOffset(), indexOfProperty()
602*/
603int QMetaObject::propertyCount() const
604{
605 int n = priv(data: d.data)->propertyCount;
606 const QMetaObject *m = d.superdata;
607 while (m) {
608 n += priv(data: m->d.data)->propertyCount;
609 m = m->d.superdata;
610 }
611 return n;
612}
613
614/*!
615 Returns the number of items of class information in this class.
616
617 \sa classInfo(), classInfoOffset(), indexOfClassInfo()
618*/
619int QMetaObject::classInfoCount() const
620{
621 int n = priv(data: d.data)->classInfoCount;
622 const QMetaObject *m = d.superdata;
623 while (m) {
624 n += priv(data: m->d.data)->classInfoCount;
625 m = m->d.superdata;
626 }
627 return n;
628}
629
630// Returns \c true if the method defined by the given meta-object&meta-method
631// matches the given name, argument count and argument types, otherwise
632// returns \c false.
633bool QMetaObjectPrivate::methodMatch(const QMetaObject *m, const QMetaMethod &method,
634 const QByteArray &name, int argc,
635 const QArgumentType *types)
636{
637 const QMetaMethod::Data &data = method.data;
638 auto priv = QMetaMethodPrivate::get(q: &method);
639 if (priv->parameterCount() != argc)
640 return false;
641
642 if (stringData(mo: m, index: data.name()) != name)
643 return false;
644
645 const QtPrivate::QMetaTypeInterface * const *ifaces = priv->parameterMetaTypeInterfaces();
646 int paramsIndex = data.parameters() + 1;
647 for (int i = 0; i < argc; ++i) {
648 uint typeInfo = m->d.data[paramsIndex + i];
649 if (int id = types[i].type()) {
650 if (id == QMetaType(ifaces[i]).id())
651 continue;
652 if (id != typeFromTypeInfo(mo: m, typeInfo))
653 return false;
654 } else {
655 if (types[i].name() == QMetaType(ifaces[i]).name())
656 continue;
657 if (types[i].name() != typeNameFromTypeInfo(mo: m, typeInfo))
658 return false;
659 }
660 }
661
662 return true;
663}
664
665/*!
666 \internal
667 Returns the first method with name \a name found in \a baseObject
668 */
669QMetaMethod QMetaObjectPrivate::firstMethod(const QMetaObject *baseObject, QByteArrayView name)
670{
671 for (const QMetaObject *currentObject = baseObject; currentObject; currentObject = currentObject->superClass()) {
672 const int start = priv(data: currentObject->d.data)->methodCount - 1;
673 const int end = 0;
674 for (int i = start; i >= end; --i) {
675 auto candidate = QMetaMethod::fromRelativeMethodIndex(mobj: currentObject, index: i);
676 if (name == candidate.name())
677 return candidate;
678 }
679 }
680 return QMetaMethod{};
681}
682
683/**
684* \internal
685* helper function for indexOf{Method,Slot,Signal}, returns the relative index of the method within
686* the baseObject
687* \a MethodType might be MethodSignal or MethodSlot, or \nullptr to match everything.
688*/
689template<int MethodType>
690inline int QMetaObjectPrivate::indexOfMethodRelative(const QMetaObject **baseObject,
691 const QByteArray &name, int argc,
692 const QArgumentType *types)
693{
694 for (const QMetaObject *m = *baseObject; m; m = m->d.superdata) {
695 Q_ASSERT(priv(m->d.data)->revision >= 7);
696 int i = (MethodType == MethodSignal)
697 ? (priv(data: m->d.data)->signalCount - 1) : (priv(data: m->d.data)->methodCount - 1);
698 const int end = (MethodType == MethodSlot)
699 ? (priv(data: m->d.data)->signalCount) : 0;
700
701 for (; i >= end; --i) {
702 auto data = QMetaMethod::fromRelativeMethodIndex(mobj: m, index: i);
703 if (methodMatch(m, method: data, name, argc, types)) {
704 *baseObject = m;
705 return i;
706 }
707 }
708 }
709 return -1;
710}
711
712
713/*!
714 \since 4.5
715
716 Finds \a constructor and returns its index; otherwise returns -1.
717
718 Note that the \a constructor has to be in normalized form, as returned
719 by normalizedSignature().
720
721 \sa constructor(), constructorCount(), normalizedSignature()
722*/
723int QMetaObject::indexOfConstructor(const char *constructor) const
724{
725 Q_ASSERT(priv(d.data)->revision >= 7);
726 QArgumentTypeArray types;
727 QByteArray name = QMetaObjectPrivate::decodeMethodSignature(signature: constructor, types);
728 return QMetaObjectPrivate::indexOfConstructor(m: this, name, argc: types.size(), types: types.constData());
729}
730
731/*!
732 Finds \a method and returns its index; otherwise returns -1.
733
734 Note that the \a method has to be in normalized form, as returned
735 by normalizedSignature().
736
737 \sa method(), methodCount(), methodOffset(), normalizedSignature()
738*/
739int QMetaObject::indexOfMethod(const char *method) const
740{
741 const QMetaObject *m = this;
742 int i;
743 Q_ASSERT(priv(m->d.data)->revision >= 7);
744 QArgumentTypeArray types;
745 QByteArray name = QMetaObjectPrivate::decodeMethodSignature(signature: method, types);
746 i = QMetaObjectPrivate::indexOfMethodRelative<0>(baseObject: &m, name, argc: types.size(), types: types.constData());
747 if (i >= 0)
748 i += m->methodOffset();
749 return i;
750}
751
752// Parses a string of comma-separated types into QArgumentTypes.
753// No normalization of the type names is performed.
754static void argumentTypesFromString(const char *str, const char *end,
755 QArgumentTypeArray &types)
756{
757 Q_ASSERT(str <= end);
758 while (str != end) {
759 if (!types.isEmpty())
760 ++str; // Skip comma
761 const char *begin = str;
762 int level = 0;
763 while (str != end && (level > 0 || *str != ',')) {
764 if (*str == '<')
765 ++level;
766 else if (*str == '>')
767 --level;
768 ++str;
769 }
770 QByteArray argType(begin, str - begin);
771 argType.replace(before: "QVector<", after: "QList<");
772 types += QArgumentType(std::move(argType));
773 }
774}
775
776// Given a method \a signature (e.g. "foo(int,double)"), this function
777// populates the argument \a types array and returns the method name.
778QByteArray QMetaObjectPrivate::decodeMethodSignature(
779 const char *signature, QArgumentTypeArray &types)
780{
781 Q_ASSERT(signature != nullptr);
782 const char *lparens = strchr(s: signature, c: '(');
783 if (!lparens)
784 return QByteArray();
785 const char *rparens = strrchr(s: lparens + 1, c: ')');
786 if (!rparens || *(rparens+1))
787 return QByteArray();
788 int nameLength = lparens - signature;
789 argumentTypesFromString(str: lparens + 1, end: rparens, types);
790 return QByteArray::fromRawData(data: signature, size: nameLength);
791}
792
793/*!
794 Finds \a signal and returns its index; otherwise returns -1.
795
796 This is the same as indexOfMethod(), except that it will return
797 -1 if the method exists but isn't a signal.
798
799 Note that the \a signal has to be in normalized form, as returned
800 by normalizedSignature().
801
802 \sa indexOfMethod(), normalizedSignature(), method(), methodCount(), methodOffset()
803*/
804int QMetaObject::indexOfSignal(const char *signal) const
805{
806 const QMetaObject *m = this;
807 int i;
808 Q_ASSERT(priv(m->d.data)->revision >= 7);
809 QArgumentTypeArray types;
810 QByteArray name = QMetaObjectPrivate::decodeMethodSignature(signature: signal, types);
811 i = QMetaObjectPrivate::indexOfSignalRelative(baseObject: &m, name, argc: types.size(), types: types.constData());
812 if (i >= 0)
813 i += m->methodOffset();
814 return i;
815}
816
817/*!
818 \internal
819 Same as QMetaObject::indexOfSignal, but the result is the local offset to the base object.
820
821 \a baseObject will be adjusted to the enclosing QMetaObject, or \nullptr if the signal is not found
822*/
823int QMetaObjectPrivate::indexOfSignalRelative(const QMetaObject **baseObject,
824 const QByteArray &name, int argc,
825 const QArgumentType *types)
826{
827 int i = indexOfMethodRelative<MethodSignal>(baseObject, name, argc, types);
828#ifndef QT_NO_DEBUG
829 const QMetaObject *m = *baseObject;
830 if (i >= 0 && m && m->d.superdata) {
831 int conflict = indexOfMethod(m: m->d.superdata, name, argc, types);
832 if (conflict >= 0) {
833 QMetaMethod conflictMethod = m->d.superdata->method(index: conflict);
834 qWarning(msg: "QMetaObject::indexOfSignal: signal %s from %s redefined in %s",
835 conflictMethod.methodSignature().constData(),
836 objectClassName(m: m->d.superdata), objectClassName(m));
837 }
838 }
839 #endif
840 return i;
841}
842
843/*!
844 Finds \a slot and returns its index; otherwise returns -1.
845
846 This is the same as indexOfMethod(), except that it will return
847 -1 if the method exists but isn't a slot.
848
849 \sa indexOfMethod(), method(), methodCount(), methodOffset()
850*/
851int QMetaObject::indexOfSlot(const char *slot) const
852{
853 const QMetaObject *m = this;
854 int i;
855 Q_ASSERT(priv(m->d.data)->revision >= 7);
856 QArgumentTypeArray types;
857 QByteArray name = QMetaObjectPrivate::decodeMethodSignature(signature: slot, types);
858 i = QMetaObjectPrivate::indexOfSlotRelative(m: &m, name, argc: types.size(), types: types.constData());
859 if (i >= 0)
860 i += m->methodOffset();
861 return i;
862}
863
864// same as indexOfSignalRelative but for slots.
865int QMetaObjectPrivate::indexOfSlotRelative(const QMetaObject **m,
866 const QByteArray &name, int argc,
867 const QArgumentType *types)
868{
869 return indexOfMethodRelative<MethodSlot>(baseObject: m, name, argc, types);
870}
871
872int QMetaObjectPrivate::indexOfSignal(const QMetaObject *m, const QByteArray &name,
873 int argc, const QArgumentType *types)
874{
875 int i = indexOfSignalRelative(baseObject: &m, name, argc, types);
876 if (i >= 0)
877 i += m->methodOffset();
878 return i;
879}
880
881int QMetaObjectPrivate::indexOfSlot(const QMetaObject *m, const QByteArray &name,
882 int argc, const QArgumentType *types)
883{
884 int i = indexOfSlotRelative(m: &m, name, argc, types);
885 if (i >= 0)
886 i += m->methodOffset();
887 return i;
888}
889
890int QMetaObjectPrivate::indexOfMethod(const QMetaObject *m, const QByteArray &name,
891 int argc, const QArgumentType *types)
892{
893 int i = indexOfMethodRelative<0>(baseObject: &m, name, argc, types);
894 if (i >= 0)
895 i += m->methodOffset();
896 return i;
897}
898
899int QMetaObjectPrivate::indexOfConstructor(const QMetaObject *m, const QByteArray &name,
900 int argc, const QArgumentType *types)
901{
902 for (int i = priv(data: m->d.data)->constructorCount-1; i >= 0; --i) {
903 const QMetaMethod method = QMetaMethod::fromRelativeConstructorIndex(mobj: m, index: i);
904 if (methodMatch(m, method, name, argc, types))
905 return i;
906 }
907 return -1;
908}
909
910/*!
911 \fn int QMetaObjectPrivate::signalOffset(const QMetaObject *m)
912 \internal
913 \since 5.0
914
915 Returns the signal offset for the class \a m; i.e., the index position
916 of the class's first signal.
917
918 Similar to QMetaObject::methodOffset(), but non-signal methods are
919 excluded.
920*/
921
922/*!
923 \internal
924 \since 5.0
925
926 Returns the number of signals for the class \a m, including the signals
927 for the base class.
928
929 Similar to QMetaObject::methodCount(), but non-signal methods are
930 excluded.
931*/
932int QMetaObjectPrivate::absoluteSignalCount(const QMetaObject *m)
933{
934 Q_ASSERT(m != nullptr);
935 int n = priv(data: m->d.data)->signalCount;
936 for (m = m->d.superdata; m; m = m->d.superdata)
937 n += priv(data: m->d.data)->signalCount;
938 return n;
939}
940
941/*!
942 \internal
943 \since 5.0
944
945 Returns the index of the signal method \a m.
946
947 Similar to QMetaMethod::methodIndex(), but non-signal methods are
948 excluded.
949*/
950int QMetaObjectPrivate::signalIndex(const QMetaMethod &m)
951{
952 if (!m.mobj)
953 return -1;
954 return QMetaMethodPrivate::get(q: &m)->ownMethodIndex() + signalOffset(m: m.mobj);
955}
956
957/*!
958 \internal
959 \since 5.0
960
961 Returns the signal for the given meta-object \a m at \a signal_index.
962
963 It it different from QMetaObject::method(); the index should not include
964 non-signal methods.
965*/
966QMetaMethod QMetaObjectPrivate::signal(const QMetaObject *m, int signal_index)
967{
968 if (signal_index < 0)
969 return QMetaMethod();
970
971 Q_ASSERT(m != nullptr);
972 int i = signal_index;
973 i -= signalOffset(m);
974 if (i < 0 && m->d.superdata)
975 return signal(m: m->d.superdata, signal_index);
976
977
978 if (i >= 0 && i < priv(data: m->d.data)->signalCount)
979 return QMetaMethod::fromRelativeMethodIndex(mobj: m, index: i);
980 return QMetaMethod();
981}
982
983/*!
984 \internal
985
986 Returns \c true if the \a signalTypes and \a methodTypes are
987 compatible; otherwise returns \c false.
988*/
989bool QMetaObjectPrivate::checkConnectArgs(int signalArgc, const QArgumentType *signalTypes,
990 int methodArgc, const QArgumentType *methodTypes)
991{
992 if (signalArgc < methodArgc)
993 return false;
994 for (int i = 0; i < methodArgc; ++i) {
995 if (signalTypes[i] != methodTypes[i])
996 return false;
997 }
998 return true;
999}
1000
1001/*!
1002 \internal
1003
1004 Returns \c true if the \a signal and \a method arguments are
1005 compatible; otherwise returns \c false.
1006*/
1007bool QMetaObjectPrivate::checkConnectArgs(const QMetaMethodPrivate *signal,
1008 const QMetaMethodPrivate *method)
1009{
1010 if (signal->methodType() != QMetaMethod::Signal)
1011 return false;
1012 if (signal->parameterCount() < method->parameterCount())
1013 return false;
1014 const QMetaObject *smeta = signal->enclosingMetaObject();
1015 const QMetaObject *rmeta = method->enclosingMetaObject();
1016 for (int i = 0; i < method->parameterCount(); ++i) {
1017 uint sourceTypeInfo = signal->parameterTypeInfo(index: i);
1018 uint targetTypeInfo = method->parameterTypeInfo(index: i);
1019 if ((sourceTypeInfo & IsUnresolvedType)
1020 || (targetTypeInfo & IsUnresolvedType)) {
1021 QByteArray sourceName = typeNameFromTypeInfo(mo: smeta, typeInfo: sourceTypeInfo);
1022 QByteArray targetName = typeNameFromTypeInfo(mo: rmeta, typeInfo: targetTypeInfo);
1023 if (sourceName != targetName)
1024 return false;
1025 } else {
1026 int sourceType = typeFromTypeInfo(mo: smeta, typeInfo: sourceTypeInfo);
1027 int targetType = typeFromTypeInfo(mo: rmeta, typeInfo: targetTypeInfo);
1028 if (sourceType != targetType)
1029 return false;
1030 }
1031 }
1032 return true;
1033}
1034
1035static const QMetaObject *QMetaObject_findMetaObject(const QMetaObject *self, const char *name)
1036{
1037 while (self) {
1038 if (strcmp(s1: objectClassName(m: self), s2: name) == 0)
1039 return self;
1040 if (self->d.relatedMetaObjects) {
1041 Q_ASSERT(priv(self->d.data)->revision >= 2);
1042 const auto *e = self->d.relatedMetaObjects;
1043 if (e) {
1044 while (*e) {
1045 if (const QMetaObject *m =QMetaObject_findMetaObject(self: (*e), name))
1046 return m;
1047 ++e;
1048 }
1049 }
1050 }
1051 self = self->d.superdata;
1052 }
1053 return self;
1054}
1055
1056/*!
1057 Finds enumerator \a name and returns its index; otherwise returns
1058 -1.
1059
1060 \sa enumerator(), enumeratorCount(), enumeratorOffset()
1061*/
1062int QMetaObject::indexOfEnumerator(const char *name) const
1063{
1064 const QMetaObject *m = this;
1065 while (m) {
1066 const QMetaObjectPrivate *d = priv(data: m->d.data);
1067 for (int i = 0; i < d->enumeratorCount; ++i) {
1068 const QMetaEnum e(m, i);
1069 const char *prop = rawStringData(mo: m, index: e.data.name());
1070 if (strcmp(s1: name, s2: prop) == 0) {
1071 i += m->enumeratorOffset();
1072 return i;
1073 }
1074 }
1075 m = m->d.superdata;
1076 }
1077 // Check alias names:
1078 m = this;
1079 while (m) {
1080 const QMetaObjectPrivate *d = priv(data: m->d.data);
1081 for (int i = 0; i < d->enumeratorCount; ++i) {
1082 const QMetaEnum e(m, i);
1083 const char *prop = rawStringData(mo: m, index: e.data.alias());
1084 if (strcmp(s1: name, s2: prop) == 0) {
1085 i += m->enumeratorOffset();
1086 return i;
1087 }
1088 }
1089 m = m->d.superdata;
1090 }
1091 return -1;
1092}
1093
1094/*!
1095 Finds property \a name and returns its index; otherwise returns
1096 -1.
1097
1098 \sa property(), propertyCount(), propertyOffset()
1099*/
1100int QMetaObject::indexOfProperty(const char *name) const
1101{
1102 const QMetaObject *m = this;
1103 while (m) {
1104 const QMetaObjectPrivate *d = priv(data: m->d.data);
1105 for (int i = 0; i < d->propertyCount; ++i) {
1106 const QMetaProperty::Data data = QMetaProperty::getMetaPropertyData(mobj: m, index: i);
1107 const char *prop = rawStringData(mo: m, index: data.name());
1108 if (strcmp(s1: name, s2: prop) == 0) {
1109 i += m->propertyOffset();
1110 return i;
1111 }
1112 }
1113 m = m->d.superdata;
1114 }
1115
1116 if (priv(data: this->d.data)->flags & DynamicMetaObject) {
1117 QAbstractDynamicMetaObject *me =
1118 const_cast<QAbstractDynamicMetaObject *>(static_cast<const QAbstractDynamicMetaObject *>(this));
1119
1120 return me->createProperty(name, nullptr);
1121 }
1122
1123 return -1;
1124}
1125
1126/*!
1127 Finds class information item \a name and returns its index;
1128 otherwise returns -1.
1129
1130 \sa classInfo(), classInfoCount(), classInfoOffset()
1131*/
1132int QMetaObject::indexOfClassInfo(const char *name) const
1133{
1134 int i = -1;
1135 const QMetaObject *m = this;
1136 while (m && i < 0) {
1137 for (i = priv(data: m->d.data)->classInfoCount-1; i >= 0; --i)
1138 if (strcmp(s1: name, s2: rawStringData(mo: m, index: m->d.data[priv(data: m->d.data)->classInfoData + 2*i])) == 0) {
1139 i += m->classInfoOffset();
1140 break;
1141 }
1142 m = m->d.superdata;
1143 }
1144 return i;
1145}
1146
1147/*!
1148 \since 4.5
1149
1150 Returns the meta-data for the constructor with the given \a index.
1151
1152 \sa constructorCount(), newInstance()
1153*/
1154QMetaMethod QMetaObject::constructor(int index) const
1155{
1156 int i = index;
1157 if (i >= 0 && i < priv(data: d.data)->constructorCount)
1158 return QMetaMethod::fromRelativeConstructorIndex(mobj: this, index: i);
1159 return QMetaMethod();
1160}
1161
1162/*!
1163 Returns the meta-data for the method with the given \a index.
1164
1165 \sa methodCount(), methodOffset(), indexOfMethod()
1166*/
1167QMetaMethod QMetaObject::method(int index) const
1168{
1169 int i = index;
1170 i -= methodOffset();
1171 if (i < 0 && d.superdata)
1172 return d.superdata->method(index);
1173
1174 if (i >= 0 && i < priv(data: d.data)->methodCount)
1175 return QMetaMethod::fromRelativeMethodIndex(mobj: this, index: i);
1176 return QMetaMethod();
1177}
1178
1179/*!
1180 Returns the meta-data for the enumerator with the given \a index.
1181
1182 \sa enumeratorCount(), enumeratorOffset(), indexOfEnumerator()
1183*/
1184QMetaEnum QMetaObject::enumerator(int index) const
1185{
1186 int i = index;
1187 i -= enumeratorOffset();
1188 if (i < 0 && d.superdata)
1189 return d.superdata->enumerator(index);
1190
1191 if (i >= 0 && i < priv(data: d.data)->enumeratorCount)
1192 return QMetaEnum(this, i);
1193 return QMetaEnum();
1194}
1195
1196/*!
1197 Returns the meta-data for the property with the given \a index.
1198 If no such property exists, a null QMetaProperty is returned.
1199
1200 \sa propertyCount(), propertyOffset(), indexOfProperty()
1201*/
1202QMetaProperty QMetaObject::property(int index) const
1203{
1204 int i = index;
1205 i -= propertyOffset();
1206 if (i < 0 && d.superdata)
1207 return d.superdata->property(index);
1208
1209 if (i >= 0 && i < priv(data: d.data)->propertyCount)
1210 return QMetaProperty(this, i);
1211 return QMetaProperty();
1212}
1213
1214/*!
1215 \since 4.2
1216
1217 Returns the property that has the \c USER flag set to true.
1218
1219 \sa QMetaProperty::isUser()
1220*/
1221QMetaProperty QMetaObject::userProperty() const
1222{
1223 const int propCount = propertyCount();
1224 for (int i = propCount - 1; i >= 0; --i) {
1225 const QMetaProperty prop = property(index: i);
1226 if (prop.isUser())
1227 return prop;
1228 }
1229 return QMetaProperty();
1230}
1231
1232/*!
1233 Returns the meta-data for the item of class information with the
1234 given \a index.
1235
1236 Example:
1237
1238 \snippet code/src_corelib_kernel_qmetaobject.cpp 0
1239
1240 \sa classInfoCount(), classInfoOffset(), indexOfClassInfo()
1241 */
1242QMetaClassInfo QMetaObject::classInfo(int index) const
1243{
1244 int i = index;
1245 i -= classInfoOffset();
1246 if (i < 0 && d.superdata)
1247 return d.superdata->classInfo(index);
1248
1249 QMetaClassInfo result;
1250 if (i >= 0 && i < priv(data: d.data)->classInfoCount) {
1251 result.mobj = this;
1252 result.data = { .d: d.data + priv(data: d.data)->classInfoData + i * QMetaClassInfo::Data::Size };
1253 }
1254 return result;
1255}
1256
1257/*!
1258 Returns \c true if the \a signal and \a method arguments are
1259 compatible; otherwise returns \c false.
1260
1261 Both \a signal and \a method are expected to be normalized.
1262
1263 \sa normalizedSignature()
1264*/
1265bool QMetaObject::checkConnectArgs(const char *signal, const char *method)
1266{
1267 const char *s1 = signal;
1268 const char *s2 = method;
1269 while (*s1++ != '(') { } // scan to first '('
1270 while (*s2++ != '(') { }
1271 if (*s2 == ')' || qstrcmp(str1: s1,str2: s2) == 0) // method has no args or
1272 return true; // exact match
1273 const auto s1len = qstrlen(str: s1);
1274 const auto s2len = qstrlen(str: s2);
1275 if (s2len < s1len && strncmp(s1: s1,s2: s2,n: s2len-1)==0 && s1[s2len-1]==',')
1276 return true; // method has less args
1277 return false;
1278}
1279
1280/*!
1281 \since 5.0
1282 \overload
1283
1284 Returns \c true if the \a signal and \a method arguments are
1285 compatible; otherwise returns \c false.
1286*/
1287bool QMetaObject::checkConnectArgs(const QMetaMethod &signal,
1288 const QMetaMethod &method)
1289{
1290 return QMetaObjectPrivate::checkConnectArgs(
1291 signal: QMetaMethodPrivate::get(q: &signal),
1292 method: QMetaMethodPrivate::get(q: &method));
1293}
1294
1295static void qRemoveWhitespace(const char *s, char *d)
1296{
1297 char last = 0;
1298 while (*s && is_space(s: *s))
1299 s++;
1300 while (*s) {
1301 while (*s && !is_space(s: *s))
1302 last = *d++ = *s++;
1303 while (*s && is_space(s: *s))
1304 s++;
1305 if (*s && ((is_ident_char(s: *s) && is_ident_char(s: last))
1306 || ((*s == ':') && (last == '<')))) {
1307 last = *d++ = ' ';
1308 }
1309 }
1310 *d = '\0';
1311}
1312
1313static char *qNormalizeType(char *d, int &templdepth, QByteArray &result)
1314{
1315 const char *t = d;
1316 while (*d && (templdepth
1317 || (*d != ',' && *d != ')'))) {
1318 if (*d == '<')
1319 ++templdepth;
1320 if (*d == '>')
1321 --templdepth;
1322 ++d;
1323 }
1324 // "void" should only be removed if this is part of a signature that has
1325 // an explicit void argument; e.g., "void foo(void)" --> "void foo()"
1326 if (strncmp(s1: "void)", s2: t, n: d - t + 1) != 0)
1327 result += normalizeTypeInternal(t, e: d);
1328
1329 return d;
1330}
1331
1332
1333/*!
1334 \since 4.2
1335
1336 Normalizes a \a type.
1337
1338 See QMetaObject::normalizedSignature() for a description on how
1339 Qt normalizes.
1340
1341 Example:
1342
1343 \snippet code/src_corelib_kernel_qmetaobject.cpp 1
1344
1345 \sa normalizedSignature()
1346 */
1347QByteArray QMetaObject::normalizedType(const char *type)
1348{
1349 return normalizeTypeInternal(t: type, e: type + qstrlen(str: type));
1350}
1351
1352/*!
1353 Normalizes the signature of the given \a method.
1354
1355 Qt uses normalized signatures to decide whether two given signals
1356 and slots are compatible. Normalization reduces whitespace to a
1357 minimum, moves 'const' to the front where appropriate, removes
1358 'const' from value types and replaces const references with
1359 values.
1360
1361 \sa checkConnectArgs(), normalizedType()
1362 */
1363QByteArray QMetaObject::normalizedSignature(const char *method)
1364{
1365 QByteArray result;
1366 if (!method || !*method)
1367 return result;
1368 int len = int(strlen(s: method));
1369 QVarLengthArray<char> stackbuf(len + 1);
1370 char *d = stackbuf.data();
1371 qRemoveWhitespace(s: method, d);
1372
1373 result.reserve(asize: len);
1374
1375 int argdepth = 0;
1376 int templdepth = 0;
1377 while (*d) {
1378 if (argdepth == 1) {
1379 d = qNormalizeType(d, templdepth, result);
1380 if (!*d) //most likely an invalid signature.
1381 break;
1382 }
1383 if (*d == '(')
1384 ++argdepth;
1385 if (*d == ')')
1386 --argdepth;
1387 result += *d++;
1388 }
1389
1390 return result;
1391}
1392
1393Q_DECL_COLD_FUNCTION static inline bool
1394printMethodNotFoundWarning(const QMetaObject *meta, QLatin1StringView name, qsizetype paramCount,
1395 const char *const *names,
1396 const QtPrivate::QMetaTypeInterface * const *metaTypes)
1397{
1398 // now find the candidates we couldn't use
1399 QByteArray candidateMessage;
1400 for (int i = 0; i < meta->methodCount(); ++i) {
1401 const QMetaMethod method = meta->method(index: i);
1402 if (method.name() == QByteArrayView(name))
1403 candidateMessage += " " + method.methodSignature() + '\n';
1404 }
1405 if (!candidateMessage.isEmpty()) {
1406 candidateMessage.prepend(s: "\nCandidates are:\n");
1407 candidateMessage.chop(n: 1);
1408 }
1409
1410 QVarLengthArray<char, 512> sig;
1411 for (qsizetype i = 1; i < paramCount; ++i) {
1412 if (names[i])
1413 sig.append(buf: names[i], sz: qstrlen(str: names[i]));
1414 else
1415 sig.append(buf: metaTypes[i]->name, sz: qstrlen(str: metaTypes[i]->name));
1416 sig.append(t: ',');
1417 }
1418 if (paramCount != 1)
1419 sig.resize(sz: sig.size() - 1);
1420
1421 qWarning(msg: "QMetaObject::invokeMethod: No such method %s::%.*s(%.*s)%.*s",
1422 meta->className(), int(name.size()), name.constData(),
1423 int(sig.size()), sig.constData(),
1424 int(candidateMessage.size()), candidateMessage.constData());
1425 return false;
1426}
1427
1428/*!
1429 \fn template <typename... Args> bool QMetaObject::invokeMethod(QObject *obj, const char *member, Qt::ConnectionType type, QMetaMethodReturnArgument r, Args &&... args)
1430 \fn template <typename... Args> bool QMetaObject::invokeMethod(QObject *obj, const char *member, QMetaMethodReturnArgument r, Args &&... args)
1431 \fn template <typename... Args> bool QMetaObject::invokeMethod(QObject *obj, const char *member, Qt::ConnectionType type, Args &&... args)
1432 \fn template <typename... Args> bool QMetaObject::invokeMethod(QObject *obj, const char *member, Args &&... args)
1433 \since 6.5
1434 \threadsafe
1435
1436 Invokes the \a member (a signal or a slot name) on the object \a
1437 obj. Returns \c true if the member could be invoked. Returns \c false
1438 if there is no such member or the parameters did not match.
1439
1440 For the overloads with a QMetaMethodReturnArgument parameter, the return
1441 value of the \a member function call is placed in \a ret. For the overloads
1442 without such a member, the return value of the called function (if any)
1443 will be discarded. QMetaMethodReturnArgument is an internal type you should
1444 not use directly. Instead, use the qReturnArg() function.
1445
1446 The overloads with a Qt::ConnectionType \a type parameter allow explicitly
1447 selecting whether the invocation will be synchronous or not:
1448
1449 \list
1450 \li If \a type is Qt::DirectConnection, the member will be invoked immediately
1451 in the current thread.
1452
1453 \li If \a type is Qt::QueuedConnection, a QEvent will be sent and the
1454 member is invoked as soon as the application enters the event loop in the
1455 thread that the \a obj was created in or was moved to.
1456
1457 \li If \a type is Qt::BlockingQueuedConnection, the method will be invoked in
1458 the same way as for Qt::QueuedConnection, except that the current thread
1459 will block until the event is delivered. Using this connection type to
1460 communicate between objects in the same thread will lead to deadlocks.
1461
1462 \li If \a type is Qt::AutoConnection, the member is invoked synchronously
1463 if \a obj lives in the same thread as the caller; otherwise it will invoke
1464 the member asynchronously. This is the behavior of the overloads that do
1465 not have the \a type parameter.
1466 \endlist
1467
1468 You only need to pass the name of the signal or slot to this function,
1469 not the entire signature. For example, to asynchronously invoke
1470 the \l{QThread::quit()}{quit()} slot on a
1471 QThread, use the following code:
1472
1473 \snippet code/src_corelib_kernel_qmetaobject.cpp 2
1474
1475 With asynchronous method invocations, the parameters must be copyable
1476 types, because Qt needs to copy the arguments to store them in an event
1477 behind the scenes. Since Qt 6.5, this function automatically registers the
1478 types being used; however, as a side-effect, it is not possible to make
1479 calls using types that are only forward-declared. Additionally, it is not
1480 possible to make asynchronous calls that use references to
1481 non-const-qualified types as parameters either.
1482
1483 To synchronously invoke the \c compute(QString, int, double) slot on
1484 some arbitrary object \c obj retrieve its return value:
1485
1486 \snippet code/src_corelib_kernel_qmetaobject.cpp invokemethod-no-macro
1487
1488 If the "compute" slot does not take exactly one \l QString, one \c int, and
1489 one \c double in the specified order, the call will fail. Note how it was
1490 necessary to be explicit about the type of the QString, as the character
1491 literal is not exactly the right type to match. If the method instead took
1492 a \l QStringView, a \l qsizetype, and a \c float, the call would need to be
1493 written as:
1494
1495 \snippet code/src_corelib_kernel_qmetaobject.cpp invokemethod-no-macro-other-types
1496
1497 The same call can be executed using the Q_ARG() and Q_RETURN_ARG() macros,
1498 as in:
1499
1500 \snippet code/src_corelib_kernel_qmetaobject.cpp 4
1501
1502 The macros are kept for compatibility with Qt 6.4 and earlier versions, and
1503 can be freely mixed with parameters that do not use the macro. They may be
1504 necessary in rare situations when calling a method that used a typedef to
1505 forward-declared type as a parameter or the return type.
1506
1507 \sa Q_ARG(), Q_RETURN_ARG(), QMetaMethod::invoke()
1508*/
1509
1510/*!
1511 \threadsafe
1512 \overload
1513 \obsolete [6.5] Please use the variadic overload of this function
1514
1515 Invokes the \a member (a signal or a slot name) on the object \a
1516 obj. Returns \c true if the member could be invoked. Returns \c false
1517 if there is no such member or the parameters did not match.
1518
1519 See the variadic invokeMethod() function for more information. This
1520 function should behave the same way as that one, with the following
1521 limitations:
1522
1523 \list
1524 \li The number of parameters is limited to 10.
1525 \li Parameter names may need to be an exact string match.
1526 \li Meta types are not automatically registered.
1527 \endlist
1528
1529 With asynchronous method invocations, the parameters must be of
1530 types that are already known to Qt's meta-object system, because Qt needs
1531 to copy the arguments to store them in an event behind the
1532 scenes. If you try to use a queued connection and get the error
1533 message
1534
1535 \snippet code/src_corelib_kernel_qmetaobject.cpp 3
1536
1537 call qRegisterMetaType() to register the data type before you
1538 call invokeMethod().
1539
1540 \sa Q_ARG(), Q_RETURN_ARG(), qRegisterMetaType(), QMetaMethod::invoke()
1541*/
1542bool QMetaObject::invokeMethod(QObject *obj,
1543 const char *member,
1544 Qt::ConnectionType type,
1545 QGenericReturnArgument ret,
1546 QGenericArgument val0,
1547 QGenericArgument val1,
1548 QGenericArgument val2,
1549 QGenericArgument val3,
1550 QGenericArgument val4,
1551 QGenericArgument val5,
1552 QGenericArgument val6,
1553 QGenericArgument val7,
1554 QGenericArgument val8,
1555 QGenericArgument val9)
1556{
1557 if (!obj)
1558 return false;
1559
1560 const char *typeNames[] = {ret.name(), val0.name(), val1.name(), val2.name(), val3.name(),
1561 val4.name(), val5.name(), val6.name(), val7.name(), val8.name(),
1562 val9.name()};
1563 const void *parameters[] = {ret.data(), val0.data(), val1.data(), val2.data(), val3.data(),
1564 val4.data(), val5.data(), val6.data(), val7.data(), val8.data(),
1565 val9.data()};
1566 int paramCount;
1567 for (paramCount = 1; paramCount < MaximumParamCount; ++paramCount) {
1568 if (qstrlen(str: typeNames[paramCount]) <= 0)
1569 break;
1570 }
1571 return invokeMethodImpl(object: obj, member, type, parameterCount: paramCount, parameters, names: typeNames, metaTypes: nullptr);
1572}
1573
1574bool QMetaObject::invokeMethodImpl(QObject *obj, const char *member, Qt::ConnectionType type,
1575 qsizetype paramCount, const void * const *parameters,
1576 const char * const *typeNames,
1577 const QtPrivate::QMetaTypeInterface * const *metaTypes)
1578{
1579 if (!obj)
1580 return false;
1581
1582 Q_ASSERT(paramCount >= 1); // includes the return type
1583 Q_ASSERT(parameters);
1584 Q_ASSERT(typeNames);
1585
1586 // find the method
1587 QLatin1StringView name(member);
1588 if (name.isEmpty())
1589 return false;
1590
1591 const QMetaObject *meta = obj->metaObject();
1592 for ( ; meta; meta = meta->superClass()) {
1593 auto priv = QMetaObjectPrivate::get(metaobject: meta);
1594 for (int i = 0; i < priv->methodCount; ++i) {
1595 QMetaMethod m = QMetaMethod::fromRelativeMethodIndex(mobj: meta, index: i);
1596 if (m.parameterCount() != (paramCount - 1))
1597 continue;
1598 if (name != stringDataView(mo: meta, index: m.data.name()))
1599 continue;
1600
1601 // attempt to call
1602 QMetaMethodPrivate::InvokeFailReason r =
1603 QMetaMethodPrivate::invokeImpl(self: m, target: obj, type, paramCount, parameters,
1604 typeNames, metaTypes);
1605 if (int(r) <= 0)
1606 return r == QMetaMethodPrivate::InvokeFailReason::None;
1607 }
1608 }
1609
1610 // This method doesn't belong to us; print out a nice warning with candidates.
1611 return printMethodNotFoundWarning(meta: obj->metaObject(), name, paramCount, names: typeNames, metaTypes);
1612}
1613
1614bool QMetaObject::invokeMethodImpl(QObject *object, QtPrivate::QSlotObjectBase *slotObj,
1615 Qt::ConnectionType type, void *ret)
1616{
1617 auto slot = QtPrivate::SlotObjUniquePtr(slotObj);
1618
1619 if (! object)
1620 return false;
1621
1622 Qt::HANDLE currentThreadId = QThread::currentThreadId();
1623 QThread *objectThread = object->thread();
1624 bool receiverInSameThread = false;
1625 if (objectThread)
1626 receiverInSameThread = currentThreadId == QThreadData::get2(thread: objectThread)->threadId.loadRelaxed();
1627
1628 if (type == Qt::AutoConnection)
1629 type = receiverInSameThread ? Qt::DirectConnection : Qt::QueuedConnection;
1630
1631 void *argv[] = { ret };
1632
1633 if (type == Qt::DirectConnection) {
1634 slot->call(r: object, a: argv);
1635 } else if (type == Qt::QueuedConnection) {
1636 if (argv[0]) {
1637 qWarning(msg: "QMetaObject::invokeMethod: Unable to invoke methods with return values in "
1638 "queued connections");
1639 return false;
1640 }
1641
1642 QCoreApplication::postEvent(receiver: object, event: new QMetaCallEvent(std::move(slot), nullptr, -1, 1));
1643 } else if (type == Qt::BlockingQueuedConnection) {
1644#if QT_CONFIG(thread)
1645 if (receiverInSameThread)
1646 qWarning(msg: "QMetaObject::invokeMethod: Dead lock detected");
1647
1648 QSemaphore semaphore;
1649 QCoreApplication::postEvent(receiver: object, event: new QMetaCallEvent(std::move(slot), nullptr, -1, argv, &semaphore));
1650 semaphore.acquire();
1651#endif // QT_CONFIG(thread)
1652 } else {
1653 qWarning(msg: "QMetaObject::invokeMethod: Unknown connection type");
1654 return false;
1655 }
1656 return true;
1657}
1658
1659/*! \fn bool QMetaObject::invokeMethod(QObject *obj, const char *member,
1660 QGenericReturnArgument ret,
1661 QGenericArgument val0 = QGenericArgument(0),
1662 QGenericArgument val1 = QGenericArgument(),
1663 QGenericArgument val2 = QGenericArgument(),
1664 QGenericArgument val3 = QGenericArgument(),
1665 QGenericArgument val4 = QGenericArgument(),
1666 QGenericArgument val5 = QGenericArgument(),
1667 QGenericArgument val6 = QGenericArgument(),
1668 QGenericArgument val7 = QGenericArgument(),
1669 QGenericArgument val8 = QGenericArgument(),
1670 QGenericArgument val9 = QGenericArgument());
1671 \threadsafe
1672 \obsolete [6.5] Please use the variadic overload of this function.
1673 \overload invokeMethod()
1674
1675 This overload always invokes the member using the connection type Qt::AutoConnection.
1676*/
1677
1678/*! \fn bool QMetaObject::invokeMethod(QObject *obj, const char *member,
1679 Qt::ConnectionType type,
1680 QGenericArgument val0 = QGenericArgument(0),
1681 QGenericArgument val1 = QGenericArgument(),
1682 QGenericArgument val2 = QGenericArgument(),
1683 QGenericArgument val3 = QGenericArgument(),
1684 QGenericArgument val4 = QGenericArgument(),
1685 QGenericArgument val5 = QGenericArgument(),
1686 QGenericArgument val6 = QGenericArgument(),
1687 QGenericArgument val7 = QGenericArgument(),
1688 QGenericArgument val8 = QGenericArgument(),
1689 QGenericArgument val9 = QGenericArgument())
1690
1691 \threadsafe
1692 \obsolete [6.5] Please use the variadic overload of this function.
1693 \overload invokeMethod()
1694
1695 This overload can be used if the return value of the member is of no interest.
1696*/
1697
1698/*!
1699 \fn bool QMetaObject::invokeMethod(QObject *obj, const char *member,
1700 QGenericArgument val0 = QGenericArgument(0),
1701 QGenericArgument val1 = QGenericArgument(),
1702 QGenericArgument val2 = QGenericArgument(),
1703 QGenericArgument val3 = QGenericArgument(),
1704 QGenericArgument val4 = QGenericArgument(),
1705 QGenericArgument val5 = QGenericArgument(),
1706 QGenericArgument val6 = QGenericArgument(),
1707 QGenericArgument val7 = QGenericArgument(),
1708 QGenericArgument val8 = QGenericArgument(),
1709 QGenericArgument val9 = QGenericArgument())
1710
1711 \threadsafe
1712 \obsolete [6.5] Please use the variadic overload of this function.
1713 \overload invokeMethod()
1714
1715 This overload invokes the member using the connection type Qt::AutoConnection and
1716 ignores return values.
1717*/
1718
1719/*!
1720 \fn template<typename Functor, typename FunctorReturnType> bool QMetaObject::invokeMethod(QObject *context, Functor &&function, Qt::ConnectionType type, FunctorReturnType *ret)
1721 \fn template<typename Functor, typename FunctorReturnType> bool QMetaObject::invokeMethod(QObject *context, Functor &&function, FunctorReturnType *ret)
1722
1723 \since 5.10
1724 \threadsafe
1725
1726 Invokes the \a function in the event loop of \a context. \a function can be a functor
1727 or a pointer to a member function. Returns \c true if the function could be invoked.
1728 Returns \c false if there is no such function or the parameters did not match.
1729 The return value of the function call is placed in \a ret.
1730
1731 If \a type is set, then the function is invoked using that connection type. Otherwise,
1732 Qt::AutoConnection will be used.
1733*/
1734
1735/*!
1736 \fn QMetaObject::Connection &QMetaObject::Connection::operator=(Connection &&other)
1737
1738 Move-assigns \a other to this object, and returns a reference.
1739*/
1740/*!
1741 \fn QMetaObject::Connection::Connection(Connection &&o)
1742
1743 Move-constructs a Connection instance, making it point to the same object
1744 that \a o was pointing to.
1745*/
1746
1747/*!
1748 \fn QMetaObject::Connection::swap(Connection &other)
1749 \since 5.15
1750
1751 Swaps this Connection instance with \a other. This operation is very fast
1752 and never fails.
1753*/
1754
1755/*!
1756 \class QMetaMethod
1757 \inmodule QtCore
1758
1759 \brief The QMetaMethod class provides meta-data about a member
1760 function.
1761
1762 \ingroup objectmodel
1763
1764 A QMetaMethod has a methodType(), a methodSignature(), a list of
1765 parameterTypes() and parameterNames(), a return typeName(), a
1766 tag(), and an access() specifier. You can use invoke() to invoke
1767 the method on an arbitrary QObject.
1768
1769 \sa QMetaObject, QMetaEnum, QMetaProperty, {Qt's Property System}
1770*/
1771
1772/*!
1773 \enum QMetaMethod::Attributes
1774
1775 \internal
1776
1777 \value Compatibility
1778 \value Cloned
1779 \value Scriptable
1780*/
1781
1782/*!
1783 \fn bool QMetaMethod::isValid() const
1784 \since 5.0
1785
1786 Returns \c true if this method is valid (can be introspected and
1787 invoked), otherwise returns \c false.
1788*/
1789
1790/*! \fn bool QMetaMethod::operator==(const QMetaMethod &m1, const QMetaMethod &m2)
1791 \since 5.0
1792 \overload
1793
1794 Returns \c true if method \a m1 is equal to method \a m2,
1795 otherwise returns \c false.
1796*/
1797
1798/*! \fn bool QMetaMethod::operator!=(const QMetaMethod &m1, const QMetaMethod &m2)
1799 \since 5.0
1800 \overload
1801
1802 Returns \c true if method \a m1 is not equal to method \a m2,
1803 otherwise returns \c false.
1804*/
1805
1806/*!
1807 \fn const QMetaObject *QMetaMethod::enclosingMetaObject() const
1808 \internal
1809*/
1810
1811/*!
1812 \enum QMetaMethod::MethodType
1813
1814 \value Method The function is a plain member function.
1815 \value Signal The function is a signal.
1816 \value Slot The function is a slot.
1817 \value Constructor The function is a constructor.
1818*/
1819
1820/*!
1821 \fn QMetaMethod::QMetaMethod()
1822 \internal
1823*/
1824
1825/*!
1826 \internal
1827*/
1828QMetaMethod QMetaMethod::fromRelativeMethodIndex(const QMetaObject *mobj, int index)
1829{
1830 Q_ASSERT(index >= 0 && index < priv(mobj->d.data)->methodCount);
1831 QMetaMethod m;
1832 m.mobj = mobj;
1833 m.data = { .d: mobj->d.data + priv(data: mobj->d.data)->methodData + index * Data::Size };
1834 return m;
1835}
1836
1837QMetaMethod QMetaMethod::fromRelativeConstructorIndex(const QMetaObject *mobj, int index)
1838{
1839 Q_ASSERT(index >= 0 && index < priv(mobj->d.data)->constructorCount);
1840 QMetaMethod m;
1841 m.mobj = mobj;
1842 m.data = { .d: mobj->d.data + priv(data: mobj->d.data)->constructorData + index * Data::Size };
1843 return m;
1844}
1845
1846/*!
1847 \macro Q_METAMETHOD_INVOKE_MAX_ARGS
1848 \relates QMetaMethod
1849
1850 Equals maximum number of arguments available for
1851 execution of the method via QMetaMethod::invoke()
1852 */
1853
1854QByteArray QMetaMethodPrivate::signature() const
1855{
1856 Q_ASSERT(priv(mobj->d.data)->revision >= 7);
1857 QByteArray result;
1858 result.reserve(asize: 256);
1859 result += name();
1860 result += '(';
1861 QList<QByteArray> argTypes = parameterTypes();
1862 for (int i = 0; i < argTypes.size(); ++i) {
1863 if (i)
1864 result += ',';
1865 result += argTypes.at(i);
1866 }
1867 result += ')';
1868 return result;
1869}
1870
1871QByteArray QMetaMethodPrivate::name() const
1872{
1873 Q_ASSERT(priv(mobj->d.data)->revision >= 7);
1874 return stringData(mo: mobj, index: data.name());
1875}
1876
1877int QMetaMethodPrivate::typesDataIndex() const
1878{
1879 Q_ASSERT(priv(mobj->d.data)->revision >= 7);
1880 return data.parameters();
1881}
1882
1883const char *QMetaMethodPrivate::rawReturnTypeName() const
1884{
1885 Q_ASSERT(priv(mobj->d.data)->revision >= 7);
1886 uint typeInfo = mobj->d.data[typesDataIndex()];
1887 if (typeInfo & IsUnresolvedType)
1888 return rawStringData(mo: mobj, index: typeInfo & TypeNameIndexMask);
1889 else
1890 return QMetaType(typeInfo).name();
1891}
1892
1893int QMetaMethodPrivate::returnType() const
1894{
1895 return parameterType(index: -1);
1896}
1897
1898int QMetaMethodPrivate::parameterCount() const
1899{
1900 Q_ASSERT(priv(mobj->d.data)->revision >= 7);
1901 return data.argc();
1902}
1903
1904inline void
1905QMetaMethodPrivate::checkMethodMetaTypeConsistency(const QtPrivate::QMetaTypeInterface *iface,
1906 int index) const
1907{
1908 uint typeInfo = parameterTypeInfo(index);
1909 QMetaType mt(iface);
1910 if (iface) {
1911 if ((typeInfo & IsUnresolvedType) == 0)
1912 Q_ASSERT(mt.id() == int(typeInfo & TypeNameIndexMask));
1913 Q_ASSERT(mt.name());
1914 } else {
1915 // The iface can only be null for a parameter if that parameter is a
1916 // const-ref to a forward-declared type. Since primitive types are
1917 // never incomplete, we can assert it's not one of them.
1918
1919#define ASSERT_NOT_PRIMITIVE_TYPE(TYPE, METATYPEID, NAME) \
1920 Q_ASSERT(typeInfo != QMetaType::TYPE);
1921 QT_FOR_EACH_STATIC_PRIMITIVE_NON_VOID_TYPE(ASSERT_NOT_PRIMITIVE_TYPE)
1922#undef ASSERT_NOT_PRIMITIVE_TYPE
1923 Q_ASSERT(typeInfo != QMetaType::QObjectStar);
1924
1925 // Prior to Qt 6.4 we failed to record void and void*
1926 if (priv(data: mobj->d.data)->revision >= 11) {
1927 Q_ASSERT(typeInfo != QMetaType::Void);
1928 Q_ASSERT(typeInfo != QMetaType::VoidStar);
1929 }
1930 }
1931}
1932
1933int QMetaMethodPrivate::parametersDataIndex() const
1934{
1935 Q_ASSERT(priv(mobj->d.data)->revision >= 7);
1936 return typesDataIndex() + 1;
1937}
1938
1939uint QMetaMethodPrivate::parameterTypeInfo(int index) const
1940{
1941 Q_ASSERT(priv(mobj->d.data)->revision >= 7);
1942 return mobj->d.data[parametersDataIndex() + index];
1943}
1944
1945const QtPrivate::QMetaTypeInterface *QMetaMethodPrivate::returnMetaTypeInterface() const
1946{
1947 Q_ASSERT(priv(mobj->d.data)->revision >= 7);
1948 if (methodType() == QMetaMethod::Constructor)
1949 return nullptr; // constructors don't have return types
1950
1951 const QtPrivate::QMetaTypeInterface *iface = mobj->d.metaTypes[data.metaTypeOffset()];
1952 checkMethodMetaTypeConsistency(iface, index: -1);
1953 return iface;
1954}
1955
1956const QtPrivate::QMetaTypeInterface * const *QMetaMethodPrivate::parameterMetaTypeInterfaces() const
1957{
1958 Q_ASSERT(priv(mobj->d.data)->revision >= 7);
1959 int offset = (methodType() == QMetaMethod::Constructor ? 0 : 1);
1960 const auto ifaces = &mobj->d.metaTypes[data.metaTypeOffset() + offset];
1961
1962 for (int i = 0; i < parameterCount(); ++i)
1963 checkMethodMetaTypeConsistency(iface: ifaces[i], index: i);
1964
1965 return ifaces;
1966}
1967
1968int QMetaMethodPrivate::parameterType(int index) const
1969{
1970 Q_ASSERT(priv(mobj->d.data)->revision >= 7);
1971 return typeFromTypeInfo(mo: mobj, typeInfo: parameterTypeInfo(index));
1972}
1973
1974void QMetaMethodPrivate::getParameterTypes(int *types) const
1975{
1976 Q_ASSERT(priv(mobj->d.data)->revision >= 7);
1977 int dataIndex = parametersDataIndex();
1978 int argc = parameterCount();
1979 for (int i = 0; i < argc; ++i) {
1980 int id = typeFromTypeInfo(mo: mobj, typeInfo: mobj->d.data[dataIndex++]);
1981 *(types++) = id;
1982 }
1983}
1984
1985QByteArray QMetaMethodPrivate::parameterTypeName(int index) const
1986{
1987 int paramsIndex = parametersDataIndex();
1988 return typeNameFromTypeInfo(mo: mobj, typeInfo: mobj->d.data[paramsIndex + index]);
1989}
1990
1991QList<QByteArray> QMetaMethodPrivate::parameterTypes() const
1992{
1993 Q_ASSERT(priv(mobj->d.data)->revision >= 7);
1994 int argc = parameterCount();
1995 QList<QByteArray> list;
1996 list.reserve(asize: argc);
1997 int paramsIndex = parametersDataIndex();
1998 for (int i = 0; i < argc; ++i)
1999 list += typeNameFromTypeInfo(mo: mobj, typeInfo: mobj->d.data[paramsIndex + i]);
2000 return list;
2001}
2002
2003QList<QByteArray> QMetaMethodPrivate::parameterNames() const
2004{
2005 Q_ASSERT(priv(mobj->d.data)->revision >= 7);
2006 int argc = parameterCount();
2007 QList<QByteArray> list;
2008 list.reserve(asize: argc);
2009 int namesIndex = parametersDataIndex() + argc;
2010 for (int i = 0; i < argc; ++i)
2011 list += stringData(mo: mobj, index: mobj->d.data[namesIndex + i]);
2012 return list;
2013}
2014
2015QByteArray QMetaMethodPrivate::tag() const
2016{
2017 Q_ASSERT(priv(mobj->d.data)->revision >= 7);
2018 return stringData(mo: mobj, index: data.tag());
2019}
2020
2021int QMetaMethodPrivate::ownMethodIndex() const
2022{
2023 // recompute the methodIndex by reversing the arithmetic in QMetaObject::method()
2024 return ( data.d - mobj->d.data - priv(data: mobj->d.data)->methodData)/Data::Size;
2025}
2026
2027int QMetaMethodPrivate::ownConstructorMethodIndex() const
2028{
2029 // recompute the methodIndex by reversing the arithmetic in QMetaObject::constructor()
2030 Q_ASSERT(methodType() == Constructor);
2031 return ( data.d - mobj->d.data - priv(data: mobj->d.data)->constructorData)/Data::Size;
2032}
2033
2034/*!
2035 \since 5.0
2036
2037 Returns the signature of this method (e.g.,
2038 \c{setValue(double)}).
2039
2040 \sa parameterTypes(), parameterNames()
2041*/
2042QByteArray QMetaMethod::methodSignature() const
2043{
2044 if (!mobj)
2045 return QByteArray();
2046 return QMetaMethodPrivate::get(q: this)->signature();
2047}
2048
2049/*!
2050 \since 5.0
2051
2052 Returns the name of this method.
2053
2054 \sa methodSignature(), parameterCount()
2055*/
2056QByteArray QMetaMethod::name() const
2057{
2058 if (!mobj)
2059 return QByteArray();
2060 return QMetaMethodPrivate::get(q: this)->name();
2061}
2062
2063/*!
2064 \since 5.0
2065
2066 Returns the return type of this method.
2067
2068 The return value is one of the types that are registered
2069 with QMetaType, or QMetaType::UnknownType if the type is not registered.
2070
2071 \sa parameterType(), QMetaType, typeName(), returnMetaType()
2072*/
2073int QMetaMethod::returnType() const
2074 {
2075 return returnMetaType().id();
2076}
2077
2078/*!
2079 \since 6.0
2080
2081 Returns the return type of this method.
2082 \sa parameterMetaType(), QMetaType, typeName()
2083*/
2084QMetaType QMetaMethod::returnMetaType() const
2085{
2086 if (!mobj || methodType() == QMetaMethod::Constructor)
2087 return QMetaType{};
2088 auto mt = QMetaType(mobj->d.metaTypes[data.metaTypeOffset()]);
2089 if (mt.id() == QMetaType::UnknownType)
2090 return QMetaType(QMetaMethodPrivate::get(q: this)->returnType());
2091 else
2092 return mt;
2093}
2094
2095/*!
2096 \since 5.0
2097
2098 Returns the number of parameters of this method.
2099
2100 \sa parameterType(), parameterNames()
2101*/
2102int QMetaMethod::parameterCount() const
2103{
2104 if (!mobj)
2105 return 0;
2106 return QMetaMethodPrivate::get(q: this)->parameterCount();
2107}
2108
2109/*!
2110 \since 5.0
2111
2112 Returns the type of the parameter at the given \a index.
2113
2114 The return value is one of the types that are registered
2115 with QMetaType, or QMetaType::UnknownType if the type is not registered.
2116
2117 \sa parameterCount(), parameterMetaType(), returnType(), QMetaType
2118*/
2119int QMetaMethod::parameterType(int index) const
2120{
2121 return parameterMetaType(index).id();
2122}
2123
2124/*!
2125 \since 6.0
2126
2127 Returns the metatype of the parameter at the given \a index.
2128
2129 If the \a index is smaller than zero or larger than
2130 parameterCount(), an invalid QMetaType is returned.
2131
2132 \sa parameterCount(), returnMetaType(), QMetaType
2133*/
2134QMetaType QMetaMethod::parameterMetaType(int index) const
2135{
2136 if (!mobj || index < 0)
2137 return {};
2138 auto priv = QMetaMethodPrivate::get(q: this);
2139 if (index >= priv->parameterCount())
2140 return {};
2141 // + 1 if there exists a return type
2142 auto parameterOffset = index + (methodType() == QMetaMethod::Constructor ? 0 : 1);
2143 auto mt = QMetaType(mobj->d.metaTypes[data.metaTypeOffset() + parameterOffset]);
2144 if (mt.id() == QMetaType::UnknownType)
2145 return QMetaType(QMetaMethodPrivate::get(q: this)->parameterType(index));
2146 else
2147 return mt;
2148}
2149
2150/*!
2151 \since 5.0
2152 \internal
2153
2154 Gets the parameter \a types of this method. The storage
2155 for \a types must be able to hold parameterCount() items.
2156
2157 \sa parameterCount(), returnType(), parameterType()
2158*/
2159void QMetaMethod::getParameterTypes(int *types) const
2160{
2161 if (!mobj)
2162 return;
2163 QMetaMethodPrivate::get(q: this)->getParameterTypes(types);
2164}
2165
2166/*!
2167 Returns a list of parameter types.
2168
2169 \sa parameterNames(), methodSignature()
2170*/
2171QList<QByteArray> QMetaMethod::parameterTypes() const
2172{
2173 if (!mobj)
2174 return QList<QByteArray>();
2175 return QMetaMethodPrivate::get(q: this)->parameterTypes();
2176}
2177
2178/*!
2179 \since 6.0
2180 Returns the name of the type at position \a index
2181 If there is no parameter at \a index, returns an empty QByteArray
2182
2183 \sa parameterNames()
2184 */
2185QByteArray QMetaMethod::parameterTypeName(int index) const
2186{
2187 if (!mobj || index < 0 || index >= parameterCount())
2188 return {};
2189 return QMetaMethodPrivate::get(q: this)->parameterTypeName(index);
2190}
2191
2192/*!
2193 Returns a list of parameter names.
2194
2195 \sa parameterTypes(), methodSignature()
2196*/
2197QList<QByteArray> QMetaMethod::parameterNames() const
2198{
2199 if (!mobj)
2200 return QList<QByteArray>();
2201 return QMetaMethodPrivate::get(q: this)->parameterNames();
2202}
2203
2204
2205/*!
2206 Returns the return type name of this method.
2207
2208 \sa returnType(), QMetaType::type()
2209*/
2210const char *QMetaMethod::typeName() const
2211{
2212 if (!mobj)
2213 return nullptr;
2214 return QMetaMethodPrivate::get(q: this)->rawReturnTypeName();
2215}
2216
2217/*!
2218 Returns the tag associated with this method.
2219
2220 Tags are special macros recognized by \c moc that make it
2221 possible to add extra information about a method.
2222
2223 Tag information can be added in the following
2224 way in the function declaration:
2225
2226 \snippet code/src_corelib_kernel_qmetaobject.cpp 10
2227
2228 and the information can be accessed by using:
2229
2230 \snippet code/src_corelib_kernel_qmetaobject.cpp 11
2231
2232 For the moment, \c moc will extract and record all tags, but it will not
2233 handle any of them specially. You can use the tags to annotate your methods
2234 differently, and treat them according to the specific needs of your
2235 application.
2236
2237 \note Since Qt 5.0, \c moc expands preprocessor macros, so it is necessary
2238 to surround the definition with \c #ifndef \c Q_MOC_RUN, as shown in the
2239 example above. This was not required in Qt 4. The code as shown above works
2240 with Qt 4 too.
2241*/
2242const char *QMetaMethod::tag() const
2243{
2244 if (!mobj)
2245 return nullptr;
2246 return QMetaMethodPrivate::get(q: this)->tag().constData();
2247}
2248
2249
2250/*!
2251 \internal
2252 */
2253int QMetaMethod::attributes() const
2254{
2255 if (!mobj)
2256 return false;
2257 return data.flags() >> 4;
2258}
2259
2260/*!
2261 \since 4.6
2262
2263 Returns this method's index.
2264*/
2265int QMetaMethod::methodIndex() const
2266{
2267 if (!mobj)
2268 return -1;
2269 return QMetaMethodPrivate::get(q: this)->ownMethodIndex() + mobj->methodOffset();
2270}
2271
2272/*!
2273 \since 6.0
2274
2275 Returns this method's local index inside.
2276*/
2277int QMetaMethod::relativeMethodIndex() const
2278{
2279 if (!mobj)
2280 return -1;
2281 return QMetaMethodPrivate::get(q: this)->ownMethodIndex();
2282}
2283
2284// This method has been around for a while, but the documentation was marked \internal until 5.1
2285/*!
2286 \since 5.1
2287 Returns the method revision if one was
2288 specified by Q_REVISION, otherwise returns 0.
2289 */
2290int QMetaMethod::revision() const
2291{
2292 if (!mobj)
2293 return 0;
2294 if (data.flags() & MethodRevisioned) {
2295 int offset = priv(data: mobj->d.data)->methodData
2296 + priv(data: mobj->d.data)->methodCount * Data::Size
2297 + QMetaMethodPrivate::get(q: this)->ownMethodIndex();
2298 return mobj->d.data[offset];
2299 }
2300 return 0;
2301}
2302
2303/*!
2304 \since 6.2
2305
2306 Returns whether the method is const qualified.
2307
2308 \note This method might erroneously return \c false for a const method
2309 if it belongs to a library compiled against an older version of Qt.
2310 */
2311bool QMetaMethod::isConst() const
2312{
2313 if (!mobj)
2314 return false;
2315 if (QMetaObjectPrivate::get(metaobject: mobj)->revision < 10)
2316 return false;
2317 return data.flags() & MethodIsConst;
2318}
2319
2320/*!
2321 Returns the access specification of this method (private,
2322 protected, or public).
2323
2324 \note Signals are always public, but you should regard that as an
2325 implementation detail. It is almost always a bad idea to emit a signal from
2326 outside its class.
2327
2328 \sa methodType()
2329*/
2330QMetaMethod::Access QMetaMethod::access() const
2331{
2332 if (!mobj)
2333 return Private;
2334 return (QMetaMethod::Access)(data.flags() & AccessMask);
2335}
2336
2337/*!
2338 Returns the type of this method (signal, slot, or method).
2339
2340 \sa access()
2341*/
2342QMetaMethod::MethodType QMetaMethod::methodType() const
2343{
2344 if (!mobj)
2345 return QMetaMethod::Method;
2346 return (QMetaMethod::MethodType)((data.flags() & MethodTypeMask)>>2);
2347}
2348
2349/*!
2350 \fn template <typename PointerToMemberFunction> QMetaMethod QMetaMethod::fromSignal(PointerToMemberFunction signal)
2351 \since 5.0
2352
2353 Returns the meta-method that corresponds to the given \a signal, or an
2354 invalid QMetaMethod if \a signal is not a signal of the class.
2355
2356 Example:
2357
2358 \snippet code/src_corelib_kernel_qmetaobject.cpp 9
2359*/
2360
2361/*!
2362 \internal
2363
2364 Implementation of the fromSignal() function.
2365
2366 \a metaObject is the class's meta-object
2367 \a signal is a pointer to a pointer to a member signal of the class
2368*/
2369QMetaMethod QMetaMethod::fromSignalImpl(const QMetaObject *metaObject, void **signal)
2370{
2371 int i = -1;
2372 void *args[] = { &i, signal };
2373 for (const QMetaObject *m = metaObject; m; m = m->d.superdata) {
2374 m->static_metacall(cl: QMetaObject::IndexOfMethod, idx: 0, argv: args);
2375 if (i >= 0)
2376 return QMetaMethod::fromRelativeMethodIndex(mobj: m, index: i);
2377 }
2378 return QMetaMethod();
2379}
2380
2381/*!
2382 \fn template <typename... Args> bool QMetaMethod::invoke(QObject *obj, Qt::ConnectionType type, QMetaMethodReturnArgument ret, Args &&... arguments) const
2383 \fn template <typename... Args> bool QMetaMethod::invoke(QObject *obj, Qt::ConnectionType type, Args &&... arguments) const
2384 \fn template <typename... Args> bool QMetaMethod::invoke(QObject *obj, QMetaMethodReturnArgument ret, Args &&... arguments) const
2385 \fn template <typename... Args> bool QMetaMethod::invoke(QObject *obj, Args &&... arguments) const
2386 \since 6.5
2387
2388 Invokes this method on the object \a object. Returns \c true if the member could be invoked.
2389 Returns \c false if there is no such member or the parameters did not match.
2390
2391 For the overloads with a QMetaMethodReturnArgument parameter, the return
2392 value of the \a member function call is placed in \a ret. For the overloads
2393 without such a member, the return value of the called function (if any)
2394 will be discarded. QMetaMethodReturnArgument is an internal type you should
2395 not use directly. Instead, use the qReturnArg() function.
2396
2397 The overloads with a Qt::ConnectionType \a type parameter allow explicitly
2398 selecting whether the invocation will be synchronous or not:
2399
2400 \list
2401 \li If \a type is Qt::DirectConnection, the member will be invoked immediately
2402 in the current thread.
2403
2404 \li If \a type is Qt::QueuedConnection, a QEvent will be sent and the
2405 member is invoked as soon as the application enters the event loop in the
2406 thread the \a obj was created in or was moved to.
2407
2408 \li If \a type is Qt::BlockingQueuedConnection, the method will be invoked in
2409 the same way as for Qt::QueuedConnection, except that the current thread
2410 will block until the event is delivered. Using this connection type to
2411 communicate between objects in the same thread will lead to deadlocks.
2412
2413 \li If \a type is Qt::AutoConnection, the member is invoked synchronously
2414 if \a obj lives in the same thread as the caller; otherwise it will invoke
2415 the member asynchronously. This is the behavior of the overloads that do
2416 not have the \a type parameter.
2417 \endlist
2418
2419 To asynchronously invoke the
2420 \l{QPushButton::animateClick()}{animateClick()} slot on a
2421 QPushButton:
2422
2423 \snippet code/src_corelib_kernel_qmetaobject.cpp 6
2424
2425 With asynchronous method invocations, the parameters must be copyable
2426 types, because Qt needs to copy the arguments to store them in an event
2427 behind the scenes. Since Qt 6.5, this function automatically registers the
2428 types being used; however, as a side-effect, it is not possible to make
2429 calls using types that are only forward-declared. Additionally, it is not
2430 possible to make asynchronous calls that use references to
2431 non-const-qualified types as parameters either.
2432
2433 To synchronously invoke the \c compute(QString, int, double) slot on
2434 some arbitrary object \c obj retrieve its return value:
2435
2436 \snippet code/src_corelib_kernel_qmetaobject.cpp invoke-no-macro
2437
2438 If the "compute" slot does not take exactly one \l QString, one \c int, and
2439 one \c double in the specified order, the call will fail. Note how it was
2440 necessary to be explicit about the type of the QString, as the character
2441 literal is not exactly the right type to match. If the method instead took
2442 a \l QByteArray, a \l qint64, and a \c{long double}, the call would need to be
2443 written as:
2444
2445 \snippet code/src_corelib_kernel_qmetaobject.cpp invoke-no-macro-other-types
2446
2447 The same call can be executed using the Q_ARG() and Q_RETURN_ARG() macros,
2448 as in:
2449
2450 \snippet code/src_corelib_kernel_qmetaobject.cpp 8
2451
2452 \warning this method will not test the validity of the arguments: \a object
2453 must be an instance of the class of the QMetaObject of which this QMetaMethod
2454 has been constructed with.
2455
2456 \sa Q_ARG(), Q_RETURN_ARG(), qRegisterMetaType(), QMetaObject::invokeMethod()
2457*/
2458
2459/*!
2460 \obsolete [6.5] Please use the variadic overload of this function
2461
2462 Invokes this method on the object \a object. Returns \c true if the member could be invoked.
2463 Returns \c false if there is no such member or the parameters did not match.
2464
2465 See the variadic invokeMethod() function for more information. This
2466 function should behave the same way as that one, with the following
2467 limitations:
2468
2469 \list
2470 \li The number of parameters is limited to 10.
2471 \li Parameter names may need to be an exact string match.
2472 \li Meta types are not automatically registered.
2473 \endlist
2474
2475 With asynchronous method invocations, the parameters must be of
2476 types that are known to Qt's meta-object system, because Qt needs
2477 to copy the arguments to store them in an event behind the
2478 scenes. If you try to use a queued connection and get the error
2479 message
2480
2481 \snippet code/src_corelib_kernel_qmetaobject.cpp 7
2482
2483 call qRegisterMetaType() to register the data type before you
2484 call QMetaMethod::invoke().
2485
2486 \warning In addition to the limitations of the variadic invoke() overload,
2487 the arguments must have the same type as the ones expected by the method,
2488 else, the behavior is undefined.
2489
2490 \sa Q_ARG(), Q_RETURN_ARG(), qRegisterMetaType(), QMetaObject::invokeMethod()
2491*/
2492bool QMetaMethod::invoke(QObject *object,
2493 Qt::ConnectionType connectionType,
2494 QGenericReturnArgument returnValue,
2495 QGenericArgument val0,
2496 QGenericArgument val1,
2497 QGenericArgument val2,
2498 QGenericArgument val3,
2499 QGenericArgument val4,
2500 QGenericArgument val5,
2501 QGenericArgument val6,
2502 QGenericArgument val7,
2503 QGenericArgument val8,
2504 QGenericArgument val9) const
2505{
2506 if (!object || !mobj)
2507 return false;
2508
2509 // check argument count (we don't allow invoking a method if given too few arguments)
2510 const char *typeNames[] = {
2511 returnValue.name(),
2512 val0.name(),
2513 val1.name(),
2514 val2.name(),
2515 val3.name(),
2516 val4.name(),
2517 val5.name(),
2518 val6.name(),
2519 val7.name(),
2520 val8.name(),
2521 val9.name()
2522 };
2523 void *param[] = {
2524 returnValue.data(),
2525 val0.data(),
2526 val1.data(),
2527 val2.data(),
2528 val3.data(),
2529 val4.data(),
2530 val5.data(),
2531 val6.data(),
2532 val7.data(),
2533 val8.data(),
2534 val9.data()
2535 };
2536
2537 int paramCount;
2538 for (paramCount = 1; paramCount < MaximumParamCount; ++paramCount) {
2539 if (qstrlen(str: typeNames[paramCount]) <= 0)
2540 break;
2541 }
2542 return invokeImpl(self: *this, target: object, connectionType, paramCount, parameters: param, typeNames, metaTypes: nullptr);
2543}
2544
2545bool QMetaMethod::invokeImpl(QMetaMethod self, void *target, Qt::ConnectionType connectionType,
2546 qsizetype paramCount, const void *const *parameters,
2547 const char *const *typeNames,
2548 const QtPrivate::QMetaTypeInterface *const *metaTypes)
2549{
2550 if (!target || !self.mobj)
2551 return false;
2552 QMetaMethodPrivate::InvokeFailReason r =
2553 QMetaMethodPrivate::invokeImpl(self, target, connectionType, paramCount, parameters,
2554 typeNames, metaTypes);
2555 if (Q_LIKELY(r == QMetaMethodPrivate::InvokeFailReason::None))
2556 return true;
2557
2558 if (int(r) >= int(QMetaMethodPrivate::InvokeFailReason::FormalParameterMismatch)) {
2559 int n = int(r) - int(QMetaMethodPrivate::InvokeFailReason::FormalParameterMismatch);
2560 qWarning(msg: "QMetaMethod::invoke: cannot convert formal parameter %d from %s in call to %s::%s",
2561 n, typeNames[n + 1] ? typeNames[n + 1] : metaTypes[n + 1]->name,
2562 self.mobj->className(), self.methodSignature().constData());
2563 }
2564 if (r == QMetaMethodPrivate::InvokeFailReason::TooFewArguments) {
2565 qWarning(msg: "QMetaMethod::invoke: too few arguments (%d) in call to %s::%s",
2566 int(paramCount), self.mobj->className(), self.methodSignature().constData());
2567 }
2568 return false;
2569}
2570
2571auto QMetaMethodInvoker::invokeImpl(QMetaMethod self, void *target,
2572 Qt::ConnectionType connectionType,
2573 qsizetype paramCount, const void *const *parameters,
2574 const char *const *typeNames,
2575 const QtPrivate::QMetaTypeInterface *const *metaTypes) -> InvokeFailReason
2576{
2577 auto object = static_cast<QObject *>(target);
2578 auto priv = QMetaMethodPrivate::get(q: &self);
2579 constexpr bool MetaTypesAreOptional = QT_VERSION < QT_VERSION_CHECK(7, 0, 0);
2580 auto methodMetaTypes = priv->parameterMetaTypeInterfaces();
2581 auto param = const_cast<void **>(parameters);
2582
2583 Q_ASSERT(priv->mobj);
2584 Q_ASSERT(self.methodType() == Constructor || object);
2585 Q_ASSERT(self.methodType() == Constructor || connectionType == Qt::ConnectionType(-1) ||
2586 priv->mobj->cast(object));
2587 Q_ASSERT(paramCount >= 1); // includes the return type
2588 Q_ASSERT(parameters);
2589 Q_ASSERT(typeNames);
2590 Q_ASSERT(MetaTypesAreOptional || metaTypes);
2591
2592 if ((paramCount - 1) < qsizetype(priv->data.argc()))
2593 return InvokeFailReason::TooFewArguments;
2594
2595 // 0 is the return type, 1 is the first formal parameter
2596 auto checkTypesAreCompatible = [=](int idx) {
2597 uint typeInfo = priv->parameterTypeInfo(index: idx - 1);
2598 QLatin1StringView userTypeName(typeNames[idx] ? typeNames[idx] : metaTypes[idx]->name);
2599
2600 if ((typeInfo & IsUnresolvedType) == 0) {
2601 // this is a built-in type
2602 if (MetaTypesAreOptional && !metaTypes)
2603 return int(typeInfo) == QMetaType::fromName(name: userTypeName).id();
2604 return int(typeInfo) == metaTypes[idx]->typeId;
2605 }
2606
2607 QLatin1StringView methodTypeName = stringDataView(mo: priv->mobj, index: typeInfo & TypeNameIndexMask);
2608 if ((MetaTypesAreOptional && !metaTypes) || !metaTypes[idx]) {
2609 // compatibility call, compare strings
2610 if (methodTypeName == userTypeName)
2611 return true;
2612
2613 // maybe the user type needs normalization
2614 QByteArray normalized = normalizeTypeInternal(t: userTypeName.begin(), e: userTypeName.end());
2615 return methodTypeName == QLatin1StringView(normalized);
2616 }
2617
2618 QMetaType userType(metaTypes[idx]);
2619 Q_ASSERT(userType.isValid());
2620 if (QMetaType(methodMetaTypes[idx - 1]) == userType)
2621 return true;
2622
2623 // if the parameter type was NOT only forward-declared, it MUST have
2624 // matched
2625 if (methodMetaTypes[idx - 1])
2626 return false;
2627
2628 // resolve from the name moc stored for us
2629 QMetaType resolved = QMetaType::fromName(name: methodTypeName);
2630 return resolved == userType;
2631 };
2632
2633 // force all types to be registered, just in case
2634 for (qsizetype i = 0; metaTypes && i < paramCount; ++i)
2635 QMetaType(metaTypes[i]).registerType();
2636
2637 // check formal parameters first (overload set)
2638 for (qsizetype i = 1; i < paramCount; ++i) {
2639 if (!checkTypesAreCompatible(i))
2640 return InvokeFailReason(int(InvokeFailReason::FormalParameterMismatch) + i - 1);
2641 }
2642
2643 // handle constructors first
2644 if (self.methodType() == Constructor) {
2645 if (object) {
2646 qWarning(msg: "QMetaMethod::invokeMethod: cannot call constructor %s on object %p",
2647 self.methodSignature().constData(), object);
2648 return InvokeFailReason::ConstructorCallOnObject;
2649 }
2650
2651 if (!parameters[0]) {
2652 qWarning(msg: "QMetaMethod::invokeMethod: constructor call to %s must assign a return type",
2653 self.methodSignature().constData());
2654 return InvokeFailReason::ConstructorCallWithoutResult;
2655 }
2656
2657 if (!MetaTypesAreOptional || metaTypes) {
2658 if (metaTypes[0]->typeId != QMetaType::QObjectStar) {
2659 qWarning(msg: "QMetaMethod::invokeMethod: cannot convert QObject* to %s on constructor call %s",
2660 metaTypes[0]->name, self.methodSignature().constData());
2661 return InvokeFailReason::ReturnTypeMismatch;
2662 }
2663 }
2664
2665 int idx = priv->ownConstructorMethodIndex();
2666 if (priv->mobj->static_metacall(cl: QMetaObject::CreateInstance, idx, argv: param) >= 0)
2667 return InvokeFailReason::ConstructorCallFailed;
2668 return {};
2669 }
2670
2671 // regular type - check return type
2672 if (parameters[0]) {
2673 if (!checkTypesAreCompatible(0)) {
2674 const char *retType = typeNames[0] ? typeNames[0] : metaTypes[0]->name;
2675 qWarning(msg: "QMetaMethod::invokeMethod: return type mismatch for method %s::%s:"
2676 " cannot convert from %s to %s during invocation",
2677 priv->mobj->className(), priv->methodSignature().constData(),
2678 priv->rawReturnTypeName(), retType);
2679 return InvokeFailReason::ReturnTypeMismatch;
2680 }
2681 }
2682
2683 Qt::HANDLE currentThreadId = nullptr;
2684 QThread *objectThread = nullptr;
2685 auto receiverInSameThread = [&]() {
2686 if (!currentThreadId) {
2687 currentThreadId = QThread::currentThreadId();
2688 objectThread = object->thread();
2689 }
2690 if (objectThread)
2691 return currentThreadId == QThreadData::get2(thread: objectThread)->threadId.loadRelaxed();
2692 return false;
2693 };
2694
2695 // check connection type
2696 if (connectionType == Qt::AutoConnection)
2697 connectionType = receiverInSameThread() ? Qt::DirectConnection : Qt::QueuedConnection;
2698 else if (connectionType == Qt::ConnectionType(-1))
2699 connectionType = Qt::DirectConnection;
2700
2701#if !QT_CONFIG(thread)
2702 if (connectionType == Qt::BlockingQueuedConnection) {
2703 connectionType = Qt::DirectConnection;
2704 }
2705#endif
2706
2707 // invoke!
2708 int idx_relative = priv->ownMethodIndex();
2709 int idx_offset = priv->mobj->methodOffset();
2710 QObjectPrivate::StaticMetaCallFunction callFunction = priv->mobj->d.static_metacall;
2711
2712 if (connectionType == Qt::DirectConnection) {
2713 if (callFunction)
2714 callFunction(object, QMetaObject::InvokeMetaMethod, idx_relative, param);
2715 else if (QMetaObject::metacall(object, cl: QMetaObject::InvokeMetaMethod, idx: idx_relative + idx_offset, argv: param) >= 0)
2716 return InvokeFailReason::CallViaVirtualFailed;
2717 } else if (connectionType == Qt::QueuedConnection) {
2718 if (parameters[0]) {
2719 qWarning(msg: "QMetaMethod::invoke: Unable to invoke methods with return values in "
2720 "queued connections");
2721 return InvokeFailReason::CouldNotQueueParameter;
2722 }
2723
2724 auto event = std::make_unique<QMetaCallEvent>(args&: idx_offset, args&: idx_relative, args&: callFunction, args: nullptr, args: -1, args&: paramCount);
2725 QMetaType *types = event->types();
2726 void **args = event->args();
2727
2728 // fill in the meta types first
2729 for (int i = 1; i < paramCount; ++i) {
2730 types[i] = QMetaType(methodMetaTypes[i - 1]);
2731 if (!types[i].iface() && (!MetaTypesAreOptional || metaTypes))
2732 types[i] = QMetaType(metaTypes[i]);
2733 if (!types[i].iface())
2734 types[i] = priv->parameterMetaType(index: i - 1);
2735 if (!types[i].iface() && typeNames[i])
2736 types[i] = QMetaType::fromName(name: typeNames[i]);
2737 if (!types[i].iface()) {
2738 qWarning(msg: "QMetaMethod::invoke: Unable to handle unregistered datatype '%s'",
2739 typeNames[i]);
2740 return InvokeFailReason(int(InvokeFailReason::CouldNotQueueParameter) - i);
2741 }
2742 }
2743
2744 // now create copies of our parameters using those meta types
2745 for (int i = 1; i < paramCount; ++i)
2746 args[i] = types[i].create(copy: parameters[i]);
2747
2748 QCoreApplication::postEvent(receiver: object, event: event.release());
2749 } else { // blocking queued connection
2750#if QT_CONFIG(thread)
2751 if (receiverInSameThread()) {
2752 qWarning(msg: "QMetaMethod::invoke: Dead lock detected in BlockingQueuedConnection: "
2753 "Receiver is %s(%p)", priv->mobj->className(), object);
2754 return InvokeFailReason::DeadLockDetected;
2755 }
2756
2757 QSemaphore semaphore;
2758 QCoreApplication::postEvent(receiver: object, event: new QMetaCallEvent(idx_offset, idx_relative, callFunction,
2759 nullptr, -1, param, &semaphore));
2760 semaphore.acquire();
2761#endif // QT_CONFIG(thread)
2762 }
2763 return {};
2764}
2765
2766/*! \fn bool QMetaMethod::invoke(QObject *object,
2767 QGenericReturnArgument returnValue,
2768 QGenericArgument val0 = QGenericArgument(0),
2769 QGenericArgument val1 = QGenericArgument(),
2770 QGenericArgument val2 = QGenericArgument(),
2771 QGenericArgument val3 = QGenericArgument(),
2772 QGenericArgument val4 = QGenericArgument(),
2773 QGenericArgument val5 = QGenericArgument(),
2774 QGenericArgument val6 = QGenericArgument(),
2775 QGenericArgument val7 = QGenericArgument(),
2776 QGenericArgument val8 = QGenericArgument(),
2777 QGenericArgument val9 = QGenericArgument()) const
2778 \obsolete [6.5] Please use the variadic overload of this function
2779 \overload invoke()
2780
2781 This overload always invokes this method using the connection type Qt::AutoConnection.
2782*/
2783
2784/*! \fn bool QMetaMethod::invoke(QObject *object,
2785 Qt::ConnectionType connectionType,
2786 QGenericArgument val0 = QGenericArgument(0),
2787 QGenericArgument val1 = QGenericArgument(),
2788 QGenericArgument val2 = QGenericArgument(),
2789 QGenericArgument val3 = QGenericArgument(),
2790 QGenericArgument val4 = QGenericArgument(),
2791 QGenericArgument val5 = QGenericArgument(),
2792 QGenericArgument val6 = QGenericArgument(),
2793 QGenericArgument val7 = QGenericArgument(),
2794 QGenericArgument val8 = QGenericArgument(),
2795 QGenericArgument val9 = QGenericArgument()) const
2796 \obsolete [6.5] Please use the variadic overload of this function
2797 \overload invoke()
2798
2799 This overload can be used if the return value of the member is of no interest.
2800*/
2801
2802/*!
2803 \fn bool QMetaMethod::invoke(QObject *object,
2804 QGenericArgument val0 = QGenericArgument(0),
2805 QGenericArgument val1 = QGenericArgument(),
2806 QGenericArgument val2 = QGenericArgument(),
2807 QGenericArgument val3 = QGenericArgument(),
2808 QGenericArgument val4 = QGenericArgument(),
2809 QGenericArgument val5 = QGenericArgument(),
2810 QGenericArgument val6 = QGenericArgument(),
2811 QGenericArgument val7 = QGenericArgument(),
2812 QGenericArgument val8 = QGenericArgument(),
2813 QGenericArgument val9 = QGenericArgument()) const
2814 \obsolete [6.5] Please use the variadic overload of this function
2815 \overload invoke()
2816
2817 This overload invokes this method using the
2818 connection type Qt::AutoConnection and ignores return values.
2819*/
2820
2821/*!
2822 \fn template <typename... Args> bool QMetaMethod::invokeOnGadget(void *gadget, QMetaMethodReturnArgument ret, Args &&... arguments) const
2823 \fn template <typename... Args> bool QMetaMethod::invokeOnGadget(void *gadget, Args &&... arguments) const
2824 \since 6.5
2825
2826 Invokes this method on a Q_GADGET. Returns \c true if the member could be invoked.
2827 Returns \c false if there is no such member or the parameters did not match.
2828
2829 The pointer \a gadget must point to an instance of the gadget class.
2830
2831 The invocation is always synchronous.
2832
2833 For the overload with a QMetaMethodReturnArgument parameter, the return
2834 value of the \a member function call is placed in \a ret. For the overload
2835 without it, the return value of the called function (if any) will be
2836 discarded. QMetaMethodReturnArgument is an internal type you should not use
2837 directly. Instead, use the qReturnArg() function.
2838
2839 \warning this method will not test the validity of the arguments: \a gadget
2840 must be an instance of the class of the QMetaObject of which this QMetaMethod
2841 has been constructed with.
2842
2843 \sa Q_ARG(), Q_RETURN_ARG(), qRegisterMetaType(), QMetaObject::invokeMethod()
2844*/
2845
2846/*!
2847 \since 5.5
2848 \obsolete [6.5] Please use the variadic overload of this function
2849
2850 Invokes this method on a Q_GADGET. Returns \c true if the member could be invoked.
2851 Returns \c false if there is no such member or the parameters did not match.
2852
2853 See the variadic invokeMethod() function for more information. This
2854 function should behave the same way as that one, with the following
2855 limitations:
2856
2857 \list
2858 \li The number of parameters is limited to 10.
2859 \li Parameter names may need to be an exact string match.
2860 \li Meta types are not automatically registered.
2861 \endlist
2862
2863 \warning In addition to the limitations of the variadic invoke() overload,
2864 the arguments must have the same type as the ones expected by the method,
2865 else, the behavior is undefined.
2866
2867 \sa Q_ARG(), Q_RETURN_ARG(), qRegisterMetaType(), QMetaObject::invokeMethod()
2868*/
2869bool QMetaMethod::invokeOnGadget(void *gadget,
2870 QGenericReturnArgument returnValue,
2871 QGenericArgument val0,
2872 QGenericArgument val1,
2873 QGenericArgument val2,
2874 QGenericArgument val3,
2875 QGenericArgument val4,
2876 QGenericArgument val5,
2877 QGenericArgument val6,
2878 QGenericArgument val7,
2879 QGenericArgument val8,
2880 QGenericArgument val9) const
2881{
2882 if (!gadget || !mobj)
2883 return false;
2884
2885 // check return type
2886 if (returnValue.data()) {
2887 const char *retType = typeName();
2888 if (qstrcmp(str1: returnValue.name(), str2: retType) != 0) {
2889 // normalize the return value as well
2890 QByteArray normalized = QMetaObject::normalizedType(type: returnValue.name());
2891 if (qstrcmp(str1: normalized.constData(), str2: retType) != 0) {
2892 // String comparison failed, try compare the metatype.
2893 int t = returnType();
2894 if (t == QMetaType::UnknownType || t != QMetaType::fromName(name: normalized).id())
2895 return false;
2896 }
2897 }
2898 }
2899
2900 // check argument count (we don't allow invoking a method if given too few arguments)
2901 const char *typeNames[] = {
2902 returnValue.name(),
2903 val0.name(),
2904 val1.name(),
2905 val2.name(),
2906 val3.name(),
2907 val4.name(),
2908 val5.name(),
2909 val6.name(),
2910 val7.name(),
2911 val8.name(),
2912 val9.name()
2913 };
2914 int paramCount;
2915 for (paramCount = 1; paramCount < MaximumParamCount; ++paramCount) {
2916 if (qstrlen(str: typeNames[paramCount]) <= 0)
2917 break;
2918 }
2919 if (paramCount <= QMetaMethodPrivate::get(q: this)->parameterCount())
2920 return false;
2921
2922 // invoke!
2923 void *param[] = {
2924 returnValue.data(),
2925 val0.data(),
2926 val1.data(),
2927 val2.data(),
2928 val3.data(),
2929 val4.data(),
2930 val5.data(),
2931 val6.data(),
2932 val7.data(),
2933 val8.data(),
2934 val9.data()
2935 };
2936 int idx_relative = QMetaMethodPrivate::get(q: this)->ownMethodIndex();
2937 Q_ASSERT(QMetaObjectPrivate::get(mobj)->revision >= 6);
2938 QObjectPrivate::StaticMetaCallFunction callFunction = mobj->d.static_metacall;
2939 if (!callFunction)
2940 return false;
2941 callFunction(reinterpret_cast<QObject*>(gadget), QMetaObject::InvokeMetaMethod, idx_relative, param);
2942 return true;
2943}
2944
2945/*!
2946 \fn bool QMetaMethod::invokeOnGadget(void *gadget,
2947 QGenericArgument val0 = QGenericArgument(0),
2948 QGenericArgument val1 = QGenericArgument(),
2949 QGenericArgument val2 = QGenericArgument(),
2950 QGenericArgument val3 = QGenericArgument(),
2951 QGenericArgument val4 = QGenericArgument(),
2952 QGenericArgument val5 = QGenericArgument(),
2953 QGenericArgument val6 = QGenericArgument(),
2954 QGenericArgument val7 = QGenericArgument(),
2955 QGenericArgument val8 = QGenericArgument(),
2956 QGenericArgument val9 = QGenericArgument()) const
2957
2958 \overload
2959 \obsolete [6.5] Please use the variadic overload of this function
2960 \since 5.5
2961
2962 This overload invokes this method for a \a gadget and ignores return values.
2963*/
2964
2965/*!
2966 \class QMetaEnum
2967 \inmodule QtCore
2968 \brief The QMetaEnum class provides meta-data about an enumerator.
2969
2970 \ingroup objectmodel
2971
2972 Use name() for the enumerator's name. The enumerator's keys (names
2973 of each enumerated item) are returned by key(); use keyCount() to find
2974 the number of keys. isFlag() returns whether the enumerator is
2975 meant to be used as a flag, meaning that its values can be combined
2976 using the OR operator.
2977
2978 The conversion functions keyToValue(), valueToKey(), keysToValue(),
2979 and valueToKeys() allow conversion between the integer
2980 representation of an enumeration or set value and its literal
2981 representation. The scope() function returns the class scope this
2982 enumerator was declared in.
2983
2984 \sa QMetaObject, QMetaMethod, QMetaProperty
2985*/
2986
2987/*!
2988 \fn bool QMetaEnum::isValid() const
2989
2990 Returns \c true if this enum is valid (has a name); otherwise returns
2991 false.
2992
2993 \sa name()
2994*/
2995
2996/*!
2997 \fn const QMetaObject *QMetaEnum::enclosingMetaObject() const
2998 \internal
2999*/
3000
3001
3002/*!
3003 \fn QMetaEnum::QMetaEnum()
3004 \internal
3005*/
3006
3007/*!
3008 Returns the name of the type (without the scope).
3009
3010 For example, the Qt::Key enumeration has \c
3011 Key as the type name and \l Qt as the scope.
3012
3013 For flags this returns the name of the flag type, not the
3014 name of the enum type.
3015
3016 \sa isValid(), scope(), enumName()
3017*/
3018const char *QMetaEnum::name() const
3019{
3020 if (!mobj)
3021 return nullptr;
3022 return rawStringData(mo: mobj, index: data.name());
3023}
3024
3025/*!
3026 Returns the enum name of the flag (without the scope).
3027
3028 For example, the Qt::AlignmentFlag flag has \c
3029 AlignmentFlag as the enum name, but \c Alignment as the type name.
3030 Non flag enums has the same type and enum names.
3031
3032 Enum names have the same scope as the type name.
3033
3034 \since 5.12
3035 \sa isValid(), name()
3036*/
3037const char *QMetaEnum::enumName() const
3038{
3039 if (!mobj)
3040 return nullptr;
3041 return rawStringData(mo: mobj, index: data.alias());
3042}
3043
3044/*!
3045 Returns the meta type of the enum.
3046
3047 If the QMetaObject this enum is part of was generated with Qt 6.5 or
3048 earlier this will be the invalid metatype.
3049
3050 \note This is the meta type of the enum itself, not of its underlying
3051 numeric type. You can retrieve the meta type of the underlying type of the
3052 enum using \l{QMetaType::underlyingType()}.
3053
3054 \since 6.6
3055 \sa QMetaType::underlyingType()
3056*/
3057QMetaType QMetaEnum::metaType() const
3058{
3059 if (!mobj)
3060 return {};
3061
3062 const QMetaObjectPrivate *p = priv(data: mobj->d.data);
3063#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
3064 if (p->revision < 12)
3065 QMetaType();
3066#endif
3067
3068 return QMetaType(mobj->d.metaTypes[data.index(mobj) + p->propertyCount]);
3069}
3070
3071/*!
3072 Returns the number of keys.
3073
3074 \sa key()
3075*/
3076int QMetaEnum::keyCount() const
3077{
3078 if (!mobj)
3079 return 0;
3080 return data.keyCount();
3081}
3082
3083/*!
3084 Returns the key with the given \a index, or \nullptr if no such key exists.
3085
3086 \sa keyCount(), value(), valueToKey()
3087*/
3088const char *QMetaEnum::key(int index) const
3089{
3090 if (!mobj)
3091 return nullptr;
3092 if (index >= 0 && index < int(data.keyCount()))
3093 return rawStringData(mo: mobj, index: mobj->d.data[data.data() + 2*index]);
3094 return nullptr;
3095}
3096
3097/*!
3098 Returns the value with the given \a index; or returns -1 if there
3099 is no such value.
3100
3101 \sa keyCount(), key(), keyToValue()
3102*/
3103int QMetaEnum::value(int index) const
3104{
3105 if (!mobj)
3106 return 0;
3107 if (index >= 0 && index < int(data.keyCount()))
3108 return mobj->d.data[data.data() + 2 * index + 1];
3109 return -1;
3110}
3111
3112/*!
3113 Returns \c true if this enumerator is used as a flag; otherwise returns
3114 false.
3115
3116 When used as flags, enumerators can be combined using the OR
3117 operator.
3118
3119 \sa keysToValue(), valueToKeys()
3120*/
3121bool QMetaEnum::isFlag() const
3122{
3123 if (!mobj)
3124 return false;
3125 return data.flags() & EnumIsFlag;
3126}
3127
3128/*!
3129 \since 5.8
3130
3131 Returns \c true if this enumerator is declared as a C++11 enum class;
3132 otherwise returns false.
3133*/
3134bool QMetaEnum::isScoped() const
3135{
3136 if (!mobj)
3137 return false;
3138 return data.flags() & EnumIsScoped;
3139}
3140
3141/*!
3142 Returns the scope this enumerator was declared in.
3143
3144 For example, the Qt::AlignmentFlag enumeration has \c Qt as
3145 the scope and \c AlignmentFlag as the name.
3146
3147 \sa name()
3148*/
3149const char *QMetaEnum::scope() const
3150{
3151 return mobj ? objectClassName(m: mobj) : nullptr;
3152}
3153
3154/*!
3155 Returns the integer value of the given enumeration \a key, or -1
3156 if \a key is not defined.
3157
3158 If \a key is not defined, *\a{ok} is set to false; otherwise
3159 *\a{ok} is set to true.
3160
3161 For flag types, use keysToValue().
3162
3163 \sa valueToKey(), isFlag(), keysToValue()
3164*/
3165int QMetaEnum::keyToValue(const char *key, bool *ok) const
3166{
3167 if (ok != nullptr)
3168 *ok = false;
3169 if (!mobj || !key)
3170 return -1;
3171 uint scope = 0;
3172 const char *qualified_key = key;
3173 const char *s = key + qstrlen(str: key);
3174 while (s > key && *s != ':')
3175 --s;
3176 if (s > key && *(s - 1) == ':') {
3177 scope = s - key - 1;
3178 key += scope + 2;
3179 }
3180 for (int i = 0; i < int(data.keyCount()); ++i) {
3181 const QByteArray className = stringData(mo: mobj, index: priv(data: mobj->d.data)->className);
3182 if ((!scope || (className.size() == int(scope) && strncmp(s1: qualified_key, s2: className.constData(), n: scope) == 0))
3183 && strcmp(s1: key, s2: rawStringData(mo: mobj, index: mobj->d.data[data.data() + 2*i])) == 0) {
3184 if (ok != nullptr)
3185 *ok = true;
3186 return mobj->d.data[data.data() + 2 * i + 1];
3187 }
3188 }
3189 return -1;
3190}
3191
3192/*!
3193 Returns the string that is used as the name of the given
3194 enumeration \a value, or \nullptr if \a value is not defined.
3195
3196 For flag types, use valueToKeys().
3197
3198 \sa isFlag(), valueToKeys()
3199*/
3200const char *QMetaEnum::valueToKey(int value) const
3201{
3202 if (!mobj)
3203 return nullptr;
3204 for (int i = 0; i < int(data.keyCount()); ++i)
3205 if (value == (int)mobj->d.data[data.data() + 2 * i + 1])
3206 return rawStringData(mo: mobj, index: mobj->d.data[data.data() + 2 * i]);
3207 return nullptr;
3208}
3209
3210static auto parse_scope(QLatin1StringView qualifiedKey) noexcept
3211{
3212 struct R {
3213 std::optional<QLatin1StringView> scope;
3214 QLatin1StringView key;
3215 };
3216 const auto scopePos = qualifiedKey.lastIndexOf(s: "::"_L1);
3217 if (scopePos < 0)
3218 return R{.scope: std::nullopt, .key: qualifiedKey};
3219 else
3220 return R{.scope: qualifiedKey.first(n: scopePos), .key: qualifiedKey.sliced(pos: scopePos + 2)};
3221}
3222
3223/*!
3224 Returns the value derived from combining together the values of
3225 the \a keys using the OR operator, or -1 if \a keys is not
3226 defined. Note that the strings in \a keys must be '|'-separated.
3227
3228 If \a keys is not defined, *\a{ok} is set to false; otherwise
3229 *\a{ok} is set to true.
3230
3231 \sa isFlag(), valueToKey(), valueToKeys()
3232*/
3233int QMetaEnum::keysToValue(const char *keys, bool *ok) const
3234{
3235 if (ok != nullptr)
3236 *ok = false;
3237 if (!mobj || !keys)
3238 return -1;
3239
3240 auto lookup = [&] (QLatin1StringView key) -> std::optional<int> {
3241 for (int i = data.keyCount() - 1; i >= 0; --i) {
3242 if (key == stringDataView(mo: mobj, index: mobj->d.data[data.data() + 2*i]))
3243 return mobj->d.data[data.data() + 2*i + 1];
3244 }
3245 return std::nullopt;
3246 };
3247 auto className = [&] { return stringDataView(mo: mobj, index: priv(data: mobj->d.data)->className); };
3248
3249 int value = 0;
3250 for (const QLatin1StringView &untrimmed : qTokenize(h: QLatin1StringView{keys}, n: u'|')) {
3251 const auto parsed = parse_scope(qualifiedKey: untrimmed.trimmed());
3252 if (parsed.scope && *parsed.scope != className())
3253 return -1; // wrong type name in qualified name
3254 if (auto thisValue = lookup(parsed.key))
3255 value |= *thisValue;
3256 else
3257 return -1; // no such enumerator
3258 }
3259 if (ok != nullptr)
3260 *ok = true;
3261 return value;
3262}
3263
3264namespace
3265{
3266template <typename String, typename Container, typename Separator>
3267void join_reversed(String &s, const Container &c, Separator sep)
3268{
3269 if (c.empty())
3270 return;
3271 qsizetype len = qsizetype(c.size()) - 1; // N - 1 separators
3272 for (auto &e : c)
3273 len += qsizetype(e.size()); // N parts
3274 s.reserve(len);
3275 bool first = true;
3276 for (auto rit = c.rbegin(), rend = c.rend(); rit != rend; ++rit) {
3277 const auto &e = *rit;
3278 if (!first)
3279 s.append(sep);
3280 first = false;
3281 s.append(e.data(), e.size());
3282 }
3283}
3284} // unnamed namespace
3285
3286/*!
3287 Returns a byte array of '|'-separated keys that represents the
3288 given \a value.
3289
3290 \sa isFlag(), valueToKey(), keysToValue()
3291*/
3292QByteArray QMetaEnum::valueToKeys(int value) const
3293{
3294 QByteArray keys;
3295 if (!mobj)
3296 return keys;
3297 QVarLengthArray<QLatin1StringView, sizeof(int) * CHAR_BIT> parts;
3298 int v = value;
3299 // reverse iterate to ensure values like Qt::Dialog=0x2|Qt::Window are processed first.
3300 for (int i = data.keyCount() - 1; i >= 0; --i) {
3301 int k = mobj->d.data[data.data() + 2 * i + 1];
3302 if ((k != 0 && (v & k) == k) || (k == value)) {
3303 v = v & ~k;
3304 parts.push_back(t: stringDataView(mo: mobj, index: mobj->d.data[data.data() + 2 * i]));
3305 }
3306 }
3307 join_reversed(s&: keys, c: parts, sep: '|');
3308 return keys;
3309}
3310
3311/*!
3312 \internal
3313 */
3314QMetaEnum::QMetaEnum(const QMetaObject *mobj, int index)
3315 : mobj(mobj), data({ .d: mobj->d.data + priv(data: mobj->d.data)->enumeratorData + index * Data::Size })
3316{
3317 Q_ASSERT(index >= 0 && index < priv(mobj->d.data)->enumeratorCount);
3318}
3319
3320int QMetaEnum::Data::index(const QMetaObject *mobj) const
3321{
3322 return (d - mobj->d.data - priv(data: mobj->d.data)->enumeratorData) / Size;
3323}
3324
3325/*!
3326 \fn QMetaEnum QMetaEnum::fromType()
3327 \since 5.5
3328
3329 Returns the QMetaEnum corresponding to the type in the template parameter.
3330 The enum needs to be declared with Q_ENUM.
3331*/
3332
3333/*!
3334 \class QMetaProperty
3335 \inmodule QtCore
3336 \brief The QMetaProperty class provides meta-data about a property.
3337
3338 \ingroup objectmodel
3339
3340 Property meta-data is obtained from an object's meta-object. See
3341 QMetaObject::property() and QMetaObject::propertyCount() for
3342 details.
3343
3344 \section1 Property Meta-Data
3345
3346 A property has a name() and a type(), as well as various
3347 attributes that specify its behavior: isReadable(), isWritable(),
3348 isDesignable(), isScriptable(), revision(), and isStored().
3349
3350 If the property is an enumeration, isEnumType() returns \c true; if the
3351 property is an enumeration that is also a flag (i.e. its values
3352 can be combined using the OR operator), isEnumType() and
3353 isFlagType() both return true. The enumerator for these types is
3354 available from enumerator().
3355
3356 The property's values are set and retrieved with read(), write(),
3357 and reset(); they can also be changed through QObject's set and get
3358 functions. See QObject::setProperty() and QObject::property() for
3359 details.
3360
3361 \section1 Copying and Assignment
3362
3363 QMetaProperty objects can be copied by value. However, each copy will
3364 refer to the same underlying property meta-data.
3365
3366 \sa QMetaObject, QMetaEnum, QMetaMethod, {Qt's Property System}
3367*/
3368
3369/*!
3370 \fn bool QMetaProperty::isValid() const
3371
3372 Returns \c true if this property is valid (readable); otherwise
3373 returns \c false.
3374
3375 \sa isReadable()
3376*/
3377
3378/*!
3379 \fn const QMetaObject *QMetaProperty::enclosingMetaObject() const
3380 \internal
3381*/
3382
3383/*!
3384 \fn QMetaProperty::QMetaProperty()
3385 \internal
3386*/
3387
3388/*!
3389 Returns this property's name.
3390
3391 \sa type(), typeName()
3392*/
3393const char *QMetaProperty::name() const
3394{
3395 if (!mobj)
3396 return nullptr;
3397 return rawStringData(mo: mobj, index: data.name());
3398}
3399
3400/*!
3401 Returns the name of this property's type.
3402
3403 \sa type(), name()
3404*/
3405const char *QMetaProperty::typeName() const
3406{
3407 if (!mobj)
3408 return nullptr;
3409 // TODO: can the metatype be invalid for dynamic metaobjects?
3410 if (const auto mt = metaType(); mt.isValid())
3411 return mt.name();
3412 return rawTypeNameFromTypeInfo(mo: mobj, typeInfo: data.type());
3413}
3414
3415/*! \fn QVariant::Type QMetaProperty::type() const
3416 \deprecated
3417
3418 Returns this property's type. The return value is one
3419 of the values of the QVariant::Type enumeration.
3420
3421 \sa typeName(), name(), metaType()
3422*/
3423
3424/*! \fn int QMetaProperty::userType() const
3425 \since 4.2
3426
3427 Returns this property's user type. The return value is one
3428 of the values that are registered with QMetaType.
3429
3430 This is equivalent to metaType().id()
3431
3432 \sa type(), QMetaType, typeName(), metaType()
3433 */
3434
3435/*! \fn int QMetaProperty::typeId() const
3436 \since 6.0
3437
3438 Returns the storage type of the property. This is
3439 the same as metaType().id().
3440
3441 \sa QMetaType, typeName(), metaType()
3442 */
3443
3444/*!
3445 \since 6.0
3446
3447 Returns this property's QMetaType.
3448
3449 \sa QMetaType
3450 */
3451QMetaType QMetaProperty::metaType() const
3452{
3453 if (!mobj)
3454 return {};
3455 return QMetaType(mobj->d.metaTypes[data.index(mobj)]);
3456}
3457
3458int QMetaProperty::Data::index(const QMetaObject *mobj) const
3459{
3460 return (d - mobj->d.data - priv(data: mobj->d.data)->propertyData) / Size;
3461}
3462
3463/*!
3464 \since 4.6
3465
3466 Returns this property's index.
3467*/
3468int QMetaProperty::propertyIndex() const
3469{
3470 if (!mobj)
3471 return -1;
3472 return data.index(mobj) + mobj->propertyOffset();
3473}
3474
3475/*!
3476 \since 5.14
3477
3478 Returns this property's index relative within the enclosing meta object.
3479*/
3480int QMetaProperty::relativePropertyIndex() const
3481{
3482 if (!mobj)
3483 return -1;
3484 return data.index(mobj);
3485}
3486
3487/*!
3488 Returns \c true if the property's type is an enumeration value that
3489 is used as a flag; otherwise returns \c false.
3490
3491 Flags can be combined using the OR operator. A flag type is
3492 implicitly also an enum type.
3493
3494 \sa isEnumType(), enumerator(), QMetaEnum::isFlag()
3495*/
3496
3497bool QMetaProperty::isFlagType() const
3498{
3499 return isEnumType() && menum.isFlag();
3500}
3501
3502/*!
3503 Returns \c true if the property's type is an enumeration value;
3504 otherwise returns \c false.
3505
3506 \sa enumerator(), isFlagType()
3507*/
3508bool QMetaProperty::isEnumType() const
3509{
3510 if (!mobj)
3511 return false;
3512 return (data.flags() & EnumOrFlag) && menum.name();
3513}
3514
3515/*!
3516 \internal
3517
3518 Returns \c true if the property has a C++ setter function that
3519 follows Qt's standard "name" / "setName" pattern. Designer and uic
3520 query hasStdCppSet() in order to avoid expensive
3521 QObject::setProperty() calls. All properties in Qt [should] follow
3522 this pattern.
3523*/
3524bool QMetaProperty::hasStdCppSet() const
3525{
3526 if (!mobj)
3527 return false;
3528 return (data.flags() & StdCppSet);
3529}
3530
3531/*!
3532 \internal
3533
3534 Returns \c true if the property is an alias.
3535 This is for instance true for a property declared in QML
3536 as 'property alias'.
3537*/
3538bool QMetaProperty::isAlias() const
3539{
3540 if (!mobj)
3541 return false;
3542 return (data.flags() & Alias);
3543}
3544
3545#if QT_DEPRECATED_SINCE(6, 4)
3546/*!
3547 \internal
3548 Historically:
3549 Executes metacall with QMetaObject::RegisterPropertyMetaType flag.
3550 Returns id of registered type or QMetaType::UnknownType if a type
3551 could not be registered for any reason.
3552 Obsolete since Qt 6
3553*/
3554int QMetaProperty::registerPropertyType() const
3555{
3556 return typeId();
3557}
3558#endif
3559
3560QMetaProperty::QMetaProperty(const QMetaObject *mobj, int index)
3561 : mobj(mobj),
3562 data(getMetaPropertyData(mobj, index))
3563{
3564 Q_ASSERT(index >= 0 && index < priv(mobj->d.data)->propertyCount);
3565
3566 if (!(data.flags() & EnumOrFlag))
3567 return;
3568 const char *type = rawTypeNameFromTypeInfo(mo: mobj, typeInfo: data.type());
3569 menum = mobj->enumerator(index: mobj->indexOfEnumerator(name: type));
3570 if (menum.isValid())
3571 return;
3572 const char *enum_name = type;
3573 const char *scope_name = objectClassName(m: mobj);
3574 char *scope_buffer = nullptr;
3575
3576 const char *colon = strrchr(s: enum_name, c: ':');
3577 // ':' will always appear in pairs
3578 Q_ASSERT(colon <= enum_name || *(colon - 1) == ':');
3579 if (colon > enum_name) {
3580 int len = colon - enum_name - 1;
3581 scope_buffer = (char *)malloc(size: len + 1);
3582 memcpy(dest: scope_buffer, src: enum_name, n: len);
3583 scope_buffer[len] = '\0';
3584 scope_name = scope_buffer;
3585 enum_name = colon + 1;
3586 }
3587
3588 const QMetaObject *scope = nullptr;
3589 if (qstrcmp(str1: scope_name, str2: "Qt") == 0)
3590 scope = &Qt::staticMetaObject;
3591 else
3592 scope = QMetaObject_findMetaObject(self: mobj, name: scope_name);
3593 if (scope)
3594 menum = scope->enumerator(index: scope->indexOfEnumerator(name: enum_name));
3595 if (scope_buffer)
3596 free(ptr: scope_buffer);
3597}
3598
3599/*!
3600 \internal
3601 Constructs the \c QMetaProperty::Data for the \a index th property of \a mobj
3602 */
3603QMetaProperty::Data QMetaProperty::getMetaPropertyData(const QMetaObject *mobj, int index)
3604{
3605 return { .d: mobj->d.data + priv(data: mobj->d.data)->propertyData + index * Data::Size };
3606}
3607
3608/*!
3609 Returns the enumerator if this property's type is an enumerator
3610 type; otherwise the returned value is undefined.
3611
3612 \sa isEnumType(), isFlagType()
3613*/
3614QMetaEnum QMetaProperty::enumerator() const
3615{
3616 return menum;
3617}
3618
3619/*!
3620 Reads the property's value from the given \a object. Returns the value
3621 if it was able to read it; otherwise returns an invalid variant.
3622
3623 \sa write(), reset(), isReadable()
3624*/
3625QVariant QMetaProperty::read(const QObject *object) const
3626{
3627 if (!object || !mobj)
3628 return QVariant();
3629
3630 // the status variable is changed by qt_metacall to indicate what it did
3631 // this feature is currently only used by Qt D-Bus and should not be depended
3632 // upon. Don't change it without looking into QDBusAbstractInterface first
3633 // -1 (unchanged): normal qt_metacall, result stored in argv[0]
3634 // changed: result stored directly in value
3635 int status = -1;
3636 QVariant value;
3637 void *argv[] = { nullptr, &value, &status };
3638 QMetaType t(mobj->d.metaTypes[data.index(mobj)]);
3639 if (t == QMetaType::fromType<QVariant>()) {
3640 argv[0] = &value;
3641 } else {
3642 value = QVariant(t, nullptr);
3643 argv[0] = value.data();
3644 }
3645 if (priv(data: mobj->d.data)->flags & PropertyAccessInStaticMetaCall && mobj->d.static_metacall) {
3646 mobj->d.static_metacall(const_cast<QObject*>(object), QMetaObject::ReadProperty, data.index(mobj), argv);
3647 } else {
3648 QMetaObject::metacall(object: const_cast<QObject*>(object), cl: QMetaObject::ReadProperty,
3649 idx: data.index(mobj) + mobj->propertyOffset(), argv);
3650 }
3651
3652 if (status != -1)
3653 return value;
3654 if (t != QMetaType::fromType<QVariant>() && argv[0] != value.data())
3655 // pointer or reference
3656 return QVariant(t, argv[0]);
3657 return value;
3658}
3659
3660/*!
3661 Writes \a value as the property's value to the given \a object. Returns
3662 true if the write succeeded; otherwise returns \c false.
3663
3664 If \a value is not of the same type as the property, a conversion
3665 is attempted. An empty QVariant() is equivalent to a call to reset()
3666 if this property is resettable, or setting a default-constructed object
3667 otherwise.
3668
3669 \note This function internally makes a copy of \a value. Prefer to use the
3670 rvalue overload when possible.
3671
3672 \sa read(), reset(), isWritable()
3673*/
3674bool QMetaProperty::write(QObject *object, const QVariant &value) const
3675{
3676 if (!object || !isWritable())
3677 return false;
3678 return write(obj: object, value: QVariant(value));
3679}
3680
3681/*!
3682 \overload
3683 \since 6.6
3684*/
3685bool QMetaProperty::write(QObject *object, QVariant &&v) const
3686{
3687 if (!object || !isWritable())
3688 return false;
3689 QMetaType t(mobj->d.metaTypes[data.index(mobj)]);
3690 if (t != QMetaType::fromType<QVariant>() && t != v.metaType()) {
3691 if (isEnumType() && !t.metaObject() && v.metaType().id() == QMetaType::QString) {
3692 // Assigning a string to a property of type Q_ENUMS (instead of Q_ENUM)
3693 bool ok;
3694 if (isFlagType())
3695 v = QVariant(menum.keysToValue(keys: v.toByteArray(), ok: &ok));
3696 else
3697 v = QVariant(menum.keyToValue(key: v.toByteArray(), ok: &ok));
3698 if (!ok)
3699 return false;
3700 } else if (!v.isValid()) {
3701 if (isResettable())
3702 return reset(obj: object);
3703 v = QVariant(t, nullptr);
3704 } else if (!v.convert(type: t)) {
3705 return false;
3706 }
3707 }
3708 // the status variable is changed by qt_metacall to indicate what it did
3709 // this feature is currently only used by Qt D-Bus and should not be depended
3710 // upon. Don't change it without looking into QDBusAbstractInterface first
3711 // -1 (unchanged): normal qt_metacall, result stored in argv[0]
3712 // changed: result stored directly in value, return the value of status
3713 int status = -1;
3714 // the flags variable is used by the declarative module to implement
3715 // interception of property writes.
3716 int flags = 0;
3717 void *argv[] = { nullptr, &v, &status, &flags };
3718 if (t == QMetaType::fromType<QVariant>())
3719 argv[0] = &v;
3720 else
3721 argv[0] = v.data();
3722 if (priv(data: mobj->d.data)->flags & PropertyAccessInStaticMetaCall && mobj->d.static_metacall)
3723 mobj->d.static_metacall(object, QMetaObject::WriteProperty, data.index(mobj), argv);
3724 else
3725 QMetaObject::metacall(object, cl: QMetaObject::WriteProperty, idx: data.index(mobj) + mobj->propertyOffset(), argv);
3726
3727 return status;
3728}
3729
3730/*!
3731 Resets the property for the given \a object with a reset method.
3732 Returns \c true if the reset worked; otherwise returns \c false.
3733
3734 Reset methods are optional; only a few properties support them.
3735
3736 \sa read(), write()
3737*/
3738bool QMetaProperty::reset(QObject *object) const
3739{
3740 if (!object || !mobj || !isResettable())
3741 return false;
3742 void *argv[] = { nullptr };
3743 if (priv(data: mobj->d.data)->flags & PropertyAccessInStaticMetaCall && mobj->d.static_metacall)
3744 mobj->d.static_metacall(object, QMetaObject::ResetProperty, data.index(mobj), argv);
3745 else
3746 QMetaObject::metacall(object, cl: QMetaObject::ResetProperty, idx: data.index(mobj) + mobj->propertyOffset(), argv);
3747 return true;
3748}
3749
3750/*!
3751 \since 6.0
3752 Returns the bindable interface for the property on a given \a object.
3753
3754 If the property doesn't support bindings, the returned interface will be
3755 invalid.
3756
3757 \sa QObjectBindableProperty, QProperty, isBindable()
3758*/
3759QUntypedBindable QMetaProperty::bindable(QObject *object) const
3760{
3761 QUntypedBindable bindable;
3762 void * argv[1] { &bindable };
3763 mobj->metacall(object, cl: QMetaObject::BindableProperty, idx: data.index(mobj) + mobj->propertyOffset(), argv);
3764 return bindable;
3765}
3766/*!
3767 \since 5.5
3768
3769 Reads the property's value from the given \a gadget. Returns the value
3770 if it was able to read it; otherwise returns an invalid variant.
3771
3772 This function should only be used if this is a property of a Q_GADGET
3773*/
3774QVariant QMetaProperty::readOnGadget(const void *gadget) const
3775{
3776 Q_ASSERT(priv(mobj->d.data)->flags & PropertyAccessInStaticMetaCall && mobj->d.static_metacall);
3777 return read(object: reinterpret_cast<const QObject*>(gadget));
3778}
3779
3780/*!
3781 \since 5.5
3782
3783 Writes \a value as the property's value to the given \a gadget. Returns
3784 true if the write succeeded; otherwise returns \c false.
3785
3786 This function should only be used if this is a property of a Q_GADGET
3787*/
3788bool QMetaProperty::writeOnGadget(void *gadget, const QVariant &value) const
3789{
3790 Q_ASSERT(priv(mobj->d.data)->flags & PropertyAccessInStaticMetaCall && mobj->d.static_metacall);
3791 return write(object: reinterpret_cast<QObject*>(gadget), value);
3792}
3793
3794/*!
3795 \overload
3796 \since 6.6
3797*/
3798bool QMetaProperty::writeOnGadget(void *gadget, QVariant &&value) const
3799{
3800 Q_ASSERT(priv(mobj->d.data)->flags & PropertyAccessInStaticMetaCall && mobj->d.static_metacall);
3801 return write(object: reinterpret_cast<QObject*>(gadget), v: std::move(value));
3802}
3803
3804/*!
3805 \since 5.5
3806
3807 Resets the property for the given \a gadget with a reset method.
3808 Returns \c true if the reset worked; otherwise returns \c false.
3809
3810 Reset methods are optional; only a few properties support them.
3811
3812 This function should only be used if this is a property of a Q_GADGET
3813*/
3814bool QMetaProperty::resetOnGadget(void *gadget) const
3815{
3816 Q_ASSERT(priv(mobj->d.data)->flags & PropertyAccessInStaticMetaCall && mobj->d.static_metacall);
3817 return reset(object: reinterpret_cast<QObject*>(gadget));
3818}
3819
3820/*!
3821 Returns \c true if this property can be reset to a default value; otherwise
3822 returns \c false.
3823
3824 \sa reset()
3825*/
3826bool QMetaProperty::isResettable() const
3827{
3828 if (!mobj)
3829 return false;
3830 return data.flags() & Resettable;
3831}
3832
3833/*!
3834 Returns \c true if this property is readable; otherwise returns \c false.
3835
3836 \sa isWritable(), read(), isValid()
3837 */
3838bool QMetaProperty::isReadable() const
3839{
3840 if (!mobj)
3841 return false;
3842 return data.flags() & Readable;
3843}
3844
3845/*!
3846 Returns \c true if this property has a corresponding change notify signal;
3847 otherwise returns \c false.
3848
3849 \sa notifySignal()
3850 */
3851bool QMetaProperty::hasNotifySignal() const
3852{
3853 if (!mobj)
3854 return false;
3855 return data.notifyIndex() != uint(-1);
3856}
3857
3858/*!
3859 \since 4.5
3860
3861 Returns the QMetaMethod instance of the property change notifying signal if
3862 one was specified, otherwise returns an invalid QMetaMethod.
3863
3864 \sa hasNotifySignal()
3865 */
3866QMetaMethod QMetaProperty::notifySignal() const
3867{
3868 int id = notifySignalIndex();
3869 if (id != -1)
3870 return mobj->method(index: id);
3871 else
3872 return QMetaMethod();
3873}
3874
3875/*!
3876 \since 4.6
3877
3878 Returns the index of the property change notifying signal if one was
3879 specified, otherwise returns -1.
3880
3881 \sa hasNotifySignal()
3882 */
3883int QMetaProperty::notifySignalIndex() const
3884{
3885 if (!mobj || data.notifyIndex() == std::numeric_limits<uint>::max())
3886 return -1;
3887 uint methodIndex = data.notifyIndex();
3888 if (methodIndex & IsUnresolvedSignal) {
3889 methodIndex &= ~IsUnresolvedSignal;
3890 const QByteArray signalName = stringData(mo: mobj, index: methodIndex);
3891 const QMetaObject *m = mobj;
3892 const int idx = QMetaObjectPrivate::indexOfMethodRelative<MethodSignal>(baseObject: &m, name: signalName, argc: 0, types: nullptr);
3893 if (idx >= 0) {
3894 return idx + m->methodOffset();
3895 } else {
3896 qWarning(msg: "QMetaProperty::notifySignal: cannot find the NOTIFY signal %s in class %s for property '%s'",
3897 signalName.constData(), objectClassName(m: mobj), name());
3898 return -1;
3899 }
3900 }
3901 return methodIndex + mobj->methodOffset();
3902}
3903
3904// This method has been around for a while, but the documentation was marked \internal until 5.1
3905/*!
3906 \since 5.1
3907
3908 Returns the property revision if one was
3909 specified by REVISION, otherwise returns 0.
3910 */
3911int QMetaProperty::revision() const
3912{
3913 if (!mobj)
3914 return 0;
3915 return data.revision();
3916}
3917
3918/*!
3919 Returns \c true if this property is writable; otherwise returns
3920 false.
3921
3922 \sa isReadable(), write()
3923 */
3924bool QMetaProperty::isWritable() const
3925{
3926 if (!mobj)
3927 return false;
3928 return data.flags() & Writable;
3929}
3930
3931/*!
3932 Returns \c false if the \c{Q_PROPERTY()}'s \c DESIGNABLE attribute
3933 is false; otherwise returns \c true.
3934
3935 \sa isScriptable(), isStored()
3936*/
3937bool QMetaProperty::isDesignable() const
3938{
3939 if (!mobj)
3940 return false;
3941 return data.flags() & Designable;
3942}
3943
3944/*!
3945 Returns \c false if the \c{Q_PROPERTY()}'s \c SCRIPTABLE attribute
3946 is false; otherwise returns true.
3947
3948 \sa isDesignable(), isStored()
3949*/
3950bool QMetaProperty::isScriptable() const
3951{
3952 if (!mobj)
3953 return false;
3954 return data.flags() & Scriptable;
3955}
3956
3957/*!
3958 Returns \c true if the property is stored; otherwise returns
3959 false.
3960
3961 The function returns \c false if the
3962 \c{Q_PROPERTY()}'s \c STORED attribute is false; otherwise returns
3963 true.
3964
3965 \sa isDesignable(), isScriptable()
3966*/
3967bool QMetaProperty::isStored() const
3968{
3969 if (!mobj)
3970 return false;
3971 return data.flags() & Stored;
3972}
3973
3974/*!
3975 Returns \c false if the \c {Q_PROPERTY()}'s \c USER attribute is false.
3976 Otherwise it returns true, indicating the property is designated as the
3977 \c USER property, i.e., the one that the user can edit or
3978 that is significant in some other way.
3979
3980 \sa QMetaObject::userProperty(), isDesignable(), isScriptable()
3981*/
3982bool QMetaProperty::isUser() const
3983{
3984 if (!mobj)
3985 return false;
3986 return data.flags() & User;
3987}
3988
3989/*!
3990 \since 4.6
3991 Returns \c true if the property is constant; otherwise returns \c false.
3992
3993 A property is constant if the \c{Q_PROPERTY()}'s \c CONSTANT attribute
3994 is set.
3995*/
3996bool QMetaProperty::isConstant() const
3997{
3998 if (!mobj)
3999 return false;
4000 return data.flags() & Constant;
4001}
4002
4003/*!
4004 \since 4.6
4005 Returns \c true if the property is final; otherwise returns \c false.
4006
4007 A property is final if the \c{Q_PROPERTY()}'s \c FINAL attribute
4008 is set.
4009*/
4010bool QMetaProperty::isFinal() const
4011{
4012 if (!mobj)
4013 return false;
4014 return data.flags() & Final;
4015}
4016
4017/*!
4018 \since 5.15
4019 Returns \c true if the property is required; otherwise returns \c false.
4020
4021 A property is final if the \c{Q_PROPERTY()}'s \c REQUIRED attribute
4022 is set.
4023*/
4024bool QMetaProperty::isRequired() const
4025{
4026 if (!mobj)
4027 return false;
4028 return data.flags() & Required;
4029}
4030
4031/*!
4032 \since 6.0
4033 Returns \c true if the \c{Q_PROPERTY()} exposes binding functionality; otherwise returns false.
4034
4035 This implies that you can create bindings that use this property as a dependency or install QPropertyObserver
4036 objects on this property. Unless the property is readonly, you can also set a binding on this property.
4037
4038 \sa QProperty, isWritable(), bindable()
4039*/
4040bool QMetaProperty::isBindable() const
4041{
4042 if (!mobj)
4043 return false;
4044 return (data.flags() & Bindable);
4045}
4046
4047/*!
4048 \class QMetaClassInfo
4049 \inmodule QtCore
4050
4051 \brief The QMetaClassInfo class provides additional information
4052 about a class.
4053
4054 \ingroup objectmodel
4055
4056 Class information items are simple \e{name}--\e{value} pairs that
4057 are specified using Q_CLASSINFO() in the source code. The
4058 information can be retrieved using name() and value(). For example:
4059
4060 \snippet code/src_corelib_kernel_qmetaobject.cpp 5
4061
4062 This mechanism is free for you to use in your Qt applications. Qt
4063 doesn't use it for any of its classes.
4064
4065 \sa QMetaObject
4066*/
4067
4068/*!
4069 \fn QMetaClassInfo::QMetaClassInfo()
4070 \internal
4071*/
4072
4073/*!
4074 \fn const QMetaObject *QMetaClassInfo::enclosingMetaObject() const
4075 \internal
4076*/
4077
4078/*!
4079 Returns the name of this item.
4080
4081 \sa value()
4082*/
4083const char *QMetaClassInfo::name() const
4084{
4085 if (!mobj)
4086 return nullptr;
4087 return rawStringData(mo: mobj, index: data.name());
4088}
4089
4090/*!
4091 Returns the value of this item.
4092
4093 \sa name()
4094*/
4095const char *QMetaClassInfo::value() const
4096{
4097 if (!mobj)
4098 return nullptr;
4099 return rawStringData(mo: mobj, index: data.value());
4100}
4101
4102/*!
4103 \class QMethodRawArguments
4104 \internal
4105
4106 A wrapper class for the void ** arguments array used by the meta
4107 object system. If a slot uses a single argument of this type,
4108 the meta object system will pass the raw arguments array directly
4109 to the slot and set the arguments count in the slot description to
4110 zero, so that any signal can connect to it.
4111
4112 This is used internally to implement signal relay functionality in
4113 our state machine and dbus.
4114*/
4115
4116/*!
4117 \macro QMetaMethodArgument Q_ARG(Type, const Type &value)
4118 \relates QMetaObject
4119
4120 This macro takes a \a Type and a \a value of that type and
4121 returns a QMetaMethodArgument, which can be passed to the template
4122 QMetaObject::invokeMethod() with the \c {Args &&...} arguments.
4123
4124 \sa Q_RETURN_ARG()
4125*/
4126
4127/*!
4128 \macro QMetaMethodReturnArgument Q_RETURN_ARG(Type, Type &value)
4129 \relates QMetaObject
4130
4131 This macro takes a \a Type and a non-const reference to a \a
4132 value of that type and returns a QMetaMethodReturnArgument, which can be
4133 passed to the template QMetaObject::invokeMethod() with the \c {Args &&...}
4134 arguments.
4135
4136 \sa Q_ARG()
4137*/
4138
4139/*!
4140 \class QGenericArgument
4141 \inmodule QtCore
4142
4143 \brief The QGenericArgument class is an internal helper class for
4144 marshalling arguments.
4145
4146 This class should never be used directly. Please use the \l Q_ARG()
4147 macro instead.
4148
4149 \sa Q_ARG(), QMetaObject::invokeMethod(), QGenericReturnArgument
4150*/
4151
4152/*!
4153 \fn QGenericArgument::QGenericArgument(const char *name, const void *data)
4154
4155 Constructs a QGenericArgument object with the given \a name and \a data.
4156*/
4157
4158/*!
4159 \fn QGenericArgument::data () const
4160
4161 Returns the data set in the constructor.
4162*/
4163
4164/*!
4165 \fn QGenericArgument::name () const
4166
4167 Returns the name set in the constructor.
4168*/
4169
4170/*!
4171 \class QGenericReturnArgument
4172 \inmodule QtCore
4173
4174 \brief The QGenericReturnArgument class is an internal helper class for
4175 marshalling arguments.
4176
4177 This class should never be used directly. Please use the
4178 Q_RETURN_ARG() macro instead.
4179
4180 \sa Q_RETURN_ARG(), QMetaObject::invokeMethod(), QGenericArgument
4181*/
4182
4183/*!
4184 \fn QGenericReturnArgument::QGenericReturnArgument(const char *name, void *data)
4185
4186 Constructs a QGenericReturnArgument object with the given \a name
4187 and \a data.
4188*/
4189
4190/*!
4191 \internal
4192 If the local_method_index is a cloned method, return the index of the original.
4193
4194 Example: if the index of "destroyed()" is passed, the index of "destroyed(QObject*)" is returned
4195 */
4196int QMetaObjectPrivate::originalClone(const QMetaObject *mobj, int local_method_index)
4197{
4198 Q_ASSERT(local_method_index < get(mobj)->methodCount);
4199 while (QMetaMethod::fromRelativeMethodIndex(mobj, index: local_method_index).data.flags() & MethodCloned) {
4200 Q_ASSERT(local_method_index > 0);
4201 --local_method_index;
4202 }
4203 return local_method_index;
4204}
4205
4206/*!
4207 \internal
4208
4209 Returns the parameter type names extracted from the given \a signature.
4210*/
4211QList<QByteArray> QMetaObjectPrivate::parameterTypeNamesFromSignature(const char *signature)
4212{
4213 QList<QByteArray> list;
4214 while (*signature && *signature != '(')
4215 ++signature;
4216 while (*signature && *signature != ')' && *++signature != ')') {
4217 const char *begin = signature;
4218 int level = 0;
4219 while (*signature && (level > 0 || *signature != ',') && *signature != ')') {
4220 if (*signature == '<')
4221 ++level;
4222 else if (*signature == '>')
4223 --level;
4224 ++signature;
4225 }
4226 list += QByteArray(begin, signature - begin);
4227 }
4228 return list;
4229}
4230
4231QT_END_NAMESPACE
4232

source code of qtbase/src/corelib/kernel/qmetaobject.cpp