// Copyright (C) 2021 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef QQMLJSREGISTERCONTENT_P_H #define QQMLJSREGISTERCONTENT_P_H // // W A R N I N G // ------------- // // This file is not part of the Qt API. It exists purely as an // implementation detail. This header file may change from version to // version without notice, or even be removed. // // We mean it. #include "qqmljsscope_p.h" #include #include QT_BEGIN_NAMESPACE struct QQmlJSRegisterContentPrivate; class Q_QMLCOMPILER_EXPORT QQmlJSRegisterContent { public: // ContentVariant determines the relation between this register content and its scope(). // For example, a property is always a property of a type. That type is given as scope. // Most content variants can carry either a specific kind of content, as commented below, // or a conversion. If two or more register contents of the same content variant are merged, // they retain their content variant but become a conversion with the original register // contents linked as conversion origins. enum ContentVariant { ObjectById, // type (scope is QML scope of binding/function) TypeByName, // type (TODO: scope is not guaranteed to be useful) Singleton, // type (scope is either import namespace or QML scope) Script, // type (scope is either import namespace or QML scope) MetaType, // type (always QMetaObject, scope is the type reprented by the metaobject) Extension, // type (scope is the type being extended) ScopeObject, // type (either QML scope of binding/function or JS global object) ParentScope, // type (scope is the child scope) Property, // property (scope is the owner (hasOwnProperty) of the property) Method, // method (retrieved as property, including overloads), like property Enum, // enumeration (scope is the type the enumeration belongs to) Attachment, // type (scope is attacher; use attacher() and attachee() for clarity) ModulePrefix, // import namespace (scope is either QML scope or type the prefix is used on) MethodCall, // method call (resolved to specific overload), like property ListValue, // property (scope is list retrieved from) ListIterator, // property (scope is list being iterated) Literal, // type (scope does not exist) Operation, // type (scope does not exist) BaseType, // type (scope is derived type) Cast, // type (scope is type casted from) Storage, // type (scope does not exist) // Either a synthetic type or a merger of multiple different variants. // In the latter case, look at conversion origins to find out more. // Synthetic types should be short lived. Unknown,the }; enum { InvalidLookupIndex = -1 }; QQmlJSRegisterContent() = default; // General properties of the register content, (mostly) independent of kind or variant bool isNull() const { return !d; } bool isValid() const; bool isList() const; bool isWritable() const; ContentVariant variant() const; QString descriptiveName() const; QString containedTypeName() const; int resultLookupIndex() const; QQmlJSScope::ConstPtr storedType() const; QQmlJSScope::ConstPtr containedType() const; QQmlJSScope::ConstPtr scopeType() const; bool contains(const QQmlJSScope::ConstPtr &type) const { return type == containedType(); } bool isStoredIn(const QQmlJSScope::ConstPtr &type) const { return type == storedType(); } // Properties of specific kinds of register contents bool isType() const; QQmlJSScope::ConstPtr type() const; bool isProperty() const; QQmlJSMetaProperty property() const; int baseLookupIndex() const; bool isEnumeration() const; QQmlJSMetaEnum enumeration() const; QString enumMember() const; bool isMethod() const; QList method() const; QQmlJSScope::ConstPtr methodType() const; bool isImportNamespace() const; uint importNamespace() const; QQmlJSScope::ConstPtr importNamespaceType() const; bool isConversion() const; QQmlJSScope::ConstPtr conversionResultType() const; QQmlJSRegisterContent conversionResultScope() const; QList conversionOrigins() const; bool isMethodCall() const; QQmlJSMetaMethod methodCall() const; bool isJavaScriptReturnValue() const; // Linked register contents QQmlJSRegisterContent attacher() const; QQmlJSRegisterContent attachee() const; QQmlJSRegisterContent scope() const; QQmlJSRegisterContent storage() const; QQmlJSRegisterContent original() const; QQmlJSRegisterContent shadowed() const; private: friend class QQmlJSRegisterContentPool; // TODO: Constant string/number/bool/enumval QQmlJSRegisterContent(QQmlJSRegisterContentPrivate *dd) : d(dd) {}; friend bool operator==(QQmlJSRegisterContent a, QQmlJSRegisterContent b) { return a.d == b.d; } friend bool operator!=(QQmlJSRegisterContent a, QQmlJSRegisterContent b) { return !(a == b); } friend size_t qHash(QQmlJSRegisterContent registerContent, size_t seed = 0) { return qHash(registerContent.d, seed); } QQmlJSRegisterContentPrivate *d = nullptr; }; class Q_QMLCOMPILER_EXPORT QQmlJSRegisterContentPool { Q_DISABLE_COPY_MOVE(QQmlJSRegisterContentPool) public: using ContentVariant = QQmlJSRegisterContent::ContentVariant; QQmlJSRegisterContentPool(); ~QQmlJSRegisterContentPool(); // Create new register contents of specific kinds QQmlJSRegisterContent createType( const QQmlJSScope::ConstPtr &type, int resultLookupIndex, ContentVariant variant, QQmlJSRegisterContent scope = {}); QQmlJSRegisterContent createProperty( const QQmlJSMetaProperty &property, int baseLookupIndex, int resultLookupIndex, ContentVariant variant, QQmlJSRegisterContent scope); QQmlJSRegisterContent createEnumeration( const QQmlJSMetaEnum &enumeration, const QString &enumMember, ContentVariant variant, QQmlJSRegisterContent scope); QQmlJSRegisterContent createMethod( const QList &methods, const QQmlJSScope::ConstPtr &methodType, ContentVariant variant, QQmlJSRegisterContent scope); QQmlJSRegisterContent createMethodCall( const QQmlJSMetaMethod &method, const QQmlJSScope::ConstPtr &returnType, QQmlJSRegisterContent scope); QQmlJSRegisterContent createImportNamespace( uint importNamespaceStringId, const QQmlJSScope::ConstPtr &importNamespaceType, ContentVariant variant, QQmlJSRegisterContent scope); QQmlJSRegisterContent createConversion( const QList &origins, const QQmlJSScope::ConstPtr &conversion, QQmlJSRegisterContent conversionScope, ContentVariant variant, QQmlJSRegisterContent scope); // Clone and possibly adapt register contents. This leaves the original intact. QQmlJSRegisterContent storedIn( QQmlJSRegisterContent content, const QQmlJSScope::ConstPtr &newStoredType); QQmlJSRegisterContent castTo( QQmlJSRegisterContent content, const QQmlJSScope::ConstPtr &newContainedType); QQmlJSRegisterContent clone(QQmlJSRegisterContent from) { return clone(from.d); } // Change the internals of the given register content. Adjusting and generalizing store a // copy of the previous content as original() and shadowed(), respectively. Storing creates // a new register content for storage(). All of those assume you only do this once per // register content (although you can adjust and generalize the storage, for example). void storeType( QQmlJSRegisterContent content, const QQmlJSScope::ConstPtr &stored); void adjustType( QQmlJSRegisterContent content, const QQmlJSScope::ConstPtr &adjusted); void generalizeType( QQmlJSRegisterContent content, const QQmlJSScope::ConstPtr &generalized); enum AllocationMode { Permanent, Temporary }; void setAllocationMode(AllocationMode mode); void clearTemporaries(); private: struct Deleter { // It's a template so that we only need the QQmlJSRegisterContentPrivate dtor on usage. template constexpr void operator()(Private *d) const { delete d; } }; using Pool = std::vector>; QQmlJSRegisterContentPrivate *clone(const QQmlJSRegisterContentPrivate *from); QQmlJSRegisterContentPrivate *create() { return clone(nullptr); } QQmlJSRegisterContentPrivate *create(QQmlJSRegisterContent scope, ContentVariant variant); Pool m_pool; qsizetype m_checkpoint = -1; }; QT_END_NAMESPACE #endif // REGISTERCONTENT_H