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