1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qqmlmetatype_p.h"
5
6#include <private/qqmlextensionplugin_p.h>
7#include <private/qqmlmetatypedata_p.h>
8#include <private/qqmlpropertycachecreator_p.h>
9#include <private/qqmlscriptblob_p.h>
10#include <private/qqmltype_p_p.h>
11#include <private/qqmltypeloader_p.h>
12#include <private/qqmltypemodule_p.h>
13#include <private/qqmlvaluetype_p.h>
14#include <private/qv4executablecompilationunit_p.h>
15
16#include <QtCore/qcoreapplication.h>
17#include <QtCore/qmutex.h>
18#include <QtCore/qloggingcategory.h>
19
20Q_STATIC_LOGGING_CATEGORY(lcTypeRegistration, "qt.qml.typeregistration")
21
22QT_BEGIN_NAMESPACE
23
24struct LockedData : private QQmlMetaTypeData
25{
26 friend class QQmlMetaTypeDataPtr;
27};
28
29Q_GLOBAL_STATIC(LockedData, metaTypeData)
30Q_GLOBAL_STATIC(QRecursiveMutex, metaTypeDataLock)
31
32struct ModuleUri : public QString
33{
34 ModuleUri(const QString &string) : QString(string) {}
35 ModuleUri(const std::unique_ptr<QQmlTypeModule> &module) : QString(module->module()) {}
36};
37
38class QQmlMetaTypeDataPtr
39{
40 Q_DISABLE_COPY_MOVE(QQmlMetaTypeDataPtr)
41public:
42 QQmlMetaTypeDataPtr() : locker(metaTypeDataLock()), data(metaTypeData()) {}
43 ~QQmlMetaTypeDataPtr() = default;
44
45 QQmlMetaTypeData &operator*() { return *data; }
46 QQmlMetaTypeData *operator->() { return data; }
47 operator QQmlMetaTypeData *() { return data; }
48
49 const QQmlMetaTypeData &operator*() const { return *data; }
50 const QQmlMetaTypeData *operator->() const { return data; }
51 operator const QQmlMetaTypeData *() const { return data; }
52
53 bool isValid() const { return data != nullptr; }
54
55private:
56 QMutexLocker<QRecursiveMutex> locker;
57 LockedData *data = nullptr;
58};
59
60static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data,
61 const QQmlPrivate::RegisterInterface &type)
62{
63 auto *d = new QQmlTypePrivate(QQmlType::InterfaceType);
64 d->extraData.interfaceTypeData = type.iid;
65 d->typeId = type.typeId;
66 d->listId = type.listId;
67 d->module = QString::fromUtf8(utf8: type.uri);
68 d->version = type.version;
69 data->registerType(priv: d);
70 return d;
71}
72
73static QQmlTypePrivate *createQQmlType(
74 QQmlMetaTypeData *data, const QString &elementName,
75 const QQmlPrivate::RegisterSingletonType &type,
76 const QQmlType::SingletonInstanceInfo::ConstPtr &siinfo)
77{
78 auto *d = new QQmlTypePrivate(QQmlType::SingletonType);
79 data->registerType(priv: d);
80
81 d->setName(uri: QString::fromUtf8(utf8: type.uri), element: elementName);
82 d->version = type.version;
83
84 if (type.qObjectApi) {
85 d->baseMetaObject = type.instanceMetaObject;
86 d->typeId = type.typeId;
87 d->revision = type.revision;
88 }
89
90 d->extraData.singletonTypeData->singletonInstanceInfo = siinfo;
91 d->extraData.singletonTypeData->extFunc = type.extensionObjectCreate;
92 d->extraData.singletonTypeData->extMetaObject = type.extensionMetaObject;
93
94 return d;
95}
96
97static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data, const QString &elementName,
98 const QQmlPrivate::RegisterType &type)
99{
100 QQmlTypePrivate *d = new QQmlTypePrivate(QQmlType::CppType);
101 data->registerType(priv: d);
102 d->setName(uri: QString::fromUtf8(utf8: type.uri), element: elementName);
103
104 d->version = type.version;
105 d->revision = type.revision;
106 d->typeId = type.typeId;
107 d->listId = type.listId;
108 d->extraData.cppTypeData->allocationSize = type.objectSize;
109 d->extraData.cppTypeData->userdata = type.userdata;
110 d->extraData.cppTypeData->newFunc = type.create;
111 d->extraData.cppTypeData->noCreationReason = type.noCreationReason;
112 d->extraData.cppTypeData->createValueTypeFunc = type.createValueType;
113 d->baseMetaObject = type.metaObject;
114 d->extraData.cppTypeData->attachedPropertiesFunc = type.attachedPropertiesFunction;
115 d->extraData.cppTypeData->attachedPropertiesType = type.attachedPropertiesMetaObject;
116 d->extraData.cppTypeData->parserStatusCast = type.parserStatusCast;
117 d->extraData.cppTypeData->propertyValueSourceCast = type.valueSourceCast;
118 d->extraData.cppTypeData->propertyValueInterceptorCast = type.valueInterceptorCast;
119 d->extraData.cppTypeData->finalizerCast = type.has(v: QQmlPrivate::RegisterType::FinalizerCast)
120 ? type.finalizerCast
121 : -1;
122 d->extraData.cppTypeData->extFunc = type.extensionObjectCreate;
123 d->extraData.cppTypeData->customParser = reinterpret_cast<QQmlCustomParser *>(type.customParser);
124 d->extraData.cppTypeData->registerEnumClassesUnscoped = true;
125 d->extraData.cppTypeData->registerEnumsFromRelatedTypes = true;
126 d->extraData.cppTypeData->constructValueType = type.has(v: QQmlPrivate::RegisterType::CreationMethod)
127 && type.creationMethod != QQmlPrivate::ValueTypeCreationMethod::None;
128 d->extraData.cppTypeData->populateValueType = type.has(v: QQmlPrivate::RegisterType::CreationMethod)
129 && type.creationMethod == QQmlPrivate::ValueTypeCreationMethod::Structured;
130
131 if (type.extensionMetaObject)
132 d->extraData.cppTypeData->extMetaObject = type.extensionMetaObject;
133
134 // Check if the user wants only scoped enum classes
135 if (d->baseMetaObject) {
136 auto indexOfUnscoped = d->baseMetaObject->indexOfClassInfo(name: "RegisterEnumClassesUnscoped");
137 if (indexOfUnscoped != -1
138 && qstrcmp(str1: d->baseMetaObject->classInfo(index: indexOfUnscoped).value(), str2: "false") == 0) {
139 d->extraData.cppTypeData->registerEnumClassesUnscoped = false;
140 }
141
142 auto indexOfRelated = d->baseMetaObject->indexOfClassInfo(name: "RegisterEnumsFromRelatedTypes");
143 if (indexOfRelated != -1
144 && qstrcmp(str1: d->baseMetaObject->classInfo(index: indexOfRelated).value(), str2: "false") == 0) {
145 d->extraData.cppTypeData->registerEnumsFromRelatedTypes = false;
146 }
147 }
148
149 return d;
150}
151
152static void addQQmlMetaTypeInterfaces(
153 QQmlMetaTypeData *data, const QUrl &url, QQmlTypePrivate *priv, const QByteArray &className)
154{
155 Q_ASSERT(!className.isEmpty());
156 QByteArray ptr = className + '*';
157 QByteArray lst = "QQmlListProperty<" + className + '>';
158
159 QQmlMetaTypeData::CompositeMetaTypes &types = data->compositeMetaTypes[url];
160 if (types.type) {
161 Q_ASSERT(types.listType);
162
163 QMetaType::unregisterMetaType(type: QMetaType(types.type));
164 QMetaType::unregisterMetaType(type: QMetaType(types.listType));
165
166 types.type->name = std::move(ptr);
167 types.type->QMetaTypeInterface::name = types.type->name.constData();
168 types.listType->name = std::move(lst);
169 types.listType->QMetaTypeInterface::name = types.listType->name.constData();
170 } else {
171 types.type = new QQmlMetaTypeInterface(std::move(ptr));
172 types.listType = new QQmlListMetaTypeInterface(std::move(lst), types.type);
173 }
174
175 QMetaType ptr_type(types.type);
176 QMetaType lst_type(types.listType);
177
178 // Retrieve the IDs once, so that the types are added to QMetaType's custom type registry.
179 ptr_type.id();
180 lst_type.id();
181
182 priv->typeId = ptr_type;
183 priv->listId = lst_type;
184}
185
186static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data, const QString &elementName,
187 const QQmlPrivate::RegisterCompositeType &type)
188{
189 auto *d = new QQmlTypePrivate(QQmlType::CompositeType);
190 data->registerType(priv: d);
191 d->setName(uri: QString::fromUtf8(utf8: type.uri), element: elementName);
192 d->version = type.version;
193
194 const QUrl normalized = QQmlTypeLoader::normalize(unNormalizedUrl: type.url);
195 d->extraData.compositeTypeData = normalized;
196 addQQmlMetaTypeInterfaces(
197 data, url: normalized, priv: d, className: QQmlPropertyCacheCreatorBase::createClassNameTypeByUrl(url: normalized));
198 return d;
199}
200
201static QQmlTypePrivate *createQQmlType(
202 QQmlMetaTypeData *data, const QString &elementName,
203 const QQmlPrivate::RegisterCompositeSingletonType &type,
204 const QQmlType::SingletonInstanceInfo::ConstPtr &siinfo)
205{
206 auto *d = new QQmlTypePrivate(QQmlType::CompositeSingletonType);
207 data->registerType(priv: d);
208 d->setName(uri: QString::fromUtf8(utf8: type.uri), element: elementName);
209
210 d->version = type.version;
211
212 d->extraData.singletonTypeData->singletonInstanceInfo = siinfo;
213 const QUrl &url = siinfo->url;
214 addQQmlMetaTypeInterfaces(
215 data, url, priv: d, className: QQmlPropertyCacheCreatorBase::createClassNameTypeByUrl(url));
216 return d;
217}
218
219void QQmlMetaType::clone(QMetaObjectBuilder &builder, const QMetaObject *mo,
220 const QMetaObject *ignoreStart, const QMetaObject *ignoreEnd,
221 QQmlMetaType::ClonePolicy policy)
222{
223 // Set classname
224 builder.setClassName(mo->className());
225
226 // Clone Q_CLASSINFO
227 for (int ii = mo->classInfoOffset(); ii < mo->classInfoCount(); ++ii) {
228 QMetaClassInfo info = mo->classInfo(index: ii);
229
230 int otherIndex = ignoreEnd->indexOfClassInfo(name: info.name());
231 if (otherIndex >= ignoreStart->classInfoOffset() + ignoreStart->classInfoCount()) {
232 // Skip
233 } else {
234 builder.addClassInfo(name: info.name(), value: info.value());
235 }
236 }
237
238 if (policy != QQmlMetaType::CloneEnumsOnly) {
239 // Clone Q_METHODS - do this first to avoid duplicating the notify signals.
240 for (int ii = mo->methodOffset(); ii < mo->methodCount(); ++ii) {
241 QMetaMethod method = mo->method(index: ii);
242
243 // More complex - need to search name
244 QByteArray name = method.name();
245
246 bool found = false;
247
248 for (int ii = ignoreStart->methodOffset() + ignoreStart->methodCount();
249 !found && ii < ignoreEnd->methodOffset() + ignoreEnd->methodCount(); ++ii) {
250
251 QMetaMethod other = ignoreEnd->method(index: ii);
252
253 found = name == other.name();
254 }
255
256 QMetaMethodBuilder m = builder.addMethod(prototype: method);
257 if (found) // SKIP
258 m.setAccess(QMetaMethod::Private);
259 }
260
261 // Clone Q_PROPERTY
262 for (int ii = mo->propertyOffset(); ii < mo->propertyCount(); ++ii) {
263 QMetaProperty property = mo->property(index: ii);
264
265 int otherIndex = ignoreEnd->indexOfProperty(name: property.name());
266 if (otherIndex >= ignoreStart->propertyOffset() + ignoreStart->propertyCount()) {
267 builder.addProperty(name: QByteArray("__qml_ignore__") + property.name(),
268 type: QByteArray("void"));
269 // Skip
270 } else {
271 builder.addProperty(prototype: property);
272 }
273 }
274 }
275
276 // Clone enums registered with the metatype system
277 for (int ii = mo->enumeratorOffset(); ii < mo->enumeratorCount(); ++ii) {
278 QMetaEnum enumerator = mo->enumerator(index: ii);
279
280 int otherIndex = ignoreEnd->indexOfEnumerator(name: enumerator.name());
281 if (otherIndex >= ignoreStart->enumeratorOffset() + ignoreStart->enumeratorCount()) {
282 // Skip
283 } else {
284 builder.addEnumerator(prototype: enumerator);
285 }
286 }
287}
288
289void QQmlMetaType::qmlInsertModuleRegistration(const QString &uri, void (*registerFunction)())
290{
291 QQmlMetaTypeDataPtr data;
292 if (data->moduleTypeRegistrationFunctions.contains(key: uri))
293 qFatal(msg: "Cannot add multiple registrations for %s", qPrintable(uri));
294 else
295 data->moduleTypeRegistrationFunctions.insert(key: uri, value: registerFunction);
296}
297
298void QQmlMetaType::qmlRemoveModuleRegistration(const QString &uri)
299{
300 QQmlMetaTypeDataPtr data;
301
302 if (!data.isValid())
303 return; // shutdown/deletion race. Not a problem.
304
305 if (!data->moduleTypeRegistrationFunctions.contains(key: uri))
306 qFatal(msg: "Cannot remove multiple registrations for %s", qPrintable(uri));
307 else
308 data->moduleTypeRegistrationFunctions.remove(key: uri);
309}
310
311bool QQmlMetaType::qmlRegisterModuleTypes(const QString &uri)
312{
313 QQmlMetaTypeDataPtr data;
314 return data->registerModuleTypes(uri);
315}
316
317void QQmlMetaType::clearTypeRegistrations()
318{
319 //Only cleans global static, assumed no running engine
320 QQmlMetaTypeDataPtr data;
321
322 data->uriToModule.clear();
323 data->types.clear();
324 data->idToType.clear();
325 data->nameToType.clear();
326 data->urlToType.clear();
327 data->typePropertyCaches.clear();
328 data->metaObjectToType.clear();
329 data->undeletableTypes.clear();
330 data->propertyCaches.clear();
331
332 qDeleteAll(c: data->metaTypeToValueType);
333 data->metaTypeToValueType.clear();
334
335 data->moduleImports.clear();
336
337 // Avoid deletion recursion (via QQmlTypePrivate dtor) by moving them out of the way first.
338 QQmlMetaTypeData::CompositeTypes emptyComposites;
339 emptyComposites.swap(other&: data->compositeTypes);
340
341 qDeleteAll(c: data->metaTypeToValueType);
342 data->metaTypeToValueType.clear();
343
344 data->clearCompositeMetaTypes();
345}
346
347void QQmlMetaType::registerTypeAlias(int typeIndex, const QString &name)
348{
349 QQmlMetaTypeDataPtr data;
350 const QQmlType type = data->types.value(i: typeIndex);
351 const QQmlTypePrivate *priv = type.priv();
352 data->nameToType.insert(key: name, value: priv);
353}
354
355int QQmlMetaType::registerAutoParentFunction(const QQmlPrivate::RegisterAutoParent &function)
356{
357 if (function.structVersion > 1)
358 qFatal(msg: "qmlRegisterType(): Cannot mix incompatible QML versions.");
359
360 QQmlMetaTypeDataPtr data;
361
362 data->parentFunctions.append(t: function.function);
363
364 return data->parentFunctions.size() - 1;
365}
366
367void QQmlMetaType::unregisterAutoParentFunction(const QQmlPrivate::AutoParentFunction &function)
368{
369 QQmlMetaTypeDataPtr data;
370 data->parentFunctions.removeOne(t: function);
371}
372
373QQmlType QQmlMetaType::registerInterface(const QQmlPrivate::RegisterInterface &type)
374{
375 if (type.structVersion > 1)
376 qFatal(msg: "qmlRegisterType(): Cannot mix incompatible QML versions.");
377
378 QQmlMetaTypeDataPtr data;
379 QQmlTypePrivate *priv = createQQmlType(data, type);
380 Q_ASSERT(priv);
381
382
383 data->idToType.insert(key: priv->typeId.id(), value: priv);
384 data->idToType.insert(key: priv->listId.id(), value: priv);
385
386 data->interfaces.insert(value: type.typeId.id());
387
388 return QQmlType(priv);
389}
390
391static QString registrationTypeString(QQmlType::RegistrationType typeType)
392{
393 QString typeStr;
394 if (typeType == QQmlType::CppType)
395 typeStr = QStringLiteral("element");
396 else if (typeType == QQmlType::SingletonType)
397 typeStr = QStringLiteral("singleton type");
398 else if (typeType == QQmlType::CompositeSingletonType)
399 typeStr = QStringLiteral("composite singleton type");
400 else if (typeType == QQmlType::SequentialContainerType)
401 typeStr = QStringLiteral("sequential container type");
402 else
403 typeStr = QStringLiteral("type");
404 return typeStr;
405}
406
407// NOTE: caller must hold a QMutexLocker on "data"
408static bool checkRegistration(
409 QQmlType::RegistrationType typeType, QQmlMetaTypeData *data, const char *uri,
410 const QString &typeName, QTypeRevision version, QMetaType::TypeFlags flags)
411{
412 if (!typeName.isEmpty()) {
413 if (typeName.at(i: 0).isLower() && (flags & QMetaType::PointerToQObject)) {
414 QString failure(QCoreApplication::translate(context: "qmlRegisterType", key: "Invalid QML %1 name \"%2\"; type names must begin with an uppercase letter"));
415 data->recordTypeRegFailure(message: failure.arg(args: registrationTypeString(typeType), args: typeName));
416 return false;
417 }
418
419 if (typeName.at(i: 0).isUpper()
420 && (flags & (QMetaType::IsGadget | QMetaType::PointerToGadget))) {
421 qCWarning(lcTypeRegistration).noquote()
422 << QCoreApplication::translate(
423 context: "qmlRegisterType",
424 key: "Invalid QML %1 name \"%2\"; "
425 "value type names should begin with a lowercase letter")
426 .arg(args: registrationTypeString(typeType), args: typeName);
427 }
428
429 // There can also be types that aren't even gadgets, and there can be types for namespaces.
430 // We cannot check those, but namespaces should be uppercase.
431
432 int typeNameLen = typeName.size();
433 for (int ii = 0; ii < typeNameLen; ++ii) {
434 if (!(typeName.at(i: ii).isLetterOrNumber() || typeName.at(i: ii) == u'_')) {
435 QString failure(QCoreApplication::translate(context: "qmlRegisterType", key: "Invalid QML %1 name \"%2\""));
436 data->recordTypeRegFailure(message: failure.arg(args: registrationTypeString(typeType), args: typeName));
437 return false;
438 }
439 }
440 }
441
442 if (uri && !typeName.isEmpty()) {
443 QString nameSpace = QString::fromUtf8(utf8: uri);
444 QQmlTypeModule *qqtm = data->findTypeModule(module: nameSpace, version);
445 if (qqtm && qqtm->lockLevel() != QQmlTypeModule::LockLevel::Open) {
446 QString failure(QCoreApplication::translate(
447 context: "qmlRegisterType",
448 key: "Cannot install %1 '%2' into protected module '%3' version '%4'"));
449 data->recordTypeRegFailure(message: failure
450 .arg(args: registrationTypeString(typeType), args: typeName, args&: nameSpace)
451 .arg(a: version.majorVersion()));
452 return false;
453 }
454 }
455
456 return true;
457}
458
459// NOTE: caller must hold a QMutexLocker on "data"
460static QQmlTypeModule *getTypeModule(
461 const QHashedString &uri, QTypeRevision version, QQmlMetaTypeData *data)
462{
463 if (QQmlTypeModule *module = data->findTypeModule(module: uri, version))
464 return module;
465 return data->addTypeModule(module: std::make_unique<QQmlTypeModule>(args: uri, args: version.majorVersion()));
466}
467
468// NOTE: caller must hold a QMutexLocker on "data"
469static void addTypeToData(QQmlTypePrivate *type, QQmlMetaTypeData *data)
470{
471 Q_ASSERT(type);
472
473 if (!type->elementName.isEmpty())
474 data->nameToType.insert(key: type->elementName, value: type);
475
476 if (type->baseMetaObject)
477 data->metaObjectToType.insert(key: type->baseMetaObject, value: type);
478
479 if (type->regType == QQmlType::SequentialContainerType) {
480 if (type->listId.isValid())
481 data->idToType.insert(key: type->listId.id(), value: type);
482 } else {
483 if (type->typeId.isValid())
484 data->idToType.insert(key: type->typeId.id(), value: type);
485
486 if (type->listId.flags().testFlag(flag: QMetaType::IsQmlList))
487 data->idToType.insert(key: type->listId.id(), value: type);
488 }
489
490 if (!type->module.isEmpty()) {
491 const QHashedString &mod = type->module;
492
493 QQmlTypeModule *module = getTypeModule(uri: mod, version: type->version, data);
494 Q_ASSERT(module);
495 module->add(type);
496 }
497}
498
499QQmlType QQmlMetaType::registerType(const QQmlPrivate::RegisterType &type)
500{
501 if (type.structVersion > int(QQmlPrivate::RegisterType::CurrentVersion))
502 qFatal(msg: "qmlRegisterType(): Cannot mix incompatible QML versions.");
503
504 QQmlMetaTypeDataPtr data;
505
506 QString elementName = QString::fromUtf8(utf8: type.elementName);
507 if (!checkRegistration(typeType: QQmlType::CppType, data, uri: type.uri, typeName: elementName, version: type.version,
508 flags: QMetaType(type.typeId).flags())) {
509 return QQmlType();
510 }
511
512 QQmlTypePrivate *priv = createQQmlType(data, elementName, type);
513 addTypeToData(type: priv, data);
514
515 return QQmlType(priv);
516}
517
518QQmlType QQmlMetaType::registerSingletonType(
519 const QQmlPrivate::RegisterSingletonType &type,
520 const QQmlType::SingletonInstanceInfo::ConstPtr &siinfo)
521{
522 if (type.structVersion > 1)
523 qFatal(msg: "qmlRegisterType(): Cannot mix incompatible QML versions.");
524
525 QQmlMetaTypeDataPtr data;
526
527 QString typeName = QString::fromUtf8(utf8: type.typeName);
528 if (!checkRegistration(typeType: QQmlType::SingletonType, data, uri: type.uri, typeName, version: type.version,
529 flags: QMetaType(type.typeId).flags())) {
530 return QQmlType();
531 }
532
533 QQmlTypePrivate *priv = createQQmlType(data, elementName: typeName, type, siinfo);
534
535 addTypeToData(type: priv, data);
536
537 return QQmlType(priv);
538}
539
540QQmlType QQmlMetaType::registerCompositeSingletonType(
541 const QQmlPrivate::RegisterCompositeSingletonType &type,
542 const QQmlType::SingletonInstanceInfo::ConstPtr &siinfo)
543{
544 if (type.structVersion > 1)
545 qFatal(msg: "qmlRegisterType(): Cannot mix incompatible QML versions.");
546
547 // Assumes URL is absolute and valid. Checking of user input should happen before the URL enters type.
548 QQmlMetaTypeDataPtr data;
549
550 QString typeName = QString::fromUtf8(utf8: type.typeName);
551 if (!checkRegistration(
552 typeType: QQmlType::CompositeSingletonType, data, uri: type.uri, typeName, version: type.version, flags: {})) {
553 return QQmlType();
554 }
555
556 QQmlTypePrivate *priv = createQQmlType(data, elementName: typeName, type, siinfo);
557 addTypeToData(type: priv, data);
558
559 data->urlToType.insert(key: siinfo->url, value: priv);
560
561 return QQmlType(priv);
562}
563
564QQmlType QQmlMetaType::registerCompositeType(const QQmlPrivate::RegisterCompositeType &type)
565{
566 if (type.structVersion > 1)
567 qFatal(msg: "qmlRegisterType(): Cannot mix incompatible QML versions.");
568
569 // Assumes URL is absolute and valid. Checking of user input should happen before the URL enters type.
570 QQmlMetaTypeDataPtr data;
571
572 QString typeName = QString::fromUtf8(utf8: type.typeName);
573 if (!checkRegistration(typeType: QQmlType::CompositeType, data, uri: type.uri, typeName, version: type.version, flags: {}))
574 return QQmlType();
575
576 QQmlTypePrivate *priv = createQQmlType(data, elementName: typeName, type);
577 addTypeToData(type: priv, data);
578
579 data->urlToType.insert(key: QQmlTypeLoader::normalize(unNormalizedUrl: type.url), value: priv);
580
581 return QQmlType(priv);
582}
583
584class QQmlMetaTypeRegistrationFailureRecorder
585{
586 Q_DISABLE_COPY_MOVE(QQmlMetaTypeRegistrationFailureRecorder)
587public:
588 QQmlMetaTypeRegistrationFailureRecorder(QQmlMetaTypeData *data, QStringList *failures)
589 : data(data)
590 {
591 data->setTypeRegistrationFailures(failures);
592 }
593
594 ~QQmlMetaTypeRegistrationFailureRecorder()
595 {
596 data->setTypeRegistrationFailures(nullptr);
597 }
598
599 QQmlMetaTypeData *data = nullptr;
600};
601
602
603static QQmlType createTypeForUrl(
604 QQmlMetaTypeData *data, const QUrl &url, const QHashedStringRef &qualifiedType,
605 QQmlMetaType::CompositeTypeLookupMode mode, QList<QQmlError> *errors, QTypeRevision version)
606{
607 const int dot = qualifiedType.indexOf(QLatin1Char('.'));
608 const QString typeName = dot < 0
609 ? qualifiedType.toString()
610 : QString(qualifiedType.constData() + dot + 1, qualifiedType.length() - dot - 1);
611
612 QStringList failures;
613 QQmlMetaTypeRegistrationFailureRecorder failureRecorder(data, &failures);
614
615 // Register the type. Note that the URI parameters here are empty; for
616 // file type imports, we do not place them in a URI as we don't
617 // necessarily have a good and unique one (picture a library import,
618 // which may be found in multiple plugin locations on disk), but there
619 // are other reasons for this too.
620 //
621 // By not putting them in a URI, we prevent the types from being
622 // registered on a QQmlTypeModule; this is important, as once types are
623 // placed on there, they cannot be easily removed, meaning if the
624 // developer subsequently loads a different import (meaning different
625 // types) with the same URI (using, say, a different plugin path), it is
626 // very undesirable that we continue to associate the types from the
627 // "old" URI with that new module.
628 //
629 // Not having URIs also means that the types cannot be found by name
630 // etc, the only way to look them up is through QQmlImports -- for
631 // better or worse.
632 QQmlType::RegistrationType registrationType;
633 switch (mode) {
634 case QQmlMetaType::Singleton:
635 registrationType = QQmlType::CompositeSingletonType;
636 break;
637 case QQmlMetaType::NonSingleton:
638 registrationType = QQmlType::CompositeType;
639 break;
640 case QQmlMetaType::JavaScript:
641 registrationType = QQmlType::JavaScriptType;
642 break;
643 default:
644 Q_UNREACHABLE_RETURN(QQmlType());
645 }
646
647 if (checkRegistration(typeType: registrationType, data, uri: nullptr, typeName, version, flags: {})) {
648
649 // TODO: Ideally we should defer most of this work using some lazy/atomic mechanism
650 // that creates the details on first use. We must not observably modify
651 // QQmlTypePrivate after it has been created since it is supposed to be immutable
652 // and shared across threads.
653
654 auto *priv = new QQmlTypePrivate(registrationType);
655 addQQmlMetaTypeInterfaces(
656 data, url, priv, className: QQmlPropertyCacheCreatorBase::createClassNameTypeByUrl(url));
657
658 priv->setName(uri: QString(), element: typeName);
659 priv->version = version;
660
661 switch (mode) {
662 case QQmlMetaType::Singleton: {
663 QQmlType::SingletonInstanceInfo::Ptr siinfo = QQmlType::SingletonInstanceInfo::create();
664 siinfo->url = url;
665 siinfo->typeName = typeName.toUtf8();
666 priv->extraData.singletonTypeData->singletonInstanceInfo =
667 QQmlType::SingletonInstanceInfo::ConstPtr(
668 siinfo.take(), QQmlType::SingletonInstanceInfo::ConstPtr::Adopt);
669 break;
670 }
671 case QQmlMetaType::NonSingleton: {
672 priv->extraData.compositeTypeData = url;
673 break;
674 }
675 case QQmlMetaType::JavaScript: {
676 priv->extraData.javaScriptTypeData = url;
677 break;
678 }
679 }
680
681 data->registerType(priv);
682 addTypeToData(type: priv, data);
683 return QQmlType(priv);
684 }
685
686 // This means that the type couldn't be found by URL, but could not be
687 // registered either, meaning we most likely were passed some kind of bad
688 // data.
689 if (errors) {
690 QQmlError error;
691 error.setDescription(failures.join(sep: u'\n'));
692 errors->prepend(t: error);
693 } else {
694 qWarning(msg: "%s", failures.join(sep: u'\n').toLatin1().constData());
695 }
696 return QQmlType();
697}
698
699QQmlType QQmlMetaType::findCompositeType(
700 const QUrl &url, const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit,
701 CompositeTypeLookupMode mode)
702{
703 const QUrl normalized = QQmlTypeLoader::normalize(unNormalizedUrl: url);
704 QQmlMetaTypeDataPtr data;
705
706 bool urlExists = true;
707 auto found = data->urlToType.constFind(key: normalized);
708 if (found == data->urlToType.cend())
709 urlExists = false;
710
711 if (urlExists) {
712 if (compilationUnit.isNull())
713 return QQmlType(*found);
714 const auto composite = data->compositeTypes.constFind(key: found.value()->typeId.iface());
715 if (composite == data->compositeTypes.constEnd() || composite.value() == compilationUnit)
716 return QQmlType(*found);
717 }
718
719 const QQmlType type = createTypeForUrl(
720 data, url: normalized, qualifiedType: QHashedStringRef(), mode, errors: nullptr, version: QTypeRevision());
721
722 if (!urlExists && type.isValid())
723 data->urlToType.insert(key: normalized, value: type.priv());
724
725 return type;
726}
727
728static QQmlType doRegisterInlineComponentType(QQmlMetaTypeData *data, const QUrl &url)
729{
730 QQmlTypePrivate *priv = new QQmlTypePrivate(QQmlType::InlineComponentType);
731 priv->setName(uri: QString(), element: url.fragment());
732
733 priv->extraData.inlineComponentTypeData = url;
734 data->registerType(priv);
735
736 addQQmlMetaTypeInterfaces(
737 data, url, priv, className: QQmlPropertyCacheCreatorBase::createClassNameForInlineComponent(url));
738 data->urlToType.insert(key: url, value: priv);
739
740 data->idToType.insert(key: priv->typeId.id(), value: priv);
741 data->idToType.insert(key: priv->listId.id(), value: priv);
742
743 return QQmlType(priv);
744}
745
746QQmlType QQmlMetaType::findInlineComponentType(
747 const QUrl &url, const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit)
748{
749 QQmlMetaTypeDataPtr data;
750
751 // If there is an "unclaimed" inline component type, we can "claim" it now. Otherwise
752 // we have to create a new one.
753 const auto it = data->urlToType.constFind(key: url);
754 if (it != data->urlToType.constEnd()) {
755 const auto jt = data->compositeTypes.constFind(key: (*it)->typeId.iface());
756 if (jt == data->compositeTypes.constEnd() || *jt == compilationUnit)
757 return QQmlType(*it);
758 }
759
760 return doRegisterInlineComponentType(data, url);
761}
762
763int QQmlMetaType::registerUnitCacheHook(
764 const QQmlPrivate::RegisterQmlUnitCacheHook &hookRegistration)
765{
766 if (hookRegistration.structVersion > 1)
767 qFatal(msg: "qmlRegisterType(): Cannot mix incompatible QML versions.");
768
769 QQmlMetaTypeDataPtr data;
770 data->lookupCachedQmlUnit << hookRegistration.lookupCachedQmlUnit;
771 return 0;
772}
773
774QQmlType QQmlMetaType::registerSequentialContainer(
775 const QQmlPrivate::RegisterSequentialContainer &container)
776{
777 if (container.structVersion > 1)
778 qFatal(msg: "qmlRegisterSequenceContainer(): Cannot mix incompatible QML versions.");
779
780 QQmlMetaTypeDataPtr data;
781
782 if (!checkRegistration(typeType: QQmlType::SequentialContainerType, data, uri: container.uri, typeName: QString(),
783 version: container.version, flags: {})) {
784 return QQmlType();
785 }
786
787 QQmlTypePrivate *priv = new QQmlTypePrivate(QQmlType::SequentialContainerType);
788
789 data->registerType(priv);
790 priv->setName(uri: QString::fromUtf8(utf8: container.uri), element: QString());
791 priv->version = container.version;
792 priv->revision = container.revision;
793 priv->typeId = container.metaSequence.valueMetaType();
794 priv->listId = container.typeId;
795 priv->extraData.sequentialContainerTypeData = container.metaSequence;
796
797 addTypeToData(type: priv, data);
798
799 return QQmlType(priv);
800}
801
802void QQmlMetaType::unregisterSequentialContainer(int id)
803{
804 unregisterType(type: id);
805}
806
807bool QQmlMetaType::protectModule(const QString &uri, QTypeRevision version,
808 bool weakProtectAllVersions)
809{
810 QQmlMetaTypeDataPtr data;
811 if (version.hasMajorVersion()) {
812 if (QQmlTypeModule *module = data->findTypeModule(module: uri, version)) {
813 if (!weakProtectAllVersions) {
814 module->setLockLevel(QQmlTypeModule::LockLevel::Strong);
815 return true;
816 }
817 } else {
818 return false;
819 }
820 }
821
822 const auto range = std::equal_range(
823 first: data->uriToModule.begin(), last: data->uriToModule.end(), val: uri,
824 comp: std::less<ModuleUri>());
825
826 for (auto it = range.first; it != range.second; ++it)
827 (*it)->setLockLevel(QQmlTypeModule::LockLevel::Weak);
828
829 return range.first != range.second;
830}
831
832void QQmlMetaType::registerModuleImport(const QString &uri, QTypeRevision moduleVersion,
833 const QQmlDirParser::Import &import)
834{
835 QQmlMetaTypeDataPtr data;
836
837 data->moduleImports.insert(key: QQmlMetaTypeData::VersionedUri(uri, moduleVersion), value: import);
838}
839
840void QQmlMetaType::unregisterModuleImport(const QString &uri, QTypeRevision moduleVersion,
841 const QQmlDirParser::Import &import)
842{
843 QQmlMetaTypeDataPtr data;
844 data->moduleImports.remove(key: QQmlMetaTypeData::VersionedUri(uri, moduleVersion), value: import);
845}
846
847QList<QQmlDirParser::Import> QQmlMetaType::moduleImports(
848 const QString &uri, QTypeRevision version)
849{
850 QQmlMetaTypeDataPtr data;
851 QList<QQmlDirParser::Import> result;
852
853 const auto unrevisioned = data->moduleImports.equal_range(
854 akey: QQmlMetaTypeData::VersionedUri(uri, QTypeRevision()));
855 for (auto it = unrevisioned.second; it != unrevisioned.first;)
856 result.append(t: *(--it));
857
858 if (version.hasMajorVersion()) {
859 const auto revisioned = data->moduleImports.equal_range(
860 akey: QQmlMetaTypeData::VersionedUri(uri, version));
861 for (auto it = revisioned.second; it != revisioned.first;)
862 result.append(t: *(--it));
863 return result;
864 }
865
866 // Use latest module available with that URI.
867 const auto begin = data->moduleImports.begin();
868 auto it = unrevisioned.first;
869 if (it == begin)
870 return result;
871
872 const QQmlMetaTypeData::VersionedUri latestVersion = (--it).key();
873 if (latestVersion.uri != uri)
874 return result;
875
876 do {
877 result += *it;
878 } while (it != begin && (--it).key() == latestVersion);
879
880 return result;
881}
882
883void QQmlMetaType::registerModule(const char *uri, QTypeRevision version)
884{
885 QQmlMetaTypeDataPtr data;
886
887 QQmlTypeModule *module = getTypeModule(uri: QString::fromUtf8(utf8: uri), version, data);
888 Q_ASSERT(module);
889
890 if (version.hasMinorVersion())
891 module->addMinorVersion(minorVersion: version.minorVersion());
892}
893
894int QQmlMetaType::typeId(const char *uri, QTypeRevision version, const char *qmlName)
895{
896 QQmlMetaTypeDataPtr data;
897
898 QQmlTypeModule *module = getTypeModule(uri: QString::fromUtf8(utf8: uri), version, data);
899 if (!module)
900 return -1;
901
902 QQmlType type = module->type(name: QHashedStringRef(QString::fromUtf8(utf8: qmlName)), version);
903 if (!type.isValid())
904 return -1;
905
906 return type.index();
907}
908
909void QQmlMetaType::registerUndeletableType(const QQmlType &dtype)
910{
911 QQmlMetaTypeDataPtr data;
912 data->undeletableTypes.insert(value: dtype);
913}
914
915static bool namespaceContainsRegistrations(const QQmlMetaTypeData *data, const QString &uri,
916 QTypeRevision version)
917{
918 // Has any type previously been installed to this namespace?
919 QHashedString nameSpace(uri);
920 for (const QQmlType &type : data->types) {
921 if (type.module() == nameSpace && type.version().majorVersion() == version.majorVersion())
922 return true;
923 }
924
925 return false;
926}
927
928QQmlMetaType::RegistrationResult QQmlMetaType::registerPluginTypes(
929 QObject *instance, const QString &basePath, const QString &uri,
930 const QString &typeNamespace, QTypeRevision version, QList<QQmlError> *errors)
931{
932 if (!typeNamespace.isEmpty() && typeNamespace != uri) {
933 // This is an 'identified' module
934 // The namespace for type registrations must match the URI for locating the module
935 if (errors) {
936 QQmlError error;
937 error.setDescription(
938 QStringLiteral("Module namespace '%1' does not match import URI '%2'")
939 .arg(args: typeNamespace, args: uri));
940 errors->prepend(t: error);
941 }
942 return RegistrationResult::Failure;
943 }
944
945 QStringList failures;
946 QQmlMetaTypeDataPtr data;
947 {
948 QQmlMetaTypeRegistrationFailureRecorder failureRecorder(data, &failures);
949 if (!typeNamespace.isEmpty()) {
950 // This is an 'identified' module
951 if (namespaceContainsRegistrations(data, uri: typeNamespace, version)) {
952 // Other modules have already installed to this namespace
953 if (errors) {
954 QQmlError error;
955 error.setDescription(QStringLiteral("Namespace '%1' has already been used "
956 "for type registration")
957 .arg(a: typeNamespace));
958 errors->prepend(t: error);
959 }
960 return RegistrationResult::Failure;
961 }
962 } else {
963 // This is not an identified module - provide a warning
964 qWarning().nospace() << qPrintable(
965 QStringLiteral("Module '%1' does not contain a module identifier directive - "
966 "it cannot be protected from external registrations.").arg(uri));
967 }
968
969 if (instance && !qobject_cast<QQmlEngineExtensionInterface *>(object: instance)) {
970 QQmlTypesExtensionInterface *iface = qobject_cast<QQmlTypesExtensionInterface *>(object: instance);
971 if (!iface) {
972 if (errors) {
973 QQmlError error;
974 // Also does not implement QQmlTypesExtensionInterface, but we want to discourage that.
975 error.setDescription(QStringLiteral("Module loaded for URI '%1' does not implement "
976 "QQmlEngineExtensionInterface").arg(a: typeNamespace));
977 errors->prepend(t: error);
978 }
979 return RegistrationResult::Failure;
980 }
981
982#if QT_DEPRECATED_SINCE(6, 3)
983 if (auto *plugin = qobject_cast<QQmlExtensionPlugin *>(object: instance)) {
984 // basepath should point to the directory of the module, not the plugin file itself:
985 QQmlExtensionPluginPrivate::get(e: plugin)->baseUrl
986 = QQmlImports::urlFromLocalFileOrQrcOrUrl(basePath);
987 }
988#else
989 Q_UNUSED(basePath)
990#endif
991
992 const QByteArray bytes = uri.toUtf8();
993 const char *moduleId = bytes.constData();
994 iface->registerTypes(uri: moduleId);
995 }
996
997 if (failures.isEmpty() && !data->registerModuleTypes(uri))
998 return RegistrationResult::NoRegistrationFunction;
999
1000 if (!failures.isEmpty()) {
1001 if (errors) {
1002 for (const QString &failure : std::as_const(t&: failures)) {
1003 QQmlError error;
1004 error.setDescription(failure);
1005 errors->prepend(t: error);
1006 }
1007 }
1008 return RegistrationResult::Failure;
1009 }
1010 }
1011
1012 return RegistrationResult::Success;
1013}
1014
1015/*
1016 \internal
1017
1018 Fetches the QQmlType instance registered for \a urlString, creating a
1019 registration for it if it is not already registered, using the associated
1020 \a typeName, \a isCompositeSingleton, \a majorVersion and \a minorVersion
1021 details.
1022
1023 Errors (if there are any) are placed into \a errors, if it is nonzero.
1024 Otherwise errors are printed as warnings.
1025*/
1026QQmlType QQmlMetaType::typeForUrl(const QString &urlString,
1027 const QHashedStringRef &qualifiedType,
1028 CompositeTypeLookupMode mode, QList<QQmlError> *errors,
1029 QTypeRevision version)
1030{
1031 // ### unfortunate (costly) conversion
1032 const QUrl url = QQmlTypeLoader::normalize(unNormalizedUrl: QUrl(urlString));
1033
1034 QQmlMetaTypeDataPtr data;
1035 {
1036 QQmlType ret(data->urlToType.value(key: url));
1037 if (ret.isValid() && ret.sourceUrl() == url)
1038 return ret;
1039 }
1040
1041 const QQmlType type = createTypeForUrl(
1042 data, url, qualifiedType, mode, errors, version);
1043 data->urlToType.insert(key: url, value: type.priv());
1044 return type;
1045}
1046
1047/*
1048 Returns the latest version of \a uri installed, or an in valid QTypeRevision().
1049*/
1050QTypeRevision QQmlMetaType::latestModuleVersion(const QString &uri)
1051{
1052 QQmlMetaTypeDataPtr data;
1053 auto upper = std::upper_bound(first: data->uriToModule.begin(), last: data->uriToModule.end(), val: uri,
1054 comp: std::less<ModuleUri>());
1055 if (upper == data->uriToModule.begin())
1056 return QTypeRevision();
1057
1058 const auto module = (--upper)->get();
1059 return (module->module() == uri)
1060 ? QTypeRevision::fromVersion(majorVersion: module->majorVersion(), minorVersion: module->maximumMinorVersion())
1061 : QTypeRevision();
1062}
1063
1064/*
1065 Returns true if a module \a uri of this version is installed and locked;
1066*/
1067bool QQmlMetaType::isStronglyLockedModule(const QString &uri, QTypeRevision version)
1068{
1069 QQmlMetaTypeDataPtr data;
1070
1071 if (QQmlTypeModule* qqtm = data->findTypeModule(module: uri, version))
1072 return qqtm->lockLevel() == QQmlTypeModule::LockLevel::Strong;
1073 return false;
1074}
1075
1076/*
1077 Returns the best matching registered version for the given \a module. If \a version is
1078 the does not have a major version, returns the latest registered version. Otherwise
1079 chooses the same major version and checks if the minor version is within the range
1080 of registered minor versions. If so, retuens the original version, otherwise returns
1081 an invalid version. If \a version does not have a minor version, chooses the latest one.
1082*/
1083QTypeRevision QQmlMetaType::matchingModuleVersion(const QString &module, QTypeRevision version)
1084{
1085 if (!version.hasMajorVersion())
1086 return latestModuleVersion(uri: module);
1087
1088 QQmlMetaTypeDataPtr data;
1089
1090 // first, check Types
1091 if (QQmlTypeModule *tm = data->findTypeModule(module, version)) {
1092 if (!version.hasMinorVersion())
1093 return QTypeRevision::fromVersion(majorVersion: version.majorVersion(), minorVersion: tm->maximumMinorVersion());
1094
1095 if (tm->minimumMinorVersion() <= version.minorVersion()
1096 && tm->maximumMinorVersion() >= version.minorVersion()) {
1097 return version;
1098 }
1099 }
1100
1101 return QTypeRevision();
1102}
1103
1104QQmlTypeModule *QQmlMetaType::typeModule(const QString &uri, QTypeRevision version)
1105{
1106 QQmlMetaTypeDataPtr data;
1107
1108 if (version.hasMajorVersion())
1109 return data->findTypeModule(module: uri, version);
1110
1111 auto range = std::equal_range(first: data->uriToModule.begin(), last: data->uriToModule.end(),
1112 val: uri, comp: std::less<ModuleUri>());
1113
1114 return range.first == range.second ? nullptr : (--range.second)->get();
1115}
1116
1117QList<QQmlPrivate::AutoParentFunction> QQmlMetaType::parentFunctions()
1118{
1119 QQmlMetaTypeDataPtr data;
1120 return data->parentFunctions;
1121}
1122
1123QObject *QQmlMetaType::toQObject(const QVariant &v, bool *ok)
1124{
1125 if (!v.metaType().flags().testFlag(flag: QMetaType::PointerToQObject)) {
1126 if (ok) *ok = false;
1127 return nullptr;
1128 }
1129
1130 if (ok) *ok = true;
1131
1132 return *(QObject *const *)v.constData();
1133}
1134
1135/*
1136 Returns the item type for a list of type \a id.
1137 */
1138QMetaType QQmlMetaType::listValueType(QMetaType metaType)
1139{
1140 if (isList(type: metaType)) {
1141 const auto iface = metaType.iface();
1142 if (iface && iface->metaObjectFn == &dynamicQmlListMarker)
1143 return QMetaType(static_cast<const QQmlListMetaTypeInterface *>(iface)->valueType);
1144 } else if (metaType.flags() & QMetaType::PointerToQObject) {
1145 return QMetaType();
1146 }
1147
1148 QQmlMetaTypeDataPtr data;
1149 Q_ASSERT(data);
1150 QQmlTypePrivate *type = data->idToType.value(key: metaType.id());
1151
1152 if (type && type->listId == metaType)
1153 return type->typeId;
1154 else
1155 return QMetaType {};
1156}
1157
1158QQmlAttachedPropertiesFunc QQmlMetaType::attachedPropertiesFunc(QQmlEnginePrivate *engine,
1159 const QMetaObject *mo)
1160{
1161 QQmlMetaTypeDataPtr data;
1162
1163 QQmlType type(data->metaObjectToType.value(key: mo));
1164 return type.attachedPropertiesFunction(enginePrivate: engine);
1165}
1166
1167QMetaProperty QQmlMetaType::defaultProperty(const QMetaObject *metaObject)
1168{
1169 int idx = metaObject->indexOfClassInfo(name: "DefaultProperty");
1170 if (-1 == idx)
1171 return QMetaProperty();
1172
1173 QMetaClassInfo info = metaObject->classInfo(index: idx);
1174 if (!info.value())
1175 return QMetaProperty();
1176
1177 idx = metaObject->indexOfProperty(name: info.value());
1178 if (-1 == idx)
1179 return QMetaProperty();
1180
1181 return metaObject->property(index: idx);
1182}
1183
1184QMetaProperty QQmlMetaType::defaultProperty(QObject *obj)
1185{
1186 if (!obj)
1187 return QMetaProperty();
1188
1189 const QMetaObject *metaObject = obj->metaObject();
1190 return defaultProperty(metaObject);
1191}
1192
1193QMetaMethod QQmlMetaType::defaultMethod(const QMetaObject *metaObject)
1194{
1195 int idx = metaObject->indexOfClassInfo(name: "DefaultMethod");
1196 if (-1 == idx)
1197 return QMetaMethod();
1198
1199 QMetaClassInfo info = metaObject->classInfo(index: idx);
1200 if (!info.value())
1201 return QMetaMethod();
1202
1203 idx = metaObject->indexOfMethod(method: info.value());
1204 if (-1 == idx)
1205 return QMetaMethod();
1206
1207 return metaObject->method(index: idx);
1208}
1209
1210QMetaMethod QQmlMetaType::defaultMethod(QObject *obj)
1211{
1212 if (!obj)
1213 return QMetaMethod();
1214
1215 const QMetaObject *metaObject = obj->metaObject();
1216 return defaultMethod(metaObject);
1217}
1218
1219/*!
1220 See qmlRegisterInterface() for information about when this will return true.
1221*/
1222bool QQmlMetaType::isInterface(QMetaType type)
1223{
1224 const QQmlMetaTypeDataPtr data;
1225 return data->interfaces.contains(value: type.id());
1226}
1227
1228const char *QQmlMetaType::interfaceIId(QMetaType metaType)
1229{
1230 const QQmlMetaTypeDataPtr data;
1231 const QQmlType type(data->idToType.value(key: metaType.id()));
1232 return (type.isInterface() && type.typeId() == metaType) ? type.interfaceIId() : nullptr;
1233}
1234
1235bool QQmlMetaType::isList(QMetaType type)
1236{
1237 if (type.flags().testFlag(flag: QMetaType::IsQmlList))
1238 return true;
1239 else
1240 return false;
1241}
1242
1243/*!
1244 Returns the type (if any) of URI-qualified named \a qualifiedName and version specified
1245 by \a version_major and \a version_minor.
1246*/
1247QQmlType QQmlMetaType::qmlType(const QString &qualifiedName, QTypeRevision version)
1248{
1249 int slash = qualifiedName.indexOf(ch: QLatin1Char('/'));
1250 if (slash <= 0)
1251 return QQmlType();
1252
1253 QHashedStringRef module(qualifiedName.constData(), slash);
1254 QHashedStringRef name(qualifiedName.constData() + slash + 1, qualifiedName.size() - slash - 1);
1255
1256 return qmlType(name, module, version);
1257}
1258
1259/*!
1260 \internal
1261 Returns the type (if any) of \a name in \a module and the specified \a version.
1262
1263 If \a version has no major version, accept any version.
1264 If \a version has no minor version, accept any minor version.
1265 If \a module is empty, search in all modules and accept any version.
1266*/
1267QQmlType QQmlMetaType::qmlType(const QHashedStringRef &name, const QHashedStringRef &module,
1268 QTypeRevision version)
1269{
1270 const QQmlMetaTypeDataPtr data;
1271
1272 const QHashedString key(QString::fromRawData(unicode: name.constData(), size: name.length()), name.hash());
1273 QQmlMetaTypeData::Names::ConstIterator it = data->nameToType.constFind(key);
1274 while (it != data->nameToType.cend() && it.key() == name) {
1275 QQmlType t(*it);
1276 if (module.isEmpty() || t.availableInVersion(module, version))
1277 return t;
1278 ++it;
1279 }
1280
1281 return QQmlType();
1282}
1283
1284/*!
1285 Returns the type (if any) that corresponds to the \a metaObject. Returns an invalid type if no
1286 such type is registered.
1287*/
1288QQmlType QQmlMetaType::qmlType(const QMetaObject *metaObject)
1289{
1290 const QQmlMetaTypeDataPtr data;
1291 return QQmlType(data->metaObjectToType.value(key: metaObject));
1292}
1293
1294/*!
1295 Returns the type (if any) that corresponds to the \a metaObject in version specified
1296 by \a version_major and \a version_minor in module specified by \a uri. Returns null if no
1297 type is registered.
1298*/
1299QQmlType QQmlMetaType::qmlType(const QMetaObject *metaObject, const QHashedStringRef &module,
1300 QTypeRevision version)
1301{
1302 const QQmlMetaTypeDataPtr data;
1303
1304 const auto range = data->metaObjectToType.equal_range(key: metaObject);
1305 for (auto it = range.first; it != range.second; ++it) {
1306 QQmlType t(*it);
1307 if (module.isEmpty() || t.availableInVersion(module, version))
1308 return t;
1309 }
1310
1311 return QQmlType();
1312}
1313
1314/*!
1315 Returns the type (if any) that corresponds to \a qmlTypeId.
1316 Returns an invalid QQmlType if no such type is registered.
1317*/
1318QQmlType QQmlMetaType::qmlTypeById(int qmlTypeId)
1319{
1320 const QQmlMetaTypeDataPtr data;
1321 QQmlType type = data->types.value(i: qmlTypeId);
1322 if (type.isValid())
1323 return type;
1324 return QQmlType();
1325}
1326
1327/*!
1328 Returns the type (if any) that corresponds to \a metaType.
1329 Returns an invalid QQmlType if no such type is registered.
1330*/
1331QQmlType QQmlMetaType::qmlType(QMetaType metaType)
1332{
1333 const QQmlMetaTypeDataPtr data;
1334 QQmlTypePrivate *type = data->idToType.value(key: metaType.id());
1335 return (type && type->typeId == metaType) ? QQmlType(type) : QQmlType();
1336}
1337
1338QQmlType QQmlMetaType::qmlListType(QMetaType metaType)
1339{
1340 const QQmlMetaTypeDataPtr data;
1341 QQmlTypePrivate *type = data->idToType.value(key: metaType.id());
1342 return (type && type->listId == metaType) ? QQmlType(type) : QQmlType();
1343}
1344
1345/*!
1346 Returns the type (if any) that corresponds to the given \a url in the set of
1347 composite types added through file imports.
1348
1349 Returns null if no such type is registered.
1350*/
1351QQmlType QQmlMetaType::qmlType(const QUrl &unNormalizedUrl)
1352{
1353 const QUrl url = QQmlTypeLoader::normalize(unNormalizedUrl);
1354 const QQmlMetaTypeDataPtr data;
1355
1356 QQmlType type(data->urlToType.value(key: url));
1357
1358 if (type.sourceUrl() == url)
1359 return type;
1360 else
1361 return QQmlType();
1362}
1363
1364QQmlType QQmlMetaType::fetchOrCreateInlineComponentTypeForUrl(const QUrl &url)
1365{
1366 QQmlMetaTypeDataPtr data;
1367 const auto it = data->urlToType.constFind(key: url);
1368 if (it != data->urlToType.constEnd())
1369 return QQmlType(*it);
1370
1371 return doRegisterInlineComponentType(data, url);
1372}
1373
1374/*!
1375Returns a QQmlPropertyCache for \a obj if one is available.
1376
1377If \a obj is null, being deleted or contains a dynamic meta object,
1378nullptr is returned.
1379*/
1380QQmlPropertyCache::ConstPtr QQmlMetaType::propertyCache(QObject *obj, QTypeRevision version)
1381{
1382 if (!obj || QObjectPrivate::get(o: obj)->metaObject || QObjectPrivate::get(o: obj)->wasDeleted)
1383 return QQmlPropertyCache::ConstPtr();
1384 return QQmlMetaType::propertyCache(metaObject: obj->metaObject(), version);
1385}
1386
1387QQmlPropertyCache::ConstPtr QQmlMetaType::propertyCache(
1388 const QMetaObject *metaObject, QTypeRevision version)
1389{
1390 QQmlMetaTypeDataPtr data; // not const: the cache is created on demand
1391 return data->propertyCache(metaObject, version);
1392}
1393
1394QQmlPropertyCache::ConstPtr QQmlMetaType::propertyCache(
1395 const QQmlType &type, QTypeRevision version)
1396{
1397 QQmlMetaTypeDataPtr data; // not const: the cache is created on demand
1398 return data->propertyCache(type, version);
1399}
1400
1401/*!
1402 * \internal
1403 *
1404 * Look up by type's baseMetaObject.
1405 */
1406QQmlMetaObject QQmlMetaType::rawMetaObjectForType(QMetaType metaType)
1407{
1408 const QQmlMetaTypeDataPtr data;
1409 if (auto composite = data->findPropertyCacheInCompositeTypes(t: metaType))
1410 return QQmlMetaObject(composite);
1411
1412 const QQmlTypePrivate *type = data->idToType.value(key: metaType.id());
1413 return (type && type->typeId == metaType) ? type->baseMetaObject : nullptr;
1414}
1415
1416/*!
1417 * \internal
1418 *
1419 * Look up by type's metaObject.
1420 */
1421QQmlMetaObject QQmlMetaType::metaObjectForType(QMetaType metaType)
1422{
1423 const QQmlMetaTypeDataPtr data;
1424 if (auto composite = data->findPropertyCacheInCompositeTypes(t: metaType))
1425 return QQmlMetaObject(composite);
1426
1427 const QQmlTypePrivate *type = data->idToType.value(key: metaType.id());
1428 return (type && type->typeId == metaType)
1429 ? QQmlType(type).metaObject()
1430 : nullptr;
1431}
1432
1433/*!
1434 * \internal
1435 *
1436 * Look up by type's metaObject and version.
1437 */
1438QQmlPropertyCache::ConstPtr QQmlMetaType::propertyCacheForType(QMetaType metaType)
1439{
1440 QQmlMetaTypeDataPtr data;
1441 if (auto composite = data->findPropertyCacheInCompositeTypes(t: metaType))
1442 return composite;
1443
1444 const QQmlTypePrivate *type = data->idToType.value(key: metaType.id());
1445 if (type && type->typeId == metaType) {
1446 if (const QMetaObject *mo = QQmlType(type).metaObject())
1447 return data->propertyCache(metaObject: mo, version: type->version);
1448 }
1449
1450 return QQmlPropertyCache::ConstPtr();
1451}
1452
1453/*!
1454 * \internal
1455 *
1456 * Look up by type's baseMetaObject and unspecified/any version.
1457 * TODO: Is this correct? Passing a plain QTypeRevision() rather than QTypeRevision::zero() or
1458 * the actual type's version seems strange. The behavior has been in place for a while.
1459 */
1460QQmlPropertyCache::ConstPtr QQmlMetaType::rawPropertyCacheForType(QMetaType metaType)
1461{
1462 QQmlMetaTypeDataPtr data;
1463 if (auto composite = QQmlMetaType::findPropertyCacheInCompositeTypes(t: metaType))
1464 return composite;
1465
1466 const QQmlTypePrivate *type = data->idToType.value(key: metaType.id());
1467 if (!type || type->typeId != metaType)
1468 return QQmlPropertyCache::ConstPtr();
1469
1470 const QMetaObject *metaObject = type->isValueType()
1471 ? type->metaObjectForValueType()
1472 : type->baseMetaObject;
1473
1474 return metaObject
1475 ? data->propertyCache(metaObject, version: QTypeRevision())
1476 : QQmlPropertyCache::ConstPtr();
1477}
1478
1479/*!
1480 * \internal
1481 *
1482 * Look up by QQmlType and version. We only fall back to lookup by metaobject if the type
1483 * has no revisiononed attributes here. Unspecified versions are interpreted as "any".
1484 */
1485QQmlPropertyCache::ConstPtr QQmlMetaType::rawPropertyCacheForType(
1486 QMetaType metaType, QTypeRevision version)
1487{
1488 QQmlMetaTypeDataPtr data;
1489 if (auto composite = data->findPropertyCacheInCompositeTypes(t: metaType))
1490 return composite;
1491
1492 const QQmlTypePrivate *typePriv = data->idToType.value(key: metaType.id());
1493 if (!typePriv || typePriv->typeId != metaType)
1494 return QQmlPropertyCache::ConstPtr();
1495
1496 const QQmlType type(typePriv);
1497 if (type.containsRevisionedAttributes()) {
1498 // It can only have (revisioned) properties or methods if it has a metaobject
1499 Q_ASSERT(type.metaObject());
1500 return data->propertyCache(type, version);
1501 }
1502
1503 if (const QMetaObject *metaObject = type.metaObject())
1504 return data->propertyCache(metaObject, version);
1505
1506 return QQmlPropertyCache::ConstPtr();
1507}
1508
1509void QQmlMetaType::unregisterType(int typeIndex)
1510{
1511 QQmlMetaTypeDataPtr data;
1512 const QQmlType type = data->types.value(i: typeIndex);
1513 if (const QQmlTypePrivate *d = type.priv()) {
1514 if (d->regType == QQmlType::CompositeType || d->regType == QQmlType::CompositeSingletonType)
1515 removeFromInlineComponents(container&: data->urlToType, reference: d);
1516 removeQQmlTypePrivate(container&: data->idToType, reference: d);
1517 removeQQmlTypePrivate(container&: data->nameToType, reference: d);
1518 removeQQmlTypePrivate(container&: data->urlToType, reference: d);
1519 removeQQmlTypePrivate(container&: data->metaObjectToType, reference: d);
1520 for (auto & module : data->uriToModule)
1521 module->remove(type: d);
1522 data->clearPropertyCachesForVersion(index: typeIndex);
1523 data->types[typeIndex] = QQmlType();
1524 data->undeletableTypes.remove(value: type);
1525 }
1526}
1527
1528void QQmlMetaType::registerMetaObjectForType(const QMetaObject *metaobject, QQmlTypePrivate *type)
1529{
1530 Q_ASSERT(type);
1531
1532 QQmlMetaTypeDataPtr data;
1533 data->metaObjectToType.insert(key: metaobject, value: type);
1534}
1535
1536static bool hasActiveInlineComponents(const QQmlMetaTypeData *data, const QQmlTypePrivate *d)
1537{
1538 for (auto it = data->urlToType.begin(), end = data->urlToType.end();
1539 it != end; ++it) {
1540 if (!QQmlMetaType::equalBaseUrls(aUrl: it.key(), bUrl: d->sourceUrl()))
1541 continue;
1542
1543 const QQmlTypePrivate *icPriv = *it;
1544 if (icPriv && icPriv->count() > 1)
1545 return true;
1546 }
1547 return false;
1548}
1549
1550static int doCountInternalCompositeTypeSelfReferences(
1551 QQmlMetaTypeData *data,
1552 const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit)
1553{
1554 int result = 0;
1555 auto doCheck = [&](const QtPrivate::QMetaTypeInterface *iface) {
1556 if (!iface)
1557 return;
1558
1559 const auto it = data->compositeTypes.constFind(key: iface);
1560 if (it != data->compositeTypes.constEnd() && *it == compilationUnit)
1561 ++result;
1562 };
1563
1564 doCheck(compilationUnit->metaType().iface());
1565 for (auto &&inlineData: compilationUnit->inlineComponentData)
1566 doCheck(inlineData.qmlType.typeId().iface());
1567
1568 return result;
1569}
1570
1571void QQmlMetaType::freeUnusedTypesAndCaches()
1572{
1573 QQmlMetaTypeDataPtr data;
1574
1575 // in case this is being called during program exit, `data` might be destructed already
1576 if (!data.isValid())
1577 return;
1578
1579 bool droppedAtLeastOneComposite;
1580 do {
1581 droppedAtLeastOneComposite = false;
1582 auto it = data->compositeTypes.begin();
1583 while (it != data->compositeTypes.end()) {
1584 if ((*it)->count() <= doCountInternalCompositeTypeSelfReferences(data, compilationUnit: *it)) {
1585 it = data->compositeTypes.erase(it);
1586 droppedAtLeastOneComposite = true;
1587 } else {
1588 ++it;
1589 }
1590 }
1591 } while (droppedAtLeastOneComposite);
1592
1593 bool deletedAtLeastOneType;
1594 do {
1595 deletedAtLeastOneType = false;
1596 QList<QQmlType>::Iterator it = data->types.begin();
1597 while (it != data->types.end()) {
1598 const QQmlTypePrivate *d = (*it).priv();
1599 if (d && d->count() == 1 && !hasActiveInlineComponents(data, d)) {
1600 deletedAtLeastOneType = true;
1601
1602 if (d->regType == QQmlType::CompositeType
1603 || d->regType == QQmlType::CompositeSingletonType) {
1604 removeFromInlineComponents(container&: data->urlToType, reference: d);
1605 }
1606 removeQQmlTypePrivate(container&: data->idToType, reference: d);
1607 removeQQmlTypePrivate(container&: data->nameToType, reference: d);
1608 removeQQmlTypePrivate(container&: data->urlToType, reference: d);
1609 removeQQmlTypePrivate(container&: data->metaObjectToType, reference: d);
1610
1611 for (auto &module : data->uriToModule)
1612 module->remove(type: d);
1613
1614 data->clearPropertyCachesForVersion(index: d->index);
1615 *it = QQmlType();
1616 } else {
1617 ++it;
1618 }
1619 }
1620 } while (deletedAtLeastOneType);
1621
1622 bool deletedAtLeastOneCache;
1623 do {
1624 deletedAtLeastOneCache = false;
1625 auto it = data->propertyCaches.begin();
1626 while (it != data->propertyCaches.end()) {
1627 if ((*it)->count() == 1) {
1628 it = data->propertyCaches.erase(it);
1629 deletedAtLeastOneCache = true;
1630 } else {
1631 ++it;
1632 }
1633 }
1634 } while (deletedAtLeastOneCache);
1635}
1636
1637/*!
1638 Returns the list of registered QML type names.
1639*/
1640QList<QString> QQmlMetaType::qmlTypeNames()
1641{
1642 const QQmlMetaTypeDataPtr data;
1643
1644 QList<QString> names;
1645 names.reserve(asize: data->nameToType.size());
1646 QQmlMetaTypeData::Names::ConstIterator it = data->nameToType.cbegin();
1647 while (it != data->nameToType.cend()) {
1648 QQmlType t(*it);
1649 names += t.qmlTypeName();
1650 ++it;
1651 }
1652
1653 return names;
1654}
1655
1656/*!
1657 Returns the list of registered QML types.
1658*/
1659QList<QQmlType> QQmlMetaType::qmlTypes()
1660{
1661 const QQmlMetaTypeDataPtr data;
1662
1663 QList<QQmlType> types;
1664 for (const QQmlTypePrivate *t : data->nameToType)
1665 types.append(t: QQmlType(t));
1666
1667 return types;
1668}
1669
1670/*!
1671 Returns the list of all registered types.
1672*/
1673QList<QQmlType> QQmlMetaType::qmlAllTypes()
1674{
1675 const QQmlMetaTypeDataPtr data;
1676 return data->types;
1677}
1678
1679/*!
1680 Returns the list of registered QML singleton types.
1681*/
1682QList<QQmlType> QQmlMetaType::qmlSingletonTypes()
1683{
1684 const QQmlMetaTypeDataPtr data;
1685
1686 QList<QQmlType> retn;
1687 for (const auto t : std::as_const(t: data->nameToType)) {
1688 QQmlType type(t);
1689 if (type.isSingleton())
1690 retn.append(t: type);
1691 }
1692 return retn;
1693}
1694
1695static bool isFullyTyped(const QQmlPrivate::CachedQmlUnit *unit)
1696{
1697 quint32 numTypedFunctions = 0;
1698 for (const QQmlPrivate::AOTCompiledFunction *function = unit->aotCompiledFunctions;
1699 function; ++function) {
1700 if (function->functionPtr)
1701 ++numTypedFunctions;
1702 else
1703 return false;
1704 }
1705 return numTypedFunctions == unit->qmlData->functionTableSize;
1706}
1707
1708const QQmlPrivate::CachedQmlUnit *QQmlMetaType::findCachedCompilationUnit(
1709 const QUrl &uri, QQmlMetaType::CacheMode mode, CachedUnitLookupError *status)
1710{
1711 Q_ASSERT(mode != RejectAll);
1712 const QQmlMetaTypeDataPtr data;
1713
1714 for (const auto lookup : std::as_const(t: data->lookupCachedQmlUnit)) {
1715 if (const QQmlPrivate::CachedQmlUnit *unit = lookup(uri)) {
1716 QString error;
1717 if (!unit->qmlData->verifyHeader(expectedSourceTimeStamp: QDateTime(), errorString: &error)) {
1718 qCDebug(DBG_DISK_CACHE) << "Error loading pre-compiled file " << uri << ":" << error;
1719 if (status)
1720 *status = CachedUnitLookupError::VersionMismatch;
1721 return nullptr;
1722 }
1723
1724 if (mode == RequireFullyTyped && !isFullyTyped(unit)) {
1725 qCDebug(DBG_DISK_CACHE)
1726 << "Error loading pre-compiled file " << uri
1727 << ": compilation unit contains functions not compiled to native code.";
1728 if (status)
1729 *status = CachedUnitLookupError::NotFullyTyped;
1730 return nullptr;
1731 }
1732
1733 if (status)
1734 *status = CachedUnitLookupError::NoError;
1735 return unit;
1736 }
1737 }
1738
1739 if (status)
1740 *status = CachedUnitLookupError::NoUnitFound;
1741
1742 return nullptr;
1743}
1744
1745void QQmlMetaType::prependCachedUnitLookupFunction(QQmlPrivate::QmlUnitCacheLookupFunction handler)
1746{
1747 QQmlMetaTypeDataPtr data;
1748 data->lookupCachedQmlUnit.prepend(t: handler);
1749}
1750
1751void QQmlMetaType::removeCachedUnitLookupFunction(QQmlPrivate::QmlUnitCacheLookupFunction handler)
1752{
1753 QQmlMetaTypeDataPtr data;
1754 data->lookupCachedQmlUnit.removeAll(t: handler);
1755}
1756
1757/*!
1758 Returns the pretty QML type name (e.g. 'Item' instead of 'QtQuickItem') for the given object.
1759 */
1760QString QQmlMetaType::prettyTypeName(const QObject *object)
1761{
1762 QString typeName;
1763
1764 if (!object)
1765 return typeName;
1766
1767 QQmlType type = QQmlMetaType::qmlType(metaObject: object->metaObject());
1768 if (type.isValid()) {
1769 typeName = type.qmlTypeName();
1770 const int lastSlash = typeName.lastIndexOf(c: QLatin1Char('/'));
1771 if (lastSlash != -1)
1772 typeName = typeName.mid(position: lastSlash + 1);
1773 }
1774
1775 if (typeName.isEmpty()) {
1776 typeName = QString::fromUtf8(utf8: object->metaObject()->className());
1777 int marker = typeName.indexOf(s: QLatin1String("_QMLTYPE_"));
1778 if (marker != -1)
1779 typeName = typeName.left(n: marker);
1780
1781 marker = typeName.indexOf(s: QLatin1String("_QML_"));
1782 if (marker != -1) {
1783 typeName = QStringView{typeName}.left(n: marker) + QLatin1Char('*');
1784 type = QQmlMetaType::qmlType(metaType: QMetaType::fromName(name: typeName.toUtf8()));
1785 if (type.isValid()) {
1786 QString qmlTypeName = type.qmlTypeName();
1787 const int lastSlash = qmlTypeName.lastIndexOf(c: QLatin1Char('/'));
1788 if (lastSlash != -1)
1789 qmlTypeName = qmlTypeName.mid(position: lastSlash + 1);
1790 if (!qmlTypeName.isEmpty())
1791 typeName = qmlTypeName;
1792 }
1793 }
1794 }
1795
1796 return typeName;
1797}
1798
1799QList<QQmlProxyMetaObject::ProxyData> QQmlMetaType::proxyData(const QMetaObject *mo,
1800 const QMetaObject *baseMetaObject,
1801 QMetaObject *lastMetaObject)
1802{
1803 QList<QQmlProxyMetaObject::ProxyData> metaObjects;
1804 mo = mo->d.superdata;
1805
1806 if (!mo)
1807 return metaObjects;
1808
1809 auto createProxyMetaObject = [&](QQmlTypePrivate *This,
1810 const QMetaObject *superdataBaseMetaObject,
1811 const QMetaObject *extMetaObject,
1812 QObject *(*extFunc)(QObject *)) {
1813 if (!extMetaObject)
1814 return;
1815
1816 QMetaObjectBuilder builder;
1817 clone(builder, mo: extMetaObject, ignoreStart: superdataBaseMetaObject, ignoreEnd: baseMetaObject,
1818 policy: extFunc ? QQmlMetaType::CloneAll : QQmlMetaType::CloneEnumsOnly);
1819 QMetaObject *mmo = builder.toMetaObject();
1820 mmo->d.superdata = baseMetaObject;
1821 if (!metaObjects.isEmpty())
1822 metaObjects.constLast().metaObject->d.superdata = mmo;
1823 else if (lastMetaObject)
1824 lastMetaObject->d.superdata = mmo;
1825 QQmlProxyMetaObject::ProxyData data = { .metaObject: mmo, .createFunc: extFunc, .propertyOffset: 0, .methodOffset: 0 };
1826 metaObjects << data;
1827 registerMetaObjectForType(metaobject: mmo, type: This);
1828 };
1829
1830 for (const QQmlMetaTypeDataPtr data; mo; mo = mo->d.superdata) {
1831 // TODO: There can in fact be multiple QQmlTypePrivate* for a single QMetaObject*.
1832 // This algorithm only accounts for the most recently inserted one. That's pretty
1833 // random. However, the availability of types depends on what documents you have
1834 // loaded before. Just adding all possible extensions would also be pretty random.
1835 // The right way to do this would be to take the relations between the QML modules
1836 // into account. For this we would need proper module dependency information.
1837 if (QQmlTypePrivate *t = data->metaObjectToType.value(key: mo)) {
1838 if (t->regType == QQmlType::CppType) {
1839 createProxyMetaObject(
1840 t, t->baseMetaObject, t->extraData.cppTypeData->extMetaObject,
1841 t->extraData.cppTypeData->extFunc);
1842 } else if (t->regType == QQmlType::SingletonType) {
1843 createProxyMetaObject(
1844 t, t->baseMetaObject, t->extraData.singletonTypeData->extMetaObject,
1845 t->extraData.singletonTypeData->extFunc);
1846 }
1847 }
1848 };
1849
1850 return metaObjects;
1851}
1852
1853static bool isInternalType(int idx)
1854{
1855 // Qt internal types
1856 switch (idx) {
1857 case QMetaType::UnknownType:
1858 case QMetaType::QStringList:
1859 case QMetaType::QObjectStar:
1860 case QMetaType::VoidStar:
1861 case QMetaType::Nullptr:
1862 case QMetaType::QVariant:
1863 case QMetaType::QLocale:
1864 case QMetaType::QImage: // scarce type, keep as QVariant
1865 case QMetaType::QPixmap: // scarce type, keep as QVariant
1866 return true;
1867 default:
1868 return false;
1869 }
1870}
1871
1872bool QQmlMetaType::isValueType(QMetaType type)
1873{
1874 if (type.flags().testFlag(flag: QMetaType::PointerToQObject))
1875 return false;
1876
1877 if (!type.isValid() || isInternalType(idx: type.id()))
1878 return false;
1879
1880 return valueType(metaType: type) != nullptr;
1881}
1882
1883const QMetaObject *QQmlMetaType::metaObjectForValueType(QMetaType metaType)
1884{
1885 switch (metaType.id()) {
1886 case QMetaType::QPoint:
1887 return &QQmlPointValueType::staticMetaObject;
1888 case QMetaType::QPointF:
1889 return &QQmlPointFValueType::staticMetaObject;
1890 case QMetaType::QSize:
1891 return &QQmlSizeValueType::staticMetaObject;
1892 case QMetaType::QSizeF:
1893 return &QQmlSizeFValueType::staticMetaObject;
1894 case QMetaType::QRect:
1895 return &QQmlRectValueType::staticMetaObject;
1896 case QMetaType::QRectF:
1897 return &QQmlRectFValueType::staticMetaObject;
1898#if QT_CONFIG(easingcurve)
1899 case QMetaType::QEasingCurve:
1900 return &QQmlEasingValueType::staticMetaObject;
1901#endif
1902 default:
1903 break;
1904 }
1905
1906 // It doesn't have to be a gadget for a QML type to exist, but we don't want to
1907 // call QObject pointers value types. Explicitly registered types also override
1908 // the implicit use of gadgets.
1909 if (!(metaType.flags() & QMetaType::PointerToQObject)) {
1910 const QQmlMetaTypeDataPtr data;
1911 const QQmlTypePrivate *type = data->idToType.value(key: metaType.id());
1912 if (type && type->regType == QQmlType::CppType && type->typeId == metaType) {
1913 if (const QMetaObject *mo = type->metaObjectForValueType())
1914 return mo;
1915 }
1916 }
1917
1918 // If it _is_ a gadget, we can just use it.
1919 if (metaType.flags() & QMetaType::IsGadget)
1920 return metaType.metaObject();
1921
1922 return nullptr;
1923}
1924
1925QQmlValueType *QQmlMetaType::valueType(QMetaType type)
1926{
1927 QQmlMetaTypeDataPtr data;
1928
1929 const auto it = data->metaTypeToValueType.constFind(key: type.id());
1930 if (it != data->metaTypeToValueType.constEnd())
1931 return *it;
1932
1933 if (const QMetaObject *mo = metaObjectForValueType(metaType: type))
1934 return *data->metaTypeToValueType.insert(key: type.id(), value: new QQmlValueType(type, mo));
1935 return *data->metaTypeToValueType.insert(key: type.id(), value: nullptr);
1936}
1937
1938QQmlPropertyCache::ConstPtr QQmlMetaType::findPropertyCacheInCompositeTypes(QMetaType t)
1939{
1940 const QQmlMetaTypeDataPtr data;
1941 return data->findPropertyCacheInCompositeTypes(t);
1942}
1943
1944void QQmlMetaType::registerInternalCompositeType(
1945 const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit)
1946{
1947 QQmlMetaTypeDataPtr data;
1948
1949 auto doInsert = [&data, &compilationUnit](const QtPrivate::QMetaTypeInterface *iface) {
1950 Q_ASSERT(iface);
1951 Q_ASSERT(compilationUnit);
1952
1953 // We can't assert on anything else here. We may get a completely new type as exposed
1954 // by the qmldiskcache test that changes a QML file in place during the execution
1955 // of the test.
1956 data->compositeTypes.insert(key: iface, value: compilationUnit);
1957 };
1958
1959 doInsert(compilationUnit->metaType().iface());
1960 for (auto &&inlineData: compilationUnit->inlineComponentData)
1961 doInsert(inlineData.qmlType.typeId().iface());
1962}
1963
1964void QQmlMetaType::unregisterInternalCompositeType(
1965 const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit)
1966{
1967 QQmlMetaTypeDataPtr data;
1968
1969 auto doRemove = [&](const QtPrivate::QMetaTypeInterface *iface) {
1970 if (!iface)
1971 return;
1972
1973 const auto it = data->compositeTypes.constFind(key: iface);
1974 if (it != data->compositeTypes.constEnd() && *it == compilationUnit)
1975 data->compositeTypes.erase(it);
1976 };
1977
1978 doRemove(compilationUnit->metaType().iface());
1979 for (auto &&inlineData: compilationUnit->inlineComponentData)
1980 doRemove(inlineData.qmlType.typeId().iface());
1981}
1982
1983int QQmlMetaType::countInternalCompositeTypeSelfReferences(
1984 const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit)
1985{
1986 QQmlMetaTypeDataPtr data;
1987 return doCountInternalCompositeTypeSelfReferences(data, compilationUnit);
1988}
1989
1990QQmlRefPointer<QV4::CompiledData::CompilationUnit> QQmlMetaType::obtainCompilationUnit(
1991 QMetaType type)
1992{
1993 const QQmlMetaTypeDataPtr data;
1994 return data->compositeTypes.value(key: type.iface());
1995}
1996
1997QQmlRefPointer<QV4::CompiledData::CompilationUnit> QQmlMetaType::obtainCompilationUnit(
1998 const QUrl &url)
1999{
2000 const QUrl normalized = QQmlTypeLoader::normalize(unNormalizedUrl: url);
2001 QQmlMetaTypeDataPtr data;
2002
2003 auto found = data->urlToType.constFind(key: normalized);
2004 if (found == data->urlToType.constEnd())
2005 return QQmlRefPointer<QV4::CompiledData::CompilationUnit>();
2006
2007 const auto composite = data->compositeTypes.constFind(key: found.value()->typeId.iface());
2008 return composite == data->compositeTypes.constEnd()
2009 ? QQmlRefPointer<QV4::CompiledData::CompilationUnit>()
2010 : composite.value();
2011}
2012
2013QT_END_NAMESPACE
2014

source code of qtdeclarative/src/qml/qml/qqmlmetatype.cpp