1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qqmlpropertycachecreator_p.h"
5
6#include <private/qqmlengine_p.h>
7
8#if QT_CONFIG(regularexpression)
9#include <QtCore/qregularexpression.h>
10#endif
11
12QT_BEGIN_NAMESPACE
13
14QAtomicInt QQmlPropertyCacheCreatorBase::classIndexCounter(0);
15
16
17QMetaType QQmlPropertyCacheCreatorBase::metaTypeForPropertyType(QV4::CompiledData::CommonType type)
18{
19 switch (type) {
20 case QV4::CompiledData::CommonType::Void: return QMetaType();
21 case QV4::CompiledData::CommonType::Var: return QMetaType::fromType<QVariant>();
22 case QV4::CompiledData::CommonType::Int: return QMetaType::fromType<int>();
23 case QV4::CompiledData::CommonType::Bool: return QMetaType::fromType<bool>();
24 case QV4::CompiledData::CommonType::Real: return QMetaType::fromType<qreal>();
25 case QV4::CompiledData::CommonType::String: return QMetaType::fromType<QString>();
26 case QV4::CompiledData::CommonType::Url: return QMetaType::fromType<QUrl>();
27 case QV4::CompiledData::CommonType::Time: return QMetaType::fromType<QTime>();
28 case QV4::CompiledData::CommonType::Date: return QMetaType::fromType<QDate>();
29 case QV4::CompiledData::CommonType::DateTime: return QMetaType::fromType<QDateTime>();
30#if QT_CONFIG(regularexpression)
31 case QV4::CompiledData::CommonType::RegExp: return QMetaType::fromType<QRegularExpression>();
32#else
33 case QV4::CompiledData::CommonType::RegExp: return QMetaType();
34#endif
35 case QV4::CompiledData::CommonType::Rect: return QMetaType::fromType<QRectF>();
36 case QV4::CompiledData::CommonType::Point: return QMetaType::fromType<QPointF>();
37 case QV4::CompiledData::CommonType::Size: return QMetaType::fromType<QSizeF>();
38 case QV4::CompiledData::CommonType::Invalid: break;
39 };
40 return QMetaType {};
41}
42
43QMetaType QQmlPropertyCacheCreatorBase::listTypeForPropertyType(QV4::CompiledData::CommonType type)
44{
45 switch (type) {
46 case QV4::CompiledData::CommonType::Void: return QMetaType();
47 case QV4::CompiledData::CommonType::Var: return QMetaType::fromType<QList<QVariant>>();
48 case QV4::CompiledData::CommonType::Int: return QMetaType::fromType<QList<int>>();
49 case QV4::CompiledData::CommonType::Bool: return QMetaType::fromType<QList<bool>>();
50 case QV4::CompiledData::CommonType::Real: return QMetaType::fromType<QList<qreal>>();
51 case QV4::CompiledData::CommonType::String: return QMetaType::fromType<QList<QString>>();
52 case QV4::CompiledData::CommonType::Url: return QMetaType::fromType<QList<QUrl>>();
53 case QV4::CompiledData::CommonType::Time: return QMetaType::fromType<QList<QTime>>();
54 case QV4::CompiledData::CommonType::Date: return QMetaType::fromType<QList<QDate>>();
55 case QV4::CompiledData::CommonType::DateTime: return QMetaType::fromType<QList<QDateTime>>();
56#if QT_CONFIG(regularexpression)
57 case QV4::CompiledData::CommonType::RegExp: return QMetaType::fromType<QList<QRegularExpression>>();
58#else
59 case QV4::CompiledData::CommonType::RegExp: return QMetaType();
60#endif
61 case QV4::CompiledData::CommonType::Rect: return QMetaType::fromType<QList<QRectF>>();
62 case QV4::CompiledData::CommonType::Point: return QMetaType::fromType<QList<QPointF>>();
63 case QV4::CompiledData::CommonType::Size: return QMetaType::fromType<QList<QSizeF>>();
64 case QV4::CompiledData::CommonType::Invalid: break;
65 };
66 return QMetaType {};
67}
68
69QByteArray QQmlPropertyCacheCreatorBase::createClassNameTypeByUrl(const QUrl &url)
70{
71 const QString path = url.path();
72 int lastSlash = path.lastIndexOf(c: QLatin1Char('/'));
73 // Not a reusable type if we don't have an absolute Url
74 if (lastSlash <= -1)
75 return QByteArray();
76 // ### this might not be correct for .ui.qml files
77 const QStringView nameBase = QStringView{path}.mid(pos: lastSlash + 1, n: path.size() - lastSlash - 5);
78 // Not a reusable type if it doesn't start with a upper case letter.
79 if (nameBase.isEmpty() || !nameBase.at(n: 0).isUpper())
80 return QByteArray();
81 return nameBase.toUtf8() + "_QMLTYPE_" +
82 QByteArray::number(classIndexCounter.fetchAndAddRelaxed(valueToAdd: 1));
83}
84
85QByteArray QQmlPropertyCacheCreatorBase::createClassNameForInlineComponent(const QUrl &baseUrl, int icId)
86{
87 QByteArray baseName = createClassNameTypeByUrl(url: baseUrl);
88 if (baseName.isEmpty())
89 baseName = QByteArray("ANON_QML_IC_") + QByteArray::number(classIndexCounter.fetchAndAddRelaxed(valueToAdd: 1));
90 baseName += "_" + QByteArray::number(icId);
91 return baseName;
92}
93
94QQmlBindingInstantiationContext::QQmlBindingInstantiationContext(
95 int referencingObjectIndex,
96 const QV4::CompiledData::Binding *instantiatingBinding,
97 const QString &instantiatingPropertyName,
98 const QQmlPropertyCache::ConstPtr &referencingObjectPropertyCache)
99 : referencingObjectIndex(referencingObjectIndex)
100 , instantiatingBinding(instantiatingBinding)
101 , instantiatingPropertyName(instantiatingPropertyName)
102 , referencingObjectPropertyCache(referencingObjectPropertyCache)
103{
104}
105
106bool QQmlBindingInstantiationContext::resolveInstantiatingProperty()
107{
108 if (!instantiatingBinding
109 || instantiatingBinding->type() != QV4::CompiledData::Binding::Type_GroupProperty) {
110 return true;
111 }
112
113 if (!referencingObjectPropertyCache)
114 return false;
115
116 Q_ASSERT(referencingObjectIndex >= 0);
117 Q_ASSERT(instantiatingBinding->propertyNameIndex != 0);
118
119 bool notInRevision = false;
120 instantiatingProperty = QQmlPropertyResolver(referencingObjectPropertyCache)
121 .property(name: instantiatingPropertyName, notInRevision: &notInRevision,
122 check: QQmlPropertyResolver::IgnoreRevision);
123 return instantiatingProperty != nullptr;
124}
125
126QQmlPropertyCache::ConstPtr QQmlBindingInstantiationContext::instantiatingPropertyCache() const
127{
128 if (instantiatingProperty) {
129 if (instantiatingProperty->isQObject()) {
130 // rawPropertyCacheForType assumes a given unspecified version means "any version".
131 // There is another overload that takes no version, which we shall not use here.
132 return QQmlMetaType::rawPropertyCacheForType(metaType: instantiatingProperty->propType(),
133 version: instantiatingProperty->typeVersion());
134 } else if (const QMetaObject *vtmo = QQmlMetaType::metaObjectForValueType(type: instantiatingProperty->propType())) {
135 return QQmlMetaType::propertyCache(metaObject: vtmo, version: instantiatingProperty->typeVersion());
136 }
137 }
138 return QQmlPropertyCache::ConstPtr();
139}
140
141void QQmlPendingGroupPropertyBindings::resolveMissingPropertyCaches(
142 QQmlPropertyCacheVector *propertyCaches) const
143{
144 for (QQmlBindingInstantiationContext pendingBinding: *this) {
145 const int groupPropertyObjectIndex = pendingBinding.instantiatingBinding->value.objectIndex;
146
147 if (propertyCaches->at(index: groupPropertyObjectIndex))
148 continue;
149
150 if (pendingBinding.instantiatingPropertyName.isEmpty()) {
151 // Generalized group property.
152 auto cache = propertyCaches->at(index: pendingBinding.referencingObjectIndex);
153 propertyCaches->set(index: groupPropertyObjectIndex, replacement: cache);
154 continue;
155 }
156
157 if (!pendingBinding.referencingObjectPropertyCache) {
158 pendingBinding.referencingObjectPropertyCache
159 = propertyCaches->at(index: pendingBinding.referencingObjectIndex);
160 }
161
162 if (!pendingBinding.resolveInstantiatingProperty())
163 continue;
164 auto cache = pendingBinding.instantiatingPropertyCache();
165 propertyCaches->set(index: groupPropertyObjectIndex, replacement: cache);
166 }
167}
168
169QT_END_NAMESPACE
170

source code of qtdeclarative/src/qml/qml/qqmlpropertycachecreator.cpp