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 \deprecated
1980 \relates QMetaMethod
1981
1982 Equals maximum number of arguments available for execution of the method
1983 via the old implementation of QMetaMethod::invoke(). The new implementation
1984 (since Qt 6.5) uses variadic arguments and does not have an upper limit.
1985 */
1986
1987QByteArray QMetaMethodPrivate::signature() const
1988{
1989 Q_ASSERT(priv(mobj->d.data)->revision >= 7);
1990 QByteArray result;
1991 result.reserve(256);
1992 result += name();
1993 result += '(';
1994 QList<QByteArray> argTypes = parameterTypes();
1995 for (int i = 0; i < argTypes.size(); ++i) {
1996 if (i)
1997 result += ',';
1998 result += argTypes.at(i);
1999 }
2000 result += ')';
2001 return result;
2002}
2003
2004QByteArrayView QMetaMethodPrivate::name() const noexcept
2005{
2006 QByteArrayView name = qualifiedName();
2007 if (qsizetype colon = name.lastIndexOf(':'); colon > 0)
2008 return name.sliced(colon + 1);
2009 return name;
2010}
2011
2012QByteArrayView QMetaMethodPrivate::qualifiedName() const noexcept
2013{
2014 Q_ASSERT(priv(mobj->d.data)->revision >= 7);
2015 return stringDataView(mobj, data.name());
2016}
2017
2018int QMetaMethodPrivate::typesDataIndex() const
2019{
2020 Q_ASSERT(priv(mobj->d.data)->revision >= 7);
2021 return data.parameters();
2022}
2023
2024const char *QMetaMethodPrivate::rawReturnTypeName() const
2025{
2026 Q_ASSERT(priv(mobj->d.data)->revision >= 7);
2027 uint typeInfo = mobj->d.data[typesDataIndex()];
2028 if (typeInfo & IsUnresolvedType)
2029 return rawStringData(mobj, typeInfo & TypeNameIndexMask);
2030 else
2031 return QMetaType(typeInfo).name();
2032}
2033
2034int QMetaMethodPrivate::returnType() const
2035{
2036 return parameterType(-1);
2037}
2038
2039int QMetaMethodPrivate::parameterCount() const
2040{
2041 Q_ASSERT(priv(mobj->d.data)->revision >= 7);
2042 return data.argc();
2043}
2044
2045inline void
2046QMetaMethodPrivate::checkMethodMetaTypeConsistency(const QtPrivate::QMetaTypeInterface *iface,
2047 int index) const
2048{
2049 uint typeInfo = parameterTypeInfo(index);
2050 QMetaType mt(iface);
2051 if (iface) {
2052 if ((typeInfo & IsUnresolvedType) == 0)
2053 Q_ASSERT(mt.rawId() == int(typeInfo & TypeNameIndexMask));
2054 Q_ASSERT(mt.name());
2055 } else {
2056 // The iface can only be null for a parameter if that parameter is a
2057 // const-ref to a forward-declared type. Since primitive types are
2058 // never incomplete, we can assert it's not one of them.
2059
2060#define ASSERT_NOT_PRIMITIVE_TYPE(TYPE, METATYPEID, NAME)
2061 Q_ASSERT(typeInfo != QMetaType::TYPE);
2062 QT_FOR_EACH_STATIC_PRIMITIVE_NON_VOID_TYPE(ASSERT_NOT_PRIMITIVE_TYPE)
2063#undef ASSERT_NOT_PRIMITIVE_TYPE
2064 Q_ASSERT(typeInfo != QMetaType::QObjectStar);
2065
2066 // Prior to Qt 6.4 we failed to record void and void*
2067 if (priv(mobj->d.data)->revision >= 11) {
2068 Q_ASSERT(typeInfo != QMetaType::Void);
2069 Q_ASSERT(typeInfo != QMetaType::VoidStar);
2070 }
2071 }
2072}
2073
2074int QMetaMethodPrivate::parametersDataIndex() const
2075{
2076 Q_ASSERT(priv(mobj->d.data)->revision >= 7);
2077 return typesDataIndex() + 1;
2078}
2079
2080uint QMetaMethodPrivate::parameterTypeInfo(int index) const
2081{
2082 Q_ASSERT(priv(mobj->d.data)->revision >= 7);
2083 return mobj->d.data[parametersDataIndex() + index];
2084}
2085
2086const QtPrivate::QMetaTypeInterface *QMetaMethodPrivate::returnMetaTypeInterface() const
2087{
2088 Q_ASSERT(priv(mobj->d.data)->revision >= 7);
2089 if (methodType() == QMetaMethod::Constructor)
2090 return nullptr; // constructors don't have return types
2091
2092 const QtPrivate::QMetaTypeInterface *iface = mobj->d.metaTypes[data.metaTypeOffset()];
2093 checkMethodMetaTypeConsistency(iface, -1);
2094 return iface;
2095}
2096
2097const QtPrivate::QMetaTypeInterface * const *QMetaMethodPrivate::parameterMetaTypeInterfaces() const
2098{
2099 Q_ASSERT(priv(mobj->d.data)->revision >= 7);
2100 int offset = (methodType() == QMetaMethod::Constructor ? 0 : 1);
2101 const auto ifaces = &mobj->d.metaTypes[data.metaTypeOffset() + offset];
2102
2103 for (int i = 0; i < parameterCount(); ++i)
2104 checkMethodMetaTypeConsistency(ifaces[i], i);
2105
2106 return ifaces;
2107}
2108
2109int QMetaMethodPrivate::parameterType(int index) const
2110{
2111 Q_ASSERT(priv(mobj->d.data)->revision >= 7);
2112 return typeFromTypeInfo(mobj, parameterTypeInfo(index));
2113}
2114
2115void QMetaMethodPrivate::getParameterTypes(int *types) const
2116{
2117 Q_ASSERT(priv(mobj->d.data)->revision >= 7);
2118 int dataIndex = parametersDataIndex();
2119 int argc = parameterCount();
2120 for (int i = 0; i < argc; ++i) {
2121 int id = typeFromTypeInfo(mobj, mobj->d.data[dataIndex++]);
2122 *(types++) = id;
2123 }
2124}
2125
2126QByteArrayView QMetaMethodPrivate::parameterTypeName(int index) const noexcept
2127{
2128 int paramsIndex = parametersDataIndex();
2129 return typeNameFromTypeInfo(mobj, mobj->d.data[paramsIndex + index]);
2130}
2131
2132QList<QByteArray> QMetaMethodPrivate::parameterTypes() const
2133{
2134 Q_ASSERT(priv(mobj->d.data)->revision >= 7);
2135 int argc = parameterCount();
2136 QList<QByteArray> list;
2137 list.reserve(argc);
2138 int paramsIndex = parametersDataIndex();
2139 for (int i = 0; i < argc; ++i) {
2140 QByteArrayView name = typeNameFromTypeInfo(mobj, mobj->d.data[paramsIndex + i]);
2141 list.emplace_back(name.toByteArray());
2142 }
2143 return list;
2144}
2145
2146QList<QByteArray> QMetaMethodPrivate::parameterNames() const
2147{
2148 Q_ASSERT(priv(mobj->d.data)->revision >= 7);
2149 int argc = parameterCount();
2150 QList<QByteArray> list;
2151 list.reserve(argc);
2152 int namesIndex = parametersDataIndex() + argc;
2153 for (int i = 0; i < argc; ++i)
2154 list += stringData(mobj, mobj->d.data[namesIndex + i]);
2155 return list;
2156}
2157
2158const char *QMetaMethodPrivate::tag() const
2159{
2160 Q_ASSERT(priv(mobj->d.data)->revision >= 7);
2161 return rawStringData(mobj, data.tag());
2162}
2163
2164int QMetaMethodPrivate::ownMethodIndex() const
2165{
2166 // recompute the methodIndex by reversing the arithmetic in QMetaObject::method()
2167 return ( data.d - mobj->d.data - priv(mobj->d.data)->methodData)/Data::Size;
2168}
2169
2170int QMetaMethodPrivate::ownConstructorMethodIndex() const
2171{
2172 // recompute the methodIndex by reversing the arithmetic in QMetaObject::constructor()
2173 Q_ASSERT(methodType() == Constructor);
2174 return ( data.d - mobj->d.data - priv(mobj->d.data)->constructorData)/Data::Size;
2175}
2176
2177/*!
2178 \since 5.0
2179
2180 Returns the signature of this method (e.g.,
2181 \c{setValue(double)}).
2182
2183 \sa parameterTypes(), parameterNames()
2184*/
2185QByteArray QMetaMethod::methodSignature() const
2186{
2187 if (!mobj)
2188 return QByteArray();
2189 return QMetaMethodPrivate::get(this)->signature();
2190}
2191
2192/*!
2193 \since 5.0
2194
2195 Returns the name of this method.
2196
2197 \sa methodSignature(), parameterCount()
2198*/
2199QByteArray QMetaMethod::name() const
2200{
2201 if (!mobj)
2202 return QByteArray();
2203 // ### Qt 7: change the return type and make noexcept
2204 return stringData(mobj, QMetaMethodPrivate::get(this)->name());
2205}
2206
2207/*!
2208 \since 6.9
2209
2210 Returns the name of this method.
2211 The returned QByteArrayView is valid as long as the meta-object of
2212 the class to which the method belongs is valid.
2213
2214 \sa name
2215 */
2216QByteArrayView QMetaMethod::nameView() const
2217{
2218 return QMetaMethodPrivate::get(this)->name();
2219}
2220
2221/*!
2222 \since 5.0
2223
2224 Returns the return type of this method.
2225
2226 The return value is one of the types that are registered
2227 with QMetaType, or QMetaType::UnknownType if the type is not registered.
2228
2229 \sa parameterType(), QMetaType, typeName(), returnMetaType()
2230*/
2231int QMetaMethod::returnType() const
2232 {
2233 return returnMetaType().rawId();
2234}
2235
2236/*!
2237 \since 6.0
2238
2239 Returns the return type of this method.
2240 \sa parameterMetaType(), QMetaType, typeName()
2241*/
2242QMetaType QMetaMethod::returnMetaType() const
2243{
2244 if (!mobj || methodType() == QMetaMethod::Constructor)
2245 return QMetaType{};
2246 auto mt = QMetaType(mobj->d.metaTypes[data.metaTypeOffset()]);
2247 if (!mt.isValid())
2248 mt = QMetaType(QMetaMethodPrivate::get(this)->returnType());
2249 mt.registerType();
2250 return mt;
2251}
2252
2253/*!
2254 \since 5.0
2255
2256 Returns the number of parameters of this method.
2257
2258 \sa parameterType(), parameterNames()
2259*/
2260int QMetaMethod::parameterCount() const
2261{
2262 if (!mobj)
2263 return 0;
2264 return QMetaMethodPrivate::get(this)->parameterCount();
2265}
2266
2267/*!
2268 \since 5.0
2269
2270 Returns the type of the parameter at the given \a index.
2271
2272 The return value is one of the types that are registered
2273 with QMetaType, or QMetaType::UnknownType if the type is not registered.
2274
2275 \sa parameterCount(), parameterMetaType(), returnType(), QMetaType
2276*/
2277int QMetaMethod::parameterType(int index) const
2278{
2279 return parameterMetaType(index).rawId();
2280}
2281
2282/*!
2283 \since 6.0
2284
2285 Returns the metatype of the parameter at the given \a index.
2286
2287 If the \a index is smaller than zero or larger than
2288 parameterCount(), an invalid QMetaType is returned.
2289
2290 \sa parameterCount(), returnMetaType(), QMetaType
2291*/
2292QMetaType QMetaMethod::parameterMetaType(int index) const
2293{
2294 if (!mobj || index < 0)
2295 return {};
2296 auto priv = QMetaMethodPrivate::get(this);
2297 if (index >= priv->parameterCount())
2298 return {};
2299 // + 1 if there exists a return type
2300 auto parameterOffset = index + (methodType() == QMetaMethod::Constructor ? 0 : 1);
2301 auto mt = QMetaType(mobj->d.metaTypes[data.metaTypeOffset() + parameterOffset]);
2302 if (!mt.isValid())
2303 mt = QMetaType(QMetaMethodPrivate::get(this)->parameterType(index));
2304 mt.registerType();
2305 return mt;
2306}
2307
2308/*!
2309 \since 5.0
2310 \internal
2311
2312 Gets the parameter \a types of this method. The storage
2313 for \a types must be able to hold parameterCount() items.
2314
2315 \sa parameterCount(), returnType(), parameterType()
2316*/
2317void QMetaMethod::getParameterTypes(int *types) const
2318{
2319 if (!mobj)
2320 return;
2321 QMetaMethodPrivate::get(this)->getParameterTypes(types);
2322}
2323
2324/*!
2325 Returns a list of parameter types.
2326
2327 \sa parameterNames(), methodSignature()
2328*/
2329QList<QByteArray> QMetaMethod::parameterTypes() const
2330{
2331 if (!mobj)
2332 return QList<QByteArray>();
2333 return QMetaMethodPrivate::get(this)->parameterTypes();
2334}
2335
2336/*!
2337 \since 6.0
2338 Returns the name of the type at position \a index
2339 If there is no parameter at \a index, returns an empty QByteArray
2340
2341 \sa parameterNames()
2342 */
2343QByteArray QMetaMethod::parameterTypeName(int index) const
2344{
2345 if (!mobj || index < 0 || index >= parameterCount())
2346 return {};
2347 // ### Qt 7: change the return type and make noexcept
2348 return stringData(mobj, QMetaMethodPrivate::get(this)->parameterTypeName(index));
2349}
2350
2351/*!
2352 Returns a list of parameter names.
2353
2354 \sa parameterTypes(), methodSignature()
2355*/
2356QList<QByteArray> QMetaMethod::parameterNames() const
2357{
2358 if (!mobj)
2359 return QList<QByteArray>();
2360 return QMetaMethodPrivate::get(this)->parameterNames();
2361}
2362
2363
2364/*!
2365 Returns the return type name of this method. If this method is a
2366 constructor, this function returns an empty string (constructors have no
2367 return types).
2368
2369 \note In Qt 7, this function will return a null pointer for constructors.
2370
2371 \sa returnType(), QMetaType::name()
2372*/
2373const char *QMetaMethod::typeName() const
2374{
2375 if (!mobj)
2376 return nullptr;
2377#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
2378 if (methodType() == QMetaMethod::Constructor)
2379 return "";
2380#endif
2381 return QMetaMethodPrivate::get(this)->rawReturnTypeName();
2382}
2383
2384/*!
2385 Returns the tag associated with this method.
2386
2387 Tags are special macros recognized by \c moc that make it
2388 possible to add extra information about a method.
2389
2390 Tag information can be added in the following
2391 way in the function declaration:
2392
2393 \snippet code/src_corelib_kernel_qmetaobject.cpp 10
2394
2395 and the information can be accessed by using:
2396
2397 \snippet code/src_corelib_kernel_qmetaobject.cpp 11
2398
2399 For the moment, \c moc will extract and record all tags, but it will not
2400 handle any of them specially. You can use the tags to annotate your methods
2401 differently, and treat them according to the specific needs of your
2402 application.
2403
2404 \note \c moc expands preprocessor macros, so it is necessary
2405 to surround the definition with \c #ifndef \c Q_MOC_RUN, as shown in the
2406 example above.
2407*/
2408const char *QMetaMethod::tag() const
2409{
2410 if (!mobj)
2411 return nullptr;
2412 return QMetaMethodPrivate::get(this)->tag();
2413}
2414
2415
2416/*!
2417 \internal
2418 */
2419int QMetaMethod::attributes() const
2420{
2421 if (!mobj)
2422 return false;
2423 return data.flags() >> 4;
2424}
2425
2426/*!
2427 \since 4.6
2428
2429 Returns this method's index.
2430*/
2431int QMetaMethod::methodIndex() const
2432{
2433 if (!mobj)
2434 return -1;
2435 return QMetaMethodPrivate::get(this)->ownMethodIndex() + mobj->methodOffset();
2436}
2437
2438/*!
2439 \since 6.0
2440
2441 Returns this method's local index inside.
2442*/
2443int QMetaMethod::relativeMethodIndex() const
2444{
2445 if (!mobj)
2446 return -1;
2447 return QMetaMethodPrivate::get(this)->ownMethodIndex();
2448}
2449
2450// This method has been around for a while, but the documentation was marked \internal until 5.1
2451/*!
2452 \since 5.1
2453 Returns the method revision if one was specified by Q_REVISION, otherwise
2454 returns 0. Since Qt 6.0, non-zero values are encoded and can be decoded
2455 using QTypeRevision::fromEncodedVersion().
2456 */
2457int QMetaMethod::revision() const
2458{
2459 if (!mobj)
2460 return 0;
2461 if ((data.flags() & MethodRevisioned) == 0)
2462 return 0;
2463#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
2464 if (priv(mobj->d.data)->revision < 13) {
2465 // revision number located elsewhere
2466 int offset = priv(mobj->d.data)->methodData
2467 + priv(mobj->d.data)->methodCount * Data::Size
2468 + QMetaMethodPrivate::get(this)->ownMethodIndex();
2469 return mobj->d.data[offset];
2470 }
2471#endif
2472
2473 return mobj->d.data[data.parameters() - 1];
2474}
2475
2476/*!
2477 \since 6.2
2478
2479 Returns whether the method is const qualified.
2480
2481 \note This method might erroneously return \c false for a const method
2482 if it belongs to a library compiled against an older version of Qt.
2483 */
2484bool QMetaMethod::isConst() const
2485{
2486 if (!mobj)
2487 return false;
2488 if (QMetaObjectPrivate::get(mobj)->revision < 10)
2489 return false;
2490 return data.flags() & MethodIsConst;
2491}
2492
2493/*!
2494 Returns the access specification of this method (private,
2495 protected, or public).
2496
2497 \note Signals are always public, but you should regard that as an
2498 implementation detail. It is almost always a bad idea to emit a signal from
2499 outside its class.
2500
2501 \sa methodType()
2502*/
2503QMetaMethod::Access QMetaMethod::access() const
2504{
2505 constexpr int AccessShift = qCountTrailingZeroBits(AccessMask);
2506 static_assert(AccessPrivate >> AccessShift == Private);
2507 static_assert(AccessProtected >> AccessShift == Protected);
2508 static_assert(AccessPublic >> AccessShift == Public);
2509 if (!mobj)
2510 return Private;
2511 return Access((data.flags() & AccessMask) >> AccessShift);
2512}
2513
2514/*!
2515 Returns the type of this method (signal, slot, or method).
2516
2517 \sa access()
2518*/
2519QMetaMethod::MethodType QMetaMethod::methodType() const
2520{
2521 constexpr int MethodShift = qCountTrailingZeroBits(MethodTypeMask);
2522 static_assert(MethodMethod >> MethodShift == Method);
2523 static_assert(MethodSignal >> MethodShift == Signal);
2524 static_assert(MethodSlot >> MethodShift == Slot);
2525 static_assert(MethodConstructor >> MethodShift == Constructor);
2526 if (!mobj)
2527 return QMetaMethod::Method;
2528 return MethodType((data.flags() & MethodTypeMask) >> MethodShift);
2529}
2530
2531/*!
2532 \fn template <typename PointerToMemberFunction> QMetaMethod QMetaMethod::fromSignal(PointerToMemberFunction signal)
2533 \since 5.0
2534
2535 Returns the meta-method that corresponds to the given \a signal, or an
2536 invalid QMetaMethod if \a signal is \c{nullptr} or not a signal of the class.
2537
2538 Example:
2539
2540 \snippet code/src_corelib_kernel_qmetaobject.cpp 9
2541*/
2542
2543/*!
2544 \internal
2545
2546 Implementation of the fromSignal() function.
2547
2548 \a metaObject is the class's meta-object
2549 \a signal is a pointer to a pointer to a member signal of the class
2550*/
2551QMetaMethod QMetaMethod::fromSignalImpl(const QMetaObject *metaObject, void **signal)
2552{
2553 int i = -1;
2554 void *args[] = { &i, signal };
2555 for (const QMetaObject *m = metaObject; m; m = m->d.superdata) {
2556 m->static_metacall(QMetaObject::IndexOfMethod, 0, args);
2557 if (i >= 0)
2558 return QMetaMethod::fromRelativeMethodIndex(m, i);
2559 }
2560 return QMetaMethod();
2561}
2562
2563/*!
2564 \fn template <typename ReturnArg, typename... Args> bool QMetaMethod::invoke(QObject *obj, Qt::ConnectionType type, QTemplatedMetaMethodReturnArgument<ReturnArg> ret, Args &&... arguments) const
2565 \fn template <typename... Args> bool QMetaMethod::invoke(QObject *obj, Qt::ConnectionType type, Args &&... arguments) const
2566 \fn template <typename ReturnArg, typename... Args> bool QMetaMethod::invoke(QObject *obj, QTemplatedMetaMethodReturnArgument<ReturnArg> ret, Args &&... arguments) const
2567 \fn template <typename... Args> bool QMetaMethod::invoke(QObject *obj, Args &&... arguments) const
2568 \since 6.5
2569
2570 Invokes this method on the object \a object. Returns \c true if the member could be invoked.
2571 Returns \c false if there is no such member or the parameters did not match.
2572
2573 For the overloads with a QTemplatedMetaMethodReturnArgument parameter, the
2574 return value of the \a member function call is placed in \a ret. For the
2575 overloads without such a member, the return value of the called function
2576 (if any) will be discarded. QTemplatedMetaMethodReturnArgument is an
2577 internal type you should not use directly. Instead, use the qReturnArg()
2578 function.
2579
2580 The overloads with a Qt::ConnectionType \a type parameter allow explicitly
2581 selecting whether the invocation will be synchronous or not:
2582
2583 \list
2584 \li If \a type is Qt::DirectConnection, the member will be invoked immediately
2585 in the current thread.
2586
2587 \li If \a type is Qt::QueuedConnection, a QEvent will be sent and the
2588 member is invoked as soon as the application enters the event loop in the
2589 thread the \a obj was created in or was moved to.
2590
2591 \li If \a type is Qt::BlockingQueuedConnection, the method will be invoked in
2592 the same way as for Qt::QueuedConnection, except that the current thread
2593 will block until the event is delivered. Using this connection type to
2594 communicate between objects in the same thread will lead to deadlocks.
2595
2596 \li If \a type is Qt::AutoConnection, the member is invoked synchronously
2597 if \a obj lives in the same thread as the caller; otherwise it will invoke
2598 the member asynchronously. This is the behavior of the overloads that do
2599 not have the \a type parameter.
2600 \endlist
2601
2602 To asynchronously invoke the
2603 \l{QPushButton::animateClick()}{animateClick()} slot on a
2604 QPushButton:
2605
2606 \snippet code/src_corelib_kernel_qmetaobject.cpp 6
2607
2608 With asynchronous method invocations, the parameters must be copyable
2609 types, because Qt needs to copy the arguments to store them in an event
2610 behind the scenes. Since Qt 6.5, this function automatically registers the
2611 types being used; however, as a side-effect, it is not possible to make
2612 calls using types that are only forward-declared. Additionally, it is not
2613 possible to make asynchronous calls that use references to
2614 non-const-qualified types as parameters either.
2615
2616 To synchronously invoke the \c compute(QString, int, double) slot on
2617 some arbitrary object \c obj retrieve its return value:
2618
2619 \snippet code/src_corelib_kernel_qmetaobject.cpp invoke-no-macro
2620
2621 If the "compute" slot does not take exactly one \l QString, one \c int, and
2622 one \c double in the specified order, the call will fail. Note how it was
2623 necessary to be explicit about the type of the QString, as the character
2624 literal is not exactly the right type to match. If the method instead took
2625 a \l QByteArray, a \l qint64, and a \c{long double}, the call would need to be
2626 written as:
2627
2628 \snippet code/src_corelib_kernel_qmetaobject.cpp invoke-no-macro-other-types
2629
2630 The same call can be executed using the Q_ARG() and Q_RETURN_ARG() macros,
2631 as in:
2632
2633 \snippet code/src_corelib_kernel_qmetaobject.cpp 8
2634
2635 \warning this method will not test the validity of the arguments: \a object
2636 must be an instance of the class of the QMetaObject of which this QMetaMethod
2637 has been constructed with.
2638
2639 \sa Q_ARG(), Q_RETURN_ARG(), qRegisterMetaType(), QMetaObject::invokeMethod()
2640*/
2641
2642/*!
2643 \obsolete [6.5] Please use the variadic overload of this function
2644
2645 Invokes this method on the object \a object. Returns \c true if the member could be invoked.
2646 Returns \c false if there is no such member or the parameters did not match.
2647
2648 See the variadic invokeMethod() function for more information. This
2649 function should behave the same way as that one, with the following
2650 limitations:
2651
2652 \list
2653 \li The number of parameters is limited to 10.
2654 \li Parameter names may need to be an exact string match.
2655 \li Meta types are not automatically registered.
2656 \endlist
2657
2658 With asynchronous method invocations, the parameters must be of
2659 types that are known to Qt's meta-object system, because Qt needs
2660 to copy the arguments to store them in an event behind the
2661 scenes. If you try to use a queued connection and get the error
2662 message
2663
2664 \snippet code/src_corelib_kernel_qmetaobject.cpp 7
2665
2666 call qRegisterMetaType() to register the data type before you
2667 call QMetaMethod::invoke().
2668
2669 \warning In addition to the limitations of the variadic invoke() overload,
2670 the arguments must have the same type as the ones expected by the method,
2671 else, the behavior is undefined.
2672
2673 \sa Q_ARG(), Q_RETURN_ARG(), qRegisterMetaType(), QMetaObject::invokeMethod()
2674*/
2675bool QMetaMethod::invoke(QObject *object,
2676 Qt::ConnectionType connectionType,
2677 QGenericReturnArgument returnValue,
2678 QGenericArgument val0,
2679 QGenericArgument val1,
2680 QGenericArgument val2,
2681 QGenericArgument val3,
2682 QGenericArgument val4,
2683 QGenericArgument val5,
2684 QGenericArgument val6,
2685 QGenericArgument val7,
2686 QGenericArgument val8,
2687 QGenericArgument val9) const
2688{
2689 if (!object || !mobj)
2690 return false;
2691
2692 // check argument count (we don't allow invoking a method if given too few arguments)
2693 const char *typeNames[] = {
2694 returnValue.name(),
2695 val0.name(),
2696 val1.name(),
2697 val2.name(),
2698 val3.name(),
2699 val4.name(),
2700 val5.name(),
2701 val6.name(),
2702 val7.name(),
2703 val8.name(),
2704 val9.name()
2705 };
2706 void *param[] = {
2707 returnValue.data(),
2708 val0.data(),
2709 val1.data(),
2710 val2.data(),
2711 val3.data(),
2712 val4.data(),
2713 val5.data(),
2714 val6.data(),
2715 val7.data(),
2716 val8.data(),
2717 val9.data()
2718 };
2719
2720 int paramCount;
2721 for (paramCount = 1; paramCount < MaximumParamCount; ++paramCount) {
2722 if (qstrlen(typeNames[paramCount]) <= 0)
2723 break;
2724 }
2725 return invokeImpl(*this, object, connectionType, paramCount, param, typeNames, nullptr);
2726}
2727
2728bool QMetaMethod::invokeImpl(QMetaMethod self, void *target, Qt::ConnectionType connectionType,
2729 qsizetype paramCount, const void *const *parameters,
2730 const char *const *typeNames,
2731 const QtPrivate::QMetaTypeInterface *const *metaTypes)
2732{
2733 if (!target || !self.mobj)
2734 return false;
2735 QMetaMethodPrivate::InvokeFailReason r =
2736 QMetaMethodPrivate::invokeImpl(self, target, connectionType, paramCount, parameters,
2737 typeNames, metaTypes);
2738 if (Q_LIKELY(r == QMetaMethodPrivate::InvokeFailReason::None))
2739 return true;
2740
2741 if (int(r) >= int(QMetaMethodPrivate::InvokeFailReason::FormalParameterMismatch)) {
2742 int n = int(r) - int(QMetaMethodPrivate::InvokeFailReason::FormalParameterMismatch);
2743 qWarning("QMetaMethod::invoke: cannot convert formal parameter %d from %s in call to %s::%s",
2744 n, typeNames[n + 1] ? typeNames[n + 1] : metaTypes[n + 1]->name,
2745 self.mobj->className(), self.methodSignature().constData());
2746 }
2747 if (r == QMetaMethodPrivate::InvokeFailReason::TooFewArguments) {
2748 qWarning("QMetaMethod::invoke: too few arguments (%d) in call to %s::%s",
2749 int(paramCount), self.mobj->className(), self.methodSignature().constData());
2750 }
2751 return false;
2752}
2753
2754auto QMetaMethodInvoker::invokeImpl(QMetaMethod self, void *target,
2755 Qt::ConnectionType connectionType,
2756 qsizetype paramCount, const void *const *parameters,
2757 const char *const *typeNames,
2758 const QtPrivate::QMetaTypeInterface *const *metaTypes) -> InvokeFailReason
2759{
2760 auto object = static_cast<QObject *>(target);
2761 auto priv = QMetaMethodPrivate::get(&self);
2762 constexpr bool MetaTypesAreOptional = QT_VERSION < QT_VERSION_CHECK(7, 0, 0);
2763 auto methodMetaTypes = priv->parameterMetaTypeInterfaces();
2764 auto param = const_cast<void **>(parameters);
2765
2766 Q_ASSERT(priv->mobj);
2767 Q_ASSERT(self.methodType() == Constructor || object);
2768 Q_ASSERT(self.methodType() == Constructor || connectionType == Qt::ConnectionType(-1) ||
2769 priv->mobj->cast(object));
2770 Q_ASSERT(paramCount >= 1); // includes the return type
2771 Q_ASSERT(parameters);
2772 Q_ASSERT(typeNames);
2773 Q_ASSERT(MetaTypesAreOptional || metaTypes);
2774
2775 if ((paramCount - 1) < qsizetype(priv->data.argc()))
2777
2778 // 0 is the return type, 1 is the first formal parameter
2779 auto checkTypesAreCompatible = [=](int idx) {
2780 uint typeInfo = priv->parameterTypeInfo(idx - 1);
2781 QByteArrayView userTypeName(typeNames[idx] ? typeNames[idx] : metaTypes[idx]->name);
2782
2783 if ((typeInfo & IsUnresolvedType) == 0) {
2784 // this is a built-in type
2785 if (MetaTypesAreOptional && !metaTypes)
2786 return int(typeInfo) == QMetaType::fromName(userTypeName).rawId();
2787 return int(typeInfo) == metaTypes[idx]->typeId;
2788 }
2789
2790 QByteArrayView methodTypeName = stringDataView(priv->mobj, typeInfo & TypeNameIndexMask);
2791 if ((MetaTypesAreOptional && !metaTypes) || !metaTypes[idx]) {
2792 // compatibility call, compare strings
2793 if (methodTypeName == userTypeName)
2794 return true;
2795
2796 // maybe the user type needs normalization
2797 QByteArray normalized = normalizeTypeInternal(userTypeName.begin(), userTypeName.end());
2798 return methodTypeName == normalized;
2799 }
2800
2801 QMetaType userType(metaTypes[idx]);
2802 Q_ASSERT(userType.isValid());
2803 if (QMetaType(methodMetaTypes[idx - 1]) == userType)
2804 return true;
2805
2806 // if the parameter type was NOT only forward-declared, it MUST have
2807 // matched
2808 if (methodMetaTypes[idx - 1])
2809 return false;
2810
2811 // resolve from the name moc stored for us
2812 QMetaType resolved = QMetaType::fromName(methodTypeName);
2813 return resolved == userType;
2814 };
2815
2816 // force all types to be registered, just in case
2817 for (qsizetype i = 0; metaTypes && i < paramCount; ++i)
2818 QMetaType(metaTypes[i]).registerType();
2819
2820 // check formal parameters first (overload set)
2821 for (qsizetype i = 1; i < paramCount; ++i) {
2822 if (!checkTypesAreCompatible(i))
2824 }
2825
2826 // handle constructors first
2827 if (self.methodType() == Constructor) {
2828 if (object) {
2829 qWarning("QMetaMethod::invokeMethod: cannot call constructor %s on object %p",
2830 self.methodSignature().constData(), object);
2832 }
2833
2834 if (!parameters[0]) {
2835 qWarning("QMetaMethod::invokeMethod: constructor call to %s must assign a return type",
2836 self.methodSignature().constData());
2838 }
2839
2840 if (!MetaTypesAreOptional || metaTypes) {
2841 if (metaTypes[0]->typeId != QMetaType::QObjectStar) {
2842 qWarning("QMetaMethod::invokeMethod: cannot convert QObject* to %s on constructor call %s",
2843 metaTypes[0]->name, self.methodSignature().constData());
2845 }
2846 }
2847
2848 int idx = priv->ownConstructorMethodIndex();
2849 if (priv->mobj->static_metacall(QMetaObject::CreateInstance, idx, param) >= 0)
2851 return {};
2852 }
2853
2854 // regular type - check return type
2855 if (parameters[0]) {
2856 if (!checkTypesAreCompatible(0)) {
2857 const char *retType = typeNames[0] ? typeNames[0] : metaTypes[0]->name;
2858 qWarning("QMetaMethod::invokeMethod: return type mismatch for method %s::%s:"
2859 " cannot convert from %s to %s during invocation",
2860 priv->mobj->className(), priv->methodSignature().constData(),
2861 priv->rawReturnTypeName(), retType);
2863 }
2864 }
2865
2866 Qt::HANDLE currentThreadId = nullptr;
2867 QThread *objectThread = nullptr;
2868 auto receiverInSameThread = [&]() {
2869 if (!currentThreadId) {
2870 currentThreadId = QThread::currentThreadId();
2871 objectThread = object->thread();
2872 }
2873 if (objectThread)
2874 return currentThreadId == QThreadData::get2(objectThread)->threadId.loadRelaxed();
2875 return false;
2876 };
2877
2878 // check connection type
2879 if (connectionType == Qt::AutoConnection)
2880 connectionType = receiverInSameThread() ? Qt::DirectConnection : Qt::QueuedConnection;
2881 else if (connectionType == Qt::ConnectionType(-1))
2882 connectionType = Qt::DirectConnection;
2883
2884#if !QT_CONFIG(thread)
2885 if (connectionType == Qt::BlockingQueuedConnection) {
2886 connectionType = Qt::DirectConnection;
2887 }
2888#endif
2889
2890 // invoke!
2891 int idx_relative = priv->ownMethodIndex();
2892 int idx_offset = priv->mobj->methodOffset();
2893 QObjectPrivate::StaticMetaCallFunction callFunction = priv->mobj->d.static_metacall;
2894
2895 if (connectionType == Qt::DirectConnection) {
2896 if (callFunction)
2897 callFunction(object, QMetaObject::InvokeMetaMethod, idx_relative, param);
2898 else if (QMetaObject::metacall(object, QMetaObject::InvokeMetaMethod, idx_relative + idx_offset, param) >= 0)
2900 } else if (connectionType == Qt::QueuedConnection) {
2901 if (parameters[0]) {
2902 qWarning("QMetaMethod::invoke: Unable to invoke methods with return values in "
2903 "queued connections");
2905 }
2906
2907 QVarLengthArray<const QtPrivate::QMetaTypeInterface *, 16> argTypes;
2908 argTypes.reserve(paramCount);
2909 argTypes.emplace_back(nullptr); // return type
2910 // fill in the meta types first
2911 for (int i = 1; i < paramCount; ++i) {
2912 QMetaType type = QMetaType(methodMetaTypes[i - 1]);
2913 if (!type.iface() && (!MetaTypesAreOptional || metaTypes))
2914 type = QMetaType(metaTypes[i]);
2915 if (!type.iface())
2916 type = priv->parameterMetaType(i - 1);
2917 if (!type.iface() && typeNames[i])
2918 type = QMetaType::fromName(typeNames[i]);
2919 if (!type.iface()) {
2920 qWarning("QMetaMethod::invoke: Unable to handle unregistered datatype '%s'",
2921 typeNames[i]);
2923 }
2924 argTypes.emplace_back(type.iface());
2925 }
2926
2927 QCoreApplication::postEvent(object, new QQueuedMetaCallEvent(idx_offset, idx_relative, callFunction, nullptr,
2928 -1, paramCount, argTypes.data(), parameters));
2929 } else { // blocking queued connection
2930#if QT_CONFIG(thread)
2931 if (receiverInSameThread()) {
2932 qWarning("QMetaMethod::invoke: Dead lock detected in BlockingQueuedConnection: "
2933 "Receiver is %s(%p)", priv->mobj->className(), object);
2934 return InvokeFailReason::DeadLockDetected;
2935 }
2936
2937 QLatch latch(1);
2938 QCoreApplication::postEvent(object, new QMetaCallEvent(idx_offset, idx_relative, callFunction,
2939 nullptr, -1, param, &latch));
2940 latch.wait();
2941#endif // QT_CONFIG(thread)
2942 }
2943 return {};
2944}
2945
2946/*! \fn bool QMetaMethod::invoke(QObject *object,
2947 QGenericReturnArgument returnValue,
2948 QGenericArgument val0 = QGenericArgument(0),
2949 QGenericArgument val1 = QGenericArgument(),
2950 QGenericArgument val2 = QGenericArgument(),
2951 QGenericArgument val3 = QGenericArgument(),
2952 QGenericArgument val4 = QGenericArgument(),
2953 QGenericArgument val5 = QGenericArgument(),
2954 QGenericArgument val6 = QGenericArgument(),
2955 QGenericArgument val7 = QGenericArgument(),
2956 QGenericArgument val8 = QGenericArgument(),
2957 QGenericArgument val9 = QGenericArgument()) const
2958 \obsolete [6.5] Please use the variadic overload of this function
2959 \overload invoke()
2960
2961 This overload always invokes this method using the connection type Qt::AutoConnection.
2962*/
2963
2964/*! \fn bool QMetaMethod::invoke(QObject *object,
2965 Qt::ConnectionType connectionType,
2966 QGenericArgument val0 = QGenericArgument(0),
2967 QGenericArgument val1 = QGenericArgument(),
2968 QGenericArgument val2 = QGenericArgument(),
2969 QGenericArgument val3 = QGenericArgument(),
2970 QGenericArgument val4 = QGenericArgument(),
2971 QGenericArgument val5 = QGenericArgument(),
2972 QGenericArgument val6 = QGenericArgument(),
2973 QGenericArgument val7 = QGenericArgument(),
2974 QGenericArgument val8 = QGenericArgument(),
2975 QGenericArgument val9 = QGenericArgument()) const
2976 \obsolete [6.5] Please use the variadic overload of this function
2977 \overload invoke()
2978
2979 This overload can be used if the return value of the member is of no interest.
2980*/
2981
2982/*!
2983 \fn bool QMetaMethod::invoke(QObject *object,
2984 QGenericArgument val0 = QGenericArgument(0),
2985 QGenericArgument val1 = QGenericArgument(),
2986 QGenericArgument val2 = QGenericArgument(),
2987 QGenericArgument val3 = QGenericArgument(),
2988 QGenericArgument val4 = QGenericArgument(),
2989 QGenericArgument val5 = QGenericArgument(),
2990 QGenericArgument val6 = QGenericArgument(),
2991 QGenericArgument val7 = QGenericArgument(),
2992 QGenericArgument val8 = QGenericArgument(),
2993 QGenericArgument val9 = QGenericArgument()) const
2994 \obsolete [6.5] Please use the variadic overload of this function
2995 \overload invoke()
2996
2997 This overload invokes this method using the
2998 connection type Qt::AutoConnection and ignores return values.
2999*/
3000
3001/*!
3002 \fn template <typename ReturnArg, typename... Args> bool QMetaMethod::invokeOnGadget(void *gadget, QTemplatedMetaMethodReturnArgument<ReturnArg> ret, Args &&... arguments) const
3003 \fn template <typename... Args> bool QMetaMethod::invokeOnGadget(void *gadget, Args &&... arguments) const
3004 \since 6.5
3005
3006 Invokes this method on a Q_GADGET. Returns \c true if the member could be invoked.
3007 Returns \c false if there is no such member or the parameters did not match.
3008
3009 The pointer \a gadget must point to an instance of the gadget class.
3010
3011 The invocation is always synchronous.
3012
3013 For the overload with a QTemplatedMetaMethodReturnArgument parameter, the
3014 return value of the \a member function call is placed in \a ret. For the
3015 overload without it, the return value of the called function (if any) will
3016 be discarded. QTemplatedMetaMethodReturnArgument is an internal type you
3017 should not use directly. Instead, use the qReturnArg() function.
3018
3019 \warning this method will not test the validity of the arguments: \a gadget
3020 must be an instance of the class of the QMetaObject of which this QMetaMethod
3021 has been constructed with.
3022
3023 \sa Q_ARG(), Q_RETURN_ARG(), qRegisterMetaType(), QMetaObject::invokeMethod()
3024*/
3025
3026/*!
3027 \since 5.5
3028 \obsolete [6.5] Please use the variadic overload of this function
3029
3030 Invokes this method on a Q_GADGET. Returns \c true if the member could be invoked.
3031 Returns \c false if there is no such member or the parameters did not match.
3032
3033 See the variadic invokeMethod() function for more information. This
3034 function should behave the same way as that one, with the following
3035 limitations:
3036
3037 \list
3038 \li The number of parameters is limited to 10.
3039 \li Parameter names may need to be an exact string match.
3040 \li Meta types are not automatically registered.
3041 \endlist
3042
3043 \warning In addition to the limitations of the variadic invoke() overload,
3044 the arguments must have the same type as the ones expected by the method,
3045 else, the behavior is undefined.
3046
3047 \sa Q_ARG(), Q_RETURN_ARG(), qRegisterMetaType(), QMetaObject::invokeMethod()
3048*/
3049bool QMetaMethod::invokeOnGadget(void *gadget,
3050 QGenericReturnArgument returnValue,
3051 QGenericArgument val0,
3052 QGenericArgument val1,
3053 QGenericArgument val2,
3054 QGenericArgument val3,
3055 QGenericArgument val4,
3056 QGenericArgument val5,
3057 QGenericArgument val6,
3058 QGenericArgument val7,
3059 QGenericArgument val8,
3060 QGenericArgument val9) const
3061{
3062 if (!gadget || !mobj)
3063 return false;
3064
3065 // check return type
3066 if (returnValue.data()) {
3067 const char *retType = typeName();
3068 if (qstrcmp(returnValue.name(), retType) != 0) {
3069 // normalize the return value as well
3070 QByteArray normalized = QMetaObject::normalizedType(returnValue.name());
3071 if (qstrcmp(normalized.constData(), retType) != 0) {
3072 // String comparison failed, try compare the metatype.
3073 int t = returnType();
3074 if (t == QMetaType::UnknownType || t != QMetaType::fromName(normalized).rawId())
3075 return false;
3076 }
3077 }
3078 }
3079
3080 // check argument count (we don't allow invoking a method if given too few arguments)
3081 const char *typeNames[] = {
3082 returnValue.name(),
3083 val0.name(),
3084 val1.name(),
3085 val2.name(),
3086 val3.name(),
3087 val4.name(),
3088 val5.name(),
3089 val6.name(),
3090 val7.name(),
3091 val8.name(),
3092 val9.name()
3093 };
3094 int paramCount;
3095 for (paramCount = 1; paramCount < MaximumParamCount; ++paramCount) {
3096 if (qstrlen(typeNames[paramCount]) <= 0)
3097 break;
3098 }
3099 if (paramCount <= QMetaMethodPrivate::get(this)->parameterCount())
3100 return false;
3101
3102 // invoke!
3103 void *param[] = {
3104 returnValue.data(),
3105 val0.data(),
3106 val1.data(),
3107 val2.data(),
3108 val3.data(),
3109 val4.data(),
3110 val5.data(),
3111 val6.data(),
3112 val7.data(),
3113 val8.data(),
3114 val9.data()
3115 };
3116 int idx_relative = QMetaMethodPrivate::get(this)->ownMethodIndex();
3117 Q_ASSERT(QMetaObjectPrivate::get(mobj)->revision >= 6);
3118 QObjectPrivate::StaticMetaCallFunction callFunction = mobj->d.static_metacall;
3119 if (!callFunction)
3120 return false;
3121 callFunction(reinterpret_cast<QObject*>(gadget), QMetaObject::InvokeMetaMethod, idx_relative, param);
3122 return true;
3123}
3124
3125/*!
3126 \fn bool QMetaMethod::invokeOnGadget(void *gadget,
3127 QGenericArgument val0 = QGenericArgument(0),
3128 QGenericArgument val1 = QGenericArgument(),
3129 QGenericArgument val2 = QGenericArgument(),
3130 QGenericArgument val3 = QGenericArgument(),
3131 QGenericArgument val4 = QGenericArgument(),
3132 QGenericArgument val5 = QGenericArgument(),
3133 QGenericArgument val6 = QGenericArgument(),
3134 QGenericArgument val7 = QGenericArgument(),
3135 QGenericArgument val8 = QGenericArgument(),
3136 QGenericArgument val9 = QGenericArgument()) const
3137
3138 \overload
3139 \obsolete [6.5] Please use the variadic overload of this function
3140 \since 5.5
3141
3142 This overload invokes this method for a \a gadget and ignores return values.
3143*/
3144
3145/*!
3146 \class QMetaEnum
3147 \inmodule QtCore
3148 \brief The QMetaEnum class provides meta-data about an enumerator.
3149
3150 \ingroup objectmodel
3151
3152 Use name() for the enumerator's name. The enumerator's keys (names
3153 of each enumerated item) are returned by key(); use keyCount() to find
3154 the number of keys. isFlag() returns whether the enumerator is
3155 meant to be used as a flag, meaning that its values can be combined
3156 using the OR operator.
3157
3158 The conversion functions keyToValue(), valueToKey(), keysToValue(),
3159 and valueToKeys() allow conversion between the integer
3160 representation of an enumeration or set value and its literal
3161 representation. The scope() function returns the class scope this
3162 enumerator was declared in.
3163
3164 To use QMetaEnum functionality, register the enumerator within the meta-object
3165 system using the Q_ENUM macro.
3166
3167 \code
3168 enum AppleType {
3169 Big,
3170 Small
3171 };
3172 Q_ENUM(AppleType)
3173
3174 QMetaEnum metaEnum = QMetaEnum::fromType<ModelApple::AppleType>();
3175 qDebug() << metaEnum.valueToKey(ModelApple::Big);
3176 \endcode
3177
3178 \sa QMetaObject, QMetaMethod, QMetaProperty
3179*/
3180
3181/*!
3182 \fn bool QMetaEnum::isValid() const
3183
3184 Returns \c true if this enum is valid (has a name); otherwise returns
3185 false.
3186
3187 \sa name()
3188*/
3189
3190/*!
3191 \fn const QMetaObject *QMetaEnum::enclosingMetaObject() const
3192 \internal
3193*/
3194
3195
3196/*!
3197 \fn QMetaEnum::QMetaEnum()
3198 \internal
3199*/
3200
3201/*!
3202 Returns the name of the type (without the scope).
3203
3204 For example, the Qt::Key enumeration has \c
3205 Key as the type name and \l Qt as the scope.
3206
3207 For flags this returns the name of the flag type, not the
3208 name of the enum type.
3209
3210 \sa isValid(), scope(), enumName()
3211*/
3212const char *QMetaEnum::name() const
3213{
3214 if (!mobj)
3215 return nullptr;
3216 return rawStringData(mobj, data.name());
3217}
3218
3219/*!
3220 Returns the enum name of the flag (without the scope).
3221
3222 For example, the Qt::AlignmentFlag flag has \c
3223 AlignmentFlag as the enum name, but \c Alignment as the type name.
3224 Non flag enums has the same type and enum names.
3225
3226 Enum names have the same scope as the type name.
3227
3228 \since 5.12
3229 \sa isValid(), name()
3230*/
3231const char *QMetaEnum::enumName() const
3232{
3233 if (!mobj)
3234 return nullptr;
3235 return rawStringData(mobj, data.alias());
3236}
3237
3238/*!
3239 Returns the meta type of the enum.
3240
3241 If the QMetaObject that this enum is part of was generated with Qt 6.5 or
3242 earlier, this will be an invalid meta type.
3243
3244 \note This is the meta type of the enum itself, not of its underlying
3245 integral type. You can retrieve the meta type of the underlying type of the
3246 enum using \l{QMetaType::underlyingType()}.
3247
3248 \since 6.6
3249*/
3250QMetaType QMetaEnum::metaType() const
3251{
3252 if (!mobj)
3253 return {};
3254
3255 const QMetaObjectPrivate *p = priv(mobj->d.data);
3256#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
3257 if (p->revision < 12)
3258 QMetaType();
3259#endif
3260
3261 QMetaType mt(mobj->d.metaTypes[data.index(mobj) + p->propertyCount]);
3262 mt.registerType();
3263 return mt;
3264}
3265
3266/*!
3267 Returns the number of keys.
3268
3269 \sa key()
3270*/
3271int QMetaEnum::keyCount() const
3272{
3273 if (!mobj)
3274 return 0;
3275 return data.keyCount();
3276}
3277
3278/*!
3279 Returns the key with the given \a index, or \nullptr if no such key exists.
3280
3281 \sa keyCount(), value(), valueToKey()
3282*/
3283const char *QMetaEnum::key(int index) const
3284{
3285 if (!mobj)
3286 return nullptr;
3287 if (index >= 0 && index < int(data.keyCount()))
3288 return rawStringData(mobj, mobj->d.data[data.data() + 2*index]);
3289 return nullptr;
3290}
3291
3292/*!
3293 Returns the value with the given \a index; or returns -1 if there
3294 is no such value.
3295
3296 If this is an enumeration with a 64-bit underlying type (see is64Bit()),
3297 this function returns the low 32-bit portion of the value. Use value64() to
3298 obtain the full value instead.
3299
3300 \sa value64(), keyCount(), key(), keyToValue()
3301*/
3302int QMetaEnum::value(int index) const
3303{
3304 return value64(index).value_or(-1);
3305}
3306
3312Q_DECL_PURE_FUNCTION static inline EnumExtendMode enumExtendMode(const QMetaEnum &e)
3313{
3314 if (e.is64Bit())
3315 return Use64Bit;
3316 if (e.isFlag())
3317 return ZeroExtend;
3318 if (e.metaType().flags() & QMetaType::IsUnsignedEnumeration)
3319 return ZeroExtend;
3320 return SignExtend;
3321}
3322
3323static constexpr bool isEnumValueSuitable(quint64 value, EnumExtendMode mode)
3324{
3325 if (mode == Use64Bit)
3326 return true; // any value is suitable
3327
3328 // 32-bit QMetaEnum
3329 if (mode == ZeroExtend)
3330 return value == uint(value);
3331 return value == quint64(int(value));
3332}
3333
3334template <typename... Mode> inline
3335quint64 QMetaEnum::value_helper(uint index, Mode... modes) const noexcept
3336{
3337 static_assert(sizeof...(Mode) < 2);
3338 if constexpr (sizeof...(Mode) == 0) {
3339 return value_helper(index, enumExtendMode(*this));
3340 } else if constexpr (sizeof...(Mode) == 1) {
3341 auto mode = (modes, ...);
3342 quint64 value = mobj->d.data[data.data() + 2U * index + 1];
3343 if (mode > 0)
3344 value |= quint64(mobj->d.data[data.data() + 2U * data.keyCount() + index]) << 32;
3345 else if (mode < 0)
3346 value = int(value); // sign extend to 64-bit
3347 return value;
3348 }
3349}
3350
3351/*!
3352 \since 6.9
3353
3354 Returns the value with the given \a index if it exists; or returns a
3355 \c{std::nullopt} if it doesn't.
3356
3357//! [qmetaenum-32bit-signextend-64bit]
3358 This function always sign-extends the value of 32-bit enumerations to 64
3359 bits, if their underlying type is signed (e.g., \c int, \c short). In most
3360 cases, this is the expected behavior.
3361
3362 A notable exception is for flag values that have bit 31 set, like
3363 0x8000'0000, because some compilers (such as Microsoft Visual Studio), do
3364 not automatically switch to an unsigned underlying type. To avoid this
3365 problem, explicitly specify the underlying type in the \c enum declaration.
3366
3367 \note For QMetaObjects compiled prior to Qt 6.6, this function always
3368 sign-extends.
3369//! [qmetaenum-32bit-signextend-64bit]
3370
3371 \sa keyCount(), key(), keyToValue(), is64Bit()
3372*/
3373std::optional<quint64> QMetaEnum::value64(int index) const
3374{
3375 if (!mobj)
3376 return std::nullopt;
3377 if (index < 0 || index >= int(data.keyCount()))
3378 return std::nullopt;
3379
3380 return value_helper(index);
3381}
3382
3383/*!
3384 Returns \c true if this enumerator is used as a flag; otherwise returns
3385 false.
3386
3387 When used as flags, enumerators can be combined using the OR
3388 operator.
3389
3390 \sa keysToValue(), valueToKeys()
3391*/
3392bool QMetaEnum::isFlag() const
3393{
3394 if (!mobj)
3395 return false;
3396 return data.flags() & EnumIsFlag;
3397}
3398
3399/*!
3400 \since 5.8
3401
3402 Returns \c true if this enumerator is declared as a C++11 enum class;
3403 otherwise returns false.
3404*/
3405bool QMetaEnum::isScoped() const
3406{
3407 if (!mobj)
3408 return false;
3409 return data.flags() & EnumIsScoped;
3410}
3411
3412/*!
3413 \since 6.9
3414
3415 Returns \c true if the underlying type of this enumeration is 64 bits wide.
3416
3417 \sa value64()
3418*/
3419bool QMetaEnum::is64Bit() const
3420{
3421 if (!mobj)
3422 return false;
3423 return data.flags() & EnumIs64Bit;
3424}
3425
3426/*!
3427 Returns the scope this enumerator was declared in.
3428
3429 For example, the Qt::AlignmentFlag enumeration has \c Qt as
3430 the scope and \c AlignmentFlag as the name.
3431
3432 \sa name()
3433*/
3434const char *QMetaEnum::scope() const
3435{
3436 return mobj ? mobj->className() : nullptr;
3437}
3438
3439static bool isScopeMatch(QByteArrayView scope, const QMetaEnum *e)
3440{
3441 const QByteArrayView className = e->enclosingMetaObject()->className();
3442
3443 // Typical use-cases:
3444 // a) Unscoped: namespace N { class C { enum E { F }; }; }; key == "N::C::F"
3445 // b) Scoped: namespace N { class C { enum class E { F }; }; }; key == "N::C::E::F"
3446 if (scope == className)
3447 return true;
3448
3449 // Not using name() because if isFlag() is true, we want the actual name
3450 // of the enum, e.g. "MyFlag", not "MyFlags", e.g.
3451 // enum MyFlag { F1, F2 }; Q_DECLARE_FLAGS(MyFlags, MyFlag);
3452 QByteArrayView name = e->enumName();
3453
3454 // Match fully qualified enumerator in unscoped enums, key == "N::C::E::F"
3455 // equivalent to use-case "a" above
3456 const auto sz = className.size();
3457 if (scope.size() == sz + qsizetype(qstrlen("::")) + name.size()
3458 && scope.startsWith(className)
3459 && scope.sliced(sz, 2) == "::"
3460 && scope.sliced(sz + 2) == name)
3461 return true;
3462
3463 return false;
3464}
3465
3466/*!
3467 Returns the integer value of the given enumeration \a key, or -1
3468 if \a key is not defined.
3469
3470 If \a key is not defined, *\a{ok} is set to false; otherwise
3471 *\a{ok} is set to true.
3472
3473 For flag types, use keysToValue().
3474
3475 If this is a 64-bit enumeration (see is64Bit()), this function returns the
3476 low 32-bit portion of the value. Use keyToValue64() to obtain the full value
3477 instead.
3478
3479 \sa keyToValue64, valueToKey(), isFlag(), keysToValue(), is64Bit()
3480*/
3481int QMetaEnum::keyToValue(const char *key, bool *ok) const
3482{
3483 auto value = keyToValue64(key);
3484 if (ok != nullptr)
3485 *ok = value.has_value();
3486 return int(value.value_or(-1));
3487}
3488
3489/*!
3490 \since 6.9
3491
3492 Returns the integer value of the given enumeration \a key, or \c
3493 std::nullopt if \a key is not defined.
3494
3495 For flag types, use keysToValue64().
3496
3497 \include qmetaobject.cpp qmetaenum-32bit-signextend-64bit
3498
3499 \sa valueToKey(), isFlag(), keysToValue64()
3500*/
3501std::optional<quint64> QMetaEnum::keyToValue64(const char *key) const
3502{
3503 if (!mobj || !key)
3504 return std::nullopt;
3505 const auto [scope, enumKey] = parse_scope(QLatin1StringView(key));
3506 for (int i = 0; i < int(data.keyCount()); ++i) {
3507 if ((!scope || isScopeMatch(*scope, this))
3508 && enumKey == stringDataView(mobj, mobj->d.data[data.data() + 2 * i])) {
3509 return value_helper(i);
3510 }
3511 }
3512 return std::nullopt;
3513}
3514
3515/*!
3516 Returns the string that is used as the name of the given
3517 enumeration \a value, or \nullptr if \a value is not defined.
3518
3519 For flag types, use valueToKeys().
3520
3521 \sa isFlag(), valueToKeys()
3522*/
3523const char *QMetaEnum::valueToKey(quint64 value) const
3524{
3525 if (!mobj)
3526 return nullptr;
3527
3528 EnumExtendMode mode = enumExtendMode(*this);
3529 if (!isEnumValueSuitable(value, mode))
3530 return nullptr;
3531
3532 for (int i = 0; i < int(data.keyCount()); ++i) {
3533 if (value == value_helper(i, mode))
3534 return rawStringData(mobj, mobj->d.data[data.data() + 2 * i]);
3535 }
3536 return nullptr;
3537}
3538
3539static bool parseEnumFlags(QByteArrayView v, QVarLengthArray<QByteArrayView, 10> &list)
3540{
3541 v = v.trimmed();
3542 if (v.empty()) {
3543 qWarning("QMetaEnum::keysToValue: empty keys string.");
3544 return false;
3545 }
3546
3547 qsizetype sep = v.indexOf('|', 0);
3548 if (sep == 0) {
3549 qWarning("QMetaEnum::keysToValue: malformed keys string, starts with '|', \"%s\"",
3550 v.constData());
3551 return false;
3552 }
3553
3554 if (sep == -1) { // One flag
3555 list.push_back(v);
3556 return true;
3557 }
3558
3559 if (v.endsWith('|')) {
3560 qWarning("QMetaEnum::keysToValue: malformed keys string, ends with '|', \"%s\"",
3561 v.constData());
3562 return false;
3563 }
3564
3565 const auto begin = v.begin();
3566 const auto end = v.end();
3567 auto b = begin;
3568 for (; b != end && sep != -1; sep = v.indexOf('|', sep)) {
3569 list.push_back({b, begin + sep});
3570 ++sep; // Skip over '|'
3571 b = begin + sep;
3572 if (*b == '|') {
3573 qWarning("QMetaEnum::keysToValue: malformed keys string, has two consecutive '|': "
3574 "\"%s\"", v.constData());
3575 return false;
3576 }
3577 }
3578
3579 // The rest of the string
3580 list.push_back({b, end});
3581 return true;
3582}
3583
3584/*!
3585 Returns the value derived from combining together the values of
3586 the \a keys using the OR operator, or -1 if \a keys is not
3587 defined. Note that the strings in \a keys must be '|'-separated.
3588
3589 If \a keys is not defined, *\a{ok} is set to false; otherwise
3590 *\a{ok} is set to true.
3591
3592 If this is a 64-bit enumeration (see is64Bit()), this function returns the
3593 low 32-bit portion of the value. Use keyToValue64() to obtain the full value
3594 instead.
3595
3596 \sa keysToValue64(), isFlag(), valueToKey(), valueToKeys(), is64Bit()
3597*/
3598int QMetaEnum::keysToValue(const char *keys, bool *ok) const
3599{
3600 auto value = keysToValue64(keys);
3601 if (ok != nullptr)
3602 *ok = value.has_value();
3603 return int(value.value_or(-1));
3604}
3605
3606/*!
3607 Returns the value derived from combining together the values of the \a keys
3608 using the OR operator, or \c std::nullopt if \a keys is not defined. Note
3609 that the strings in \a keys must be '|'-separated.
3610
3611 \include qmetaobject.cpp qmetaenum-32bit-signextend-64bit
3612
3613 \sa isFlag(), valueToKey(), valueToKeys()
3614*/
3615std::optional<quint64> QMetaEnum::keysToValue64(const char *keys) const
3616{
3617 if (!mobj || !keys)
3618 return std::nullopt;
3619
3620 EnumExtendMode mode = enumExtendMode(*this);
3621 auto lookup = [&] (QByteArrayView key) -> std::optional<quint64> {
3622 for (int i = data.keyCount() - 1; i >= 0; --i) {
3623 if (key == stringDataView(mobj, mobj->d.data[data.data() + 2*i]))
3624 return value_helper(i, mode);
3625 }
3626 return std::nullopt;
3627 };
3628
3629 quint64 value = 0;
3630 QVarLengthArray<QByteArrayView, 10> list;
3631 const bool r = parseEnumFlags(QByteArrayView{keys}, list);
3632 if (!r)
3633 return std::nullopt;
3634 for (const auto &untrimmed : list) {
3635 const auto parsed = parse_scope(untrimmed.trimmed());
3636 if (parsed.scope && !isScopeMatch(*parsed.scope, this))
3637 return std::nullopt; // wrong type name in qualified name
3638 if (auto thisValue = lookup(parsed.key))
3639 value |= *thisValue;
3640 else
3641 return std::nullopt; // no such enumerator
3642 }
3643 return value;
3644}
3645
3646namespace
3647{
3648template <typename String, typename Container, typename Separator>
3649void join_reversed(String &s, const Container &c, Separator sep)
3650{
3651 if (c.empty())
3652 return;
3653 qsizetype len = qsizetype(c.size()) - 1; // N - 1 separators
3654 for (auto &e : c)
3655 len += qsizetype(e.size()); // N parts
3656 s.reserve(len);
3657 bool first = true;
3658 for (auto rit = c.rbegin(), rend = c.rend(); rit != rend; ++rit) {
3659 const auto &e = *rit;
3660 if (!first)
3661 s.append(sep);
3662 first = false;
3663 s.append(e.data(), e.size());
3664 }
3665}
3666} // unnamed namespace
3667
3668/*!
3669 Returns a byte array of '|'-separated keys that represents the
3670 given \a value.
3671
3672 \note Passing a 64-bit \a value to an enumeration whose underlying type is
3673 32-bit (that is, if is64Bit() returns \c false) results in an empty string
3674 being returned.
3675
3676 \sa isFlag(), valueToKey(), keysToValue()
3677*/
3678QByteArray QMetaEnum::valueToKeys(quint64 value) const
3679{
3680 QByteArray keys;
3681 if (!mobj)
3682 return keys;
3683
3684 EnumExtendMode mode = enumExtendMode(*this);
3685 if (!isEnumValueSuitable(value, mode))
3686 return keys;
3687
3688 QVarLengthArray<QByteArrayView, sizeof(int) * CHAR_BIT> parts;
3689 quint64 v = value;
3690
3691 // reverse iterate to ensure values like Qt::Dialog=0x2|Qt::Window are processed first.
3692 for (int i = data.keyCount() - 1; i >= 0; --i) {
3693 quint64 k = value_helper(i, mode);
3694 if ((k != 0 && (v & k) == k) || (k == value)) {
3695 v = v & ~k;
3696 parts.push_back(stringDataView(mobj, mobj->d.data[data.data() + 2 * i]));
3697 }
3698 }
3699 join_reversed(keys, parts, '|');
3700 return keys;
3701}
3702
3703/*!
3704 \internal
3705 */
3706QMetaEnum::QMetaEnum(const QMetaObject *mobj, int index)
3707 : mobj(mobj), data({ mobj->d.data + priv(mobj->d.data)->enumeratorData + index * Data::Size })
3708{
3709 Q_ASSERT(index >= 0 && index < priv(mobj->d.data)->enumeratorCount);
3710}
3711
3712int QMetaEnum::Data::index(const QMetaObject *mobj) const
3713{
3714#if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0)
3715# warning "Consider changing Size to a power of 2"
3716#endif
3717 return (unsigned(d - mobj->d.data) - priv(mobj->d.data)->enumeratorData) / Size;
3718}
3719
3720/*!
3721 \fn template<typename T> QMetaEnum QMetaEnum::fromType()
3722 \since 5.5
3723
3724 Returns the QMetaEnum corresponding to the type in the template parameter.
3725 The enum needs to be declared with Q_ENUM.
3726*/
3727
3728/*!
3729 \class QMetaProperty
3730 \inmodule QtCore
3731 \brief The QMetaProperty class provides meta-data about a property.
3732
3733 \ingroup objectmodel
3734
3735 Property meta-data is obtained from an object's meta-object. See
3736 QMetaObject::property() and QMetaObject::propertyCount() for
3737 details.
3738
3739 \section1 Property Meta-Data
3740
3741 A property has a name() and a metaType(), as well as various
3742 attributes that specify its behavior: isReadable(), isWritable(),
3743 isDesignable(), isScriptable(), revision(), and isStored().
3744
3745 If the property is an enumeration, isEnumType() returns \c true; if the
3746 property is an enumeration that is also a flag (i.e. its values
3747 can be combined using the OR operator), isEnumType() and
3748 isFlagType() both return true. The enumerator for these types is
3749 available from enumerator().
3750
3751 The property's values are set and retrieved with read(), write(),
3752 and reset(); they can also be changed through QObject's set and get
3753 functions. See QObject::setProperty() and QObject::property() for
3754 details.
3755
3756 \section1 Copying and Assignment
3757
3758 QMetaProperty objects can be copied by value. However, each copy will
3759 refer to the same underlying property meta-data.
3760
3761 \sa QMetaObject, QMetaEnum, QMetaMethod, {Qt's Property System}
3762*/
3763
3764/*!
3765 \fn bool QMetaProperty::isValid() const
3766
3767 Returns \c true if this property is valid (readable); otherwise
3768 returns \c false.
3769
3770 \sa isReadable()
3771*/
3772
3773/*!
3774 \fn const QMetaObject *QMetaProperty::enclosingMetaObject() const
3775 \internal
3776*/
3777
3778/*!
3779 \fn QMetaProperty::QMetaProperty()
3780 \internal
3781*/
3782
3783/*!
3784 Returns this property's name.
3785
3786 \sa type(), typeName()
3787*/
3788const char *QMetaProperty::name() const
3789{
3790 if (!mobj)
3791 return nullptr;
3792 return rawStringData(mobj, data.name());
3793}
3794
3795/*!
3796 Returns the name of this property's type.
3797
3798 \sa type(), name()
3799*/
3800const char *QMetaProperty::typeName() const
3801{
3802 if (!mobj)
3803 return nullptr;
3804 // TODO: can the metatype be invalid for dynamic metaobjects?
3805 if (const auto mt = metaType(); mt.isValid())
3806 return mt.name();
3807 return typeNameFromTypeInfo(mobj, data.type()).constData();
3808}
3809
3810/*! \fn QVariant::Type QMetaProperty::type() const
3811 \deprecated
3812
3813 Returns this property's type. The return value is one
3814 of the values of the QVariant::Type enumeration.
3815
3816 \sa typeName(), name(), metaType()
3817*/
3818
3819/*! \fn int QMetaProperty::userType() const
3820 \since 4.2
3821
3822 Returns this property's user type. The return value is one
3823 of the values that are registered with QMetaType.
3824
3825 This is equivalent to metaType().id()
3826
3827 \sa type(), QMetaType, typeName(), metaType()
3828 */
3829
3830/*! \fn int QMetaProperty::typeId() const
3831 \since 6.0
3832
3833 Returns the storage type of the property. This is
3834 the same as metaType().id().
3835
3836 \sa QMetaType, typeName(), metaType()
3837 */
3838
3839/*!
3840 \since 6.0
3841
3842 Returns this property's QMetaType.
3843
3844 \sa QMetaType
3845 */
3846QMetaType QMetaProperty::metaType() const
3847{
3848 if (!mobj)
3849 return {};
3850 QMetaType mt(mobj->d.metaTypes[data.index(mobj)]);
3851 mt.registerType();
3852 return mt;
3853}
3854
3855int QMetaProperty::Data::index(const QMetaObject *mobj) const
3856{
3857#if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0)
3858# warning "Consider changing Size to a power of 2"
3859#endif
3860 return (unsigned(d - mobj->d.data) - priv(mobj->d.data)->propertyData) / Size;
3861}
3862
3863/*!
3864 \since 4.6
3865
3866 Returns this property's index.
3867*/
3868int QMetaProperty::propertyIndex() const
3869{
3870 if (!mobj)
3871 return -1;
3872 return data.index(mobj) + mobj->propertyOffset();
3873}
3874
3875/*!
3876 \since 5.14
3877
3878 Returns this property's index relative within the enclosing meta object.
3879*/
3880int QMetaProperty::relativePropertyIndex() const
3881{
3882 if (!mobj)
3883 return -1;
3884 return data.index(mobj);
3885}
3886
3887/*!
3888 Returns \c true if the property's type is an enumeration value that
3889 is used as a flag; otherwise returns \c false.
3890
3891 Flags can be combined using the OR operator. A flag type is
3892 implicitly also an enum type.
3893
3894 \sa isEnumType(), enumerator(), QMetaEnum::isFlag()
3895*/
3896
3897bool QMetaProperty::isFlagType() const
3898{
3899 return isEnumType() && menum.isFlag();
3900}
3901
3902/*!
3903 Returns \c true if the property's type is an enumeration value;
3904 otherwise returns \c false.
3905
3906 \sa enumerator(), isFlagType()
3907*/
3908bool QMetaProperty::isEnumType() const
3909{
3910 if (!mobj)
3911 return false;
3912 return (data.flags() & EnumOrFlag) && menum.name();
3913}
3914
3915/*!
3916 \internal
3917
3918 Returns \c true if the property has a C++ setter function that
3919 follows Qt's standard "name" / "setName" pattern. Designer and uic
3920 query hasStdCppSet() in order to avoid expensive
3921 QObject::setProperty() calls. All properties in Qt [should] follow
3922 this pattern.
3923*/
3924bool QMetaProperty::hasStdCppSet() const
3925{
3926 if (!mobj)
3927 return false;
3928 return (data.flags() & StdCppSet);
3929}
3930
3931/*!
3932 \internal
3933
3934 Returns \c true if the property is an alias.
3935 This is for instance true for a property declared in QML
3936 as 'property alias'.
3937*/
3938bool QMetaProperty::isAlias() const
3939{
3940 if (!mobj)
3941 return false;
3942 return (data.flags() & Alias);
3943}
3944
3945#if QT_DEPRECATED_SINCE(6, 4)
3946/*!
3947 \internal
3948 Historically:
3949 Executes metacall with QMetaObject::RegisterPropertyMetaType flag.
3950 Returns id of registered type or QMetaType::UnknownType if a type
3951 could not be registered for any reason.
3952 Obsolete since Qt 6
3953*/
3954int QMetaProperty::registerPropertyType() const
3955{
3956 return typeId();
3957}
3958#endif
3959
3960QMetaProperty::QMetaProperty(const QMetaObject *mobj, int index)
3961 : mobj(mobj),
3962 data(getMetaPropertyData(mobj, index))
3963{
3964 Q_ASSERT(index >= 0 && index < priv(mobj->d.data)->propertyCount);
3965 // The code below here just resolves menum if the property is an enum type:
3966 if (!(data.flags() & EnumOrFlag) || !metaType().flags().testFlag(QMetaType::IsEnumeration))
3967 return;
3968 QByteArrayView enum_name = typeNameFromTypeInfo(mobj, data.type());
3969 menum = mobj->enumerator(QMetaObjectPrivate::indexOfEnumerator(mobj, enum_name));
3970 if (menum.isValid())
3971 return;
3972
3973 QByteArrayView scope_name;
3974 const auto parsed = parse_scope(enum_name);
3975 if (parsed.scope) {
3976 scope_name = *parsed.scope;
3977 enum_name = parsed.key;
3978 } else {
3979 scope_name = objectClassName(mobj);
3980 }
3981
3982 const QMetaObject *scope = nullptr;
3983 if (scope_name == "Qt")
3984 scope = &Qt::staticMetaObject;
3985 else
3986 scope = QMetaObject_findMetaObject(mobj, QByteArrayView(scope_name));
3987
3988 if (scope)
3989 menum = scope->enumerator(QMetaObjectPrivate::indexOfEnumerator(scope, enum_name));
3990}
3991
3992/*!
3993 \internal
3994 Constructs the \c QMetaProperty::Data for the \a index th property of \a mobj
3995 */
3996QMetaProperty::Data QMetaProperty::getMetaPropertyData(const QMetaObject *mobj, int index)
3997{
3998 return { mobj->d.data + priv(mobj->d.data)->propertyData + index * Data::Size };
3999}
4000
4001/*!
4002 Returns the enumerator if this property's type is an enumerator
4003 type; otherwise the returned value is undefined.
4004
4005 \sa isEnumType(), isFlagType()
4006*/
4007QMetaEnum QMetaProperty::enumerator() const
4008{
4009 return menum;
4010}
4011
4012/*!
4013 Reads the property's value from the given \a object. Returns the value
4014 if it was able to read it; otherwise returns an invalid variant.
4015
4016 \sa write(), reset(), isReadable()
4017*/
4018QVariant QMetaProperty::read(const QObject *object) const
4019{
4020 if (!object || !mobj)
4021 return QVariant();
4022
4023 // the status variable is changed by qt_metacall to indicate what it did
4024 // this feature is currently only used by Qt D-Bus and should not be depended
4025 // upon. Don't change it without looking into QDBusAbstractInterface first
4026 // -1 (unchanged): normal qt_metacall, result stored in argv[0]
4027 // changed: result stored directly in value
4028 int status = -1;
4029 QVariant value;
4030 void *argv[] = { nullptr, &value, &status };
4031 QMetaType t(mobj->d.metaTypes[data.index(mobj)]);
4032 if (t == QMetaType::fromType<QVariant>()) {
4033 argv[0] = &value;
4034 } else {
4035 value = QVariant(t, nullptr);
4036 argv[0] = value.data();
4037 }
4038 if (priv(mobj->d.data)->flags & PropertyAccessInStaticMetaCall && mobj->d.static_metacall) {
4039 mobj->d.static_metacall(const_cast<QObject*>(object), QMetaObject::ReadProperty, data.index(mobj), argv);
4040 } else {
4041 QMetaObject::metacall(const_cast<QObject*>(object), QMetaObject::ReadProperty,
4042 data.index(mobj) + mobj->propertyOffset(), argv);
4043 }
4044
4045 if (status != -1)
4046 return value;
4047 if (t != QMetaType::fromType<QVariant>() && argv[0] != value.data())
4048 // pointer or reference
4049 return QVariant(t, argv[0]);
4050 return value;
4051}
4052
4053/*!
4054 Writes \a value as the property's value to the given \a object. Returns
4055 true if the write succeeded; otherwise returns \c false.
4056
4057 If \a value is not of the same type as the property, a conversion
4058 is attempted. An empty QVariant() is equivalent to a call to reset()
4059 if this property is resettable, or setting a default-constructed object
4060 otherwise.
4061
4062 \note This function internally makes a copy of \a value. Prefer to use the
4063 rvalue overload when possible.
4064
4065 \sa read(), reset(), isWritable()
4066*/
4067bool QMetaProperty::write(QObject *object, const QVariant &value) const
4068{
4069 if (!object || !isWritable())
4070 return false;
4071 return write(object, QVariant(value));
4072}
4073
4074/*!
4075 \overload
4076 \since 6.6
4077*/
4078bool QMetaProperty::write(QObject *object, QVariant &&v) const
4079{
4080 if (!object || !isWritable())
4081 return false;
4082 QMetaType t(mobj->d.metaTypes[data.index(mobj)]);
4083 if (t != QMetaType::fromType<QVariant>() && t != v.metaType()) {
4084 if (isEnumType() && !t.metaObject() && v.metaType() == QMetaType::fromType<QString>()) {
4085 // Assigning a string to a property of type Q_ENUMS (instead of Q_ENUM)
4086 // means the QMetaType has no associated QMetaObject, so it can't
4087 // do the conversion (see qmetatype.cpp:convertToEnum()).
4088 std::optional value = isFlagType() ? menum.keysToValue64(v.toByteArray())
4089 : menum.keyToValue64(v.toByteArray());
4090 if (value)
4091 v = QVariant(qlonglong(*value));
4092
4093 // If the key(s)ToValue64 call failed, the convert() call below
4094 // gives QMetaType one last chance.
4095 }
4096 if (!v.isValid()) {
4097 if (isResettable())
4098 return reset(object);
4099 v = QVariant(t, nullptr);
4100 } else if (!v.convert(t)) {
4101 return false;
4102 }
4103 }
4104 // the status variable is changed by qt_metacall to indicate what it did
4105 // this feature is currently only used by Qt D-Bus and should not be depended
4106 // upon. Don't change it without looking into QDBusAbstractInterface first
4107 // -1 (unchanged): normal qt_metacall, result stored in argv[0]
4108 // changed: result stored directly in value, return the value of status
4109 int status = -1;
4110 // the flags variable is used by the declarative module to implement
4111 // interception of property writes.
4112 int flags = 0;
4113 void *argv[] = { nullptr, &v, &status, &flags };
4114 if (t == QMetaType::fromType<QVariant>())
4115 argv[0] = &v;
4116 else
4117 argv[0] = v.data();
4118 if (priv(mobj->d.data)->flags & PropertyAccessInStaticMetaCall && mobj->d.static_metacall)
4119 mobj->d.static_metacall(object, QMetaObject::WriteProperty, data.index(mobj), argv);
4120 else
4121 QMetaObject::metacall(object, QMetaObject::WriteProperty, data.index(mobj) + mobj->propertyOffset(), argv);
4122
4123 return status;
4124}
4125
4126/*!
4127 Resets the property for the given \a object with a reset method.
4128 Returns \c true if the reset worked; otherwise returns \c false.
4129
4130 Reset methods are optional; only a few properties support them.
4131
4132 \sa read(), write()
4133*/
4134bool QMetaProperty::reset(QObject *object) const
4135{
4136 if (!object || !mobj || !isResettable())
4137 return false;
4138 void *argv[] = { nullptr };
4139 if (priv(mobj->d.data)->flags & PropertyAccessInStaticMetaCall && mobj->d.static_metacall)
4140 mobj->d.static_metacall(object, QMetaObject::ResetProperty, data.index(mobj), argv);
4141 else
4142 QMetaObject::metacall(object, QMetaObject::ResetProperty, data.index(mobj) + mobj->propertyOffset(), argv);
4143 return true;
4144}
4145
4146/*!
4147 \since 6.0
4148 Returns the bindable interface for the property on a given \a object.
4149
4150 If the property doesn't support bindings, the returned interface will be
4151 invalid.
4152
4153 \sa QObjectBindableProperty, QProperty, isBindable()
4154*/
4155QUntypedBindable QMetaProperty::bindable(QObject *object) const
4156{
4157 QUntypedBindable bindable;
4158 void * argv[1] { &bindable };
4159 mobj->metacall(object, QMetaObject::BindableProperty, data.index(mobj) + mobj->propertyOffset(), argv);
4160 return bindable;
4161}
4162/*!
4163 \since 5.5
4164
4165 Reads the property's value from the given \a gadget. Returns the value
4166 if it was able to read it; otherwise returns an invalid variant.
4167
4168 This function should only be used if this is a property of a Q_GADGET
4169*/
4170QVariant QMetaProperty::readOnGadget(const void *gadget) const
4171{
4172 Q_ASSERT(priv(mobj->d.data)->flags & PropertyAccessInStaticMetaCall && mobj->d.static_metacall);
4173 return read(reinterpret_cast<const QObject*>(gadget));
4174}
4175
4176/*!
4177 \since 5.5
4178
4179 Writes \a value as the property's value to the given \a gadget. Returns
4180 true if the write succeeded; otherwise returns \c false.
4181
4182 This function should only be used if this is a property of a Q_GADGET
4183*/
4184bool QMetaProperty::writeOnGadget(void *gadget, const QVariant &value) const
4185{
4186 Q_ASSERT(priv(mobj->d.data)->flags & PropertyAccessInStaticMetaCall && mobj->d.static_metacall);
4187 return write(reinterpret_cast<QObject*>(gadget), value);
4188}
4189
4190/*!
4191 \overload
4192 \since 6.6
4193*/
4194bool QMetaProperty::writeOnGadget(void *gadget, QVariant &&value) const
4195{
4196 Q_ASSERT(priv(mobj->d.data)->flags & PropertyAccessInStaticMetaCall && mobj->d.static_metacall);
4197 return write(reinterpret_cast<QObject*>(gadget), std::move(value));
4198}
4199
4200/*!
4201 \since 5.5
4202
4203 Resets the property for the given \a gadget with a reset method.
4204 Returns \c true if the reset worked; otherwise returns \c false.
4205
4206 Reset methods are optional; only a few properties support them.
4207
4208 This function should only be used if this is a property of a Q_GADGET
4209*/
4210bool QMetaProperty::resetOnGadget(void *gadget) const
4211{
4212 Q_ASSERT(priv(mobj->d.data)->flags & PropertyAccessInStaticMetaCall && mobj->d.static_metacall);
4213 return reset(reinterpret_cast<QObject*>(gadget));
4214}
4215
4216/*!
4217 Returns \c true if this property can be reset to a default value; otherwise
4218 returns \c false.
4219
4220 \sa reset()
4221*/
4222bool QMetaProperty::isResettable() const
4223{
4224 if (!mobj)
4225 return false;
4226 return data.flags() & Resettable;
4227}
4228
4229/*!
4230 Returns \c true if this property is readable; otherwise returns \c false.
4231
4232 \sa isWritable(), read(), isValid()
4233 */
4234bool QMetaProperty::isReadable() const
4235{
4236 if (!mobj)
4237 return false;
4238 return data.flags() & Readable;
4239}
4240
4241/*!
4242 Returns \c true if this property has a corresponding change notify signal;
4243 otherwise returns \c false.
4244
4245 \sa notifySignal()
4246 */
4247bool QMetaProperty::hasNotifySignal() const
4248{
4249 if (!mobj)
4250 return false;
4251 return data.notifyIndex() != uint(-1);
4252}
4253
4254/*!
4255 \since 4.5
4256
4257 Returns the QMetaMethod instance of the property change notifying signal if
4258 one was specified, otherwise returns an invalid QMetaMethod.
4259
4260 \sa hasNotifySignal()
4261 */
4262QMetaMethod QMetaProperty::notifySignal() const
4263{
4264 int id = notifySignalIndex();
4265 if (id != -1)
4266 return mobj->method(id);
4267 else
4268 return QMetaMethod();
4269}
4270
4271/*!
4272 \since 4.6
4273
4274 Returns the index of the property change notifying signal if one was
4275 specified, otherwise returns -1.
4276
4277 \sa hasNotifySignal()
4278 */
4279int QMetaProperty::notifySignalIndex() const
4280{
4281 if (!mobj || data.notifyIndex() == std::numeric_limits<uint>::max())
4282 return -1;
4283 uint methodIndex = data.notifyIndex();
4284 if (!(methodIndex & IsUnresolvedSignal))
4285 return methodIndex + mobj->methodOffset();
4286 methodIndex &= ~IsUnresolvedSignal;
4287 const QByteArrayView signalName = stringDataView(mobj, methodIndex);
4288 const QMetaObject *m = mobj;
4289 // try 0-arg signal
4290 int idx = QMetaObjectPrivate::indexOfMethodRelative(&m, signalName, {}, QMetaMethod::Signal);
4291 if (idx >= 0)
4292 return idx + m->methodOffset();
4293 // try 1-arg signal
4294 QArgumentType argType[] = {metaType()};
4295 idx = QMetaObjectPrivate::indexOfMethodRelative(&m, signalName, argType, QMetaMethod::Signal);
4296 if (idx >= 0)
4297 return idx + m->methodOffset();
4298 qWarning("QMetaProperty::notifySignal: cannot find the NOTIFY signal %s in class %s for property '%s'",
4299 signalName.constData(), mobj->className(), name());
4300 return -1;
4301}
4302
4303// This method has been around for a while, but the documentation was marked \internal until 5.1
4304/*!
4305 \since 5.1
4306
4307 Returns the property revision if one was specified by Q_REVISION, otherwise
4308 returns 0. Since Qt 6.0, non-zero values are encoded and can be decoded
4309 using QTypeRevision::fromEncodedVersion().
4310 */
4311int QMetaProperty::revision() const
4312{
4313 if (!mobj)
4314 return 0;
4315 return data.revision();
4316}
4317
4318/*!
4319 Returns \c true if this property is writable; otherwise returns
4320 false.
4321
4322 \sa isReadable(), write()
4323 */
4324bool QMetaProperty::isWritable() const
4325{
4326 if (!mobj)
4327 return false;
4328 return data.flags() & Writable;
4329}
4330
4331/*!
4332 Returns \c false if the \c{Q_PROPERTY()}'s \c DESIGNABLE attribute
4333 is false; otherwise returns \c true.
4334
4335 \sa isScriptable(), isStored()
4336*/
4337bool QMetaProperty::isDesignable() const
4338{
4339 if (!mobj)
4340 return false;
4341 return data.flags() & Designable;
4342}
4343
4344/*!
4345 Returns \c false if the \c{Q_PROPERTY()}'s \c SCRIPTABLE attribute
4346 is false; otherwise returns true.
4347
4348 \sa isDesignable(), isStored()
4349*/
4350bool QMetaProperty::isScriptable() const
4351{
4352 if (!mobj)
4353 return false;
4354 return data.flags() & Scriptable;
4355}
4356
4357/*!
4358 Returns \c true if the property is stored; otherwise returns
4359 false.
4360
4361 The function returns \c false if the
4362 \c{Q_PROPERTY()}'s \c STORED attribute is false; otherwise returns
4363 true.
4364
4365 \sa isDesignable(), isScriptable()
4366*/
4367bool QMetaProperty::isStored() const
4368{
4369 if (!mobj)
4370 return false;
4371 return data.flags() & Stored;
4372}
4373
4374/*!
4375 Returns \c false if the \c {Q_PROPERTY()}'s \c USER attribute is false.
4376 Otherwise it returns true, indicating the property is designated as the
4377 \c USER property, i.e., the one that the user can edit or
4378 that is significant in some other way.
4379
4380 \sa QMetaObject::userProperty(), isDesignable(), isScriptable()
4381*/
4382bool QMetaProperty::isUser() const
4383{
4384 if (!mobj)
4385 return false;
4386 return data.flags() & User;
4387}
4388
4389/*!
4390 \since 4.6
4391 Returns \c true if the property is constant; otherwise returns \c false.
4392
4393 A property is constant if the \c{Q_PROPERTY()}'s \c CONSTANT attribute
4394 is set.
4395*/
4396bool QMetaProperty::isConstant() const
4397{
4398 if (!mobj)
4399 return false;
4400 return data.flags() & Constant;
4401}
4402
4403/*!
4404 \since 4.6
4405 Returns \c true if the property is final; otherwise returns \c false.
4406
4407 A property is final if the \c{Q_PROPERTY()}'s \c FINAL attribute
4408 is set.
4409*/
4410bool QMetaProperty::isFinal() const
4411{
4412 if (!mobj)
4413 return false;
4414 return data.flags() & Final;
4415}
4416
4417/*!
4418 \since 6.11
4419 Returns \c true if the property is virtual; otherwise returns \c false.
4420
4421 A property is virtual if the \c{Q_PROPERTY()}'s \c VIRTUAL attribute
4422 is set.
4423*/
4424bool QMetaProperty::isVirtual() const
4425{
4426 if (!mobj)
4427 return false;
4428 return data.flags() & Virtual;
4429}
4430
4431/*!
4432 \since 6.11
4433 Returns \c true if the property does override; otherwise returns \c false.
4434
4435 A property does override if the \c{Q_PROPERTY()}'s \c OVERRIDE attribute
4436 is set.
4437*/
4438bool QMetaProperty::isOverride() const
4439{
4440 if (!mobj)
4441 return false;
4442 return data.flags() & Override;
4443}
4444
4445/*!
4446 \since 5.15
4447 Returns \c true if the property is required; otherwise returns \c false.
4448
4449 A property is final if the \c{Q_PROPERTY()}'s \c REQUIRED attribute
4450 is set.
4451*/
4452bool QMetaProperty::isRequired() const
4453{
4454 if (!mobj)
4455 return false;
4456 return data.flags() & Required;
4457}
4458
4459/*!
4460 \since 6.0
4461 Returns \c true if the \c{Q_PROPERTY()} exposes binding functionality; otherwise returns false.
4462
4463 This implies that you can create bindings that use this property as a dependency or install QPropertyObserver
4464 objects on this property. Unless the property is readonly, you can also set a binding on this property.
4465
4466 \sa QProperty, isWritable(), bindable()
4467*/
4468bool QMetaProperty::isBindable() const
4469{
4470 if (!mobj)
4471 return false;
4472 return (data.flags() & Bindable);
4473}
4474
4475/*!
4476 \class QMetaClassInfo
4477 \inmodule QtCore
4478
4479 \brief The QMetaClassInfo class provides additional information
4480 about a class.
4481
4482 \ingroup objectmodel
4483
4484 Class information items are simple \e{name}--\e{value} pairs that
4485 are specified using Q_CLASSINFO() in the source code. The
4486 information can be retrieved using name() and value(). For example:
4487
4488 \snippet code/src_corelib_kernel_qmetaobject.cpp 0
4489
4490 This mechanism is free for you to use in your Qt applications.
4491
4492 \note It's also used by the \l[ActiveQt]{Active Qt},
4493 \l[QtDBus]{Qt D-Bus}, \l[QtQml]{Qt Qml}, and \l{Qt Remote Objects}
4494 modules. Some keys might be set when using these modules.
4495
4496 \sa QMetaObject
4497*/
4498
4499/*!
4500 \fn QMetaClassInfo::QMetaClassInfo()
4501 \internal
4502*/
4503
4504/*!
4505 \fn const QMetaObject *QMetaClassInfo::enclosingMetaObject() const
4506 \internal
4507*/
4508
4509/*!
4510 Returns the name of this item.
4511
4512 \sa value()
4513*/
4514const char *QMetaClassInfo::name() const
4515{
4516 if (!mobj)
4517 return nullptr;
4518 return rawStringData(mobj, data.name());
4519}
4520
4521/*!
4522 Returns the value of this item.
4523
4524 \sa name()
4525*/
4526const char *QMetaClassInfo::value() const
4527{
4528 if (!mobj)
4529 return nullptr;
4530 return rawStringData(mobj, data.value());
4531}
4532
4533/*!
4534 \class QMethodRawArguments
4535 \internal
4536
4537 A wrapper class for the void ** arguments array used by the meta
4538 object system. If a slot uses a single argument of this type,
4539 the meta object system will pass the raw arguments array directly
4540 to the slot and set the arguments count in the slot description to
4541 zero, so that any signal can connect to it.
4542
4543 This is used internally to implement signal relay functionality in
4544 our state machine and dbus.
4545*/
4546
4547/*!
4548 \macro QMetaMethodArgument Q_ARG(Type, const Type &value)
4549 \relates QMetaObject
4550
4551 This macro takes a \a Type and a \a value of that type and
4552 returns a QMetaMethodArgument, which can be passed to the template
4553 QMetaObject::invokeMethod() with the \c {Args &&...} arguments.
4554
4555 \sa Q_RETURN_ARG()
4556*/
4557
4558/*!
4559 \macro QMetaMethodReturnArgument Q_RETURN_ARG(Type, Type &value)
4560 \relates QMetaObject
4561
4562 This macro takes a \a Type and a non-const reference to a \a
4563 value of that type and returns a QMetaMethodReturnArgument, which can be
4564 passed to the template QMetaObject::invokeMethod() with the \c {Args &&...}
4565 arguments.
4566
4567 \sa Q_ARG()
4568*/
4569
4570/*!
4571 \class QGenericArgument
4572 \inmodule QtCore
4573
4574 \brief The QGenericArgument class is an internal helper class for
4575 marshalling arguments.
4576
4577 This class should never be used directly. Please use the \l Q_ARG()
4578 macro instead.
4579
4580 \sa Q_ARG(), QMetaObject::invokeMethod(), QGenericReturnArgument
4581*/
4582
4583/*!
4584 \fn QGenericArgument::QGenericArgument(const char *name, const void *data)
4585
4586 Constructs a QGenericArgument object with the given \a name and \a data.
4587*/
4588
4589/*!
4590 \fn QGenericArgument::data () const
4591
4592 Returns the data set in the constructor.
4593*/
4594
4595/*!
4596 \fn QGenericArgument::name () const
4597
4598 Returns the name set in the constructor.
4599*/
4600
4601/*!
4602 \class QGenericReturnArgument
4603 \inmodule QtCore
4604
4605 \brief The QGenericReturnArgument class is an internal helper class for
4606 marshalling arguments.
4607
4608 This class should never be used directly. Please use the
4609 Q_RETURN_ARG() macro instead.
4610
4611 \sa Q_RETURN_ARG(), QMetaObject::invokeMethod(), QGenericArgument
4612*/
4613
4614/*!
4615 \fn QGenericReturnArgument::QGenericReturnArgument(const char *name, void *data)
4616
4617 Constructs a QGenericReturnArgument object with the given \a name
4618 and \a data.
4619*/
4620
4621/*!
4622 \internal
4623 If the \a local_method_index is a cloned method, return the index of the original.
4624
4625 A "cloned" method is a function with a default argument, this is handled by
4626 pretending there is an overload without the argument, and the original function
4627 is the overload with all arguments present.
4628
4629 Example: for a function \c {QObject::destroyed(QObject *o = nullptr}, if the
4630 index of \c {destroyed()} is passed, the index of \c {destroyed(QObject*)}
4631 is returned.
4632 */
4633int QMetaObjectPrivate::originalClone(const QMetaObject *mobj, int local_method_index)
4634{
4635 Q_ASSERT(local_method_index < get(mobj)->methodCount);
4636 while (QMetaMethod::fromRelativeMethodIndex(mobj, local_method_index).data.flags() & MethodCloned) {
4637 Q_ASSERT(local_method_index > 0);
4638 --local_method_index;
4639 }
4640 return local_method_index;
4641}
4642
4643/*!
4644 \internal
4645
4646 Given a method \a signature (e.g. foo(int,double)), this function populates
4647 the \a types array with the parameter type names, and returns the method name.
4648
4649 No normalization of the type names is performed.
4650
4651*/
4652QByteArrayView
4653QMetaObjectPrivate::parameterTypeNamesFromSignature(QByteArrayView sig,
4654 QVarLengthArray<QByteArrayView, 10> &typeNames)
4655{
4656 const char *signature = static_cast<const char *>(memchr(sig.begin(), '(', sig.size()));
4657 if (!signature)
4658 return {};
4659 auto name = QByteArrayView{sig.begin(), signature};
4660 ++signature; // skip '('
4661 if (!sig.endsWith(')'))
4662 return {};
4663 const char *end = sig.end() - 1; // exclude ')'
4664 while (signature != end) {
4665 if (*signature == ',')
4666 ++signature;
4667 const char *begin = signature;
4668 int level = 0;
4669 while (signature != end && (level > 0 || *signature != ',')) {
4670 if (*signature == '<')
4671 ++level;
4672 else if (*signature == '>')
4673 --level;
4674 ++signature;
4675 }
4676 typeNames.append(QByteArrayView{begin, signature - begin});
4677 }
4678 return name;
4679}
4680
4681QT_END_NAMESPACE
QByteArray signature() const
\macro Q_METAMETHOD_INVOKE_MAX_ARGS
\inmodule QtCore
Definition qmetatype.h:395
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)