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