Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qqmlmetatypedata.cpp
Go to the documentation of this file.
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
5
6#include <private/qqmltype_p_p.h>
7#include <private/qqmltypemodule_p.h>
8#include <private/qqmlpropertycache_p.h>
9
11
12QQmlMetaTypeData::QQmlMetaTypeData()
13{
14}
15
17{
19 propertyCaches.clear();
20 // Do this before the attached properties disappear.
21 types.clear();
22 undeletableTypes.clear();
23 qDeleteAll(metaTypeToValueType);
25}
26
27// This expects a "fresh" QQmlTypePrivate and adopts its reference.
28void QQmlMetaTypeData::registerType(QQmlTypePrivate *priv)
29{
30 for (int i = 0; i < types.size(); ++i) {
31 if (!types.at(i).isValid()) {
32 types[i] = QQmlType(priv);
33 priv->index = i;
34 priv->release();
35 return;
36 }
37 }
38 types.append(QQmlType(priv));
39 priv->index = types.size() - 1;
40 priv->release();
41}
42
43QQmlMetaTypeData::VersionedUri::VersionedUri(const std::unique_ptr<QQmlTypeModule> &module)
45{
46}
47
48QQmlTypeModule *QQmlMetaTypeData::findTypeModule(const QString &module, QTypeRevision version)
49{
50 const auto qqtm = std::lower_bound(
51 uriToModule.begin(), uriToModule.end(), VersionedUri(module, version),
52 std::less<QQmlMetaTypeData::VersionedUri>());
53 if (qqtm == uriToModule.end())
54 return nullptr;
55
56 QQmlTypeModule *candidate = qqtm->get();
57 return (candidate->module() == module && candidate->majorVersion() == version.majorVersion())
58 ? candidate
59 : nullptr;
60}
61
62QQmlTypeModule *QQmlMetaTypeData::addTypeModule(std::unique_ptr<QQmlTypeModule> module)
63{
64 QQmlTypeModule *ret = module.get();
65 uriToModule.emplace_back(std::move(module));
66 std::sort(uriToModule.begin(), uriToModule.end(),
67 [](const std::unique_ptr<QQmlTypeModule> &a,
68 const std::unique_ptr<QQmlTypeModule> &b) {
69 const int diff = a->module().compare(b->module());
70 return diff < 0 || (diff == 0 && a->majorVersion() < b->majorVersion());
71 });
72 return ret;
73}
74
75bool QQmlMetaTypeData::registerModuleTypes(const QString &uri)
76{
77 auto function = moduleTypeRegistrationFunctions.constFind(uri);
78 if (function != moduleTypeRegistrationFunctions.constEnd()) {
79 (*function)();
80 return true;
81 }
82 return false;
83}
84
86 int index, QTypeRevision version) const
87{
88 return (index < typePropertyCaches.size())
89 ? typePropertyCaches.at(index).value(version)
90 : QQmlPropertyCache::ConstPtr();
91}
92
93void QQmlMetaTypeData::setPropertyCacheForVersion(int index, QTypeRevision version,
94 const QQmlPropertyCache::ConstPtr &cache)
95{
96 if (index >= typePropertyCaches.size())
97 typePropertyCaches.resize(index + 1);
98 typePropertyCaches[index][version] = cache;
99}
100
102{
103 if (index < typePropertyCaches.size())
104 typePropertyCaches[index].clear();
105}
106
108 const QMetaObject *metaObject, QTypeRevision version)
109{
110 if (QQmlPropertyCache::ConstPtr rv = propertyCaches.value(metaObject))
111 return rv;
112
113 QQmlPropertyCache::ConstPtr rv;
114 if (const QMetaObject *superMeta = metaObject->superClass())
115 rv = propertyCache(superMeta, version)->copyAndAppend(metaObject, version);
116 else
117 rv = QQmlPropertyCache::createStandalone(metaObject);
118
119 const auto *mop = reinterpret_cast<const QMetaObjectPrivate *>(metaObject->d.data);
120 if (!(mop->flags & DynamicMetaObject))
121 propertyCaches.insert(metaObject, rv);
122
123 return rv;
124}
125
127 const QQmlType &type, QTypeRevision version)
128{
129 Q_ASSERT(type.isValid());
130
131 if (auto pc = propertyCacheForVersion(type.index(), version))
132 return pc;
133
134 QVector<QQmlType> types;
135
136 quint8 maxMinorVersion = 0;
137
138 const QMetaObject *metaObject = type.metaObject();
139 Q_ASSERT(metaObject);
140
141 const QTypeRevision combinedVersion = version.hasMajorVersion()
142 ? version
143 : (version.hasMinorVersion()
144 ? QTypeRevision::fromVersion(type.version().majorVersion(),
145 version.minorVersion())
146 : QTypeRevision::fromMajorVersion(type.version().majorVersion()));
147
148 while (metaObject) {
149 QQmlType t = QQmlMetaType::qmlType(metaObject, type.module(), combinedVersion);
150 if (t.isValid()) {
151 maxMinorVersion = qMax(maxMinorVersion, t.version().minorVersion());
152 types << t;
153 } else {
154 types << QQmlType();
155 }
156
157 metaObject = metaObject->superClass();
158 }
159
160 const QTypeRevision maxVersion = QTypeRevision::fromVersion(combinedVersion.majorVersion(),
161 maxMinorVersion);
162 if (auto pc = propertyCacheForVersion(type.index(), maxVersion)) {
163 setPropertyCacheForVersion(type.index(), maxVersion, pc);
164 return pc;
165 }
166
167 QQmlPropertyCache::ConstPtr raw = propertyCache(type.metaObject(), combinedVersion);
168 QQmlPropertyCache::Ptr copied;
169
170 for (int ii = 0; ii < types.size(); ++ii) {
171 const QQmlType &currentType = types.at(ii);
172 if (!currentType.isValid())
173 continue;
174
175 QTypeRevision rev = currentType.metaObjectRevision();
176 int moIndex = types.size() - 1 - ii;
177
178 if (raw->allowedRevision(moIndex) != rev) {
179 if (copied.isNull()) {
180 copied = raw->copy();
181 raw = copied;
182 }
183 copied->setAllowedRevision(moIndex, rev);
184 }
185 }
186
187 // Test revision compatibility - the basic rule is:
188 // * Anything that is excluded, cannot overload something that is not excluded *
189
190 // Signals override:
191 // * other signals and methods of the same name.
192 // * properties named on<Signal Name>
193 // * automatic <property name>Changed notify signals
194
195 // Methods override:
196 // * other methods of the same name
197
198 // Properties override:
199 // * other elements of the same name
200
201#if 0
202 bool overloadError = false;
203 QString overloadName;
204
205 for (QQmlPropertyCache::StringCache::ConstIterator iter = raw->stringCache.begin();
206 !overloadError && iter != raw->stringCache.end();
207 ++iter) {
208
209 const QQmlPropertyData *d = *iter;
210 if (raw->isAllowedInRevision(d))
211 continue; // Not excluded - no problems
212
213 // check that a regular "name" overload isn't happening
214 const QQmlPropertyData *current = d;
215 while (!overloadError && current) {
216 current = d->overrideData(current);
217 if (current && raw->isAllowedInRevision(current))
218 overloadError = true;
219 }
220 }
221
222 if (overloadError) {
223 if (hasCopied) raw->release();
224
225 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."));
226 return 0;
227 }
228#endif
229
230 setPropertyCacheForVersion(type.index(), version, raw);
231
232 if (version != maxVersion)
233 setPropertyCacheForVersion(type.index(), maxVersion, raw);
234
235 return raw;
236}
237
239 QMetaType t, const QQmlMetaTypeData::CompositeTypes::const_iterator &iter) {
240 if (t != (*iter)->metaType()) {
241 // this is an inline component, and what we have in the iterator is currently the parent compilation unit
242 for (auto &&icDatum: (*iter)->inlineComponentData)
243 if (icDatum.qmlType.typeId() == t)
244 return (*iter)->propertyCaches.at(icDatum.objectIndex);
245 }
246 return (*iter)->rootPropertyCache();
247}
248
250{
251 // Last inserted
252 auto iter = compositeTypes.constFind(t.iface());
253 return (iter == compositeTypes.constEnd())
254 ? QQmlPropertyCache::ConstPtr()
255 : propertyCacheForPotentialInlineComponentType(t, iter);
256}
257
259{
260 // Unregister all remaining composite types.
261 // Avoid deletion recursion (via QQmlTypePrivate dtor) by moving them out of the way first.
262 CompositeTypes emptyComposites;
263 emptyComposites.swap(compositeTypes);
264
265 // ECMAScript modules can form cycles. Clear the edges first, so that we don't leak memory.
266 for (const auto &cu : std::as_const(emptyComposites))
267 clearCompositeType(cu);
268}
269
271{
272 for (const auto &compositeMetaType : std::as_const(compositeMetaTypes)) {
273 Q_ASSERT(compositeMetaType.type);
274 QMetaType::unregisterMetaType(QMetaType(compositeMetaType.type));
275 delete compositeMetaType.type;
276
277 Q_ASSERT(compositeMetaType.listType);
278 QMetaType::unregisterMetaType(QMetaType(compositeMetaType.listType));
279 delete compositeMetaType.listType;
280 }
281 compositeMetaTypes.clear();
282}
283
284QT_END_NAMESPACE
static QQmlPropertyCache::ConstPtr propertyCacheForPotentialInlineComponentType(QMetaType t, const QQmlMetaTypeData::CompositeTypes::const_iterator &iter)
VersionedUri(const std::unique_ptr< QQmlTypeModule > &module)
bool registerModuleTypes(const QString &uri)
QQmlTypeModule * findTypeModule(const QString &module, QTypeRevision version)
QQmlPropertyCache::ConstPtr propertyCache(const QMetaObject *metaObject, QTypeRevision version)
QQmlPropertyCache::ConstPtr propertyCache(const QQmlType &type, QTypeRevision version)
void registerType(QQmlTypePrivate *priv)
QQmlPropertyCache::ConstPtr findPropertyCacheInCompositeTypes(QMetaType t) const
QQmlPropertyCache::ConstPtr propertyCacheForVersion(int index, QTypeRevision version) const
void clearPropertyCachesForVersion(int index)
void setPropertyCacheForVersion(int index, QTypeRevision version, const QQmlPropertyCache::ConstPtr &cache)