Revision control
++ // Copyright (C) 2021 The Qt Company Ltd.
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
++ // Qt-Security score:significant
++
++ #include "qqmljsregistercontent_p.h"
++
++ #include <variant>
++
++ QT_BEGIN_NAMESPACE
++
++ using namespace Qt::StringLiterals;
++
++ struct QQmlJSRegisterContentPrivate
++ {
++ public:
++
++ using ContentVariant = QQmlJSRegisterContent::ContentVariant;
++
++ enum class Kind : size_t {
++ Type, Property, Enum, Method, ImportNamespace, Conversion, MethodCall
++ };
++
++ struct ConvertedTypes
++ {
++ QList<QQmlJSRegisterContent> origins;
++ QQmlJSScope::ConstPtr result;
++ QQmlJSRegisterContent resultScope;
++
++ friend size_t qHash(const ConvertedTypes &types, size_t seed = 0)
++ {
++ return qHashMulti(seed, types.origins, types.result, types.resultScope);
++ }
++
++ friend bool operator==(const ConvertedTypes &a, const ConvertedTypes &b)
++ {
++ return a.origins == b.origins && a.result == b.result && a.resultScope == b.resultScope;
++ }
++
++ friend bool operator!=(const ConvertedTypes &a, const ConvertedTypes &b)
++ {
++ return !(a == b);
++ }
++ };
++
++ struct PropertyLookup
++ {
++ QQmlJSMetaProperty property;
++ int baseLookupIndex = QQmlJSRegisterContent::InvalidLookupIndex;
++ int resultLookupIndex = QQmlJSRegisterContent::InvalidLookupIndex;
++
++ friend size_t qHash(const PropertyLookup &property, size_t seed = 0)
++ {
++ return qHashMulti(
++ seed, property.property, property.baseLookupIndex, property.resultLookupIndex);
++ }
++
++ friend bool operator==(const PropertyLookup &a, const PropertyLookup &b)
++ {
++ return a.baseLookupIndex == b.baseLookupIndex
++ && a.resultLookupIndex == b.resultLookupIndex
++ && a.property == b.property;
++ }
++
++ friend bool operator!=(const PropertyLookup &a, const PropertyLookup &b)
++ {
++ return !(a == b);
++ }
++ };
++
++ using Content = std::variant<
++ std::pair<QQmlJSScope::ConstPtr, int>,
++ PropertyLookup,
++ std::pair<QQmlJSMetaEnum, QString>,
++ std::pair<QList<QQmlJSMetaMethod>, QQmlJSScope::ConstPtr>,
++ std::pair<uint, QQmlJSScope::ConstPtr>,
++ ConvertedTypes,
++ QQmlJSMetaMethod
++ >;
++
++ friend size_t qHash(const QQmlJSRegisterContentPrivate ®isterContent, size_t seed = 0)
++ {
++ seed = qHashMulti(
++ seed, registerContent.m_storage, registerContent.m_content.index(),
++ registerContent.m_variant, registerContent.m_scope);
++
++ switch (Kind(registerContent.m_content.index())) {
++ case Kind::Type:
++ return qHash(std::get<std::pair<QQmlJSScope::ConstPtr, int>>(registerContent.m_content),
++ seed);
++ case Kind::Property:
++ return qHash(std::get<PropertyLookup>(registerContent.m_content), seed);
++ case Kind::Enum:
++ return qHash(std::get<std::pair<QQmlJSMetaEnum, QString>>(registerContent.m_content),
++ seed);
++ case Kind::Method:
++ return qHash(std::get<std::pair<QList<QQmlJSMetaMethod>, QQmlJSScope::ConstPtr>>(
++ registerContent.m_content), seed);
++ case Kind::ImportNamespace:
++ return qHash(std::get<std::pair<uint, QQmlJSScope::ConstPtr>>(
++ registerContent.m_content), seed);
++ case Kind::Conversion:
++ return qHash(std::get<ConvertedTypes>(registerContent.m_content), seed);
++ case Kind::MethodCall:
++ return qHash(std::get<QQmlJSMetaMethod>(registerContent.m_content), seed);
++ }
++
++ Q_UNREACHABLE_RETURN(seed);
++ }
++
++ friend bool operator==(
++ const QQmlJSRegisterContentPrivate &a, const QQmlJSRegisterContentPrivate &b)
++ {
++ return a.m_storage == b.m_storage && a.m_variant == b.m_variant
++ && a.m_scope == b.m_scope && a.m_content == b.m_content;
++ }
++
++ friend bool operator!=(
++ const QQmlJSRegisterContentPrivate &a, const QQmlJSRegisterContentPrivate &b)
++ {
++ return !(a == b);
++ }
++
++ QQmlJSRegisterContent m_storage;
++ QQmlJSRegisterContent m_scope;
++ Content m_content;
++ ContentVariant m_variant = ContentVariant::Unknown;
++
++ QQmlJSRegisterContent m_original;
++ QQmlJSRegisterContent m_shadowed;
++
++ int resultLookupIndex() const
++ {
++ switch (Kind(m_content.index())) {
++ case Kind::Type:
++ return std::get<std::pair<QQmlJSScope::ConstPtr, int>>(m_content).second;
++ case Kind::Property:
++ return std::get<PropertyLookup>(m_content).resultLookupIndex;
++ default:
++ return QQmlJSRegisterContent::InvalidLookupIndex;
++ }
++ }
++
++ void setType(const QQmlJSScope::ConstPtr &type)
++ {
++ switch (Kind(m_content.index())) {
++ case Kind::Type:
++ std::get<std::pair<QQmlJSScope::ConstPtr, int>>(m_content).first = type;
++ return;
++ case Kind::Property:
++ std::get<PropertyLookup>(m_content).property.setType(type);
++ return;
++ case Kind::Enum:
++ std::get<std::pair<QQmlJSMetaEnum, QString>>(m_content).first.setType(type);
++ return;
++ case Kind::Method:
++ std::get<std::pair<QList<QQmlJSMetaMethod>, QQmlJSScope::ConstPtr>>(m_content)
++ .second = type;
++ return;
++ case Kind::ImportNamespace:
++ std::get<std::pair<uint, QQmlJSScope::ConstPtr>>(m_content).second = type;
++ return;
++ case Kind::Conversion:
++ std::get<ConvertedTypes>(m_content).result = type;
++ return;
++ case Kind::MethodCall:
++ std::get<QQmlJSMetaMethod>(m_content).setReturnType({ type });
++ return;
++ }
++
++ Q_UNREACHABLE_RETURN();
++ }
++
++ private:
++ friend class QQmlJSRegisterContentPool;
++
++ QQmlJSRegisterContentPrivate() = default;
++ ~QQmlJSRegisterContentPrivate() = default;
++ QQmlJSRegisterContentPrivate(const QQmlJSRegisterContentPrivate &) = default;
++ QQmlJSRegisterContentPrivate(QQmlJSRegisterContentPrivate &&) = default;
++ QQmlJSRegisterContentPrivate &operator=(const QQmlJSRegisterContentPrivate &) = default;
++ QQmlJSRegisterContentPrivate &operator=(QQmlJSRegisterContentPrivate &&) = default;
++ };
++
++ bool QQmlJSRegisterContent::isValid() const
++ {
++ return !containedType().isNull();
++ };
++
++ QString QQmlJSRegisterContent::descriptiveName() const
++ {
++ using Kind = QQmlJSRegisterContentPrivate::Kind;
++
++ if (!d || (!d->m_storage.isValid() && containedType().isNull()))
++ return u"(invalid type)"_s;
++
++ const auto scope = [this]() -> QString {
++ if (!d->m_scope.isValid())
++ return u"(invalid type)::"_s;
++
++ const QQmlJSScope::ConstPtr scopeContained = d->m_scope.containedType();
++ if (scopeContained.isNull())
++ return u"(invalid type)::"_s;
++
++ return (scopeContained->internalName().isEmpty()
++ ? (scopeContained->filePath().isEmpty()
++ ? u"??"_s
++ : (u"(component in "_s + scopeContained->filePath() + u")"_s))
++ : scopeContained->internalName())
++ + u"::"_s;
++ };
++
++ QString result;
++ switch (Kind(d->m_content.index())) {
++ case Kind::Type: {
++ const QQmlJSScope::ConstPtr contained = type();
++ result += contained->internalName();
++ const QQmlJSScope::ConstPtr stored = d->m_storage.containedType();
++ if (stored && stored->internalName() != contained->internalName())
++ result += u" stored as "_s + stored->internalName();
++ return result;
++ }
++ case Kind::Property: {
++ const QQmlJSMetaProperty prop = property();
++ result += scope() + prop.propertyName() + u" with type "_s + prop.typeName();
++
++ QStringList details;
++ if (original().isValid() && !prop.type()->internalName().isEmpty())
++ details.append(u"adjusted to " + prop.type()->internalName());
++ const QQmlJSScope::ConstPtr stored = d->m_storage.containedType();
++ if (stored && stored->internalName() != prop.typeName())
++ details.append(u"stored as "_s + stored->internalName());
++
++ if (!details.isEmpty())
++ result += u" (%1)"_s.arg(details.join(u", "));
++
++ return result;
++ }
++ case Kind::Method: {
++ const auto methods = method();
++ if (methods.isEmpty())
++ result = scope() + u"(unknown method)"_s;
++ else
++ result = scope() + methods[0].methodName() + u"(...)"_s;
++ if (d->m_storage.isValid())
++ return result + u" (stored as "_s + d->m_storage.containedType()->internalName() + u")";
++ return result;
++ }
++ case Kind::Enum: {
++ const QString enumName = enumeration().name();
++ const QString memberName = enumMember();
++ if (memberName.isEmpty())
++ result = scope() + enumName;
++ else
++ result = scope() + enumName + u"::"_s + memberName;
++ if (d->m_storage.isValid())
++ return result + u" (stored as "_s + d->m_storage.containedType()->internalName() + u")";
++ return result;
++ }
++ case Kind::ImportNamespace: {
++ return u"import namespace %1"_s.arg(importNamespace());
++ }
++ case Kind::Conversion: {
++ return u"conversion to %1"_s.arg(conversionResultType()->internalName());
++ }
++ case Kind::MethodCall: {
++ const QQmlJSMetaMethod &method = std::get<QQmlJSMetaMethod>(d->m_content);
++ return u"call to method %1, returning %2"_s.arg(
++ method.methodName(), method.returnTypeName());
++ }
++ }
++
++ Q_UNREACHABLE_RETURN(result + u"wat?"_s);
++ }
++
++ QString QQmlJSRegisterContent::containedTypeName() const
++ {
++ QQmlJSScope::ConstPtr type;
++
++ switch (variant()) {
++ case QQmlJSRegisterContent::MetaType:
++ type = scopeType();
++ break;
++ default:
++ type = containedType();
++ break;
++ }
++
++ return QQmlJSScope::prettyName(
++ type->internalName().isEmpty() ? type->baseTypeName() : type->internalName());
++ }
++
++ bool QQmlJSRegisterContent::isType() const
++ {
++ return d && d->m_content.index() == size_t(QQmlJSRegisterContentPrivate::Kind::Type);
++ }
++
++ bool QQmlJSRegisterContent::isProperty() const
++ {
++ return d && d->m_content.index() == size_t(QQmlJSRegisterContentPrivate::Kind::Property);
++ }
++
++ bool QQmlJSRegisterContent::isEnumeration() const
++ {
++ return d && d->m_content.index() == size_t(QQmlJSRegisterContentPrivate::Kind::Enum);
++ }
++
++ bool QQmlJSRegisterContent::isMethod() const
++ {
++ return d && d->m_content.index() == size_t(QQmlJSRegisterContentPrivate::Kind::Method);
++ }
++
++ bool QQmlJSRegisterContent::isImportNamespace() const
++ {
++ return d && d->m_content.index() == size_t(QQmlJSRegisterContentPrivate::Kind::ImportNamespace);
++ }
++
++ bool QQmlJSRegisterContent::isConversion() const
++ {
++ return d && d->m_content.index() == size_t(QQmlJSRegisterContentPrivate::Kind::Conversion);
++ }
++
++ bool QQmlJSRegisterContent::isMethodCall() const
++ {
++ return d && d->m_content.index() == size_t(QQmlJSRegisterContentPrivate::Kind::MethodCall);
++ }
++
++ bool QQmlJSRegisterContent::isList() const
++ {
++ using Kind = QQmlJSRegisterContentPrivate::Kind;
++
++ if (!d)
++ return false;
++
++ switch (Kind(d->m_content.index())) {
++ case Kind::Type:
++ return std::get<std::pair<QQmlJSScope::ConstPtr, int>>(d->m_content).first
++ ->accessSemantics() == QQmlJSScope::AccessSemantics::Sequence;
++ case Kind::Property:
++ return std::get<QQmlJSRegisterContentPrivate::PropertyLookup>(d->m_content).property.type()
++ ->accessSemantics() == QQmlJSScope::AccessSemantics::Sequence;
++ case Kind::Conversion:
++ return std::get<QQmlJSRegisterContentPrivate::ConvertedTypes>(d->m_content).result
++ ->accessSemantics() == QQmlJSScope::AccessSemantics::Sequence;
++ case Kind::MethodCall:
++ return std::get<QQmlJSMetaMethod>(d->m_content).returnType()
++ ->accessSemantics() == QQmlJSScope::AccessSemantics::Sequence;
++ default:
++ return false;
++ }
++ }
++
++ bool QQmlJSRegisterContent::isWritable() const
++ {
++ using Kind = QQmlJSRegisterContentPrivate::Kind;
++
++ if (!d)
++ return false;
++
++ switch (Kind(d->m_content.index())) {
++ case Kind::Property:
++ return std::get<QQmlJSRegisterContentPrivate::PropertyLookup>(d->m_content)
++ .property.isWritable();
++
++ // TODO: What can we actually write?
++ default:
++ break;
++ }
++
++ return true;
++ }
++
++ bool QQmlJSRegisterContent::isJavaScriptReturnValue() const
++ {
++ return d && isMethodCall() && std::get<QQmlJSMetaMethod>(d->m_content).isJavaScriptFunction();
++ }
++
++ /*!
++ * \internal
++ * Precondition: This is an attachment.
++ * Return the type that does the attaching.
++ */
++ QQmlJSRegisterContent QQmlJSRegisterContent::attacher() const
++ {
++ Q_ASSERT(d);
++ Q_ASSERT(d->m_variant == Attachment);
++ return scope();
++ }
++
++ /*!
++ * \internal
++ * Precondition: This is an attachment.
++ * Return the type of the object the attachment is attached to.
++ */
++ QQmlJSRegisterContent QQmlJSRegisterContent::attachee() const
++ {
++ Q_ASSERT(d);
++ Q_ASSERT(d->m_variant == Attachment);
++ QQmlJSRegisterContent attachee = attacher().scope();
++ while (attachee.variant() == ModulePrefix)
++ attachee = attachee.scope();
++ return attachee;
++ }
++
++ QQmlJSScope::ConstPtr QQmlJSRegisterContent::storedType() const
++ {
++ return d ? d->m_storage.containedType() : QQmlJSScope::ConstPtr();
++ }
++
++ QQmlJSScope::ConstPtr QQmlJSRegisterContent::containedType() const
++ {
++ if (!d)
++ return QQmlJSScope::ConstPtr();
++ if (isType())
++ return type();
++ if (isProperty())
++ return std::get<QQmlJSRegisterContentPrivate::PropertyLookup>(d->m_content).property.type();
++ if (isEnumeration())
++ return std::get<std::pair<QQmlJSMetaEnum, QString>>(d->m_content).first.type();
++ if (isMethod())
++ return methodType();
++ if (isImportNamespace())
++ return importNamespaceType();
++ if (isConversion())
++ return conversionResultType();
++ if (isMethodCall())
++ return std::get<QQmlJSMetaMethod>(d->m_content).returnType();
++
++ Q_UNREACHABLE_RETURN({});
++ }
++
++ QQmlJSScope::ConstPtr QQmlJSRegisterContent::scopeType() const
++ {
++ return d ? d->m_scope.containedType() : QQmlJSScope::ConstPtr();
++ }
++
++ QQmlJSScope::ConstPtr QQmlJSRegisterContent::type() const
++ {
++ Q_ASSERT(isType());
++ return std::get<std::pair<QQmlJSScope::ConstPtr, int>>(d->m_content).first;
++ }
++
++ QQmlJSMetaProperty QQmlJSRegisterContent::property() const
++ {
++ Q_ASSERT(isProperty());
++ return std::get<QQmlJSRegisterContentPrivate::PropertyLookup>(d->m_content).property;
++ }
++
++ int QQmlJSRegisterContent::baseLookupIndex() const
++ {
++ Q_ASSERT(isProperty());
++ return std::get<QQmlJSRegisterContentPrivate::PropertyLookup>(d->m_content).baseLookupIndex;
++ }
++
++ int QQmlJSRegisterContent::resultLookupIndex() const
++ {
++ return d ? d->resultLookupIndex() : InvalidLookupIndex;
++ }
++
++ QQmlJSMetaEnum QQmlJSRegisterContent::enumeration() const
++ {
++ Q_ASSERT(isEnumeration());
++ return std::get<std::pair<QQmlJSMetaEnum, QString>>(d->m_content).first;
++ }
++
++ QString QQmlJSRegisterContent::enumMember() const
++ {
++ Q_ASSERT(isEnumeration());
++ return std::get<std::pair<QQmlJSMetaEnum, QString>>(d->m_content).second;
++ }
++
++ QList<QQmlJSMetaMethod> QQmlJSRegisterContent::method() const
++ {
++ Q_ASSERT(isMethod());
++ return std::get<std::pair<QList<QQmlJSMetaMethod>, QQmlJSScope::ConstPtr>>(d->m_content).first;
++ }
++
++ QQmlJSScope::ConstPtr QQmlJSRegisterContent::methodType() const
++ {
++ Q_ASSERT(isMethod());
++ return std::get<std::pair<QList<QQmlJSMetaMethod>, QQmlJSScope::ConstPtr>>(d->m_content).second;
++ }
++
++ uint QQmlJSRegisterContent::importNamespace() const
++ {
++ Q_ASSERT(isImportNamespace());
++ return std::get<std::pair<uint, QQmlJSScope::ConstPtr>>(d->m_content).first;
++ }
++
++ QQmlJSScope::ConstPtr QQmlJSRegisterContent::importNamespaceType() const
++ {
++ Q_ASSERT(isImportNamespace());
++ return std::get<std::pair<uint, QQmlJSScope::ConstPtr>>(d->m_content).second;
++ }
++
++ QQmlJSScope::ConstPtr QQmlJSRegisterContent::conversionResultType() const
++ {
++ Q_ASSERT(isConversion());
++ return std::get<QQmlJSRegisterContentPrivate::ConvertedTypes>(d->m_content).result;
++ }
++
++ QQmlJSRegisterContent QQmlJSRegisterContent::conversionResultScope() const
++ {
++ Q_ASSERT(isConversion());
++ return std::get<QQmlJSRegisterContentPrivate::ConvertedTypes>(d->m_content).resultScope;
++ }
++
++ const QList<QQmlJSRegisterContent> &QQmlJSRegisterContent::conversionOrigins() const
++ {
++ Q_ASSERT(isConversion());
++ return std::get<QQmlJSRegisterContentPrivate::ConvertedTypes>(d->m_content).origins;
++ }
++
++ QQmlJSMetaMethod QQmlJSRegisterContent::methodCall() const
++ {
++ Q_ASSERT(isMethodCall());
++ return std::get<QQmlJSMetaMethod>(d->m_content);
++ }
++
++ QQmlJSRegisterContent::ContentVariant QQmlJSRegisterContent::variant() const
++ {
++ return d ? d->m_variant : Unknown;
++ }
++
++ QQmlJSRegisterContent QQmlJSRegisterContent::scope() const
++ {
++ return d ? d->m_scope : QQmlJSRegisterContent();
++ }
++
++ QQmlJSRegisterContent QQmlJSRegisterContent::storage() const
++ {
++ return d ? d->m_storage : QQmlJSRegisterContent();
++ }
++
++ QQmlJSRegisterContent QQmlJSRegisterContent::original() const
++ {
++ return d ? d->m_original : QQmlJSRegisterContent();
++ }
++
++ QQmlJSRegisterContent QQmlJSRegisterContent::shadowed() const
++ {
++ return d ? d->m_shadowed : QQmlJSRegisterContent();
++ }
++
++ QQmlJSRegisterContentPool::QQmlJSRegisterContentPool() = default;
++ QQmlJSRegisterContentPool::~QQmlJSRegisterContentPool() = default;
++
++ QQmlJSRegisterContent QQmlJSRegisterContentPool::createType(
++ const QQmlJSScope::ConstPtr &type, int resultLookupIndex,
++ QQmlJSRegisterContent::ContentVariant variant, QQmlJSRegisterContent scope)
++ {
++ QQmlJSRegisterContentPrivate *result = create(scope, variant);
++ result->m_content = std::make_pair(type, resultLookupIndex);
++ return result;
++ }
++
++ QQmlJSRegisterContent QQmlJSRegisterContentPool::createProperty(
++ const QQmlJSMetaProperty &property, int baseLookupIndex, int resultLookupIndex,
++ QQmlJSRegisterContent::ContentVariant variant, QQmlJSRegisterContent scope)
++ {
++ QQmlJSRegisterContentPrivate *result = create(scope, variant);
++ result->m_content = QQmlJSRegisterContentPrivate::PropertyLookup {
++ property,
++ baseLookupIndex,
++ resultLookupIndex
++ };
++ return result;
++ }
++
++ QQmlJSRegisterContent QQmlJSRegisterContentPool::createEnumeration(
++ const QQmlJSMetaEnum &enumeration, const QString &enumMember,
++ QQmlJSRegisterContent::ContentVariant variant, QQmlJSRegisterContent scope)
++ {
++ QQmlJSRegisterContentPrivate *result = create(scope, variant);
++ result->m_content = std::make_pair(enumeration, enumMember);
++ return result;
++ }
++
++ QQmlJSRegisterContent QQmlJSRegisterContentPool::createMethod(
++ const QList<QQmlJSMetaMethod> &methods, const QQmlJSScope::ConstPtr &methodType,
++ QQmlJSRegisterContent::ContentVariant variant, QQmlJSRegisterContent scope)
++ {
++ // Methods can only be stored in QJSValue.
++ Q_ASSERT(methodType->internalName() == u"QJSValue"_s);
++ QQmlJSRegisterContentPrivate *result = create(scope, variant);
++ result->m_content = std::make_pair(methods, methodType);
++ return result;
++ }
++
++ QQmlJSRegisterContent QQmlJSRegisterContentPool::createMethodCall(
++ const QQmlJSMetaMethod &method, const QQmlJSScope::ConstPtr &returnType,
++ QQmlJSRegisterContent scope)
++ {
++ QQmlJSRegisterContentPrivate *result = create(scope, ContentVariant::MethodCall);
++
++ QQmlJSMetaMethod resultMethod = method;
++ resultMethod.setReturnType({ returnType });
++ resultMethod.setReturnTypeName(returnType->internalName());
++ result->m_content = std::move(resultMethod);
++
++ return result;
++ }
++
++ QQmlJSRegisterContent QQmlJSRegisterContentPool::createImportNamespace(
++ uint importNamespaceStringId, const QQmlJSScope::ConstPtr &importNamespaceType,
++ QQmlJSRegisterContent::ContentVariant variant, QQmlJSRegisterContent scope)
++ {
++ QQmlJSRegisterContentPrivate *result = create(scope, variant);
++ result->m_content = std::make_pair(importNamespaceStringId, importNamespaceType);
++ return result;
++ }
++
++ QQmlJSRegisterContent QQmlJSRegisterContentPool::createConversion(
++ const QList<QQmlJSRegisterContent> &origins, const QQmlJSScope::ConstPtr &conversion,
++ QQmlJSRegisterContent conversionScope, ContentVariant variant,
++ QQmlJSRegisterContent scope)
++ {
++ QQmlJSRegisterContentPrivate *result = create(scope, variant);
++
++ result->m_content = QQmlJSRegisterContentPrivate::ConvertedTypes {
++ origins,
++ conversion,
++ conversionScope
++ };
++
++ return result;
++ }
++
++ QQmlJSRegisterContent QQmlJSRegisterContentPool::storedIn(
++ QQmlJSRegisterContent content, const QQmlJSScope::ConstPtr &newStoredType)
++ {
++ Q_ASSERT(content.d);
++ QQmlJSRegisterContentPrivate *result = clone(content.d);
++ result->m_storage = createType(
++ newStoredType, QQmlJSRegisterContent::InvalidLookupIndex, ContentVariant::Storage);
++ return result;
++ }
++
++ QQmlJSRegisterContent QQmlJSRegisterContentPool::castTo(
++ QQmlJSRegisterContent content, const QQmlJSScope::ConstPtr &newContainedType)
++ {
++ // This is not a conversion but a run time cast. It may result in null or undefined.
++ QQmlJSRegisterContentPrivate *result = create(content, ContentVariant::Cast);
++ result->m_content = std::make_pair(newContainedType, result->resultLookupIndex());
++ return result;
++ }
++
++ void QQmlJSRegisterContentPool::storeType(
++ QQmlJSRegisterContent content, const QQmlJSScope::ConstPtr &stored)
++ {
++ QQmlJSRegisterContentPrivate *d = content.d;
++
++ Q_ASSERT(d);
++ Q_ASSERT(d->m_storage.isNull());
++ d->m_storage = createType(
++ stored, QQmlJSRegisterContent::InvalidLookupIndex, ContentVariant::Storage);
++ }
++
++ void QQmlJSRegisterContentPool::adjustType(
++ QQmlJSRegisterContent content, const QQmlJSScope::ConstPtr &adjusted)
++ {
++ QQmlJSRegisterContentPrivate *d = content.d;
++
++ Q_ASSERT(d);
++ Q_ASSERT(d->m_original.isNull());
++ d->m_original = clone(d);
++ d->setType(adjusted);
++ }
++
++ void QQmlJSRegisterContentPool::generalizeType(
++ QQmlJSRegisterContent content, const QQmlJSScope::ConstPtr &generalized)
++ {
++ QQmlJSRegisterContentPrivate *d = content.d;
++
++ Q_ASSERT(d);
++ Q_ASSERT(d->m_shadowed.isNull());
++ d->m_shadowed = clone(d);
++ d->setType(generalized);
++ }
++
++ void QQmlJSRegisterContentPool::setAllocationMode(AllocationMode mode)
++ {
++ m_checkpoint = (mode == Temporary) ? m_pool.size() : -1;
++ }
++
++ void QQmlJSRegisterContentPool::clearTemporaries()
++ {
++ if (m_checkpoint != -1)
++ m_pool.resize(m_checkpoint);
++ }
++
++ QQmlJSRegisterContentPrivate *QQmlJSRegisterContentPool::clone(
++ const QQmlJSRegisterContentPrivate *from)
++ {
++ m_pool.push_back(std::unique_ptr<QQmlJSRegisterContentPrivate, Deleter>(from
++ ? new QQmlJSRegisterContentPrivate(*from)
++ : new QQmlJSRegisterContentPrivate));
++ return m_pool.back().get();
++ }
++
++ QQmlJSRegisterContentPrivate *QQmlJSRegisterContentPool::create(
++ QQmlJSRegisterContent scope, ContentVariant variant)
++ {
++ QQmlJSRegisterContentPrivate *result = create();
++ result->m_scope = scope;
++ result->m_variant = variant;
++ return result;
++ }
++
++ QT_END_NAMESPACE