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