1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtQml module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qqmlmetatype_p.h"
41
42#include <private/qqmlmetatypedata_p.h>
43#include <private/qqmltypemodule_p_p.h>
44#include <private/qqmltype_p_p.h>
45#include <private/qqmltypeloader_p.h>
46#include <private/qqmlextensionplugin_p.h>
47#include <private/qv4executablecompilationunit_p.h>
48
49#include <QtCore/qcoreapplication.h>
50#include <QtCore/qmutex.h>
51#include <QtCore/qloggingcategory.h>
52
53Q_DECLARE_LOGGING_CATEGORY(DBG_DISK_CACHE)
54
55QT_BEGIN_NAMESPACE
56
57struct LockedData : private QQmlMetaTypeData
58{
59 friend class QQmlMetaTypeDataPtr;
60};
61
62Q_GLOBAL_STATIC(LockedData, metaTypeData)
63Q_GLOBAL_STATIC(QRecursiveMutex, metaTypeDataLock)
64
65class QQmlMetaTypeDataPtr
66{
67 Q_DISABLE_COPY_MOVE(QQmlMetaTypeDataPtr)
68public:
69 QQmlMetaTypeDataPtr() : locker(metaTypeDataLock()), data(metaTypeData()) {}
70 ~QQmlMetaTypeDataPtr() = default;
71
72 QQmlMetaTypeData &operator*() { return *data; }
73 QQmlMetaTypeData *operator->() { return data; }
74 operator QQmlMetaTypeData *() { return data; }
75
76 const QQmlMetaTypeData &operator*() const { return *data; }
77 const QQmlMetaTypeData *operator->() const { return data; }
78 operator const QQmlMetaTypeData *() const { return data; }
79
80 bool isValid() const { return data != nullptr; }
81
82private:
83 QMutexLocker locker;
84 LockedData *data = nullptr;
85};
86
87static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data,
88 const QQmlPrivate::RegisterInterface &type)
89{
90 auto *d = new QQmlTypePrivate(QQmlType::InterfaceType);
91 d->iid = type.iid;
92 d->typeId = type.typeId;
93 d->listId = type.listId;
94 d->isSetup = true;
95 d->version_min = 0;
96 if (type.version > 0) {
97 d->module = QString::fromUtf8(str: type.uri);
98 d->version_maj = type.versionMajor;
99 } else {
100 d->version_maj = 0;
101 }
102 data->registerType(priv: d);
103 return d;
104}
105
106static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data, const QString &elementName,
107 const QQmlPrivate::RegisterSingletonType &type)
108{
109 auto *d = new QQmlTypePrivate(QQmlType::SingletonType);
110 data->registerType(priv: d);
111
112 d->setName(uri: QString::fromUtf8(str: type.uri), element: elementName);
113 d->version_maj = type.versionMajor;
114 d->version_min = type.versionMinor;
115
116 if (type.qobjectApi || (type.version >= 3 && type.generalizedQobjectApi)) {
117 if (type.version >= 1) // static metaobject added in version 1
118 d->baseMetaObject = type.instanceMetaObject;
119 if (type.version >= 2) // typeId added in version 2
120 d->typeId = type.typeId;
121 if (type.version >= 2) // revisions added in version 2
122 d->revision = type.revision;
123 }
124
125 d->extraData.sd->singletonInstanceInfo = new QQmlType::SingletonInstanceInfo;
126 d->extraData.sd->singletonInstanceInfo->scriptCallback = type.scriptApi;
127 if (type.version >= 3) {
128 d->extraData.sd->singletonInstanceInfo->qobjectCallback = type.generalizedQobjectApi;
129 } else {
130 d->extraData.sd->singletonInstanceInfo->qobjectCallback = type.qobjectApi;
131 }
132 d->extraData.sd->singletonInstanceInfo->typeName = QString::fromUtf8(str: type.typeName);
133 d->extraData.sd->singletonInstanceInfo->instanceMetaObject
134 = ((type.qobjectApi || (type.version >= 3 && type.generalizedQobjectApi) ) && type.version >= 1) ? type.instanceMetaObject : nullptr;
135
136 return d;
137}
138
139static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data, const QString &elementName,
140 const QQmlPrivate::RegisterType &type)
141{
142 QQmlTypePrivate *d = new QQmlTypePrivate(QQmlType::CppType);
143 data->registerType(priv: d);
144 d->setName(uri: QString::fromUtf8(str: type.uri), element: elementName);
145
146 d->version_maj = type.versionMajor;
147 d->version_min = type.versionMinor;
148 if (type.version >= 1) // revisions added in version 1
149 d->revision = type.revision;
150 d->typeId = type.typeId;
151 d->listId = type.listId;
152 d->extraData.cd->allocationSize = type.objectSize;
153 d->extraData.cd->newFunc = type.create;
154 d->extraData.cd->noCreationReason = type.noCreationReason;
155 d->baseMetaObject = type.metaObject;
156 d->extraData.cd->attachedPropertiesFunc = type.attachedPropertiesFunction;
157 d->extraData.cd->attachedPropertiesType = type.attachedPropertiesMetaObject;
158 d->extraData.cd->parserStatusCast = type.parserStatusCast;
159 d->extraData.cd->propertyValueSourceCast = type.valueSourceCast;
160 d->extraData.cd->propertyValueInterceptorCast = type.valueInterceptorCast;
161 d->extraData.cd->extFunc = type.extensionObjectCreate;
162 d->extraData.cd->customParser = reinterpret_cast<QQmlCustomParser *>(type.customParser);
163 d->extraData.cd->registerEnumClassesUnscoped = true;
164
165 if (type.extensionMetaObject)
166 d->extraData.cd->extMetaObject = type.extensionMetaObject;
167
168 // Check if the user wants only scoped enum classes
169 if (d->baseMetaObject) {
170 auto indexOfClassInfo = d->baseMetaObject->indexOfClassInfo(name: "RegisterEnumClassesUnscoped");
171 if (indexOfClassInfo != -1 && QString::fromUtf8(str: d->baseMetaObject->classInfo(index: indexOfClassInfo).value()) == QLatin1String("false"))
172 d->extraData.cd->registerEnumClassesUnscoped = false;
173 }
174
175 return d;
176}
177
178static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data, const QString &elementName,
179 const QQmlPrivate::RegisterCompositeType &type)
180{
181 auto *d = new QQmlTypePrivate(QQmlType::CompositeType);
182 data->registerType(priv: d);
183 d->setName(uri: QString::fromUtf8(str: type.uri), element: elementName);
184 d->version_maj = type.versionMajor;
185 d->version_min = type.versionMinor;
186
187 d->extraData.fd->url = QQmlTypeLoader::normalize(unNormalizedUrl: type.url);
188 return d;
189}
190
191static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data, const QString &elementName,
192 const QQmlPrivate::RegisterCompositeSingletonType &type)
193{
194 auto *d = new QQmlTypePrivate(QQmlType::CompositeSingletonType);
195 data->registerType(priv: d);
196 d->setName(uri: QString::fromUtf8(str: type.uri), element: elementName);
197
198 d->version_maj = type.versionMajor;
199 d->version_min = type.versionMinor;
200
201 d->extraData.sd->singletonInstanceInfo = new QQmlType::SingletonInstanceInfo;
202 d->extraData.sd->singletonInstanceInfo->url = QQmlTypeLoader::normalize(unNormalizedUrl: type.url);
203 d->extraData.sd->singletonInstanceInfo->typeName = QString::fromUtf8(str: type.typeName);
204 return d;
205}
206
207void QQmlMetaType::clone(QMetaObjectBuilder &builder, const QMetaObject *mo,
208 const QMetaObject *ignoreStart, const QMetaObject *ignoreEnd)
209{
210 // Set classname
211 builder.setClassName(ignoreEnd->className());
212
213 // Clone Q_CLASSINFO
214 for (int ii = mo->classInfoOffset(); ii < mo->classInfoCount(); ++ii) {
215 QMetaClassInfo info = mo->classInfo(index: ii);
216
217 int otherIndex = ignoreEnd->indexOfClassInfo(name: info.name());
218 if (otherIndex >= ignoreStart->classInfoOffset() + ignoreStart->classInfoCount()) {
219 // Skip
220 } else {
221 builder.addClassInfo(name: info.name(), value: info.value());
222 }
223 }
224
225 // Clone Q_PROPERTY
226 for (int ii = mo->propertyOffset(); ii < mo->propertyCount(); ++ii) {
227 QMetaProperty property = mo->property(index: ii);
228
229 int otherIndex = ignoreEnd->indexOfProperty(name: property.name());
230 if (otherIndex >= ignoreStart->propertyOffset() + ignoreStart->propertyCount()) {
231 builder.addProperty(name: QByteArray("__qml_ignore__") + property.name(), type: QByteArray("void"));
232 // Skip
233 } else {
234 builder.addProperty(prototype: property);
235 }
236 }
237
238 // Clone Q_METHODS
239 for (int ii = mo->methodOffset(); ii < mo->methodCount(); ++ii) {
240 QMetaMethod method = mo->method(index: ii);
241
242 // More complex - need to search name
243 QByteArray name = method.name();
244
245
246 bool found = false;
247
248 for (int ii = ignoreStart->methodOffset() + ignoreStart->methodCount();
249 !found && ii < ignoreEnd->methodOffset() + ignoreEnd->methodCount();
250 ++ii) {
251
252 QMetaMethod other = ignoreEnd->method(index: ii);
253
254 found = name == other.name();
255 }
256
257 QMetaMethodBuilder m = builder.addMethod(prototype: method);
258 if (found) // SKIP
259 m.setAccess(QMetaMethod::Private);
260 }
261
262 // Clone Q_ENUMS
263 for (int ii = mo->enumeratorOffset(); ii < mo->enumeratorCount(); ++ii) {
264 QMetaEnum enumerator = mo->enumerator(index: ii);
265
266 int otherIndex = ignoreEnd->indexOfEnumerator(name: enumerator.name());
267 if (otherIndex >= ignoreStart->enumeratorOffset() + ignoreStart->enumeratorCount()) {
268 // Skip
269 } else {
270 builder.addEnumerator(prototype: enumerator);
271 }
272 }
273}
274
275void QQmlMetaType::qmlInsertModuleRegistration(const QString &uri, int majorVersion,
276 void (*registerFunction)())
277{
278 const QQmlMetaTypeData::VersionedUri versionedUri(uri, majorVersion);
279 QQmlMetaTypeDataPtr data;
280 if (data->moduleTypeRegistrationFunctions.contains(akey: versionedUri))
281 qFatal(msg: "Cannot add multiple registrations for %s %d", qPrintable(uri), majorVersion);
282 else
283 data->moduleTypeRegistrationFunctions.insert(akey: versionedUri, avalue: registerFunction);
284}
285
286void QQmlMetaType::qmlRemoveModuleRegistration(const QString &uri, int majorVersion)
287{
288 const QQmlMetaTypeData::VersionedUri versionedUri(uri, majorVersion);
289 QQmlMetaTypeDataPtr data;
290
291 if (!data.isValid())
292 return; // shutdown/deletion race. Not a problem.
293
294 if (!data->moduleTypeRegistrationFunctions.contains(akey: versionedUri))
295 qFatal(msg: "Cannot remove multiple registrations for %s %d", qPrintable(uri), majorVersion);
296 else
297 data->moduleTypeRegistrationFunctions.remove(akey: versionedUri);
298}
299
300bool QQmlMetaType::qmlRegisterModuleTypes(const QString &uri, int majorVersion)
301{
302 QQmlMetaTypeDataPtr data;
303 return data->registerModuleTypes(versionedUri: QQmlMetaTypeData::VersionedUri(uri, majorVersion));
304}
305
306/*!
307 \internal
308 Method is only used to in tst_qqmlenginecleanup.cpp to test whether all
309 types have been removed from qmlLists after shutdown of QQmlEngine
310 */
311int QQmlMetaType::qmlRegisteredListTypeCount()
312{
313 QQmlMetaTypeDataPtr data;
314 return data->qmlLists.count();
315}
316
317void QQmlMetaType::clearTypeRegistrations()
318{
319 //Only cleans global static, assumed no running engine
320 QQmlMetaTypeDataPtr data;
321
322 for (QQmlMetaTypeData::TypeModules::const_iterator i = data->uriToModule.constBegin(), cend = data->uriToModule.constEnd(); i != cend; ++i)
323 delete *i;
324
325 data->types.clear();
326 data->idToType.clear();
327 data->nameToType.clear();
328 data->urlToType.clear();
329 data->typePropertyCaches.clear();
330 data->urlToNonFileImportType.clear();
331 data->metaObjectToType.clear();
332 data->uriToModule.clear();
333 data->undeletableTypes.clear();
334}
335
336int QQmlMetaType::registerAutoParentFunction(const QQmlPrivate::RegisterAutoParent &autoparent)
337{
338 QQmlMetaTypeDataPtr data;
339
340 data->parentFunctions.append(t: autoparent.function);
341
342 return data->parentFunctions.count() - 1;
343}
344
345void QQmlMetaType::unregisterAutoParentFunction(const QQmlPrivate::AutoParentFunction &function)
346{
347 QQmlMetaTypeDataPtr data;
348 data->parentFunctions.removeOne(t: function);
349}
350
351QQmlType QQmlMetaType::registerInterface(const QQmlPrivate::RegisterInterface &type)
352{
353 if (type.version > 1)
354 qFatal(msg: "qmlRegisterType(): Cannot mix incompatible QML versions.");
355
356 QQmlMetaTypeDataPtr data;
357 QQmlTypePrivate *priv = createQQmlType(data, type);
358 Q_ASSERT(priv);
359
360 data->idToType.insert(akey: priv->typeId, avalue: priv);
361 data->idToType.insert(akey: priv->listId, avalue: priv);
362
363 if (data->interfaces.size() <= type.typeId)
364 data->interfaces.resize(size: type.typeId + 16);
365 if (data->lists.size() <= type.listId)
366 data->lists.resize(size: type.listId + 16);
367 data->interfaces.setBit(i: type.typeId, val: true);
368 data->lists.setBit(i: type.listId, val: true);
369
370 return QQmlType(priv);
371}
372
373QString registrationTypeString(QQmlType::RegistrationType typeType)
374{
375 QString typeStr;
376 if (typeType == QQmlType::CppType)
377 typeStr = QStringLiteral("element");
378 else if (typeType == QQmlType::SingletonType)
379 typeStr = QStringLiteral("singleton type");
380 else if (typeType == QQmlType::CompositeSingletonType)
381 typeStr = QStringLiteral("composite singleton type");
382 else
383 typeStr = QStringLiteral("type");
384 return typeStr;
385}
386
387// NOTE: caller must hold a QMutexLocker on "data"
388bool checkRegistration(QQmlType::RegistrationType typeType, QQmlMetaTypeData *data,
389 const char *uri, const QString &typeName, int majorVersion)
390{
391 if (!typeName.isEmpty()) {
392 if (typeName.at(i: 0).isLower()) {
393 QString failure(QCoreApplication::translate(context: "qmlRegisterType", key: "Invalid QML %1 name \"%2\"; type names must begin with an uppercase letter"));
394 data->recordTypeRegFailure(message: failure.arg(a: registrationTypeString(typeType)).arg(a: typeName));
395 return false;
396 }
397
398 int typeNameLen = typeName.length();
399 for (int ii = 0; ii < typeNameLen; ++ii) {
400 if (!(typeName.at(i: ii).isLetterOrNumber() || typeName.at(i: ii) == '_')) {
401 QString failure(QCoreApplication::translate(context: "qmlRegisterType", key: "Invalid QML %1 name \"%2\""));
402 data->recordTypeRegFailure(message: failure.arg(a: registrationTypeString(typeType)).arg(a: typeName));
403 return false;
404 }
405 }
406 }
407
408 if (uri && !typeName.isEmpty()) {
409 QString nameSpace = QString::fromUtf8(str: uri);
410 QQmlMetaTypeData::VersionedUri versionedUri;
411 versionedUri.uri = nameSpace;
412 versionedUri.majorVersion = majorVersion;
413 if (QQmlTypeModule* qqtm = data->uriToModule.value(akey: versionedUri, adefaultValue: 0)){
414 if (qqtm->isLocked()){
415 QString failure(QCoreApplication::translate(context: "qmlRegisterType",
416 key: "Cannot install %1 '%2' into protected module '%3' version '%4'"));
417 data->recordTypeRegFailure(message: failure.arg(a: registrationTypeString(typeType)).arg(a: typeName).arg(a: nameSpace).arg(a: majorVersion));
418 return false;
419 }
420 }
421 }
422
423 return true;
424}
425
426// NOTE: caller must hold a QMutexLocker on "data"
427QQmlTypeModule *getTypeModule(const QHashedString &uri, int majorVersion, QQmlMetaTypeData *data)
428{
429 QQmlMetaTypeData::VersionedUri versionedUri(uri, majorVersion);
430 QQmlTypeModule *module = data->uriToModule.value(akey: versionedUri);
431 if (!module) {
432 module = new QQmlTypeModule(versionedUri.uri, versionedUri.majorVersion);
433 data->uriToModule.insert(akey: versionedUri, avalue: module);
434 }
435 return module;
436}
437
438// NOTE: caller must hold a QMutexLocker on "data"
439void addTypeToData(QQmlTypePrivate *type, QQmlMetaTypeData *data)
440{
441 Q_ASSERT(type);
442
443 if (!type->elementName.isEmpty())
444 data->nameToType.insert(akey: type->elementName, avalue: type);
445
446 if (type->baseMetaObject)
447 data->metaObjectToType.insert(akey: type->baseMetaObject, avalue: type);
448
449 if (type->typeId) {
450 data->idToType.insert(akey: type->typeId, avalue: type);
451 if (data->objects.size() <= type->typeId)
452 data->objects.resize(size: type->typeId + 16);
453 data->objects.setBit(i: type->typeId, val: true);
454 }
455
456 if (type->listId) {
457 if (data->lists.size() <= type->listId)
458 data->lists.resize(size: type->listId + 16);
459 data->lists.setBit(i: type->listId, val: true);
460 data->idToType.insert(akey: type->listId, avalue: type);
461 }
462
463 if (!type->module.isEmpty()) {
464 const QHashedString &mod = type->module;
465
466 QQmlTypeModule *module = getTypeModule(uri: mod, majorVersion: type->version_maj, data);
467 Q_ASSERT(module);
468 module->add(type);
469 }
470}
471
472QQmlType QQmlMetaType::registerType(const QQmlPrivate::RegisterType &type)
473{
474 QQmlMetaTypeDataPtr data;
475
476 QString elementName = QString::fromUtf8(str: type.elementName);
477 if (!checkRegistration(typeType: QQmlType::CppType, data, uri: type.uri, typeName: elementName, majorVersion: type.versionMajor))
478 return QQmlType();
479
480 QQmlTypePrivate *priv = createQQmlType(data, elementName, type);
481
482 addTypeToData(type: priv, data);
483 if (!type.typeId)
484 data->idToType.insert(akey: priv->typeId, avalue: priv);
485
486 return QQmlType(priv);
487}
488
489QQmlType QQmlMetaType::registerSingletonType(const QQmlPrivate::RegisterSingletonType &type)
490{
491 QQmlMetaTypeDataPtr data;
492
493 QString typeName = QString::fromUtf8(str: type.typeName);
494 if (!checkRegistration(typeType: QQmlType::SingletonType, data, uri: type.uri, typeName, majorVersion: type.versionMajor))
495 return QQmlType();
496
497 QQmlTypePrivate *priv = createQQmlType(data, elementName: typeName, type);
498
499 addTypeToData(type: priv, data);
500
501 return QQmlType(priv);
502}
503
504QQmlType QQmlMetaType::registerCompositeSingletonType(const QQmlPrivate::RegisterCompositeSingletonType &type)
505{
506 // Assumes URL is absolute and valid. Checking of user input should happen before the URL enters type.
507 QQmlMetaTypeDataPtr data;
508
509 QString typeName = QString::fromUtf8(str: type.typeName);
510 bool fileImport = false;
511 if (*(type.uri) == '\0')
512 fileImport = true;
513 if (!checkRegistration(typeType: QQmlType::CompositeSingletonType, data, uri: fileImport ? nullptr : type.uri,
514 typeName, majorVersion: type.versionMajor)) {
515 return QQmlType();
516 }
517
518 QQmlTypePrivate *priv = createQQmlType(data, elementName: typeName, type);
519 addTypeToData(type: priv, data);
520
521 QQmlMetaTypeData::Files *files = fileImport ? &(data->urlToType) : &(data->urlToNonFileImportType);
522 files->insert(akey: QQmlTypeLoader::normalize(unNormalizedUrl: type.url), avalue: priv);
523
524 return QQmlType(priv);
525}
526
527QQmlType QQmlMetaType::registerCompositeType(const QQmlPrivate::RegisterCompositeType &type)
528{
529 // Assumes URL is absolute and valid. Checking of user input should happen before the URL enters type.
530 QQmlMetaTypeDataPtr data;
531
532 QString typeName = QString::fromUtf8(str: type.typeName);
533 bool fileImport = false;
534 if (*(type.uri) == '\0')
535 fileImport = true;
536 if (!checkRegistration(typeType: QQmlType::CompositeType, data, uri: fileImport?nullptr:type.uri, typeName, majorVersion: type.versionMajor))
537 return QQmlType();
538
539 QQmlTypePrivate *priv = createQQmlType(data, elementName: typeName, type);
540 addTypeToData(type: priv, data);
541
542 QQmlMetaTypeData::Files *files = fileImport ? &(data->urlToType) : &(data->urlToNonFileImportType);
543 files->insert(akey: QQmlTypeLoader::normalize(unNormalizedUrl: type.url), avalue: priv);
544
545 return QQmlType(priv);
546}
547
548CompositeMetaTypeIds QQmlMetaType::registerInternalCompositeType(const QByteArray &className)
549{
550 QByteArray ptr = className + '*';
551 QByteArray lst = "QQmlListProperty<" + className + '>';
552
553 int ptr_type = QMetaType::registerNormalizedType(normalizedTypeName: ptr,
554 destructor: QtMetaTypePrivate::QMetaTypeFunctionHelper<QObject*>::Destruct,
555 constructor: QtMetaTypePrivate::QMetaTypeFunctionHelper<QObject*>::Construct,
556 size: sizeof(QObject*),
557 flags: static_cast<QFlags<QMetaType::TypeFlag> >(QtPrivate::QMetaTypeTypeFlags<QObject*>::Flags),
558 metaObject: nullptr);
559 int lst_type = QMetaType::registerNormalizedType(normalizedTypeName: lst,
560 destructor: QtMetaTypePrivate::QMetaTypeFunctionHelper<QQmlListProperty<QObject> >::Destruct,
561 constructor: QtMetaTypePrivate::QMetaTypeFunctionHelper<QQmlListProperty<QObject> >::Construct,
562 size: sizeof(QQmlListProperty<QObject>),
563 flags: static_cast<QFlags<QMetaType::TypeFlag> >(QtPrivate::QMetaTypeTypeFlags<QQmlListProperty<QObject> >::Flags),
564 metaObject: static_cast<QMetaObject*>(nullptr));
565
566 QQmlMetaTypeDataPtr data;
567 data->qmlLists.insert(akey: lst_type, avalue: ptr_type);
568
569 return {ptr_type, lst_type};
570}
571
572void QQmlMetaType::unregisterInternalCompositeType(const CompositeMetaTypeIds &typeIds)
573{
574 QQmlMetaTypeDataPtr data;
575 data->qmlLists.remove(akey: typeIds.listId);
576
577 QMetaType::unregisterType(type: typeIds.id);
578 QMetaType::unregisterType(type: typeIds.listId);
579}
580
581int QQmlMetaType::registerUnitCacheHook(
582 const QQmlPrivate::RegisterQmlUnitCacheHook &hookRegistration)
583{
584 if (hookRegistration.version > 0)
585 qFatal(msg: "qmlRegisterType(): Cannot mix incompatible QML versions.");
586
587 QQmlMetaTypeDataPtr data;
588 data->lookupCachedQmlUnit << hookRegistration.lookupCachedQmlUnit;
589 return 0;
590}
591
592bool QQmlMetaType::protectModule(const QString &uri, int majVersion)
593{
594 QQmlMetaTypeDataPtr data;
595
596 QQmlMetaTypeData::VersionedUri versionedUri;
597 versionedUri.uri = uri;
598 versionedUri.majorVersion = majVersion;
599
600 if (QQmlTypeModule* qqtm = data->uriToModule.value(akey: versionedUri, adefaultValue: 0)) {
601 qqtm->lock();
602 return true;
603 }
604 return false;
605}
606
607void QQmlMetaType::registerModule(const char *uri, int versionMajor, int versionMinor)
608{
609 QQmlMetaTypeDataPtr data;
610
611 QQmlTypeModule *module = getTypeModule(uri: QString::fromUtf8(str: uri), majorVersion: versionMajor, data);
612 Q_ASSERT(module);
613
614 module->addMinorVersion(minorVersion: versionMinor);
615}
616
617int QQmlMetaType::typeId(const char *uri, int versionMajor, int versionMinor, const char *qmlName)
618{
619 QQmlMetaTypeDataPtr data;
620
621 QQmlTypeModule *module = getTypeModule(uri: QString::fromUtf8(str: uri), majorVersion: versionMajor, data);
622 if (!module)
623 return -1;
624
625 QQmlType type = module->type(QHashedStringRef(QString::fromUtf8(str: qmlName)), versionMinor);
626 if (!type.isValid())
627 return -1;
628
629 return type.index();
630}
631
632void QQmlMetaType::registerUndeletableType(const QQmlType &dtype)
633{
634 QQmlMetaTypeDataPtr data;
635 data->undeletableTypes.insert(value: dtype);
636}
637
638static bool namespaceContainsRegistrations(const QQmlMetaTypeData *data, const QString &uri,
639 int majorVersion)
640{
641 // Has any type previously been installed to this namespace?
642 QHashedString nameSpace(uri);
643 for (const QQmlType &type : data->types) {
644 if (type.module() == nameSpace && type.majorVersion() == majorVersion)
645 return true;
646 }
647
648 return false;
649}
650
651class QQmlMetaTypeRegistrationFailureRecorder
652{
653 Q_DISABLE_COPY_MOVE(QQmlMetaTypeRegistrationFailureRecorder)
654public:
655 QQmlMetaTypeRegistrationFailureRecorder(QQmlMetaTypeData *data, QStringList *failures)
656 : data(data)
657 {
658 data->setTypeRegistrationFailures(failures);
659 }
660
661 ~QQmlMetaTypeRegistrationFailureRecorder()
662 {
663 data->setTypeRegistrationFailures(nullptr);
664 }
665
666 QQmlMetaTypeData *data = nullptr;
667};
668
669
670bool QQmlMetaType::registerPluginTypes(QObject *instance, const QString &basePath,
671 const QString &uri, const QString &typeNamespace, int vmaj,
672 QList<QQmlError> *errors)
673{
674 if (!typeNamespace.isEmpty() && typeNamespace != uri) {
675 // This is an 'identified' module
676 // The namespace for type registrations must match the URI for locating the module
677 if (errors) {
678 QQmlError error;
679 error.setDescription(
680 QStringLiteral("Module namespace '%1' does not match import URI '%2'")
681 .arg(a: typeNamespace).arg(a: uri));
682 errors->prepend(t: error);
683 }
684 return false;
685 }
686
687 QStringList failures;
688 QQmlMetaTypeDataPtr data;
689 {
690 QQmlMetaTypeRegistrationFailureRecorder failureRecorder(data, &failures);
691 if (!typeNamespace.isEmpty()) {
692 // This is an 'identified' module
693 if (namespaceContainsRegistrations(data, uri: typeNamespace, majorVersion: vmaj)) {
694 // Other modules have already installed to this namespace
695 if (errors) {
696 QQmlError error;
697 error.setDescription(QStringLiteral("Namespace '%1' has already been used "
698 "for type registration")
699 .arg(a: typeNamespace));
700 errors->prepend(t: error);
701 }
702 return false;
703 }
704 } else {
705 // This is not an identified module - provide a warning
706 qWarning().nospace() << qPrintable(
707 QStringLiteral("Module '%1' does not contain a module identifier directive - "
708 "it cannot be protected from external registrations.").arg(uri));
709 }
710
711 if (!qobject_cast<QQmlEngineExtensionInterface *>(object: instance)) {
712 QQmlTypesExtensionInterface *iface = qobject_cast<QQmlTypesExtensionInterface *>(object: instance);
713 if (!iface) {
714 if (errors) {
715 QQmlError error;
716 // Also does not implement QQmlTypesExtensionInterface, but we want to discourage that.
717 error.setDescription(QStringLiteral("Module loaded for URI '%1' does not implement "
718 "QQmlEngineExtensionInterface").arg(a: typeNamespace));
719 errors->prepend(t: error);
720 }
721 return false;
722 }
723
724 if (auto *plugin = qobject_cast<QQmlExtensionPlugin *>(object: instance)) {
725 // basepath should point to the directory of the module, not the plugin file itself:
726 QQmlExtensionPluginPrivate::get(e: plugin)->baseUrl
727 = QQmlImports::urlFromLocalFileOrQrcOrUrl(basePath);
728 }
729
730 const QByteArray bytes = uri.toUtf8();
731 const char *moduleId = bytes.constData();
732 iface->registerTypes(uri: moduleId);
733 }
734
735 data->registerModuleTypes(versionedUri: QQmlMetaTypeData::VersionedUri(uri, vmaj));
736
737 if (!failures.isEmpty()) {
738 if (errors) {
739 for (const QString &failure : qAsConst(t&: failures)) {
740 QQmlError error;
741 error.setDescription(failure);
742 errors->prepend(t: error);
743 }
744 }
745 return false;
746 }
747 }
748
749 return true;
750}
751
752/*
753 \internal
754
755 Fetches the QQmlType instance registered for \a urlString, creating a
756 registration for it if it is not already registered, using the associated
757 \a typeName, \a isCompositeSingleton, \a majorVersion and \a minorVersion
758 details.
759
760 Errors (if there are any) are placed into \a errors, if it is nonzero.
761 Otherwise errors are printed as warnings.
762*/
763QQmlType QQmlMetaType::typeForUrl(const QString &urlString,
764 const QHashedStringRef &qualifiedType,
765 bool isCompositeSingleton, QList<QQmlError> *errors,
766 int majorVersion, int minorVersion)
767{
768 // ### unfortunate (costly) conversion
769 const QUrl url = QQmlTypeLoader::normalize(unNormalizedUrl: QUrl(urlString));
770
771 QQmlMetaTypeDataPtr data;
772 {
773 QQmlType ret(data->urlToType.value(akey: url));
774 if (ret.isValid() && ret.sourceUrl() == url)
775 return ret;
776 }
777 {
778 QQmlType ret(data->urlToNonFileImportType.value(akey: url));
779 if (ret.isValid() && ret.sourceUrl() == url)
780 return ret;
781 }
782
783 const int dot = qualifiedType.indexOf(QLatin1Char('.'));
784 const QString typeName = dot < 0
785 ? qualifiedType.toString()
786 : QString(qualifiedType.constData() + dot + 1, qualifiedType.length() - dot - 1);
787
788 QStringList failures;
789 QQmlMetaTypeRegistrationFailureRecorder failureRecorder(data, &failures);
790
791 // Register the type. Note that the URI parameters here are empty; for
792 // file type imports, we do not place them in a URI as we don't
793 // necessarily have a good and unique one (picture a library import,
794 // which may be found in multiple plugin locations on disk), but there
795 // are other reasons for this too.
796 //
797 // By not putting them in a URI, we prevent the types from being
798 // registered on a QQmlTypeModule; this is important, as once types are
799 // placed on there, they cannot be easily removed, meaning if the
800 // developer subsequently loads a different import (meaning different
801 // types) with the same URI (using, say, a different plugin path), it is
802 // very undesirable that we continue to associate the types from the
803 // "old" URI with that new module.
804 //
805 // Not having URIs also means that the types cannot be found by name
806 // etc, the only way to look them up is through QQmlImports -- for
807 // better or worse.
808 const QQmlType::RegistrationType registrationType = isCompositeSingleton
809 ? QQmlType::CompositeSingletonType
810 : QQmlType::CompositeType;
811 if (checkRegistration(typeType: registrationType, data, uri: nullptr, typeName, majorVersion)) {
812 auto *priv = new QQmlTypePrivate(registrationType);
813 priv->setName(uri: QString(), element: typeName);
814 priv->version_maj = majorVersion;
815 priv->version_min = minorVersion;
816
817 if (isCompositeSingleton) {
818 priv->extraData.sd->singletonInstanceInfo = new QQmlType::SingletonInstanceInfo;
819 priv->extraData.sd->singletonInstanceInfo->url = url;
820 priv->extraData.sd->singletonInstanceInfo->typeName = typeName;
821 } else {
822 priv->extraData.fd->url = url;
823 }
824
825 data->registerType(priv);
826 addTypeToData(type: priv, data);
827 data->urlToType.insert(akey: url, avalue: priv);
828 return QQmlType(priv);
829 }
830
831 // This means that the type couldn't be found by URL, but could not be
832 // registered either, meaning we most likely were passed some kind of bad
833 // data.
834 if (errors) {
835 QQmlError error;
836 error.setDescription(failures.join(sep: '\n'));
837 errors->prepend(t: error);
838 } else {
839 qWarning(msg: "%s", failures.join(sep: '\n').toLatin1().constData());
840 }
841 return QQmlType();
842}
843
844QRecursiveMutex *QQmlMetaType::typeRegistrationLock()
845{
846 return metaTypeDataLock();
847}
848
849/*
850 Returns true if a module \a uri of any version is installed.
851*/
852bool QQmlMetaType::isAnyModule(const QString &uri)
853{
854 QQmlMetaTypeDataPtr data;
855
856 for (QQmlMetaTypeData::TypeModules::ConstIterator iter = data->uriToModule.cbegin();
857 iter != data->uriToModule.cend(); ++iter) {
858 if ((*iter)->module() == uri)
859 return true;
860 }
861
862 return false;
863}
864
865/*
866 Returns true if a module \a uri of this version is installed and locked;
867*/
868bool QQmlMetaType::isLockedModule(const QString &uri, int majVersion)
869{
870 QQmlMetaTypeDataPtr data;
871
872 QQmlMetaTypeData::VersionedUri versionedUri;
873 versionedUri.uri = uri;
874 versionedUri.majorVersion = majVersion;
875 if (QQmlTypeModule* qqtm = data->uriToModule.value(akey: versionedUri, adefaultValue: 0))
876 return qqtm->isLocked();
877 return false;
878}
879
880/*
881 Returns true if any type or API has been registered for the given \a module with at least
882 versionMajor.versionMinor, or if types have been registered for \a module with at most
883 versionMajor.versionMinor.
884
885 So if only 4.7 and 4.9 have been registered, 4.7,4.8, and 4.9 are valid, but not 4.6 nor 4.10.
886*/
887bool QQmlMetaType::isModule(const QString &module, int versionMajor, int versionMinor)
888{
889 Q_ASSERT(versionMajor >= 0 && versionMinor >= 0);
890 QQmlMetaTypeDataPtr data;
891
892 // first, check Types
893 QQmlTypeModule *tm =
894 data->uriToModule.value(akey: QQmlMetaTypeData::VersionedUri(module, versionMajor));
895 if (tm && tm->minimumMinorVersion() <= versionMinor && tm->maximumMinorVersion() >= versionMinor)
896 return true;
897
898 return false;
899}
900
901QQmlTypeModule *QQmlMetaType::typeModule(const QString &uri, int majorVersion)
902{
903 QQmlMetaTypeDataPtr data;
904 return data->uriToModule.value(akey: QQmlMetaTypeData::VersionedUri(uri, majorVersion));
905}
906
907QList<QQmlPrivate::AutoParentFunction> QQmlMetaType::parentFunctions()
908{
909 QQmlMetaTypeDataPtr data;
910 return data->parentFunctions;
911}
912
913QObject *QQmlMetaType::toQObject(const QVariant &v, bool *ok)
914{
915 if (!isQObject(v.userType())) {
916 if (ok) *ok = false;
917 return nullptr;
918 }
919
920 if (ok) *ok = true;
921
922 return *(QObject *const *)v.constData();
923}
924
925bool QQmlMetaType::isQObject(int userType)
926{
927 if (userType == QMetaType::QObjectStar)
928 return true;
929
930 QQmlMetaTypeDataPtr data;
931 return userType >= 0 && userType < data->objects.size() && data->objects.testBit(i: userType);
932}
933
934/*
935 Returns the item type for a list of type \a id.
936 */
937int QQmlMetaType::listType(int id)
938{
939 QQmlMetaTypeDataPtr data;
940 QHash<int, int>::ConstIterator iter = data->qmlLists.constFind(akey: id);
941 if (iter != data->qmlLists.cend())
942 return *iter;
943 QQmlTypePrivate *type = data->idToType.value(akey: id);
944 if (type && type->listId == id)
945 return type->typeId;
946 else
947 return 0;
948}
949
950#if QT_DEPRECATED_SINCE(5, 14)
951int QQmlMetaType::attachedPropertiesFuncId(QQmlEnginePrivate *engine, const QMetaObject *mo)
952{
953 QQmlMetaTypeDataPtr data;
954
955 for (auto it = data->metaObjectToType.constFind(akey: mo), end = data->metaObjectToType.constEnd();
956 it != end && it.key() == mo; ++it) {
957 if (const QQmlTypePrivate *type = it.value()) {
958 if (const QQmlTypePrivate *base = type->attachedPropertiesBase(engine))
959 return base->index;
960 }
961 }
962 return -1;
963}
964
965QQmlAttachedPropertiesFunc QQmlMetaType::attachedPropertiesFuncById(QQmlEnginePrivate *engine, int id)
966{
967 if (id < 0)
968 return nullptr;
969 QQmlMetaTypeDataPtr data;
970 return data->types.at(i: id).attachedPropertiesFunction(engine);
971}
972#endif
973
974QQmlAttachedPropertiesFunc QQmlMetaType::attachedPropertiesFunc(QQmlEnginePrivate *engine,
975 const QMetaObject *mo)
976{
977 QQmlMetaTypeDataPtr data;
978
979 QQmlType type(data->metaObjectToType.value(akey: mo));
980 return type.attachedPropertiesFunction(engine);
981}
982
983QMetaProperty QQmlMetaType::defaultProperty(const QMetaObject *metaObject)
984{
985 int idx = metaObject->indexOfClassInfo(name: "DefaultProperty");
986 if (-1 == idx)
987 return QMetaProperty();
988
989 QMetaClassInfo info = metaObject->classInfo(index: idx);
990 if (!info.value())
991 return QMetaProperty();
992
993 idx = metaObject->indexOfProperty(name: info.value());
994 if (-1 == idx)
995 return QMetaProperty();
996
997 return metaObject->property(index: idx);
998}
999
1000QMetaProperty QQmlMetaType::defaultProperty(QObject *obj)
1001{
1002 if (!obj)
1003 return QMetaProperty();
1004
1005 const QMetaObject *metaObject = obj->metaObject();
1006 return defaultProperty(metaObject);
1007}
1008
1009QMetaMethod QQmlMetaType::defaultMethod(const QMetaObject *metaObject)
1010{
1011 int idx = metaObject->indexOfClassInfo(name: "DefaultMethod");
1012 if (-1 == idx)
1013 return QMetaMethod();
1014
1015 QMetaClassInfo info = metaObject->classInfo(index: idx);
1016 if (!info.value())
1017 return QMetaMethod();
1018
1019 idx = metaObject->indexOfMethod(method: info.value());
1020 if (-1 == idx)
1021 return QMetaMethod();
1022
1023 return metaObject->method(index: idx);
1024}
1025
1026QMetaMethod QQmlMetaType::defaultMethod(QObject *obj)
1027{
1028 if (!obj)
1029 return QMetaMethod();
1030
1031 const QMetaObject *metaObject = obj->metaObject();
1032 return defaultMethod(metaObject);
1033}
1034
1035QQmlMetaType::TypeCategory QQmlMetaType::typeCategory(int userType)
1036{
1037 if (userType < 0)
1038 return Unknown;
1039 if (userType == QMetaType::QObjectStar)
1040 return Object;
1041
1042 QQmlMetaTypeDataPtr data;
1043 if (data->qmlLists.contains(akey: userType))
1044 return List;
1045 else if (userType < data->objects.size() && data->objects.testBit(i: userType))
1046 return Object;
1047 else if (userType < data->lists.size() && data->lists.testBit(i: userType))
1048 return List;
1049 else
1050 return Unknown;
1051}
1052
1053/*!
1054 See qmlRegisterInterface() for information about when this will return true.
1055*/
1056bool QQmlMetaType::isInterface(int userType)
1057{
1058 const QQmlMetaTypeDataPtr data;
1059 return userType >= 0 && userType < data->interfaces.size() && data->interfaces.testBit(i: userType);
1060}
1061
1062const char *QQmlMetaType::interfaceIId(int userType)
1063{
1064
1065 QQmlTypePrivate *typePrivate = nullptr;
1066 {
1067 QQmlMetaTypeDataPtr data;
1068 typePrivate = data->idToType.value(akey: userType);
1069 }
1070
1071 QQmlType type(typePrivate);
1072 if (type.isInterface() && type.typeId() == userType)
1073 return type.interfaceIId();
1074 else
1075 return nullptr;
1076}
1077
1078bool QQmlMetaType::isList(int userType)
1079{
1080 const QQmlMetaTypeDataPtr data;
1081 if (data->qmlLists.contains(akey: userType))
1082 return true;
1083 return userType >= 0 && userType < data->lists.size() && data->lists.testBit(i: userType);
1084}
1085
1086/*!
1087 A custom string convertor allows you to specify a function pointer that
1088 returns a variant of \a type. For example, if you have written your own icon
1089 class that you want to support as an object property assignable in QML:
1090
1091 \code
1092 int type = qRegisterMetaType<SuperIcon>("SuperIcon");
1093 QML::addCustomStringConvertor(type, &SuperIcon::pixmapFromString);
1094 \endcode
1095
1096 The function pointer must be of the form:
1097 \code
1098 QVariant (*StringConverter)(const QString &);
1099 \endcode
1100 */
1101void QQmlMetaType::registerCustomStringConverter(int type, StringConverter converter)
1102{
1103 QQmlMetaTypeDataPtr data;
1104 if (data->stringConverters.contains(akey: type))
1105 return;
1106 data->stringConverters.insert(akey: type, avalue: converter);
1107}
1108
1109/*!
1110 Return the custom string converter for \a type, previously installed through
1111 registerCustomStringConverter()
1112 */
1113QQmlMetaType::StringConverter QQmlMetaType::customStringConverter(int type)
1114{
1115 const QQmlMetaTypeDataPtr data;
1116 return data->stringConverters.value(akey: type);
1117}
1118
1119/*!
1120 Returns the type (if any) of URI-qualified named \a qualifiedName and version specified
1121 by \a version_major and \a version_minor.
1122*/
1123QQmlType QQmlMetaType::qmlType(const QString &qualifiedName, int version_major, int version_minor)
1124{
1125 int slash = qualifiedName.indexOf(c: QLatin1Char('/'));
1126 if (slash <= 0)
1127 return QQmlType();
1128
1129 QHashedStringRef module(qualifiedName.constData(), slash);
1130 QHashedStringRef name(qualifiedName.constData() + slash + 1, qualifiedName.length() - slash - 1);
1131
1132 return qmlType(name, module, version_major, version_minor);
1133}
1134
1135/*!
1136 Returns the type (if any) of \a name in \a module and version specified
1137 by \a version_major and \a version_minor.
1138*/
1139QQmlType QQmlMetaType::qmlType(const QHashedStringRef &name, const QHashedStringRef &module, int version_major, int version_minor)
1140{
1141 Q_ASSERT(version_major >= 0 && version_minor >= 0);
1142 const QQmlMetaTypeDataPtr data;
1143
1144 QQmlMetaTypeData::Names::ConstIterator it = data->nameToType.constFind(akey: name);
1145 while (it != data->nameToType.cend() && it.key() == name) {
1146 QQmlType t(*it);
1147 // XXX version_major<0 just a kludge for QQmlPropertyPrivate::initProperty
1148 if (version_major < 0 || module.isEmpty() || t.availableInVersion(module, vmajor: version_major,vminor: version_minor))
1149 return t;
1150 ++it;
1151 }
1152
1153 return QQmlType();
1154}
1155
1156/*!
1157 Returns the type (if any) that corresponds to the \a metaObject. Returns null if no
1158 type is registered.
1159*/
1160QQmlType QQmlMetaType::qmlType(const QMetaObject *metaObject)
1161{
1162 const QQmlMetaTypeDataPtr data;
1163 return QQmlType(data->metaObjectToType.value(akey: metaObject));
1164}
1165
1166/*!
1167 Returns the type (if any) that corresponds to the \a metaObject in version specified
1168 by \a version_major and \a version_minor in module specified by \a uri. Returns null if no
1169 type is registered.
1170*/
1171QQmlType QQmlMetaType::qmlType(const QMetaObject *metaObject, const QHashedStringRef &module, int version_major, int version_minor)
1172{
1173 Q_ASSERT(version_major >= 0 && version_minor >= 0);
1174 const QQmlMetaTypeDataPtr data;
1175
1176 QQmlMetaTypeData::MetaObjects::const_iterator it = data->metaObjectToType.constFind(akey: metaObject);
1177 while (it != data->metaObjectToType.cend() && it.key() == metaObject) {
1178 QQmlType t(*it);
1179 if (version_major < 0 || module.isEmpty() || t.availableInVersion(module, vmajor: version_major,vminor: version_minor))
1180 return t;
1181 ++it;
1182 }
1183
1184 return QQmlType();
1185}
1186
1187/*!
1188 Returns the type (if any) that corresponds to \a typeId. Depending on \a category, the
1189 \a typeId is interpreted either as QVariant::Type or as QML type id returned by one of the
1190 qml type registration functions. Returns null if no type is registered.
1191*/
1192QQmlType QQmlMetaType::qmlType(int typeId, TypeIdCategory category)
1193{
1194 const QQmlMetaTypeDataPtr data;
1195
1196 if (category == TypeIdCategory::MetaType) {
1197 QQmlTypePrivate *type = data->idToType.value(akey: typeId);
1198 if (type && type->typeId == typeId)
1199 return QQmlType(type);
1200 } else if (category == TypeIdCategory::QmlType) {
1201 QQmlType type = data->types.value(i: typeId);
1202 if (type.isValid())
1203 return type;
1204 }
1205 return QQmlType();
1206}
1207
1208/*!
1209 Returns the type (if any) that corresponds to the given \a url in the set of
1210 composite types added through file imports.
1211
1212 Returns null if no such type is registered.
1213*/
1214QQmlType QQmlMetaType::qmlType(const QUrl &unNormalizedUrl, bool includeNonFileImports /* = false */)
1215{
1216 const QUrl url = QQmlTypeLoader::normalize(unNormalizedUrl);
1217 const QQmlMetaTypeDataPtr data;
1218
1219 QQmlType type(data->urlToType.value(akey: url));
1220 if (!type.isValid() && includeNonFileImports)
1221 type = QQmlType(data->urlToNonFileImportType.value(akey: url));
1222
1223 if (type.sourceUrl() == url)
1224 return type;
1225 else
1226 return QQmlType();
1227}
1228
1229QQmlPropertyCache *QQmlMetaType::propertyCache(const QMetaObject *metaObject, int minorVersion, bool doRef)
1230{
1231 QQmlMetaTypeDataPtr data; // not const: the cache is created on demand
1232 auto ret = data->propertyCache(metaObject, minorVersion);
1233 if (doRef)
1234 return ret.take();
1235 else
1236 return ret.data();
1237}
1238
1239QQmlPropertyCache *QQmlMetaType::propertyCache(const QQmlType &type, int minorVersion)
1240{
1241 QQmlMetaTypeDataPtr data; // not const: the cache is created on demand
1242 return data->propertyCache(type, minorVersion);
1243}
1244
1245void QQmlMetaType::unregisterType(int typeIndex)
1246{
1247 QQmlMetaTypeDataPtr data;
1248 const QQmlType type = data->types.value(i: typeIndex);
1249 if (const QQmlTypePrivate *d = type.priv()) {
1250 removeQQmlTypePrivate(container&: data->idToType, reference: d);
1251 removeQQmlTypePrivate(container&: data->nameToType, reference: d);
1252 removeQQmlTypePrivate(container&: data->urlToType, reference: d);
1253 removeQQmlTypePrivate(container&: data->urlToNonFileImportType, reference: d);
1254 removeQQmlTypePrivate(container&: data->metaObjectToType, reference: d);
1255 for (auto & module : data->uriToModule)
1256 module->remove(type: d);
1257 data->clearPropertyCachesForMinorVersion(index: typeIndex);
1258 data->types[typeIndex] = QQmlType();
1259 data->undeletableTypes.remove(value: type);
1260 }
1261}
1262
1263static bool hasActiveInlineComponents(const QQmlTypePrivate *d)
1264{
1265 for (const QQmlType &ic : qAsConst(t&: d->objectIdToICType)) {
1266 const QQmlTypePrivate *icPriv = ic.priv();
1267 if (icPriv && icPriv->count() > 1)
1268 return true;
1269 }
1270 return false;
1271}
1272
1273void QQmlMetaType::freeUnusedTypesAndCaches()
1274{
1275 QQmlMetaTypeDataPtr data;
1276
1277 // in case this is being called during program exit, `data` might be destructed already
1278 if (!data.isValid())
1279 return;
1280
1281 bool deletedAtLeastOneType;
1282 do {
1283 deletedAtLeastOneType = false;
1284 QList<QQmlType>::Iterator it = data->types.begin();
1285 while (it != data->types.end()) {
1286 const QQmlTypePrivate *d = (*it).priv();
1287 if (d && d->count() == 1 && !hasActiveInlineComponents(d)) {
1288 deletedAtLeastOneType = true;
1289
1290 removeQQmlTypePrivate(container&: data->idToType, reference: d);
1291 removeQQmlTypePrivate(container&: data->nameToType, reference: d);
1292 removeQQmlTypePrivate(container&: data->urlToType, reference: d);
1293 removeQQmlTypePrivate(container&: data->urlToNonFileImportType, reference: d);
1294 removeQQmlTypePrivate(container&: data->metaObjectToType, reference: d);
1295
1296 for (auto &module : data->uriToModule)
1297 module->remove(type: d);
1298
1299 data->clearPropertyCachesForMinorVersion(index: d->index);
1300 *it = QQmlType();
1301 } else {
1302 ++it;
1303 }
1304 }
1305 } while (deletedAtLeastOneType);
1306
1307 bool deletedAtLeastOneCache;
1308 do {
1309 deletedAtLeastOneCache = false;
1310 QHash<const QMetaObject *, QQmlPropertyCache *>::Iterator it = data->propertyCaches.begin();
1311 while (it != data->propertyCaches.end()) {
1312
1313 if ((*it)->count() == 1) {
1314 QQmlPropertyCache *pc = nullptr;
1315 qSwap(value1&: pc, value2&: *it);
1316 it = data->propertyCaches.erase(it);
1317 pc->release();
1318 deletedAtLeastOneCache = true;
1319 } else {
1320 ++it;
1321 }
1322 }
1323 } while (deletedAtLeastOneCache);
1324}
1325
1326/*!
1327 Returns the list of registered QML type names.
1328*/
1329QList<QString> QQmlMetaType::qmlTypeNames()
1330{
1331 const QQmlMetaTypeDataPtr data;
1332
1333 QList<QString> names;
1334 names.reserve(alloc: data->nameToType.count());
1335 QQmlMetaTypeData::Names::ConstIterator it = data->nameToType.cbegin();
1336 while (it != data->nameToType.cend()) {
1337 QQmlType t(*it);
1338 names += t.qmlTypeName();
1339 ++it;
1340 }
1341
1342 return names;
1343}
1344
1345/*!
1346 Returns the list of registered QML types.
1347*/
1348QList<QQmlType> QQmlMetaType::qmlTypes()
1349{
1350 const QQmlMetaTypeDataPtr data;
1351
1352 QList<QQmlType> types;
1353 for (QQmlTypePrivate *t : data->nameToType)
1354 types.append(t: QQmlType(t));
1355
1356 return types;
1357}
1358
1359/*!
1360 Returns the list of all registered types.
1361*/
1362QList<QQmlType> QQmlMetaType::qmlAllTypes()
1363{
1364 const QQmlMetaTypeDataPtr data;
1365 return data->types;
1366}
1367
1368/*!
1369 Returns the list of registered QML singleton types.
1370*/
1371QList<QQmlType> QQmlMetaType::qmlSingletonTypes()
1372{
1373 const QQmlMetaTypeDataPtr data;
1374
1375 QList<QQmlType> retn;
1376 for (const auto t : qAsConst(t: data->nameToType)) {
1377 QQmlType type(t);
1378 if (type.isSingleton())
1379 retn.append(t: type);
1380 }
1381 return retn;
1382}
1383
1384const QV4::CompiledData::Unit *QQmlMetaType::findCachedCompilationUnit(const QUrl &uri, CachedUnitLookupError *status)
1385{
1386 const QQmlMetaTypeDataPtr data;
1387
1388 for (const auto lookup : qAsConst(t: data->lookupCachedQmlUnit)) {
1389 if (const QQmlPrivate::CachedQmlUnit *unit = lookup(uri)) {
1390 QString error;
1391 if (!QV4::ExecutableCompilationUnit::verifyHeader(unit: unit->qmlData, expectedSourceTimeStamp: QDateTime(), errorString: &error)) {
1392 qCDebug(DBG_DISK_CACHE) << "Error loading pre-compiled file " << uri << ":" << error;
1393 if (status)
1394 *status = CachedUnitLookupError::VersionMismatch;
1395 return nullptr;
1396 }
1397 if (status)
1398 *status = CachedUnitLookupError::NoError;
1399 return unit->qmlData;
1400 }
1401 }
1402
1403 if (status)
1404 *status = CachedUnitLookupError::NoUnitFound;
1405
1406 return nullptr;
1407}
1408
1409void QQmlMetaType::prependCachedUnitLookupFunction(QQmlPrivate::QmlUnitCacheLookupFunction handler)
1410{
1411 QQmlMetaTypeDataPtr data;
1412 data->lookupCachedQmlUnit.prepend(t: handler);
1413}
1414
1415void QQmlMetaType::removeCachedUnitLookupFunction(QQmlPrivate::QmlUnitCacheLookupFunction handler)
1416{
1417 QQmlMetaTypeDataPtr data;
1418 data->lookupCachedQmlUnit.removeAll(t: handler);
1419}
1420
1421/*!
1422 Returns the pretty QML type name (e.g. 'Item' instead of 'QtQuickItem') for the given object.
1423 */
1424QString QQmlMetaType::prettyTypeName(const QObject *object)
1425{
1426 QString typeName;
1427
1428 if (!object)
1429 return typeName;
1430
1431 QQmlType type = QQmlMetaType::qmlType(metaObject: object->metaObject());
1432 if (type.isValid()) {
1433 typeName = type.qmlTypeName();
1434 const int lastSlash = typeName.lastIndexOf(c: QLatin1Char('/'));
1435 if (lastSlash != -1)
1436 typeName = typeName.mid(position: lastSlash + 1);
1437 }
1438
1439 if (typeName.isEmpty()) {
1440 typeName = QString::fromUtf8(str: object->metaObject()->className());
1441 int marker = typeName.indexOf(s: QLatin1String("_QMLTYPE_"));
1442 if (marker != -1)
1443 typeName = typeName.left(n: marker);
1444
1445 marker = typeName.indexOf(s: QLatin1String("_QML_"));
1446 if (marker != -1) {
1447 typeName = typeName.leftRef(n: marker) + QLatin1Char('*');
1448 type = QQmlMetaType::qmlType(typeId: QMetaType::type(typeName: typeName.toLatin1()));
1449 if (type.isValid()) {
1450 QString qmlTypeName = type.qmlTypeName();
1451 const int lastSlash = qmlTypeName.lastIndexOf(c: QLatin1Char('/'));
1452 if (lastSlash != -1)
1453 qmlTypeName = qmlTypeName.mid(position: lastSlash + 1);
1454 if (!qmlTypeName.isEmpty())
1455 typeName = qmlTypeName;
1456 }
1457 }
1458 }
1459
1460 return typeName;
1461}
1462
1463QList<QQmlProxyMetaObject::ProxyData> QQmlMetaType::proxyData(const QMetaObject *mo,
1464 const QMetaObject *baseMetaObject,
1465 QMetaObject *lastMetaObject)
1466{
1467 QList<QQmlProxyMetaObject::ProxyData> metaObjects;
1468 mo = mo->d.superdata;
1469
1470 const QQmlMetaTypeDataPtr data;
1471
1472 while (mo) {
1473 QQmlTypePrivate *t = data->metaObjectToType.value(akey: mo);
1474 if (t) {
1475 if (t->regType == QQmlType::CppType) {
1476 if (t->extraData.cd->extFunc) {
1477 QMetaObjectBuilder builder;
1478 clone(builder, mo: t->extraData.cd->extMetaObject, ignoreStart: t->baseMetaObject, ignoreEnd: baseMetaObject);
1479 builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
1480 QMetaObject *mmo = builder.toMetaObject();
1481 mmo->d.superdata = baseMetaObject;
1482 if (!metaObjects.isEmpty())
1483 metaObjects.constLast().metaObject->d.superdata = mmo;
1484 else if (lastMetaObject)
1485 lastMetaObject->d.superdata = mmo;
1486 QQmlProxyMetaObject::ProxyData data = { .metaObject: mmo, .createFunc: t->extraData.cd->extFunc, .propertyOffset: 0, .methodOffset: 0 };
1487 metaObjects << data;
1488 }
1489 }
1490 }
1491 mo = mo->d.superdata;
1492 }
1493
1494 return metaObjects;
1495}
1496
1497QT_END_NAMESPACE
1498

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