Revision control

++ // Copyright (C) 2019 The Qt Company Ltd.
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
++ // Qt-Security score:significant
++
++ #include "qqmltype_p_p.h"
++
++ #include <QtQml/qjsvalue.h>
++ #include <QtQml/qqmlengine.h>
++ #include <QtQml/qqmlcontext.h>
++ #include <QtQml/qqmlcomponent.h>
++
++ #include <private/qqmlcustomparser_p.h>
++ #include <private/qqmldata_p.h>
++ #include <private/qqmlmetatypedata_p.h>
++ #include <private/qqmlpropertycache_p.h>
++ #include <private/qqmltypedata_p.h>
++
++ QT_BEGIN_NAMESPACE
++
++ QQmlTypePrivate::QQmlTypePrivate(QQmlType::RegistrationType type)
++ : regType(type)
++ {
++ switch (type) {
++ case QQmlType::CppType:
++ extraData.cppTypeData = new QQmlCppTypeData;
++ extraData.cppTypeData->allocationSize = 0;
++ extraData.cppTypeData->newFunc = nullptr;
++ extraData.cppTypeData->createValueTypeFunc = nullptr;
++ extraData.cppTypeData->parserStatusCast = -1;
++ extraData.cppTypeData->extFunc = nullptr;
++ extraData.cppTypeData->extMetaObject = nullptr;
++ extraData.cppTypeData->customParser = nullptr;
++ extraData.cppTypeData->attachedPropertiesFunc = nullptr;
++ extraData.cppTypeData->attachedPropertiesType = nullptr;
++ extraData.cppTypeData->propertyValueSourceCast = -1;
++ extraData.cppTypeData->propertyValueInterceptorCast = -1;
++ extraData.cppTypeData->finalizerCast = -1;
++ extraData.cppTypeData->registerEnumClassesUnscoped = true;
++ extraData.cppTypeData->registerEnumsFromRelatedTypes = true;
++ break;
++ case QQmlType::SingletonType:
++ case QQmlType::CompositeSingletonType:
++ extraData.singletonTypeData = new QQmlSingletonTypeData;
++ extraData.singletonTypeData->singletonInstanceInfo = nullptr;
++ extraData.singletonTypeData->extFunc = nullptr;
++ extraData.singletonTypeData->extMetaObject = nullptr;
++ break;
++ case QQmlType::InterfaceType:
++ extraData.interfaceTypeData = nullptr;
++ break;
++ case QQmlType::CompositeType:
++ new (&extraData.compositeTypeData) QUrl();
++ break;
++ case QQmlType::InlineComponentType:
++ new (&extraData.inlineComponentTypeData) QUrl();
++ break;
++ case QQmlType::SequentialContainerType:
++ new (&extraData.sequentialContainerTypeData) QMetaSequence();
++ break;
++ case QQmlType::JavaScriptType:
++ new (&extraData.javaScriptTypeData) QUrl();
++ break;
++ default: qFatal("QQmlTypePrivate Internal Error.");
++ }
++ }
++
++ QQmlTypePrivate::~QQmlTypePrivate()
++ {
++ delete enums.fetchAndStoreAcquire(nullptr);
++ delete proxyMetaObjects.fetchAndStoreAcquire(nullptr);
++
++ switch (regType) {
++ case QQmlType::CppType:
++ delete extraData.cppTypeData->customParser;
++ delete extraData.cppTypeData;
++ break;
++ case QQmlType::SingletonType:
++ case QQmlType::CompositeSingletonType:
++ extraData.singletonTypeData->singletonInstanceInfo.reset();
++ delete extraData.singletonTypeData;
++ break;
++ case QQmlType::CompositeType:
++ extraData.compositeTypeData.~QUrl();
++ break;
++ case QQmlType::InlineComponentType:
++ extraData.inlineComponentTypeData.~QUrl();
++ break;
++ case QQmlType::SequentialContainerType:
++ extraData.sequentialContainerTypeData.~QMetaSequence();
++ break;
++ case QQmlType::JavaScriptType:
++ extraData.javaScriptTypeData.~QUrl();
++ break;
++ default: //Also InterfaceType, because it has no extra data
++ break;
++ }
++ }
++
++ QQmlType::QQmlType() = default;
++ QQmlType::QQmlType(const QQmlType &) = default;
++ QQmlType::QQmlType(QQmlType &&) = default;
++ QQmlType &QQmlType::operator =(const QQmlType &other) = default;
++ QQmlType &QQmlType::operator =(QQmlType &&other) = default;
++ QQmlType::QQmlType(const QQmlTypePrivate *priv) : d(priv) {}
++ QQmlType::~QQmlType() = default;
++
++ QHashedString QQmlType::module() const
++ {
++ if (!d)
++ return QHashedString();
++ return d->module;
++ }
++
++ QTypeRevision QQmlType::version() const
++ {
++ if (!d)
++ return QTypeRevision();
++ return d->version;
++ }
++
++ bool QQmlType::availableInVersion(QTypeRevision version) const
++ {
++ if (!d)
++ return false;
++
++ if (!version.hasMajorVersion())
++ return true;
++
++ if (version.majorVersion() != d->version.majorVersion())
++ return false;
++
++ return !version.hasMinorVersion() || version.minorVersion() >= d->version.minorVersion();
++ }
++
++ bool QQmlType::availableInVersion(const QHashedStringRef &module, QTypeRevision version) const
++ {
++ if (!d || module != d->module)
++ return false;
++
++ return availableInVersion(version);
++ }
++
++ QQmlType QQmlTypePrivate::resolveCompositeBaseType(QQmlTypeLoader *typeLoader) const
++ {
++ Q_ASSERT(isComposite());
++ if (!typeLoader)
++ return QQmlType();
++ QQmlRefPointer<QQmlTypeData> td(typeLoader->getType(sourceUrl()));
++ if (td.isNull() || !td->isComplete())
++ return QQmlType();
++ QV4::CompiledData::CompilationUnit *compilationUnit = td->compilationUnit();
++ if (const auto cache = compilationUnit->rootPropertyCache())
++ return QQmlMetaType::qmlType(cache->firstCppMetaObject());
++ return QQmlType();
++ }
++
++ QQmlPropertyCache::ConstPtr QQmlTypePrivate::compositePropertyCache(
++ QQmlTypeLoader *typeLoader) const
++ {
++ // similar logic to resolveCompositeBaseType
++ Q_ASSERT(isComposite());
++ if (!typeLoader)
++ return nullptr;
++ QQmlRefPointer<QQmlTypeData> td(typeLoader->getType(sourceUrl()));
++ if (td.isNull() || !td->isComplete())
++ return nullptr;
++ QV4::CompiledData::CompilationUnit *compilationUnit = td->compilationUnit();
++ return compilationUnit->rootPropertyCache();
++ }
++
++ static bool isPropertyRevisioned(const QMetaObject *mo, int index)
++ {
++ return mo->property(index).revision();
++ }
++
++ const QQmlTypePrivate::ProxyMetaObjects *QQmlTypePrivate::init() const
++ {
++ if (const ProxyMetaObjects *result = proxyMetaObjects.loadRelaxed())
++ return result;
++
++ ProxyMetaObjects *proxies = new ProxyMetaObjects;
++ auto finalize = [this, proxies]() -> const ProxyMetaObjects *{
++ const ProxyMetaObjects *concurrentModification;
++ if (proxyMetaObjects.testAndSetOrdered(nullptr, proxies, concurrentModification))
++ return proxies;
++
++ delete proxies;
++ return concurrentModification;
++ };
++
++ const QMetaObject *mo = baseMetaObject;
++ if (!mo) {
++ // version 0 singleton type without metaobject information
++ return finalize();
++ }
++
++ QList<QQmlProxyMetaObject::ProxyData> metaObjects;
++
++ auto setupExtendedMetaObject = [&](const QMetaObject *extMetaObject,
++ QObject *(*extFunc)(QObject *)) {
++ if (!extMetaObject)
++ return;
++
++ // XXX - very inefficient
++ QMetaObjectBuilder builder;
++ QQmlMetaType::clone(builder, extMetaObject, extMetaObject, extMetaObject,
++ extFunc ? QQmlMetaType::CloneAll : QQmlMetaType::CloneEnumsOnly);
++ QMetaObject *mmo = builder.toMetaObject();
++ mmo->d.superdata = mo;
++ QQmlProxyMetaObject::ProxyData data = { mmo, extFunc, 0, 0 };
++ metaObjects << data;
++ QQmlMetaType::registerMetaObjectForType(mmo, this);
++ };
++
++ if (regType == QQmlType::SingletonType)
++ setupExtendedMetaObject(extraData.singletonTypeData->extMetaObject, extraData.singletonTypeData->extFunc);
++ else if (regType == QQmlType::CppType)
++ setupExtendedMetaObject(extraData.cppTypeData->extMetaObject, extraData.cppTypeData->extFunc);
++
++ metaObjects.append(QQmlMetaType::proxyData(
++ mo, baseMetaObject, metaObjects.isEmpty() ? nullptr
++ : metaObjects.constLast().metaObject));
++
++ for (int ii = 0; ii < metaObjects.size(); ++ii) {
++ metaObjects[ii].propertyOffset =
++ metaObjects.at(ii).metaObject->propertyOffset();
++ metaObjects[ii].methodOffset =
++ metaObjects.at(ii).metaObject->methodOffset();
++ }
++
++ bool containsRevisionedAttributes = false;
++
++ // Check for revisioned details
++ {
++ const QMetaObject *mo = nullptr;
++ if (metaObjects.isEmpty())
++ mo = baseMetaObject;
++ else
++ mo = metaObjects.constFirst().metaObject;
++
++ for (int ii = 0; !containsRevisionedAttributes && ii < mo->propertyCount(); ++ii) {
++ if (isPropertyRevisioned(mo, ii))
++ containsRevisionedAttributes = true;
++ }
++
++ for (int ii = 0; !containsRevisionedAttributes && ii < mo->methodCount(); ++ii) {
++ if (mo->method(ii).revision() != 0)
++ containsRevisionedAttributes = true;
++ }
++ }
++
++ proxies->data = std::move(metaObjects);
++ proxies->containsRevisionedAttributes = containsRevisionedAttributes;
++
++ return finalize();
++ }
++
++ const QQmlTypePrivate::Enums *QQmlTypePrivate::initEnums(QQmlTypeLoader *typeLoader) const
++ {
++ if (const Enums *result = enums.loadRelaxed())
++ return result;
++
++ QQmlPropertyCache::ConstPtr cache;
++ if (isComposite()) {
++ cache = compositePropertyCache(typeLoader);
++ if (!cache)
++ return nullptr; // Composite type not ready, yet.
++ }
++
++ Enums *newEnums = new Enums;
++
++ // beware: It could be a singleton type without metaobject
++
++ if (cache)
++ insertEnumsFromPropertyCache(newEnums, cache);
++
++ if (baseMetaObject) {
++ // init() can add to the metaObjects list. Therefore, check proxies->data only below
++ const ProxyMetaObjects *proxies = init();
++ insertEnums(
++ newEnums,
++ proxies->data.isEmpty() ? baseMetaObject : proxies->data.constFirst().metaObject);
++ }
++
++ const Enums *concurrentModification;
++ if (enums.testAndSetOrdered(nullptr, newEnums, concurrentModification))
++ return newEnums;
++
++ delete newEnums;
++ return concurrentModification;
++ }
++
++ void QQmlTypePrivate::insertEnums(Enums *enums, const QMetaObject *metaObject) const
++ {
++ // Add any enum values defined by 'related' classes
++ if (regType != QQmlType::CppType || extraData.cppTypeData->registerEnumsFromRelatedTypes) {
++ if (const auto *related = metaObject->d.relatedMetaObjects) {
++ while (const QMetaObject *relatedMetaObject = *related) {
++ insertEnums(enums, relatedMetaObject);
++ ++related;
++ }
++ }
++ }
++
++ QSet<QString> localEnums;
++ const QMetaObject *localMetaObject = nullptr;
++
++ // ### TODO (QTBUG-123294): track this at instance creation time
++ auto shouldSingletonAlsoRegisterUnscoped = [&](){
++ Q_ASSERT(regType == QQmlType::SingletonType);
++ if (!baseMetaObject)
++ return true;
++ int idx = baseMetaObject->indexOfClassInfo("RegisterEnumClassesUnscoped");
++ if (idx == -1)
++ return true;
++ if (qstrcmp(baseMetaObject->classInfo(idx).value(), "false") == 0)
++ return false;
++ return true;
++ };
++
++ // Add any enum values defined by this class, overwriting any inherited values
++ for (int ii = 0; ii < metaObject->enumeratorCount(); ++ii) {
++ QMetaEnum me = metaObject->enumerator(ii);
++ const bool isScoped = me.isScoped();
++ QStringHash<int> *e = new QStringHash<int>();
++
++ // We allow enums in sub-classes to overwrite enums from base-classes, such as
++ // ListView.Center (from enum PositionMode) overwriting Item.Center (from enum TransformOrigin).
++ // This is acceptable because the _use_ of the enum from the QML side requires qualification
++ // anyway, i.e. ListView.Center vs. Item.Center.
++ // However if a class defines two enums with the same value, then that must produce a warning
++ // because it represents a valid conflict.
++ if (me.enclosingMetaObject() != localMetaObject) {
++ localEnums.clear();
++ localMetaObject = me.enclosingMetaObject();
++ }
++ const bool shouldRegisterUnscoped = !isScoped
++ || (regType == QQmlType::CppType && extraData.cppTypeData->registerEnumClassesUnscoped)
++ || (regType == QQmlType::SingletonType && shouldSingletonAlsoRegisterUnscoped())
++ ;
++
++ for (int jj = 0; jj < me.keyCount(); ++jj) {
++ const QString key = QString::fromUtf8(me.key(jj));
++ const int value = me.value(jj);
++ if (shouldRegisterUnscoped) {
++ if (localEnums.contains(key)) {
++ auto existingEntry = enums->enums.find(key);
++ if (existingEntry != enums->enums.end() && existingEntry.value() != value) {
++ qWarning("Previously registered enum will be overwritten due to name clash: %s.%s", metaObject->className(), key.toUtf8().constData());
++ createEnumConflictReport(metaObject, key);
++ }
++ } else {
++ localEnums.insert(key);
++ }
++ enums->enums.insert(key, value);
++ }
++ e->insert(key, value);
++ }
++
++ if (isScoped) {
++ enums->scopedEnumIndex.insert(QString::fromUtf8(me.name()), enums->scopedEnums.size());
++ enums->scopedEnums << e;
++ } else {
++ enums->unscopedEnumIndex.insert(QString::fromUtf8(me.name()), enums->unscopedEnums.size());
++ enums->unscopedEnums << e;
++ }
++ }
++ }
++
++ void QQmlTypePrivate::createListOfPossibleConflictingItems(const QMetaObject *metaObject, QList<EnumInfo> &enumInfoList, QStringList path) const
++ {
++ path.append(QString::fromUtf8(metaObject->className()));
++
++ if (metaObject->d.relatedMetaObjects) {
++ const auto *related = metaObject->d.relatedMetaObjects;
++ if (related) {
++ while (*related)
++ createListOfPossibleConflictingItems(*related++, enumInfoList, path);
++ }
++ }
++
++ for (int ii = 0; ii < metaObject->enumeratorCount(); ++ii) {
++ const auto e = metaObject->enumerator(ii);
++
++ for (int jj = 0; jj < e.keyCount(); ++jj) {
++ const QString key = QString::fromUtf8(e.key(jj));
++
++ EnumInfo enumInfo;
++ enumInfo.metaObjectName = QString::fromUtf8(metaObject->className());
++ enumInfo.enumName = QString::fromUtf8(e.name());
++ enumInfo.enumKey = key;
++ enumInfo.scoped = e.isScoped();
++ enumInfo.path = path;
++ enumInfo.metaEnumScope = QString::fromUtf8(e.scope());
++ enumInfoList.append(enumInfo);
++ }
++ }
++ }
++
++ void QQmlTypePrivate::createEnumConflictReport(const QMetaObject *metaObject, const QString &conflictingKey) const
++ {
++ QList<EnumInfo> enumInfoList;
++
++ if (baseMetaObject) // prefer baseMetaObject if available
++ metaObject = baseMetaObject;
++
++ if (!metaObject) { // If there is no metaObject at all return early
++ qWarning() << "No meta object information available. Skipping conflict analysis.";
++ return;
++ }
++
++ createListOfPossibleConflictingItems(metaObject, enumInfoList, QStringList());
++
++ qWarning().noquote() << QLatin1String("Possible conflicting items:");
++ // find items with conflicting key
++ for (const auto &i : std::as_const(enumInfoList)) {
++ if (i.enumKey == conflictingKey)
++ qWarning().noquote().nospace() << " " << i.metaObjectName << "." << i.enumName << "." << i.enumKey << " from scope "
++ << i.metaEnumScope << " injected by " << i.path.join(QLatin1String("->"));
++ }
++ }
++
++ void QQmlTypePrivate::insertEnumsFromPropertyCache(
++ Enums *enums, const QQmlPropertyCache::ConstPtr &cache) const
++ {
++ const QMetaObject *cppMetaObject = cache->firstCppMetaObject();
++
++ for (const QQmlPropertyCache *currentCache = cache.data();
++ currentCache && currentCache->metaObject() != cppMetaObject;
++ currentCache = currentCache->parent().data()) {
++
++ int count = currentCache->ownEnumCount();
++ for (int ii = 0; ii < count; ++ii) {
++ QStringHash<int> *scoped = new QStringHash<int>();
++ QQmlEnumData *enumData = currentCache->qmlEnum(ii);
++
++ for (int jj = 0; jj < enumData->values.size(); ++jj) {
++ const QQmlEnumValue &value = enumData->values.at(jj);
++ enums->enums.insert(value.namedValue, value.value);
++ scoped->insert(value.namedValue, value.value);
++ }
++ enums->scopedEnums << scoped;
++ enums->scopedEnumIndex.insert(enumData->name, enums->scopedEnums.size()-1);
++ }
++ }
++ insertEnums(enums, cppMetaObject);
++ }
++
++ void QQmlTypePrivate::setName(const QString &uri, const QString &element)
++ {
++ module = uri;
++ elementName = element;
++ name = uri.isEmpty() ? element : (uri + QLatin1Char('/') + element);
++ }
++
++ QByteArray QQmlType::typeName() const
++ {
++ if (d) {
++ if (d->regType == SingletonType || d->regType == CompositeSingletonType)
++ return d->extraData.singletonTypeData->singletonInstanceInfo->typeName;
++ else if (d->baseMetaObject)
++ return d->baseMetaObject->className();
++ }
++ return QByteArray();
++ }
++
++ QString QQmlType::elementName() const
++ {
++ if (!d)
++ return QString();
++ return d->elementName;
++ }
++
++ QString QQmlType::qmlTypeName() const
++ {
++ if (!d)
++ return QString();
++ return d->name;
++ }
++
++ /*!
++ \internal
++ Allocates and initializes an object if the type is creatable.
++ Returns a pointer to the object, or nullptr if the type was
++ not creatable.
++ */
++ QObject *QQmlType::create() const
++ {
++ void *unused;
++ return create(&unused, 0);
++ }
++
++ /*!
++ \internal
++ \brief Like create without arguments, but allocates some extra space after the object.
++ \param memory An out-only argument. *memory will point to the start of the additionally
++ allocated memory.
++ \param additionalMemory The amount of extra memory in bytes that shoudld be allocated.
++
++ \note This function is used to allocate the QQmlData next to the object in the
++ QQmlObjectCreator.
++
++ \overload
++ */
++ QObject *QQmlType::create(void **memory, size_t additionalMemory) const
++ {
++ if (!d || !isCreatable())
++ return nullptr;
++
++ QObject *rv = (QObject *)operator new(d->extraData.cppTypeData->allocationSize + additionalMemory);
++ d->extraData.cppTypeData->newFunc(rv, d->extraData.cppTypeData->userdata);
++
++ createProxy(rv);
++ *memory = ((char *)rv) + d->extraData.cppTypeData->allocationSize;
++ return rv;
++ }
++
++ /*!
++ \internal
++ Like create, but also allocates memory behind the object, constructs a QQmlData there
++ and lets the objects declarativeData point to the newly created QQmlData.
++ */
++ QObject *QQmlType::createWithQQmlData() const
++ {
++ void *ddataMemory = nullptr;
++ auto instance = create(&ddataMemory, sizeof(QQmlData));
++ if (!instance)
++ return nullptr;
++ QObjectPrivate* p = QObjectPrivate::get(instance);
++ Q_ASSERT(!p->isDeletingChildren);
++ if (!p->declarativeData)
++ p->declarativeData = new (ddataMemory) QQmlData(QQmlData::DoesNotOwnMemory);
++ return instance;
++ }
++
++ QQmlType::SingletonInstanceInfo::ConstPtr QQmlType::singletonInstanceInfo() const
++ {
++ if (!d)
++ return {};
++ if (d->regType != SingletonType && d->regType != CompositeSingletonType)
++ return {};
++ return d->extraData.singletonTypeData->singletonInstanceInfo;
++ }
++
++ QQmlCustomParser *QQmlType::customParser() const
++ {
++ if (!d)
++ return nullptr;
++ if (d->regType != CppType)
++ return nullptr;
++ return d->extraData.cppTypeData->customParser;
++ }
++
++ QQmlType::CreateValueTypeFunc QQmlType::createValueTypeFunction() const
++ {
++ if (!d || d->regType != CppType)
++ return nullptr;
++ return d->extraData.cppTypeData->createValueTypeFunc;
++ }
++
++ bool QQmlType::canConstructValueType() const
++ {
++ if (!d || d->regType != CppType)
++ return false;
++ return d->extraData.cppTypeData->constructValueType;
++ }
++
++ bool QQmlType::canPopulateValueType() const
++ {
++ if (!d || d->regType != CppType)
++ return false;
++ return d->extraData.cppTypeData->populateValueType;
++ }
++
++ QQmlType::CreateFunc QQmlType::createFunction() const
++ {
++ if (!d || d->regType != CppType)
++ return nullptr;
++ return d->extraData.cppTypeData->newFunc;
++ }
++
++ QString QQmlType::noCreationReason() const
++ {
++ if (!d || d->regType != CppType)
++ return QString();
++ return d->extraData.cppTypeData->noCreationReason;
++ }
++
++ bool QQmlType::isCreatable() const
++ {
++ return d && d->regType == CppType && d->extraData.cppTypeData->newFunc;
++ }
++
++ QQmlType::ExtensionFunc QQmlType::extensionFunction() const
++ {
++ if (!d)
++ return nullptr;
++
++ switch (d->regType) {
++ case CppType:
++ return d->extraData.cppTypeData->extFunc;
++ case SingletonType:
++ return d->extraData.singletonTypeData->extFunc;
++ default:
++ return nullptr;
++ }
++ }
++
++ const QMetaObject *QQmlType::extensionMetaObject() const
++ {
++ if (!d)
++ return nullptr;
++
++ switch (d->regType) {
++ case CppType:
++ return d->extraData.cppTypeData->extMetaObject;
++ case SingletonType:
++ return d->extraData.singletonTypeData->extMetaObject;
++ default:
++ return nullptr;
++ }
++ }
++
++ bool QQmlType::isExtendedType() const
++ {
++ return d && !d->init()->data.isEmpty();
++ }
++
++ bool QQmlType::isSingleton() const
++ {
++ return d && (d->regType == SingletonType || d->regType == CompositeSingletonType);
++ }
++
++ bool QQmlType::isInterface() const
++ {
++ return d && d->regType == InterfaceType;
++ }
++
++ bool QQmlType::isComposite() const
++ {
++ return d && d->isComposite();
++ }
++
++ bool QQmlType::isCompositeSingleton() const
++ {
++ return d && d->regType == CompositeSingletonType;
++ }
++
++ bool QQmlType::isQObjectSingleton() const
++ {
++ return d && d->regType == SingletonType && d->extraData.singletonTypeData->singletonInstanceInfo->qobjectCallback;
++ }
++
++ bool QQmlType::isQJSValueSingleton() const
++ {
++ return d && d->regType == SingletonType && d->extraData.singletonTypeData->singletonInstanceInfo->scriptCallback;
++ }
++
++ bool QQmlType::isSequentialContainer() const
++ {
++ return d && d->regType == SequentialContainerType;
++ }
++
++ bool QQmlType::isValueType() const
++ {
++ return d && d->isValueType();
++ }
++
++ QMetaType QQmlType::typeId() const
++ {
++ return d ? d->typeId : QMetaType{};
++ }
++
++ QMetaType QQmlType::qListTypeId() const
++ {
++ return d ? d->listId : QMetaType{};
++ }
++
++ QMetaSequence QQmlType::listMetaSequence() const
++ {
++ return isSequentialContainer() ? d->extraData.sequentialContainerTypeData : QMetaSequence();
++ }
++
++ const QMetaObject *QQmlType::metaObject() const
++ {
++ return d ? d->metaObject() : nullptr;
++ }
++
++ const QMetaObject *QQmlType::metaObjectForValueType() const
++ {
++ Q_ASSERT(d);
++ return d->metaObjectForValueType();
++ }
++
++ const QMetaObject *QQmlType::baseMetaObject() const
++ {
++ return d ? d->baseMetaObject : nullptr;
++ }
++
++ bool QQmlType::containsRevisionedAttributes() const
++ {
++ return d && d->init()->containsRevisionedAttributes;
++ }
++
++ QTypeRevision QQmlType::metaObjectRevision() const
++ {
++ return d ? d->revision : QTypeRevision();
++ }
++
++ QQmlAttachedPropertiesFunc QQmlType::attachedPropertiesFunction(QQmlTypeLoader *typeLoader) const
++ {
++ if (const QQmlTypePrivate *base = d ? d->attachedPropertiesBase(typeLoader) : nullptr)
++ return base->extraData.cppTypeData->attachedPropertiesFunc;
++ return nullptr;
++ }
++
++ const QMetaObject *QQmlType::attachedPropertiesType(QQmlTypeLoader *typeLoader) const
++ {
++ if (const QQmlTypePrivate *base = d ? d->attachedPropertiesBase(typeLoader) : nullptr)
++ return base->extraData.cppTypeData->attachedPropertiesType;
++ return nullptr;
++ }
++
++ int QQmlType::parserStatusCast() const
++ {
++ if (!d || d->regType != CppType)
++ return -1;
++ return d->extraData.cppTypeData->parserStatusCast;
++ }
++
++ int QQmlType::propertyValueSourceCast() const
++ {
++ if (!d || d->regType != CppType)
++ return -1;
++ return d->extraData.cppTypeData->propertyValueSourceCast;
++ }
++
++ int QQmlType::propertyValueInterceptorCast() const
++ {
++ if (!d || d->regType != CppType)
++ return -1;
++ return d->extraData.cppTypeData->propertyValueInterceptorCast;
++ }
++
++ int QQmlType::finalizerCast() const
++ {
++ if (!d || d->regType != CppType)
++ return -1;
++ return d->extraData.cppTypeData->finalizerCast;
++ }
++
++ const char *QQmlType::interfaceIId() const
++ {
++ if (!d || d->regType != InterfaceType)
++ return nullptr;
++ return d->extraData.interfaceTypeData;
++ }
++
++ int QQmlType::index() const
++ {
++ return d ? d->index : -1;
++ }
++
++ bool QQmlType::isInlineComponent() const
++ {
++ return d && d->regType == QQmlType::InlineComponentType;
++ }
++
++ QUrl QQmlType::sourceUrl() const
++ {
++ return d ? d->sourceUrl() : QUrl();
++ }
++
++ int QQmlType::enumValue(QQmlTypeLoader *typeLoader, const QHashedStringRef &name, bool *ok) const
++ {
++ return QQmlTypePrivate::enumValue(d, typeLoader, name, ok);
++ }
++
++ int QQmlType::enumValue(QQmlTypeLoader *typeLoader, const QHashedCStringRef &name, bool *ok) const
++ {
++ return QQmlTypePrivate::enumValue(d, typeLoader, name, ok);
++ }
++
++ int QQmlType::enumValue(QQmlTypeLoader *typeLoader, const QV4::String *name, bool *ok) const
++ {
++ return QQmlTypePrivate::enumValue(d, typeLoader, name, ok);
++ }
++
++ int QQmlType::scopedEnumIndex(QQmlTypeLoader *typeLoader, const QV4::String *name, bool *ok) const
++ {
++ return QQmlTypePrivate::enumIndex<QQmlTypePrivate::Enums::Scoped>(
++ d, typeLoader, name, ok);
++ }
++
++ int QQmlType::scopedEnumIndex(QQmlTypeLoader *typeLoader, const QString &name, bool *ok) const
++ {
++ return QQmlTypePrivate::enumIndex<QQmlTypePrivate::Enums::Scoped>(
++ d, typeLoader, name, ok);
++ }
++
++ int QQmlType::unscopedEnumIndex(QQmlTypeLoader *typeLoader, const QV4::String *name, bool *ok) const
++ {
++ return QQmlTypePrivate::enumIndex<QQmlTypePrivate::Enums::Unscoped>(
++ d, typeLoader, name, ok);
++ }
++
++ int QQmlType::unscopedEnumIndex(QQmlTypeLoader *typeLoader, const QString &name, bool *ok) const
++ {
++ return QQmlTypePrivate::enumIndex<QQmlTypePrivate::Enums::Unscoped>(
++ d, typeLoader, name, ok);
++ }
++
++ int QQmlType::scopedEnumValue(QQmlTypeLoader *typeLoader, int index, const QV4::String *name, bool *ok) const
++ {
++ return QQmlTypePrivate::enumValue<QQmlTypePrivate::Enums::Scoped>(
++ d, typeLoader, index, name, ok);
++ }
++
++ int QQmlType::scopedEnumValue(QQmlTypeLoader *typeLoader, int index, const QString &name, bool *ok) const
++ {
++ return QQmlTypePrivate::enumValue<QQmlTypePrivate::Enums::Scoped>(
++ d, typeLoader, index, name, ok);
++ }
++
++ int QQmlType::scopedEnumValue(QQmlTypeLoader *typeLoader, const QHashedStringRef &scopedEnumName, const QHashedStringRef &name, bool *ok) const
++ {
++ return QQmlTypePrivate::enumValue<QQmlTypePrivate::Enums::Scoped>(
++ d, typeLoader, scopedEnumName, name, ok);
++ }
++
++ int QQmlType::unscopedEnumValue(QQmlTypeLoader *typeLoader, int index, const QV4::String *name, bool *ok) const
++ {
++ return QQmlTypePrivate::enumValue<QQmlTypePrivate::Enums::Unscoped>(
++ d, typeLoader, index, name, ok);
++ }
++
++ int QQmlType::unscopedEnumValue(QQmlTypeLoader *typeLoader, int index, const QString &name, bool *ok) const
++ {
++ return QQmlTypePrivate::enumValue<QQmlTypePrivate::Enums::Unscoped>(
++ d, typeLoader, index, name, ok);
++ }
++
++ int QQmlType::unscopedEnumValue(QQmlTypeLoader *typeLoader, const QHashedStringRef &scopedEnumName, const QHashedStringRef &name, bool *ok) const
++ {
++ return QQmlTypePrivate::enumValue<QQmlTypePrivate::Enums::Unscoped>(
++ d, typeLoader, scopedEnumName, name, ok);
++ }
++
++ QString QQmlType::scopedEnumKey(QQmlTypeLoader *typeLoader, int index, int value, bool *ok) const
++ {
++ return QQmlTypePrivate::enumKey<QQmlTypePrivate::Enums::Scoped>(
++ d, typeLoader, index, value, ok);
++ }
++
++ QStringList QQmlType::scopedEnumKeys(QQmlTypeLoader *typeLoader, int index, int value, bool *ok) const
++ {
++ return QQmlTypePrivate::enumKeys<QQmlTypePrivate::Enums::Scoped>(
++ d, typeLoader, index, value, ok);
++ }
++
++ QString QQmlType::unscopedEnumKey(QQmlTypeLoader *typeLoader, int index, int value, bool *ok) const
++ {
++ return QQmlTypePrivate::enumKey<QQmlTypePrivate::Enums::Unscoped>(
++ d, typeLoader, index, value, ok);
++ }
++
++ QStringList QQmlType::unscopedEnumKeys(QQmlTypeLoader *typeLoader, int index, int value,
++ bool *ok) const
++ {
++ return QQmlTypePrivate::enumKeys<QQmlTypePrivate::Enums::Unscoped>(
++ d, typeLoader, index, value, ok);
++ }
++
++
++ void QQmlType::refHandle(const QQmlTypePrivate *priv)
++ {
++ if (priv)
++ priv->addref();
++ }
++
++ void QQmlType::derefHandle(const QQmlTypePrivate *priv)
++ {
++ if (priv)
++ priv->release();
++ }
++
++ int QQmlType::refCount(const QQmlTypePrivate *priv)
++ {
++ if (priv)
++ return priv->count();
++ return -1;
++ }
++
++ void QQmlType::createProxy(QObject *instance) const
++ {
++ const QQmlTypePrivate::ProxyMetaObjects *proxies = d->init();
++ if (!proxies->data.isEmpty())
++ (void)new QQmlProxyMetaObject(instance, &proxies->data);
++ }
++
++ QT_END_NAMESPACE