1// Copyright (C) 2019 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 "qqmlmetatypedata_p.h"
5
6#include <private/qqmltype_p_p.h>
7#include <private/qqmltypemodule_p.h>
8#include <private/qqmlpropertycache_p.h>
9
10QT_BEGIN_NAMESPACE
11
12QQmlMetaTypeData::QQmlMetaTypeData()
13{
14}
15
16QQmlMetaTypeData::~QQmlMetaTypeData()
17{
18 for (auto iter = compositeTypes.cbegin(), end = compositeTypes.cend(); iter != end; ++iter)
19 iter.value()->isRegistered = false;
20
21 propertyCaches.clear();
22 // Do this before the attached properties disappear.
23 types.clear();
24 undeletableTypes.clear();
25 qDeleteAll(c: metaTypeToValueType);
26}
27
28// This expects a "fresh" QQmlTypePrivate and adopts its reference.
29void QQmlMetaTypeData::registerType(QQmlTypePrivate *priv)
30{
31 for (int i = 0; i < types.size(); ++i) {
32 if (!types.at(i).isValid()) {
33 types[i] = QQmlType(priv);
34 priv->index = i;
35 priv->release();
36 return;
37 }
38 }
39 types.append(t: QQmlType(priv));
40 priv->index = types.size() - 1;
41 priv->release();
42}
43
44QQmlMetaTypeData::VersionedUri::VersionedUri(const std::unique_ptr<QQmlTypeModule> &module)
45 : uri(module->module()), majorVersion(module->majorVersion())
46{
47}
48
49QQmlTypeModule *QQmlMetaTypeData::findTypeModule(const QString &module, QTypeRevision version)
50{
51 const auto qqtm = std::lower_bound(
52 first: uriToModule.begin(), last: uriToModule.end(), val: VersionedUri(module, version),
53 comp: std::less<QQmlMetaTypeData::VersionedUri>());
54 if (qqtm == uriToModule.end())
55 return nullptr;
56
57 QQmlTypeModule *candidate = qqtm->get();
58 return (candidate->module() == module && candidate->majorVersion() == version.majorVersion())
59 ? candidate
60 : nullptr;
61}
62
63QQmlTypeModule *QQmlMetaTypeData::addTypeModule(std::unique_ptr<QQmlTypeModule> module)
64{
65 QQmlTypeModule *ret = module.get();
66 uriToModule.emplace_back(args: std::move(module));
67 std::sort(first: uriToModule.begin(), last: uriToModule.end(),
68 comp: [](const std::unique_ptr<QQmlTypeModule> &a,
69 const std::unique_ptr<QQmlTypeModule> &b) {
70 const int diff = a->module().compare(s: b->module());
71 return diff < 0 || (diff == 0 && a->majorVersion() < b->majorVersion());
72 });
73 return ret;
74}
75
76bool QQmlMetaTypeData::registerModuleTypes(const QString &uri)
77{
78 auto function = moduleTypeRegistrationFunctions.constFind(key: uri);
79 if (function != moduleTypeRegistrationFunctions.constEnd()) {
80 (*function)();
81 return true;
82 }
83 return false;
84}
85
86QQmlPropertyCache::ConstPtr QQmlMetaTypeData::propertyCacheForVersion(
87 int index, QTypeRevision version) const
88{
89 return (index < typePropertyCaches.size())
90 ? typePropertyCaches.at(i: index).value(key: version)
91 : QQmlPropertyCache::ConstPtr();
92}
93
94void QQmlMetaTypeData::setPropertyCacheForVersion(int index, QTypeRevision version,
95 const QQmlPropertyCache::ConstPtr &cache)
96{
97 if (index >= typePropertyCaches.size())
98 typePropertyCaches.resize(size: index + 1);
99 typePropertyCaches[index][version] = cache;
100}
101
102void QQmlMetaTypeData::clearPropertyCachesForVersion(int index)
103{
104 if (index < typePropertyCaches.size())
105 typePropertyCaches[index].clear();
106}
107
108QQmlPropertyCache::ConstPtr QQmlMetaTypeData::propertyCache(
109 const QMetaObject *metaObject, QTypeRevision version)
110{
111 if (QQmlPropertyCache::ConstPtr rv = propertyCaches.value(key: metaObject))
112 return rv;
113
114 QQmlPropertyCache::ConstPtr rv;
115 if (const QMetaObject *superMeta = metaObject->superClass())
116 rv = propertyCache(metaObject: superMeta, version)->copyAndAppend(metaObject, typeVersion: version);
117 else
118 rv = QQmlPropertyCache::createStandalone(metaObject);
119
120 const auto *mop = reinterpret_cast<const QMetaObjectPrivate *>(metaObject->d.data);
121 if (!(mop->flags & DynamicMetaObject))
122 propertyCaches.insert(key: metaObject, value: rv);
123
124 return rv;
125}
126
127QQmlPropertyCache::ConstPtr QQmlMetaTypeData::propertyCache(
128 const QQmlType &type, QTypeRevision version)
129{
130 Q_ASSERT(type.isValid());
131
132 if (auto pc = propertyCacheForVersion(index: type.index(), version))
133 return pc;
134
135 QVector<QQmlType> types;
136
137 quint8 maxMinorVersion = 0;
138
139 const QMetaObject *metaObject = type.metaObject();
140 Q_ASSERT(metaObject);
141
142 const QTypeRevision combinedVersion = version.hasMajorVersion()
143 ? version
144 : (version.hasMinorVersion()
145 ? QTypeRevision::fromVersion(majorVersion: type.version().majorVersion(),
146 minorVersion: version.minorVersion())
147 : QTypeRevision::fromMajorVersion(majorVersion: type.version().majorVersion()));
148
149 while (metaObject) {
150 QQmlType t = QQmlMetaType::qmlType(metaObject, module: type.module(), version: combinedVersion);
151 if (t.isValid()) {
152 maxMinorVersion = qMax(a: maxMinorVersion, b: t.version().minorVersion());
153 types << t;
154 } else {
155 types << QQmlType();
156 }
157
158 metaObject = metaObject->superClass();
159 }
160
161 const QTypeRevision maxVersion = QTypeRevision::fromVersion(majorVersion: combinedVersion.majorVersion(),
162 minorVersion: maxMinorVersion);
163 if (auto pc = propertyCacheForVersion(index: type.index(), version: maxVersion)) {
164 setPropertyCacheForVersion(index: type.index(), version: maxVersion, cache: pc);
165 return pc;
166 }
167
168 QQmlPropertyCache::ConstPtr raw = propertyCache(metaObject: type.metaObject(), version: combinedVersion);
169 QQmlPropertyCache::Ptr copied;
170
171 for (int ii = 0; ii < types.size(); ++ii) {
172 const QQmlType &currentType = types.at(i: ii);
173 if (!currentType.isValid())
174 continue;
175
176 QTypeRevision rev = currentType.metaObjectRevision();
177 int moIndex = types.size() - 1 - ii;
178
179 if (raw->allowedRevision(index: moIndex) != rev) {
180 if (copied.isNull()) {
181 copied = raw->copy();
182 raw = copied;
183 }
184 copied->setAllowedRevision(index: moIndex, allowed: rev);
185 }
186 }
187
188 // Test revision compatibility - the basic rule is:
189 // * Anything that is excluded, cannot overload something that is not excluded *
190
191 // Signals override:
192 // * other signals and methods of the same name.
193 // * properties named on<Signal Name>
194 // * automatic <property name>Changed notify signals
195
196 // Methods override:
197 // * other methods of the same name
198
199 // Properties override:
200 // * other elements of the same name
201
202#if 0
203 bool overloadError = false;
204 QString overloadName;
205
206 for (QQmlPropertyCache::StringCache::ConstIterator iter = raw->stringCache.begin();
207 !overloadError && iter != raw->stringCache.end();
208 ++iter) {
209
210 const QQmlPropertyData *d = *iter;
211 if (raw->isAllowedInRevision(d))
212 continue; // Not excluded - no problems
213
214 // check that a regular "name" overload isn't happening
215 const QQmlPropertyData *current = d;
216 while (!overloadError && current) {
217 current = d->overrideData(current);
218 if (current && raw->isAllowedInRevision(current))
219 overloadError = true;
220 }
221 }
222
223 if (overloadError) {
224 if (hasCopied) raw->release();
225
226 error.setDescription(QLatin1String("Type ") + type.qmlTypeName() + QLatin1Char(' ') + QString::number(type.majorVersion()) + QLatin1Char('.') + QString::number(minorVersion) + QLatin1String(" contains an illegal property \"") + overloadName + QLatin1String("\". This is an error in the type's implementation."));
227 return 0;
228 }
229#endif
230
231 setPropertyCacheForVersion(index: type.index(), version, cache: raw);
232
233 if (version != maxVersion)
234 setPropertyCacheForVersion(index: type.index(), version: maxVersion, cache: raw);
235
236 return raw;
237}
238
239static QQmlPropertyCache::ConstPtr propertyCacheForPotentialInlineComponentType(
240 QMetaType t,
241 const QHash<const QtPrivate::QMetaTypeInterface *,
242 QV4::ExecutableCompilationUnit *>::const_iterator &iter) {
243 if (t != (*iter)->typeIds.id) {
244 // this is an inline component, and what we have in the iterator is currently the parent compilation unit
245 for (auto &&icDatum: (*iter)->inlineComponentData)
246 if (icDatum.typeIds.id == t)
247 return (*iter)->propertyCaches.at(index: icDatum.objectIndex);
248 }
249 return (*iter)->rootPropertyCache();
250}
251
252QQmlPropertyCache::ConstPtr QQmlMetaTypeData::findPropertyCacheInCompositeTypes(QMetaType t) const
253{
254 auto iter = compositeTypes.constFind(key: t.iface());
255 return (iter == compositeTypes.constEnd())
256 ? QQmlPropertyCache::ConstPtr()
257 : propertyCacheForPotentialInlineComponentType(t, iter);
258}
259
260QT_END_NAMESPACE
261

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