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