1 /****************************************************************************
2 **
3 ** Copyright (C) 2019 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 "qqmltype_p_p.h"
41 
42 #include <QtQml/qjsvalue.h>
43 #include <QtQml/qqmlengine.h>
44 #include <QtQml/qqmlcontext.h>
45 #include <QtQml/qqmlcomponent.h>
46 
47 #include <private/qqmlcustomparser_p.h>
48 #include <private/qqmldata_p.h>
49 #include <private/qqmlmetatypedata_p.h>
50 #include <private/qqmlpropertycache_p.h>
51 #include <private/qqmltypedata_p.h>
52 
53 QT_BEGIN_NAMESPACE
54 
QQmlTypePrivate(QQmlType::RegistrationType type)55 QQmlTypePrivate::QQmlTypePrivate(QQmlType::RegistrationType type)
56     : regType(type), iid(nullptr), typeId(0), listId(0), revision(0),
57     containsRevisionedAttributes(false), baseMetaObject(nullptr),
58     index(-1), isSetup(false), isEnumFromCacheSetup(false), isEnumFromBaseSetup(false),
59     haveSuperType(false)
60 {
61     switch (type) {
62     case QQmlType::CppType:
63         extraData.cd = new QQmlCppTypeData;
64         extraData.cd->allocationSize = 0;
65         extraData.cd->newFunc = nullptr;
66         extraData.cd->parserStatusCast = -1;
67         extraData.cd->extFunc = nullptr;
68         extraData.cd->extMetaObject = nullptr;
69         extraData.cd->customParser = nullptr;
70         extraData.cd->attachedPropertiesFunc = nullptr;
71         extraData.cd->attachedPropertiesType = nullptr;
72         extraData.cd->propertyValueSourceCast = -1;
73         extraData.cd->propertyValueInterceptorCast = -1;
74         extraData.cd->registerEnumClassesUnscoped = true;
75         break;
76     case QQmlType::SingletonType:
77     case QQmlType::CompositeSingletonType:
78         extraData.sd = new QQmlSingletonTypeData;
79         extraData.sd->singletonInstanceInfo = nullptr;
80         break;
81     case QQmlType::InterfaceType:
82         extraData.cd = nullptr;
83         break;
84     case QQmlType::CompositeType:
85         extraData.fd = new QQmlCompositeTypeData;
86         break;
87     case QQmlType::InlineComponentType:
88         extraData.id = new QQmlInlineTypeData;
89         break;
90     default: qFatal("QQmlTypePrivate Internal Error.");
91     }
92 }
93 
~QQmlTypePrivate()94 QQmlTypePrivate::~QQmlTypePrivate()
95 {
96     qDeleteAll(scopedEnums);
97     for (const auto &metaObject : metaObjects)
98         free(metaObject.metaObject);
99     switch (regType) {
100     case QQmlType::CppType:
101         delete extraData.cd->customParser;
102         delete extraData.cd;
103         break;
104     case QQmlType::SingletonType:
105     case QQmlType::CompositeSingletonType:
106         delete extraData.sd->singletonInstanceInfo;
107         delete extraData.sd;
108         break;
109     case QQmlType::CompositeType:
110         delete extraData.fd;
111         break;
112     case QQmlType::InlineComponentType:
113         delete  extraData.id;
114         break;
115     default: //Also InterfaceType, because it has no extra data
116         break;
117     }
118 }
119 
120 QQmlType::QQmlType() = default;
121 QQmlType::QQmlType(const QQmlType &) = default;
122 QQmlType::QQmlType(QQmlType &&) = default;
123 QQmlType &QQmlType::operator =(const QQmlType &other) = default;
124 QQmlType &QQmlType::operator =(QQmlType &&other) = default;
QQmlType(const QQmlTypePrivate * priv)125 QQmlType::QQmlType(const QQmlTypePrivate *priv) : d(priv) {}
126 QQmlType::~QQmlType() = default;
127 
module() const128 QHashedString QQmlType::module() const
129 {
130     if (!d)
131         return QHashedString();
132     return d->module;
133 }
134 
majorVersion() const135 int QQmlType::majorVersion() const
136 {
137     if (!d)
138         return -1;
139     return d->version_maj;
140 }
141 
minorVersion() const142 int QQmlType::minorVersion() const
143 {
144     if (!d)
145         return -1;
146     return d->version_min;
147 }
148 
availableInVersion(int vmajor,int vminor) const149 bool QQmlType::availableInVersion(int vmajor, int vminor) const
150 {
151     Q_ASSERT(vmajor >= 0 && vminor >= 0);
152     if (!d)
153         return false;
154     return vmajor == d->version_maj && vminor >= d->version_min;
155 }
156 
availableInVersion(const QHashedStringRef & module,int vmajor,int vminor) const157 bool QQmlType::availableInVersion(const QHashedStringRef &module, int vmajor, int vminor) const
158 {
159     Q_ASSERT(vmajor >= 0 && vminor >= 0);
160     if (!d)
161         return false;
162     return module == d->module && vmajor == d->version_maj && vminor >= d->version_min;
163 }
164 
resolveCompositeBaseType(QQmlEnginePrivate * engine) const165 QQmlType QQmlTypePrivate::resolveCompositeBaseType(QQmlEnginePrivate *engine) const
166 {
167     Q_ASSERT(isComposite());
168     if (!engine)
169         return QQmlType();
170     QQmlRefPointer<QQmlTypeData> td(engine->typeLoader.getType(sourceUrl()));
171     if (td.isNull() || !td->isComplete())
172         return QQmlType();
173     QV4::ExecutableCompilationUnit *compilationUnit = td->compilationUnit();
174     const QMetaObject *mo = compilationUnit->rootPropertyCache()->firstCppMetaObject();
175     return QQmlMetaType::qmlType(mo);
176 }
177 
compositePropertyCache(QQmlEnginePrivate * engine) const178 QQmlPropertyCache *QQmlTypePrivate::compositePropertyCache(QQmlEnginePrivate *engine) const
179 {
180     // similar logic to resolveCompositeBaseType
181     Q_ASSERT(isComposite());
182     if (!engine)
183         return nullptr;
184     QQmlRefPointer<QQmlTypeData> td(engine->typeLoader.getType(sourceUrl()));
185     if (td.isNull() || !td->isComplete())
186         return nullptr;
187     QV4::ExecutableCompilationUnit *compilationUnit = td->compilationUnit();
188     return compilationUnit->rootPropertyCache().data();
189 }
190 
isPropertyRevisioned(const QMetaObject * mo,int index)191 static bool isPropertyRevisioned(const QMetaObject *mo, int index)
192 {
193     int i = index;
194     i -= mo->propertyOffset();
195     if (i < 0 && mo->d.superdata)
196         return isPropertyRevisioned(mo->d.superdata, index);
197 
198     const QMetaObjectPrivate *mop = reinterpret_cast<const QMetaObjectPrivate*>(mo->d.data);
199     if (i >= 0 && i < mop->propertyCount) {
200         int handle = mop->propertyData + 3*i;
201         int flags = mo->d.data[handle + 2];
202 
203         return (flags & Revisioned);
204     }
205 
206     return false;
207 }
208 
init() const209 void QQmlTypePrivate::init() const
210 {
211     if (isSetup)
212         return;
213 
214     QMutexLocker lock(QQmlMetaType::typeRegistrationLock());
215     if (isSetup)
216         return;
217 
218     const QMetaObject *mo = baseMetaObject;
219     if (!mo) {
220         // version 0 singleton type without metaobject information
221         return;
222     }
223 
224     if (regType == QQmlType::CppType) {
225         // Setup extended meta object
226         // XXX - very inefficient
227         if (extraData.cd->extFunc) {
228             QMetaObjectBuilder builder;
229             QQmlMetaType::clone(builder, extraData.cd->extMetaObject, extraData.cd->extMetaObject,
230                                 extraData.cd->extMetaObject);
231             builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
232             QMetaObject *mmo = builder.toMetaObject();
233             mmo->d.superdata = mo;
234             QQmlProxyMetaObject::ProxyData data = { mmo, extraData.cd->extFunc, 0, 0 };
235             metaObjects << data;
236         }
237     }
238 
239     metaObjects.append(QQmlMetaType::proxyData(
240             mo, baseMetaObject, metaObjects.isEmpty() ? nullptr
241                                                       : metaObjects.constLast().metaObject));
242 
243     for (int ii = 0; ii < metaObjects.count(); ++ii) {
244         metaObjects[ii].propertyOffset =
245                 metaObjects.at(ii).metaObject->propertyOffset();
246         metaObjects[ii].methodOffset =
247                 metaObjects.at(ii).metaObject->methodOffset();
248     }
249 
250     // Check for revisioned details
251     {
252         const QMetaObject *mo = nullptr;
253         if (metaObjects.isEmpty())
254             mo = baseMetaObject;
255         else
256             mo = metaObjects.constFirst().metaObject;
257 
258         for (int ii = 0; !containsRevisionedAttributes && ii < mo->propertyCount(); ++ii) {
259             if (isPropertyRevisioned(mo, ii))
260                 containsRevisionedAttributes = true;
261         }
262 
263         for (int ii = 0; !containsRevisionedAttributes && ii < mo->methodCount(); ++ii) {
264             if (mo->method(ii).revision() != 0)
265                 containsRevisionedAttributes = true;
266         }
267     }
268 
269     isSetup = true;
270     lock.unlock();
271 }
272 
initEnums(QQmlEnginePrivate * engine) const273 void QQmlTypePrivate::initEnums(QQmlEnginePrivate *engine) const
274 {
275     const QQmlPropertyCache *cache = (!isEnumFromCacheSetup && isComposite())
276             ? compositePropertyCache(engine)
277             : nullptr;
278 
279     const QMetaObject *metaObject = !isEnumFromBaseSetup
280             ? baseMetaObject // beware: It could be a singleton type without metaobject
281             : nullptr;
282 
283     if (!cache && !metaObject)
284         return;
285 
286     init();
287 
288     QMutexLocker lock(QQmlMetaType::typeRegistrationLock());
289 
290     if (cache) {
291         insertEnumsFromPropertyCache(cache);
292         isEnumFromCacheSetup = true;
293     }
294 
295     if (metaObject) {
296         insertEnums(metaObject);
297         isEnumFromBaseSetup = true;
298     }
299 }
300 
insertEnums(const QMetaObject * metaObject) const301 void QQmlTypePrivate::insertEnums(const QMetaObject *metaObject) const
302 {
303     // Add any enum values defined by 'related' classes
304     if (metaObject->d.relatedMetaObjects) {
305         const auto *related = metaObject->d.relatedMetaObjects;
306         if (related) {
307             while (*related)
308                 insertEnums(*related++);
309         }
310     }
311 
312     QSet<QString> localEnums;
313     const QMetaObject *localMetaObject = nullptr;
314 
315     // Add any enum values defined by this class, overwriting any inherited values
316     for (int ii = 0; ii < metaObject->enumeratorCount(); ++ii) {
317         QMetaEnum e = metaObject->enumerator(ii);
318         const bool isScoped = e.isScoped();
319         QStringHash<int> *scoped = isScoped ? new QStringHash<int>() : nullptr;
320 
321     // We allow enums in sub-classes to overwrite enums from base-classes, such as
322     // ListView.Center (from enum PositionMode) overwriting Item.Center (from enum TransformOrigin).
323     // This is acceptable because the _use_ of the enum from the QML side requires qualification
324     // anyway, i.e. ListView.Center vs. Item.Center.
325         // However if a class defines two enums with the same value, then that must produce a warning
326         // because it represents a valid conflict.
327         if (e.enclosingMetaObject() != localMetaObject) {
328             localEnums.clear();
329             localMetaObject = e.enclosingMetaObject();
330         }
331 
332         for (int jj = 0; jj < e.keyCount(); ++jj) {
333             const QString key = QString::fromUtf8(e.key(jj));
334             const int value = e.value(jj);
335             if (!isScoped || (regType == QQmlType::CppType && extraData.cd->registerEnumClassesUnscoped)) {
336                 if (localEnums.contains(key)) {
337                     auto existingEntry = enums.find(key);
338                     if (existingEntry != enums.end() && existingEntry.value() != value) {
339                         qWarning("Previously registered enum will be overwritten due to name clash: %s.%s", metaObject->className(), key.toUtf8().constData());
340                         createEnumConflictReport(metaObject, key);
341                     }
342                 } else {
343                     localEnums.insert(key);
344                 }
345                 enums.insert(key, value);
346             }
347             if (isScoped)
348                 scoped->insert(key, value);
349         }
350 
351         if (isScoped) {
352             scopedEnums << scoped;
353             scopedEnumIndex.insert(QString::fromUtf8(e.name()), scopedEnums.count()-1);
354         }
355     }
356 }
357 
createListOfPossibleConflictingItems(const QMetaObject * metaObject,QList<EnumInfo> & enumInfoList,QStringList path) const358 void QQmlTypePrivate::createListOfPossibleConflictingItems(const QMetaObject *metaObject, QList<EnumInfo> &enumInfoList, QStringList path) const
359 {
360     path.append(QString::fromUtf8(metaObject->className()));
361 
362     if (metaObject->d.relatedMetaObjects) {
363         const auto *related = metaObject->d.relatedMetaObjects;
364         if (related) {
365             while (*related)
366                 createListOfPossibleConflictingItems(*related++, enumInfoList, path);
367         }
368     }
369 
370     for (int ii = 0; ii < metaObject->enumeratorCount(); ++ii) {
371         const auto e = metaObject->enumerator(ii);
372 
373         for (int jj = 0; jj < e.keyCount(); ++jj) {
374             const QString key = QString::fromUtf8(e.key(jj));
375 
376             EnumInfo enumInfo;
377             enumInfo.metaObjectName = QString::fromUtf8(metaObject->className());
378             enumInfo.enumName = QString::fromUtf8(e.name());
379             enumInfo.enumKey = key;
380             enumInfo.scoped = e.isScoped();
381             enumInfo.path = path;
382             enumInfo.metaEnumScope = QString::fromUtf8(e.scope());
383             enumInfoList.append(enumInfo);
384         }
385     }
386 }
387 
createEnumConflictReport(const QMetaObject * metaObject,const QString & conflictingKey) const388 void QQmlTypePrivate::createEnumConflictReport(const QMetaObject *metaObject, const QString &conflictingKey) const
389 {
390     QList<EnumInfo> enumInfoList;
391 
392     if (baseMetaObject) // prefer baseMetaObject if available
393         metaObject = baseMetaObject;
394 
395     if (!metaObject) { // If there is no metaObject at all return early
396         qWarning() << "No meta object information available. Skipping conflict analysis.";
397         return;
398     }
399 
400     createListOfPossibleConflictingItems(metaObject, enumInfoList, QStringList());
401 
402     qWarning().noquote() << QLatin1String("Possible conflicting items:");
403     // find items with conflicting key
404     for (const auto &i : qAsConst(enumInfoList)) {
405         if (i.enumKey == conflictingKey)
406         qWarning().noquote().nospace() << "    " << i.metaObjectName << "." << i.enumName << "." << i.enumKey << " from scope "
407                                            << i.metaEnumScope << " injected by " << i.path.join(QLatin1String("->"));
408     }
409 }
410 
insertEnumsFromPropertyCache(const QQmlPropertyCache * cache) const411 void QQmlTypePrivate::insertEnumsFromPropertyCache(const QQmlPropertyCache *cache) const
412 {
413     const QMetaObject *cppMetaObject = cache->firstCppMetaObject();
414 
415     while (cache && cache->metaObject() != cppMetaObject) {
416 
417         int count = cache->qmlEnumCount();
418         for (int ii = 0; ii < count; ++ii) {
419             QStringHash<int> *scoped = new QStringHash<int>();
420             QQmlEnumData *enumData = cache->qmlEnum(ii);
421 
422             for (int jj = 0; jj < enumData->values.count(); ++jj) {
423                 const QQmlEnumValue &value = enumData->values.at(jj);
424                 enums.insert(value.namedValue, value.value);
425                 scoped->insert(value.namedValue, value.value);
426             }
427             scopedEnums << scoped;
428             scopedEnumIndex.insert(enumData->name, scopedEnums.count()-1);
429         }
430         cache = cache->parent();
431     }
432     insertEnums(cppMetaObject);
433 }
434 
setContainingType(QQmlType * containingType)435 void QQmlTypePrivate::setContainingType(QQmlType *containingType)
436 {
437     Q_ASSERT(regType == QQmlType::InlineComponentType);
438     extraData.id->containingType = containingType->d.data();
439 }
440 
setName(const QString & uri,const QString & element)441 void QQmlTypePrivate::setName(const QString &uri, const QString &element)
442 {
443     module = uri;
444     elementName = element;
445     name = uri.isEmpty() ? element : (uri + QLatin1Char('/') + element);
446 }
447 
typeName() const448 QByteArray QQmlType::typeName() const
449 {
450     if (d) {
451         if (d->regType == SingletonType || d->regType == CompositeSingletonType)
452             return d->extraData.sd->singletonInstanceInfo->typeName.toUtf8();
453         else if (d->baseMetaObject)
454             return d->baseMetaObject->className();
455         else if (d->regType == InlineComponentType)
456             return d->extraData.id->inlineComponentName.toUtf8();
457     }
458     return QByteArray();
459 }
460 
elementName() const461 QString QQmlType::elementName() const
462 {
463     if (!d)
464         return QString();
465     return d->elementName;
466 }
467 
qmlTypeName() const468 QString QQmlType::qmlTypeName() const
469 {
470     if (!d)
471         return QString();
472     return d->name;
473 }
474 
create() const475 QObject *QQmlType::create() const
476 {
477     if (!d || !isCreatable())
478         return nullptr;
479 
480     d->init();
481 
482     QObject *rv = (QObject *)operator new(d->extraData.cd->allocationSize);
483     d->extraData.cd->newFunc(rv);
484 
485     if (rv && !d->metaObjects.isEmpty())
486         (void)new QQmlProxyMetaObject(rv, &d->metaObjects);
487 
488     return rv;
489 }
490 
create(QObject ** out,void ** memory,size_t additionalMemory) const491 void QQmlType::create(QObject **out, void **memory, size_t additionalMemory) const
492 {
493     if (!d || !isCreatable())
494         return;
495 
496     d->init();
497 
498     QObject *rv = (QObject *)operator new(d->extraData.cd->allocationSize + additionalMemory);
499     d->extraData.cd->newFunc(rv);
500 
501     if (rv && !d->metaObjects.isEmpty())
502         (void)new QQmlProxyMetaObject(rv, &d->metaObjects);
503 
504     *out = rv;
505     *memory = ((char *)rv) + d->extraData.cd->allocationSize;
506 }
507 
singletonInstanceInfo() const508 QQmlType::SingletonInstanceInfo *QQmlType::singletonInstanceInfo() const
509 {
510     if (!d)
511         return nullptr;
512     if (d->regType != SingletonType && d->regType != CompositeSingletonType)
513         return nullptr;
514     return d->extraData.sd->singletonInstanceInfo;
515 }
516 
customParser() const517 QQmlCustomParser *QQmlType::customParser() const
518 {
519     if (!d)
520         return nullptr;
521     if (d->regType != CppType)
522         return nullptr;
523     return d->extraData.cd->customParser;
524 }
525 
createFunction() const526 QQmlType::CreateFunc QQmlType::createFunction() const
527 {
528     if (!d || d->regType != CppType)
529         return nullptr;
530     return d->extraData.cd->newFunc;
531 }
532 
noCreationReason() const533 QString QQmlType::noCreationReason() const
534 {
535     if (!d || d->regType != CppType)
536         return QString();
537     return d->extraData.cd->noCreationReason;
538 }
539 
isCreatable() const540 bool QQmlType::isCreatable() const
541 {
542     return d && d->regType == CppType && d->extraData.cd->newFunc;
543 }
544 
extensionFunction() const545 QQmlType::ExtensionFunc QQmlType::extensionFunction() const
546 {
547     if (!d || d->regType != CppType)
548         return nullptr;
549     return d->extraData.cd->extFunc;
550 }
551 
isExtendedType() const552 bool QQmlType::isExtendedType() const
553 {
554     if (!d)
555         return false;
556     d->init();
557 
558     return !d->metaObjects.isEmpty();
559 }
560 
isSingleton() const561 bool QQmlType::isSingleton() const
562 {
563     return d && (d->regType == SingletonType || d->regType == CompositeSingletonType);
564 }
565 
isInterface() const566 bool QQmlType::isInterface() const
567 {
568     return d && d->regType == InterfaceType;
569 }
570 
isComposite() const571 bool QQmlType::isComposite() const
572 {
573     return d && d->isComposite();
574 }
575 
isCompositeSingleton() const576 bool QQmlType::isCompositeSingleton() const
577 {
578     // if the outer type is a composite singleton, d->regType will indicate that even for
579     // the inline component type
580     // however, inline components can -at least for now- never be singletons
581     // so we just do one additional check
582     return d && d->regType == CompositeSingletonType && !isInlineComponentType();
583 }
584 
isQObjectSingleton() const585 bool QQmlType::isQObjectSingleton() const
586 {
587     return d && d->regType == SingletonType && d->extraData.sd->singletonInstanceInfo->qobjectCallback;
588 }
589 
isQJSValueSingleton() const590 bool QQmlType::isQJSValueSingleton() const
591 {
592     return d && d->regType == SingletonType && d->extraData.sd->singletonInstanceInfo->scriptCallback;
593 }
594 
typeId() const595 int QQmlType::typeId() const
596 {
597     return d ? d->typeId : -1;
598 }
599 
qListTypeId() const600 int QQmlType::qListTypeId() const
601 {
602     return d ? d->listId : -1;
603 }
604 
metaObject() const605 const QMetaObject *QQmlType::metaObject() const
606 {
607     if (!d)
608         return nullptr;
609     d->init();
610 
611     if (d->metaObjects.isEmpty())
612         return d->baseMetaObject;
613     else
614         return d->metaObjects.constFirst().metaObject;
615 
616 }
617 
baseMetaObject() const618 const QMetaObject *QQmlType::baseMetaObject() const
619 {
620     return d ? d->baseMetaObject : nullptr;
621 }
622 
containsRevisionedAttributes() const623 bool QQmlType::containsRevisionedAttributes() const
624 {
625     if (!d)
626         return false;
627     d->init();
628 
629     return d->containsRevisionedAttributes;
630 }
631 
metaObjectRevision() const632 int QQmlType::metaObjectRevision() const
633 {
634     return d ? d->revision : -1;
635 }
636 
attachedPropertiesFunction(QQmlEnginePrivate * engine) const637 QQmlAttachedPropertiesFunc QQmlType::attachedPropertiesFunction(QQmlEnginePrivate *engine) const
638 {
639     if (const QQmlTypePrivate *base = d ? d->attachedPropertiesBase(engine) : nullptr)
640         return base->extraData.cd->attachedPropertiesFunc;
641     return nullptr;
642 }
643 
attachedPropertiesType(QQmlEnginePrivate * engine) const644 const QMetaObject *QQmlType::attachedPropertiesType(QQmlEnginePrivate *engine) const
645 {
646     if (const QQmlTypePrivate *base = d ? d->attachedPropertiesBase(engine) : nullptr)
647         return base->extraData.cd->attachedPropertiesType;
648     return nullptr;
649 }
650 
651 #if QT_DEPRECATED_SINCE(5, 14)
652 /*
653 This is the id passed to qmlAttachedPropertiesById().  This is different from the index
654 for the case that a single class is registered under two or more names (eg. Item in
655 Qt 4.7 and QtQuick 1.0).
656 */
attachedPropertiesId(QQmlEnginePrivate * engine) const657 int QQmlType::attachedPropertiesId(QQmlEnginePrivate *engine) const
658 {
659     if (const QQmlTypePrivate *base = d->attachedPropertiesBase(engine))
660         return base->index;
661     return -1;
662 }
663 #endif
664 
parserStatusCast() const665 int QQmlType::parserStatusCast() const
666 {
667     if (!d || d->regType != CppType)
668         return -1;
669     return d->extraData.cd->parserStatusCast;
670 }
671 
propertyValueSourceCast() const672 int QQmlType::propertyValueSourceCast() const
673 {
674     if (!d || d->regType != CppType)
675         return -1;
676     return d->extraData.cd->propertyValueSourceCast;
677 }
678 
propertyValueInterceptorCast() const679 int QQmlType::propertyValueInterceptorCast() const
680 {
681     if (!d || d->regType != CppType)
682         return -1;
683     return d->extraData.cd->propertyValueInterceptorCast;
684 }
685 
interfaceIId() const686 const char *QQmlType::interfaceIId() const
687 {
688     if (!d || d->regType != InterfaceType)
689         return nullptr;
690     return d->iid;
691 }
692 
index() const693 int QQmlType::index() const
694 {
695     return d ? d->index : -1;
696 }
697 
isInlineComponentType() const698 bool QQmlType::isInlineComponentType() const {
699     return d ? d->regType == QQmlType::InlineComponentType : false;
700 }
701 
inlineComponendId() const702 int QQmlType::inlineComponendId() const {
703     bool ok = false;
704     if (d->regType == QQmlType::RegistrationType::InlineComponentType) {
705         Q_ASSERT(d->extraData.id->objectId != -1);
706         return d->extraData.id->objectId;
707     }
708     int subObjectId = sourceUrl().fragment().toInt(&ok);
709     return ok ? subObjectId : -1;
710 }
711 
sourceUrl() const712 QUrl QQmlType::sourceUrl() const
713 {
714     auto url = d ? d->sourceUrl() : QUrl();
715     if (url.isValid() && d->regType == QQmlType::RegistrationType::InlineComponentType && d->extraData.id->objectId) {
716         Q_ASSERT(url.hasFragment());
717         url.setFragment(QString::number(inlineComponendId()));
718     }
719     return url;
720 }
721 
enumValue(QQmlEnginePrivate * engine,const QHashedStringRef & name,bool * ok) const722 int QQmlType::enumValue(QQmlEnginePrivate *engine, const QHashedStringRef &name, bool *ok) const
723 {
724     Q_ASSERT(ok);
725     if (d) {
726         *ok = true;
727 
728         d->initEnums(engine);
729 
730         int *rv = d->enums.value(name);
731         if (rv)
732             return *rv;
733     }
734 
735     *ok = false;
736     return -1;
737 }
738 
enumValue(QQmlEnginePrivate * engine,const QHashedCStringRef & name,bool * ok) const739 int QQmlType::enumValue(QQmlEnginePrivate *engine, const QHashedCStringRef &name, bool *ok) const
740 {
741     Q_ASSERT(ok);
742     if (d) {
743         *ok = true;
744 
745         d->initEnums(engine);
746 
747         int *rv = d->enums.value(name);
748         if (rv)
749             return *rv;
750     }
751 
752     *ok = false;
753     return -1;
754 }
755 
enumValue(QQmlEnginePrivate * engine,const QV4::String * name,bool * ok) const756 int QQmlType::enumValue(QQmlEnginePrivate *engine, const QV4::String *name, bool *ok) const
757 {
758     Q_ASSERT(ok);
759     if (d) {
760         *ok = true;
761 
762         d->initEnums(engine);
763 
764         int *rv = d->enums.value(name);
765         if (rv)
766             return *rv;
767     }
768 
769     *ok = false;
770     return -1;
771 }
772 
scopedEnumIndex(QQmlEnginePrivate * engine,const QV4::String * name,bool * ok) const773 int QQmlType::scopedEnumIndex(QQmlEnginePrivate *engine, const QV4::String *name, bool *ok) const
774 {
775     Q_ASSERT(ok);
776     if (d) {
777         *ok = true;
778 
779         d->initEnums(engine);
780 
781         int *rv = d->scopedEnumIndex.value(name);
782         if (rv)
783             return *rv;
784     }
785 
786     *ok = false;
787     return -1;
788 }
789 
scopedEnumIndex(QQmlEnginePrivate * engine,const QString & name,bool * ok) const790 int QQmlType::scopedEnumIndex(QQmlEnginePrivate *engine, const QString &name, bool *ok) const
791 {
792     Q_ASSERT(ok);
793     if (d) {
794         *ok = true;
795 
796         d->initEnums(engine);
797 
798         int *rv = d->scopedEnumIndex.value(name);
799         if (rv)
800             return *rv;
801     }
802 
803     *ok = false;
804     return -1;
805 }
806 
scopedEnumValue(QQmlEnginePrivate * engine,int index,const QV4::String * name,bool * ok) const807 int QQmlType::scopedEnumValue(QQmlEnginePrivate *engine, int index, const QV4::String *name, bool *ok) const
808 {
809     Q_UNUSED(engine)
810     Q_ASSERT(ok);
811     *ok = true;
812 
813     if (d) {
814         Q_ASSERT(index > -1 && index < d->scopedEnums.count());
815         int *rv = d->scopedEnums.at(index)->value(name);
816         if (rv)
817             return *rv;
818     }
819 
820     *ok = false;
821     return -1;
822 }
823 
scopedEnumValue(QQmlEnginePrivate * engine,int index,const QString & name,bool * ok) const824 int QQmlType::scopedEnumValue(QQmlEnginePrivate *engine, int index, const QString &name, bool *ok) const
825 {
826     Q_UNUSED(engine)
827     Q_ASSERT(ok);
828     *ok = true;
829 
830     if (d) {
831         Q_ASSERT(index > -1 && index < d->scopedEnums.count());
832         int *rv = d->scopedEnums.at(index)->value(name);
833         if (rv)
834             return *rv;
835     }
836 
837     *ok = false;
838     return -1;
839 }
840 
scopedEnumValue(QQmlEnginePrivate * engine,const QByteArray & scopedEnumName,const QByteArray & name,bool * ok) const841 int QQmlType::scopedEnumValue(QQmlEnginePrivate *engine, const QByteArray &scopedEnumName, const QByteArray &name, bool *ok) const
842 {
843     Q_ASSERT(ok);
844     if (d) {
845         *ok = true;
846 
847         d->initEnums(engine);
848 
849         int *rv = d->scopedEnumIndex.value(QHashedCStringRef(scopedEnumName.constData(), scopedEnumName.length()));
850         if (rv) {
851             int index = *rv;
852             Q_ASSERT(index > -1 && index < d->scopedEnums.count());
853             rv = d->scopedEnums.at(index)->value(QHashedCStringRef(name.constData(), name.length()));
854             if (rv)
855                 return *rv;
856         }
857     }
858 
859     *ok = false;
860     return -1;
861 }
862 
scopedEnumValue(QQmlEnginePrivate * engine,const QStringRef & scopedEnumName,const QStringRef & name,bool * ok) const863 int QQmlType::scopedEnumValue(QQmlEnginePrivate *engine, const QStringRef &scopedEnumName, const QStringRef &name, bool *ok) const
864 {
865     Q_ASSERT(ok);
866     if (d) {
867         *ok = true;
868 
869         d->initEnums(engine);
870 
871         int *rv = d->scopedEnumIndex.value(QHashedStringRef(scopedEnumName));
872         if (rv) {
873             int index = *rv;
874             Q_ASSERT(index > -1 && index < d->scopedEnums.count());
875             rv = d->scopedEnums.at(index)->value(QHashedStringRef(name));
876             if (rv)
877                 return *rv;
878         }
879     }
880 
881     *ok = false;
882     return -1;
883 }
884 
inlineComponentObjectId()885 int QQmlType::inlineComponentObjectId()
886 {
887     if (!isInlineComponentType())
888         return -1;
889     return d->extraData.id->objectId;
890 }
891 
setInlineComponentObjectId(int id) const892 void QQmlType::setInlineComponentObjectId(int id) const
893 {
894     Q_ASSERT(d && d->regType == QQmlType::InlineComponentType);
895     d->extraData.id->objectId = id;
896 }
897 
refHandle(const QQmlTypePrivate * priv)898 void QQmlType::refHandle(const QQmlTypePrivate *priv)
899 {
900     if (priv)
901         priv->addref();
902 }
903 
derefHandle(const QQmlTypePrivate * priv)904 void QQmlType::derefHandle(const QQmlTypePrivate *priv)
905 {
906     if (priv)
907         priv->release();
908 }
909 
refCount(const QQmlTypePrivate * priv)910 int QQmlType::refCount(const QQmlTypePrivate *priv)
911 {
912     if (priv)
913         return priv->count();
914     return -1;
915 }
916 
lookupInlineComponentIdByName(const QString & name) const917 int QQmlType::lookupInlineComponentIdByName(const QString &name) const
918 {
919     Q_ASSERT(d);
920     return d->namesToInlineComponentObjectIndex.value(name, -1);
921 }
922 
containingType() const923 QQmlType QQmlType::containingType() const
924 {
925     Q_ASSERT(d && d->regType == QQmlType::RegistrationType::InlineComponentType);
926     auto ret = QQmlType {d->extraData.id->containingType};
927     Q_ASSERT(!ret.isInlineComponentType());
928     return ret;
929 }
930 
lookupInlineComponentById(int objectid) const931 QQmlType QQmlType::lookupInlineComponentById(int objectid) const
932 {
933     Q_ASSERT(d);
934     return d->objectIdToICType.value(objectid, QQmlType(nullptr));
935 }
936 
generatePlaceHolderICId() const937 int QQmlType::generatePlaceHolderICId() const
938 {
939     Q_ASSERT(d);
940     int id = -2;
941     for (auto it = d->objectIdToICType.keyBegin(); it != d->objectIdToICType.keyEnd(); ++it)
942         if (*it < id)
943                 id = *it;
944     return id;
945 }
946 
associateInlineComponent(const QString & name,int objectID,const CompositeMetaTypeIds & metaTypeIds,QQmlType existingType)947 void QQmlType::associateInlineComponent(const QString &name, int objectID, const CompositeMetaTypeIds &metaTypeIds, QQmlType existingType)
948 {
949     bool const reuseExistingType = existingType.isValid();
950     auto priv = reuseExistingType ? const_cast<QQmlTypePrivate *>(existingType.d.data()) : new QQmlTypePrivate { RegistrationType::InlineComponentType } ;
951     priv->setName( QString::fromUtf8(typeName()), name);
952     auto icUrl = QUrl(sourceUrl());
953     icUrl.setFragment(QString::number(objectID));
954     priv->extraData.id->url = icUrl;
955     priv->extraData.id->containingType = d.data();
956     priv->extraData.id->objectId = objectID;
957     priv->typeId = metaTypeIds.id;
958     priv->listId = metaTypeIds.listId;
959     d->namesToInlineComponentObjectIndex.insert(name, objectID);
960     QQmlType icType(priv);
961     d->objectIdToICType.insert(objectID, icType);
962     if (!reuseExistingType)
963         priv->release();
964 }
965 
setPendingResolutionName(const QString & name)966 void QQmlType::setPendingResolutionName(const QString &name)
967 {
968     Q_ASSERT(d && d->regType == QQmlType::RegistrationType::InlineComponentType);
969     Q_ASSERT(d->extraData.id->inlineComponentName == name|| d->extraData.id->inlineComponentName.isEmpty());
970     d->extraData.id->inlineComponentName = name;
971 }
972 
pendingResolutionName() const973 QString QQmlType::pendingResolutionName() const
974 {
975     Q_ASSERT(d && d->regType == QQmlType::RegistrationType::InlineComponentType);
976     return d->extraData.id->inlineComponentName;
977 }
978 
979 QT_END_NAMESPACE
980