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