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