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

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