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