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

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