diff options
Diffstat (limited to 'src/qmlcompiler/qqmljsmetatypes_p.h')
-rw-r--r-- | src/qmlcompiler/qqmljsmetatypes_p.h | 794 |
1 files changed, 687 insertions, 107 deletions
diff --git a/src/qmlcompiler/qqmljsmetatypes_p.h b/src/qmlcompiler/qqmljsmetatypes_p.h index 57328af836..0ea7020a2d 100644 --- a/src/qmlcompiler/qqmljsmetatypes_p.h +++ b/src/qmlcompiler/qqmljsmetatypes_p.h @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2019 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the tools applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2019 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef QQMLJSMETATYPES_P_H #define QQMLJSMETATYPES_P_H @@ -39,9 +14,20 @@ // // We mean it. +#include <qtqmlcompilerexports.h> + #include <QtCore/qstring.h> #include <QtCore/qstringlist.h> #include <QtCore/qsharedpointer.h> +#include <QtCore/qvariant.h> +#include <QtCore/qhash.h> + +#include <QtQml/private/qqmljssourcelocation_p.h> +#include <QtQml/private/qqmltranslation_p.h> + +#include "qqmlsaconstants.h" +#include "qqmlsa.h" +#include "qqmljsannotation_p.h" // MetaMethod and MetaProperty have both type names and actual QQmlJSScope types. // When parsing the information from the relevant QML or qmltypes files, we only @@ -55,6 +41,14 @@ QT_BEGIN_NAMESPACE +enum ScriptBindingValueType : unsigned int { + ScriptValue_Unknown, + ScriptValue_Undefined // property int p: undefined +}; + +using QQmlJSMetaMethodType = QQmlSA::MethodType; + +class QQmlJSTypeResolver; class QQmlJSScope; class QQmlJSMetaEnum { @@ -62,8 +56,11 @@ class QQmlJSMetaEnum QList<int> m_values; // empty if values unknown. QString m_name; QString m_alias; + QString m_typeName; QSharedPointer<const QQmlJSScope> m_type; bool m_isFlag = false; + bool m_isScoped = false; + bool m_isQml = false; public: QQmlJSMetaEnum() = default; @@ -80,6 +77,12 @@ public: bool isFlag() const { return m_isFlag; } void setIsFlag(bool isFlag) { m_isFlag = isFlag; } + bool isScoped() const { return m_isScoped; } + void setIsScoped(bool v) { m_isScoped = v; } + + bool isQml() const { return m_isQml; } + void setIsQml(bool v) { m_isQml = v; } + void addKey(const QString &key) { m_keys.append(key); } QStringList keys() const { return m_keys; } @@ -90,6 +93,9 @@ public: int value(const QString &key) const { return m_values.value(m_keys.indexOf(key)); } bool hasKey(const QString &key) const { return m_keys.indexOf(key) != -1; } + QString typeName() const { return m_typeName; } + void setTypeName(const QString &typeName) { m_typeName = typeName; } + QSharedPointer<const QQmlJSScope> type() const { return m_type; } void setType(const QSharedPointer<const QQmlJSScope> &type) { m_type = type; } @@ -100,7 +106,8 @@ public: && a.m_name == b.m_name && a.m_alias == b.m_alias && a.m_isFlag == b.m_isFlag - && a.m_type == b.m_type; + && a.m_type == b.m_type + && a.m_isScoped == b.m_isScoped; } friend bool operator!=(const QQmlJSMetaEnum &a, const QQmlJSMetaEnum &b) @@ -110,89 +117,201 @@ public: friend size_t qHash(const QQmlJSMetaEnum &e, size_t seed = 0) { - return qHashMulti(seed, e.m_keys, e.m_values, e.m_name, e.m_alias, e.m_isFlag, e.m_type); + return qHashMulti( + seed, e.m_keys, e.m_values, e.m_name, e.m_alias, e.m_isFlag, e.m_type, e.m_isScoped); } }; -class QQmlJSMetaMethod +class QQmlJSMetaParameter { public: - enum Type { - Signal, - Slot, - Method + /*! + \internal + A non-const parameter is passed either by pointer or by value, depending on its access + semantics. For types with reference access semantics, they can be const and will be passed + then as const pointer. Const references are treated like values (i.e. non-const). + */ + enum Constness { + NonConst = 0, + Const, }; - enum Access { - Private, - Protected, - Public - }; + QQmlJSMetaParameter(QString name = QString(), QString typeName = QString(), + Constness typeQualifier = NonConst, + QWeakPointer<const QQmlJSScope> type = {}) + : m_name(std::move(name)), + m_typeName(std::move(typeName)), + m_type(type), + m_typeQualifier(typeQualifier) + { + } + + QString name() const { return m_name; } + void setName(const QString &name) { m_name = name; } + QString typeName() const { return m_typeName; } + void setTypeName(const QString &typeName) { m_typeName = typeName; } + QSharedPointer<const QQmlJSScope> type() const { return m_type.toStrongRef(); } + void setType(QWeakPointer<const QQmlJSScope> type) { m_type = type; } + Constness typeQualifier() const { return m_typeQualifier; } + void setTypeQualifier(Constness typeQualifier) { m_typeQualifier = typeQualifier; } + bool isPointer() const { return m_isPointer; } + void setIsPointer(bool isPointer) { m_isPointer = isPointer; } + bool isList() const { return m_isList; } + void setIsList(bool isList) { m_isList = isList; } + + friend bool operator==(const QQmlJSMetaParameter &a, const QQmlJSMetaParameter &b) + { + return a.m_name == b.m_name && a.m_typeName == b.m_typeName + && a.m_type.owner_equal(b.m_type) + && a.m_typeQualifier == b.m_typeQualifier; + } + + friend bool operator!=(const QQmlJSMetaParameter &a, const QQmlJSMetaParameter &b) + { + return !(a == b); + } + + friend size_t qHash(const QQmlJSMetaParameter &e, size_t seed = 0) + { + return qHashMulti(seed, e.m_name, e.m_typeName, e.m_type.owner_hash(), + e.m_typeQualifier); + } + +private: + QString m_name; + QString m_typeName; + QWeakPointer<const QQmlJSScope> m_type; + Constness m_typeQualifier = NonConst; + bool m_isPointer = false; + bool m_isList = false; +}; + +using QQmlJSMetaReturnType = QQmlJSMetaParameter; + +class QQmlJSMetaMethod +{ +public: + enum Access { Private, Protected, Public }; + using MethodType = QQmlJSMetaMethodType; + +public: + /*! \internal + + Represents a relative JavaScript function/expression index within a type + in a QML document. Used as a typed alternative to int with an explicit + invalid state. + */ + enum class RelativeFunctionIndex : int { Invalid = -1 }; + + /*! \internal + + Represents an absolute JavaScript function/expression index pointing + into the QV4::ExecutableCompilationUnit::runtimeFunctions array. Used as + a typed alternative to int with an explicit invalid state. + */ + enum class AbsoluteFunctionIndex : int { Invalid = -1 }; QQmlJSMetaMethod() = default; explicit QQmlJSMetaMethod(QString name, QString returnType = QString()) - : m_name(std::move(name)) - , m_returnTypeName(std::move(returnType)) - , m_methodType(Method) - , m_methodAccess(Public) + : m_name(std::move(name)), + m_returnType(QString(), std::move(returnType)), + m_methodType(MethodType::Method) {} QString methodName() const { return m_name; } void setMethodName(const QString &name) { m_name = name; } - QString returnTypeName() const { return m_returnTypeName; } - QSharedPointer<const QQmlJSScope> returnType() const { return m_returnType.toStrongRef(); } - void setReturnTypeName(const QString &type) { m_returnTypeName = type; } - void setReturnType(const QSharedPointer<const QQmlJSScope> &type) - { - m_returnType = type; - } + QQmlJS::SourceLocation sourceLocation() const { return m_sourceLocation; } + void setSourceLocation(QQmlJS::SourceLocation location) { m_sourceLocation = location; } - QStringList parameterNames() const { return m_paramNames; } - QStringList parameterTypeNames() const { return m_paramTypeNames; } - QList<QSharedPointer<const QQmlJSScope>> parameterTypes() const - { - QList<QSharedPointer<const QQmlJSScope>> result; - for (const auto &type : m_paramTypes) - result.append(type.toStrongRef()); - return result; - } - void setParameterTypes(const QList<QSharedPointer<const QQmlJSScope>> &types) + QQmlJSMetaReturnType returnValue() const { return m_returnType; } + void setReturnValue(const QQmlJSMetaReturnType returnValue) { m_returnType = returnValue; } + QString returnTypeName() const { return m_returnType.typeName(); } + void setReturnTypeName(const QString &typeName) { m_returnType.setTypeName(typeName); } + QSharedPointer<const QQmlJSScope> returnType() const { return m_returnType.type(); } + void setReturnType(QWeakPointer<const QQmlJSScope> type) { m_returnType.setType(type); } + + QList<QQmlJSMetaParameter> parameters() const { return m_parameters; } + QPair<QList<QQmlJSMetaParameter>::iterator, QList<QQmlJSMetaParameter>::iterator> + mutableParametersRange() { - Q_ASSERT(types.length() == m_paramNames.length()); - m_paramTypes.clear(); - for (const auto &type : types) - m_paramTypes.append(type); + return { m_parameters.begin(), m_parameters.end() }; } - void addParameter(const QString &name, const QString &typeName, - const QSharedPointer<const QQmlJSScope> &type = {}) + + QStringList parameterNames() const { - m_paramNames.append(name); - m_paramTypeNames.append(typeName); - m_paramTypes.append(type); + QStringList names; + for (const auto &p : m_parameters) + names.append(p.name()); + + return names; } - int methodType() const { return m_methodType; } - void setMethodType(Type methodType) { m_methodType = methodType; } + void setParameters(const QList<QQmlJSMetaParameter> ¶meters) { m_parameters = parameters; } + + void addParameter(const QQmlJSMetaParameter &p) { m_parameters.append(p); } + + QQmlJSMetaMethodType methodType() const { return m_methodType; } + void setMethodType(MethodType methodType) { m_methodType = methodType; } Access access() const { return m_methodAccess; } int revision() const { return m_revision; } void setRevision(int r) { m_revision = r; } + bool isCloned() const { return m_isCloned; } + void setIsCloned(bool isCloned) { m_isCloned= isCloned; } + + bool isConstructor() const { return m_isConstructor; } + void setIsConstructor(bool isConstructor) { m_isConstructor = isConstructor; } + + bool isJavaScriptFunction() const { return m_isJavaScriptFunction; } + void setIsJavaScriptFunction(bool isJavaScriptFunction) + { + m_isJavaScriptFunction = isJavaScriptFunction; + } + + bool isImplicitQmlPropertyChangeSignal() const { return m_isImplicitQmlPropertyChangeSignal; } + void setIsImplicitQmlPropertyChangeSignal(bool isPropertyChangeSignal) + { + m_isImplicitQmlPropertyChangeSignal = isPropertyChangeSignal; + } + bool isValid() const { return !m_name.isEmpty(); } + const QVector<QQmlJSAnnotation>& annotations() const { return m_annotations; } + void setAnnotations(QVector<QQmlJSAnnotation> annotations) { m_annotations = annotations; } + + void setJsFunctionIndex(RelativeFunctionIndex index) + { + Q_ASSERT(!m_isConstructor); + m_relativeFunctionIndex = index; + } + + RelativeFunctionIndex jsFunctionIndex() const + { + Q_ASSERT(!m_isConstructor); + return m_relativeFunctionIndex; + } + + void setConstructorIndex(RelativeFunctionIndex index) + { + Q_ASSERT(m_isConstructor); + m_relativeFunctionIndex = index; + } + + RelativeFunctionIndex constructorIndex() const + { + Q_ASSERT(m_isConstructor); + return m_relativeFunctionIndex; + } + friend bool operator==(const QQmlJSMetaMethod &a, const QQmlJSMetaMethod &b) { - return a.m_name == b.m_name - && a.m_returnTypeName == b.m_returnTypeName - && a.m_returnType == b.m_returnType - && a.m_paramNames == b.m_paramNames - && a.m_paramTypeNames == b.m_paramTypeNames - && a.m_paramTypes == b.m_paramTypes - && a.m_methodType == b.m_methodType - && a.m_methodAccess == b.m_methodAccess - && a.m_revision == b.m_revision; + return a.m_name == b.m_name && a.m_returnType == b.m_returnType + && a.m_parameters == b.m_parameters && a.m_annotations == b.m_annotations + && a.m_methodType == b.m_methodType && a.m_methodAccess == b.m_methodAccess + && a.m_revision == b.m_revision && a.m_isConstructor == b.m_isConstructor; } friend bool operator!=(const QQmlJSMetaMethod &a, const QQmlJSMetaMethod &b) @@ -205,44 +324,59 @@ public: QtPrivate::QHashCombine combine; seed = combine(seed, method.m_name); - seed = combine(seed, method.m_returnTypeName); - seed = combine(seed, method.m_returnType.toStrongRef().data()); - seed = combine(seed, method.m_paramNames); + seed = combine(seed, method.m_returnType); + seed = combine(seed, method.m_annotations); seed = combine(seed, method.m_methodType); seed = combine(seed, method.m_methodAccess); seed = combine(seed, method.m_revision); + seed = combine(seed, method.m_isConstructor); - for (const auto &type : method.m_paramTypes) - seed = combine(seed, type.toStrongRef().data()); + for (const auto &type : method.m_parameters) { + seed = combine(seed, type); + } return seed; } private: QString m_name; - QString m_returnTypeName; - QWeakPointer<const QQmlJSScope> m_returnType; - QStringList m_paramNames; - QStringList m_paramTypeNames; - QList<QWeakPointer<const QQmlJSScope>> m_paramTypes; + QQmlJS::SourceLocation m_sourceLocation; + + QQmlJSMetaReturnType m_returnType; + QList<QQmlJSMetaParameter> m_parameters; + QList<QQmlJSAnnotation> m_annotations; - Type m_methodType = Signal; - Access m_methodAccess = Private; + MethodType m_methodType = MethodType::Signal; + Access m_methodAccess = Public; int m_revision = 0; + RelativeFunctionIndex m_relativeFunctionIndex = RelativeFunctionIndex::Invalid; + bool m_isCloned = false; + bool m_isConstructor = false; + bool m_isJavaScriptFunction = false; + bool m_isImplicitQmlPropertyChangeSignal = false; }; class QQmlJSMetaProperty { QString m_propertyName; QString m_typeName; + QString m_read; + QString m_write; + QString m_reset; QString m_bindable; + QString m_notify; + QString m_privateClass; + QString m_aliasExpr; QWeakPointer<const QQmlJSScope> m_type; + QVector<QQmlJSAnnotation> m_annotations; bool m_isList = false; bool m_isWritable = false; bool m_isPointer = false; - bool m_isAlias = false; + bool m_isFinal = false; + bool m_isConstant = false; int m_revision = 0; + int m_index = -1; // relative property index within owning QQmlJSScope public: QQmlJSMetaProperty() = default; @@ -253,12 +387,31 @@ public: void setTypeName(const QString &typeName) { m_typeName = typeName; } QString typeName() const { return m_typeName; } + void setRead(const QString &read) { m_read = read; } + QString read() const { return m_read; } + + void setWrite(const QString &write) { m_write = write; } + QString write() const { return m_write; } + + void setReset(const QString &reset) { m_reset = reset; } + QString reset() const { return m_reset; } + void setBindable(const QString &bindable) { m_bindable = bindable; } QString bindable() const { return m_bindable; } + void setNotify(const QString ¬ify) { m_notify = notify; } + QString notify() const { return m_notify; } + + void setPrivateClass(const QString &privateClass) { m_privateClass = privateClass; } + QString privateClass() const { return m_privateClass; } + bool isPrivate() const { return !m_privateClass.isEmpty(); } // exists for convenience + void setType(const QSharedPointer<const QQmlJSScope> &type) { m_type = type; } QSharedPointer<const QQmlJSScope> type() const { return m_type.toStrongRef(); } + void setAnnotations(const QList<QQmlJSAnnotation> &annotation) { m_annotations = annotation; } + const QList<QQmlJSAnnotation> &annotations() const { return m_annotations; } + void setIsList(bool isList) { m_isList = isList; } bool isList() const { return m_isList; } @@ -268,23 +421,32 @@ public: void setIsPointer(bool isPointer) { m_isPointer = isPointer; } bool isPointer() const { return m_isPointer; } - void setIsAlias(bool isAlias) { m_isAlias = isAlias; } - bool isAlias() const { return m_isAlias; } + void setAliasExpression(const QString &aliasString) { m_aliasExpr = aliasString; } + QString aliasExpression() const { return m_aliasExpr; } + bool isAlias() const { return !m_aliasExpr.isEmpty(); } // exists for convenience + + void setIsFinal(bool isFinal) { m_isFinal = isFinal; } + bool isFinal() const { return m_isFinal; } + + void setIsConstant(bool isConstant) { m_isConstant = isConstant; } + bool isConstant() const { return m_isConstant; } void setRevision(int revision) { m_revision = revision; } int revision() const { return m_revision; } + void setIndex(int index) { m_index = index; } + int index() const { return m_index; } + + bool isValid() const { return !m_propertyName.isEmpty(); } + friend bool operator==(const QQmlJSMetaProperty &a, const QQmlJSMetaProperty &b) { - return a.m_propertyName == b.m_propertyName - && a.m_typeName == b.m_typeName - && a.m_bindable == b.m_bindable - && a.m_type == b.m_type - && a.m_isList == b.m_isList - && a.m_isWritable == b.m_isWritable - && a.m_isPointer == b.m_isPointer - && a.m_isAlias == b.m_isAlias - && a.m_revision == b.m_revision; + return a.m_index == b.m_index && a.m_propertyName == b.m_propertyName + && a.m_typeName == b.m_typeName && a.m_bindable == b.m_bindable + && a.m_type.owner_equal(b.m_type) && a.m_isList == b.m_isList + && a.m_isWritable == b.m_isWritable && a.m_isPointer == b.m_isPointer + && a.m_aliasExpr == b.m_aliasExpr && a.m_revision == b.m_revision + && a.m_isFinal == b.m_isFinal; } friend bool operator!=(const QQmlJSMetaProperty &a, const QQmlJSMetaProperty &b) @@ -295,12 +457,430 @@ public: friend size_t qHash(const QQmlJSMetaProperty &prop, size_t seed = 0) { return qHashMulti(seed, prop.m_propertyName, prop.m_typeName, prop.m_bindable, - prop.m_type.toStrongRef().data(), - prop.m_isList, prop.m_isWritable, prop.m_isPointer, prop.m_isAlias, - prop.m_revision); + prop.m_type.toStrongRef().data(), prop.m_isList, prop.m_isWritable, + prop.m_isPointer, prop.m_aliasExpr, prop.m_revision, prop.m_isFinal, + prop.m_index); } }; +/*! + \class QQmlJSMetaPropertyBinding + + \internal + + Represents a single QML binding of a specific type. Typically, when you + create a new binding, you know all the details of it already, so you should + just set all the data at once. +*/ +class Q_QMLCOMPILER_EXPORT QQmlJSMetaPropertyBinding +{ + using BindingType = QQmlSA::BindingType; + using ScriptBindingKind = QQmlSA::ScriptBindingKind; + + // needs to be kept in sync with the BindingType enum + struct Content { + using Invalid = std::monostate; + struct BoolLiteral { + bool value; + friend bool operator==(BoolLiteral a, BoolLiteral b) { return a.value == b.value; } + friend bool operator!=(BoolLiteral a, BoolLiteral b) { return !(a == b); } + }; + struct NumberLiteral { + QT_WARNING_PUSH + QT_WARNING_DISABLE_CLANG("-Wfloat-equal") + QT_WARNING_DISABLE_GCC("-Wfloat-equal") + friend bool operator==(NumberLiteral a, NumberLiteral b) { return a.value == b.value; } + friend bool operator!=(NumberLiteral a, NumberLiteral b) { return !(a == b); } + QT_WARNING_POP + + double value; // ### TODO: int? + }; + struct StringLiteral { + friend bool operator==(StringLiteral a, StringLiteral b) { return a.value == b.value; } + friend bool operator!=(StringLiteral a, StringLiteral b) { return !(a == b); } + QString value; + }; + struct RegexpLiteral { + friend bool operator==(RegexpLiteral a, RegexpLiteral b) { return a.value == b.value; } + friend bool operator!=(RegexpLiteral a, RegexpLiteral b) { return !(a == b); } + QString value; + }; + struct Null { + friend bool operator==(Null , Null ) { return true; } + friend bool operator!=(Null a, Null b) { return !(a == b); } + }; + struct TranslationString { + friend bool operator==(TranslationString a, TranslationString b) + { + return a.text == b.text && a.comment == b.comment && a.number == b.number && a.context == b.context; + } + friend bool operator!=(TranslationString a, TranslationString b) { return !(a == b); } + QString text; + QString comment; + QString context; + int number; + }; + struct TranslationById { + friend bool operator==(TranslationById a, TranslationById b) + { + return a.id == b.id && a.number == b.number; + } + friend bool operator!=(TranslationById a, TranslationById b) { return !(a == b); } + QString id; + int number; + }; + struct Script { + friend bool operator==(Script a, Script b) + { + return a.index == b.index && a.kind == b.kind; + } + friend bool operator!=(Script a, Script b) { return !(a == b); } + QQmlJSMetaMethod::RelativeFunctionIndex index = + QQmlJSMetaMethod::RelativeFunctionIndex::Invalid; + ScriptBindingKind kind = ScriptBindingKind::Invalid; + ScriptBindingValueType valueType = ScriptBindingValueType::ScriptValue_Unknown; + }; + struct Object { + friend bool operator==(Object a, Object b) { return a.value.owner_equal(b.value) && a.typeName == b.typeName; } + friend bool operator!=(Object a, Object b) { return !(a == b); } + QString typeName; + QWeakPointer<const QQmlJSScope> value; + }; + struct Interceptor { + friend bool operator==(Interceptor a, Interceptor b) + { + return a.value.owner_equal(b.value) && a.typeName == b.typeName; + } + friend bool operator!=(Interceptor a, Interceptor b) { return !(a == b); } + QString typeName; + QWeakPointer<const QQmlJSScope> value; + }; + struct ValueSource { + friend bool operator==(ValueSource a, ValueSource b) + { + return a.value.owner_equal(b.value) && a.typeName == b.typeName; + } + friend bool operator!=(ValueSource a, ValueSource b) { return !(a == b); } + QString typeName; + QWeakPointer<const QQmlJSScope> value; + }; + struct AttachedProperty { + /* + AttachedProperty binding is a grouping for a series of bindings + belonging to the same scope(QQmlJSScope::AttachedPropertyScope). + Thus, the attached property binding itself only exposes the + attaching type object. Such object is unique per the enclosing + scope, so attaching types attached to different QML scopes are + different (think of them as objects in C++ terms). + + An attaching type object, being a QQmlJSScope, has bindings + itself. For instance: + ``` + Type { + Keys.enabled: true + } + ``` + tells us that "Type" has an AttachedProperty binding with + property name "Keys". The attaching object of that binding + (binding.attachingType()) has type "Keys" and a BoolLiteral + binding with property name "enabled". + */ + friend bool operator==(AttachedProperty a, AttachedProperty b) + { + return a.value.owner_equal(b.value); + } + friend bool operator!=(AttachedProperty a, AttachedProperty b) { return !(a == b); } + QWeakPointer<const QQmlJSScope> value; + }; + struct GroupProperty { + /* Given a group property declaration like + anchors.left: root.left + the QQmlJSMetaPropertyBinding will have name "anchors", and a m_bindingContent + of type GroupProperty, with groupScope pointing to the scope introudced by anchors + In that scope, there will be another QQmlJSMetaPropertyBinding, with name "left" and + m_bindingContent Script (for root.left). + There should never be more than one GroupProperty for the same name in the same + scope, though: If the scope also contains anchors.top: root.top that should reuse the + GroupProperty content (and add a top: root.top binding in it). There might however + still be an additional object or script binding ( anchors: {left: foo, right: bar }; + anchors: root.someFunction() ) or another binding to the property in a "derived" + type. + + ### TODO: Obtaining the effective binding result requires some resolving function + */ + QWeakPointer<const QQmlJSScope> groupScope; + friend bool operator==(GroupProperty a, GroupProperty b) { return a.groupScope.owner_equal(b.groupScope); } + friend bool operator!=(GroupProperty a, GroupProperty b) { return !(a == b); } + }; + using type = std::variant<Invalid, BoolLiteral, NumberLiteral, StringLiteral, + RegexpLiteral, Null, TranslationString, + TranslationById, Script, Object, Interceptor, + ValueSource, AttachedProperty, GroupProperty + >; + }; + using BindingContent = Content::type; + + QQmlJS::SourceLocation m_sourceLocation; + QString m_propertyName; // TODO: this is a debug-only information + BindingContent m_bindingContent; + + void ensureSetBindingTypeOnce() + { + Q_ASSERT(bindingType() == BindingType::Invalid); + } + + bool isLiteralBinding() const { return isLiteralBinding(bindingType()); } + + +public: + static bool isLiteralBinding(BindingType type) + { + return type == BindingType::BoolLiteral || type == BindingType::NumberLiteral + || type == BindingType::StringLiteral || type == BindingType::RegExpLiteral + || type == BindingType::Null; // special. we record it as literal + } + + QQmlJSMetaPropertyBinding(); + QQmlJSMetaPropertyBinding(QQmlJS::SourceLocation location) : m_sourceLocation(location) { } + explicit QQmlJSMetaPropertyBinding(QQmlJS::SourceLocation location, const QString &propName) + : m_sourceLocation(location), m_propertyName(propName) + { + } + explicit QQmlJSMetaPropertyBinding(QQmlJS::SourceLocation location, + const QQmlJSMetaProperty &prop) + : QQmlJSMetaPropertyBinding(location, prop.propertyName()) + { + } + + void setPropertyName(const QString &propertyName) { m_propertyName = propertyName; } + QString propertyName() const { return m_propertyName; } + + const QQmlJS::SourceLocation &sourceLocation() const { return m_sourceLocation; } + + BindingType bindingType() const { return BindingType(m_bindingContent.index()); } + + bool isValid() const; + + void setStringLiteral(QAnyStringView value) + { + ensureSetBindingTypeOnce(); + m_bindingContent = Content::StringLiteral { value.toString() }; + } + + void + setScriptBinding(QQmlJSMetaMethod::RelativeFunctionIndex value, ScriptBindingKind kind, + ScriptBindingValueType valueType = ScriptBindingValueType::ScriptValue_Unknown) + { + ensureSetBindingTypeOnce(); + m_bindingContent = Content::Script { value, kind, valueType }; + } + + void setGroupBinding(const QSharedPointer<const QQmlJSScope> &groupScope) + { + ensureSetBindingTypeOnce(); + m_bindingContent = Content::GroupProperty { groupScope }; + } + + void setAttachedBinding(const QSharedPointer<const QQmlJSScope> &attachingScope) + { + ensureSetBindingTypeOnce(); + m_bindingContent = Content::AttachedProperty { attachingScope }; + } + + void setBoolLiteral(bool value) + { + ensureSetBindingTypeOnce(); + m_bindingContent = Content::BoolLiteral { value }; + } + + void setNullLiteral() + { + ensureSetBindingTypeOnce(); + m_bindingContent = Content::Null {}; + } + + void setNumberLiteral(double value) + { + ensureSetBindingTypeOnce(); + m_bindingContent = Content::NumberLiteral { value }; + } + + void setRegexpLiteral(QAnyStringView value) + { + ensureSetBindingTypeOnce(); + m_bindingContent = Content::RegexpLiteral { value.toString() }; + } + + void setTranslation(QStringView text, QStringView comment, QStringView context, int number) + { + ensureSetBindingTypeOnce(); + m_bindingContent = + Content::TranslationString{ text.toString(), comment.toString(), context.toString(), number }; + } + + void setTranslationId(QStringView id, int number) + { + ensureSetBindingTypeOnce(); + m_bindingContent = Content::TranslationById{ id.toString(), number }; + } + + void setObject(const QString &typeName, const QSharedPointer<const QQmlJSScope> &type) + { + ensureSetBindingTypeOnce(); + m_bindingContent = Content::Object { typeName, type }; + } + + void setInterceptor(const QString &typeName, const QSharedPointer<const QQmlJSScope> &type) + { + ensureSetBindingTypeOnce(); + m_bindingContent = Content::Interceptor { typeName, type }; + } + + void setValueSource(const QString &typeName, const QSharedPointer<const QQmlJSScope> &type) + { + ensureSetBindingTypeOnce(); + m_bindingContent = Content::ValueSource { typeName, type }; + } + + // ### TODO: here and below: Introduce an allowConversion parameter, if yes, enable conversions e.g. bool -> number? + bool boolValue() const; + + double numberValue() const; + + QString stringValue() const; + + QString regExpValue() const; + + QQmlTranslation translationDataValue(QString qmlFileNameForContext = QStringLiteral("")) const; + + QSharedPointer<const QQmlJSScope> literalType(const QQmlJSTypeResolver *resolver) const; + + QQmlJSMetaMethod::RelativeFunctionIndex scriptIndex() const + { + if (auto *script = std::get_if<Content::Script>(&m_bindingContent)) + return script->index; + // warn + return QQmlJSMetaMethod::RelativeFunctionIndex::Invalid; + } + + ScriptBindingKind scriptKind() const + { + if (auto *script = std::get_if<Content::Script>(&m_bindingContent)) + return script->kind; + // warn + return ScriptBindingKind::Invalid; + } + + ScriptBindingValueType scriptValueType() const + { + if (auto *script = std::get_if<Content::Script>(&m_bindingContent)) + return script->valueType; + // warn + return ScriptBindingValueType::ScriptValue_Unknown; + } + + QString objectTypeName() const + { + if (auto *object = std::get_if<Content::Object>(&m_bindingContent)) + return object->typeName; + // warn + return {}; + } + QSharedPointer<const QQmlJSScope> objectType() const + { + if (auto *object = std::get_if<Content::Object>(&m_bindingContent)) + return object->value.lock(); + // warn + return {}; + } + + QString interceptorTypeName() const + { + if (auto *interceptor = std::get_if<Content::Interceptor>(&m_bindingContent)) + return interceptor->typeName; + // warn + return {}; + } + QSharedPointer<const QQmlJSScope> interceptorType() const + { + if (auto *interceptor = std::get_if<Content::Interceptor>(&m_bindingContent)) + return interceptor->value.lock(); + // warn + return {}; + } + + QString valueSourceTypeName() const + { + if (auto *valueSource = std::get_if<Content::ValueSource>(&m_bindingContent)) + return valueSource->typeName; + // warn + return {}; + } + QSharedPointer<const QQmlJSScope> valueSourceType() const + { + if (auto *valueSource = std::get_if<Content::ValueSource>(&m_bindingContent)) + return valueSource->value.lock(); + // warn + return {}; + } + + QSharedPointer<const QQmlJSScope> groupType() const + { + if (auto *group = std::get_if<Content::GroupProperty>(&m_bindingContent)) + return group->groupScope.lock(); + // warn + return {}; + } + + QSharedPointer<const QQmlJSScope> attachingType() const + { + if (auto *attached = std::get_if<Content::AttachedProperty>(&m_bindingContent)) + return attached->value.lock(); + // warn + return {}; + } + + bool hasLiteral() const + { + // TODO: Assumption: if the type is literal, we must have one + return isLiteralBinding(); + } + bool hasObject() const { return bindingType() == BindingType::Object; } + bool hasInterceptor() const + { + return bindingType() == BindingType::Interceptor; + } + bool hasValueSource() const + { + return bindingType() == BindingType::ValueSource; + } + + friend bool operator==(const QQmlJSMetaPropertyBinding &a, const QQmlJSMetaPropertyBinding &b) + { + return a.m_propertyName == b.m_propertyName + && a.m_bindingContent == b.m_bindingContent + && a.m_sourceLocation == b.m_sourceLocation; + } + + friend bool operator!=(const QQmlJSMetaPropertyBinding &a, const QQmlJSMetaPropertyBinding &b) + { + return !(a == b); + } + + friend size_t qHash(const QQmlJSMetaPropertyBinding &binding, size_t seed = 0) + { + // we don't need to care about the actual binding content when hashing + return qHashMulti(seed, binding.m_propertyName, binding.m_sourceLocation, + binding.bindingType()); + } +}; + +struct Q_QMLCOMPILER_EXPORT QQmlJSMetaSignalHandler +{ + QStringList signalParameters; + bool isMultiline; +}; + QT_END_NAMESPACE #endif // QQMLJSMETATYPES_P_H |