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