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 Type &type = types[i];
32 if (!type.type.isValid()) {
33 type.type = QQmlType(priv);
34 priv->index = i;
35 priv->release();
36 return;
37 }
38 }
39 types.append({QQmlType(priv), {}});
40 priv->index = types.size() - 1;
41 priv->release();
42}
43
44QQmlMetaTypeData::VersionedUri::VersionedUri(const std::unique_ptr<QQmlTypeModule> &module)
46{
47}
48
49QQmlTypeModule *QQmlMetaTypeData::findTypeModule(const QString &module, QTypeRevision version)
50{
51 const auto qqtm = std::lower_bound(
52 uriToModule.begin(), uriToModule.end(), VersionedUri(module, version),
53 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(std::move(module));
67 std::sort(uriToModule.begin(), uriToModule.end(),
68 [](const std::unique_ptr<QQmlTypeModule> &a,
69 const std::unique_ptr<QQmlTypeModule> &b) {
70 const int diff = a->module().compare(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(uri);
79 if (function != moduleTypeRegistrationFunctions.constEnd()) {
80 (*function)();
81 return true;
82 }
83 return false;
84}
85
87 int index, QTypeRevision version) const
88{
89 return (index < types.size())
90 ? types[index].propertyCaches.value(version)
91 : QQmlPropertyCache::ConstPtr();
92}
93
94void QQmlMetaTypeData::setPropertyCacheForVersion(int index, QTypeRevision version,
95 const QQmlPropertyCache::ConstPtr &cache)
96{
97 if (index >= types.size())
98 types.resize(index + 1);
99 types[index].propertyCaches[version] = cache;
100}
101
103 const QMetaObject *metaObject, QTypeRevision version)
104{
105 if (QQmlPropertyCache::ConstPtr rv = propertyCaches.value(metaObject))
106 return rv;
107
108 QQmlPropertyCache::ConstPtr rv;
109 if (const QMetaObject *superMeta = metaObject->superClass())
110 rv = propertyCache(superMeta, version)->copyAndAppend(metaObject, version);
111 else
112 rv = QQmlPropertyCache::createStandalone(metaObject);
113
114 const auto *mop = reinterpret_cast<const QMetaObjectPrivate *>(metaObject->d.data);
115 if (!(mop->flags & DynamicMetaObject))
116 propertyCaches.insert(metaObject, rv);
117
118 return rv;
119}
120
122 const QQmlType &type, QTypeRevision version)
123{
124 Q_ASSERT(type.isValid());
125
126 if (auto pc = propertyCacheForVersion(type.index(), version))
127 return pc;
128
129 QList<QQmlType> types;
130
131 quint8 maxMinorVersion = 0;
132
133 const QMetaObject *metaObject = type.metaObject();
134 Q_ASSERT(metaObject);
135
136 const QTypeRevision combinedVersion = version.hasMajorVersion()
137 ? version
138 : (version.hasMinorVersion()
139 ? QTypeRevision::fromVersion(type.version().majorVersion(),
140 version.minorVersion())
141 : QTypeRevision::fromMajorVersion(type.version().majorVersion()));
142
143 while (metaObject) {
144 QQmlType t = QQmlMetaType::qmlType(metaObject, type.module(), combinedVersion);
145 if (t.isValid()) {
146 maxMinorVersion = qMax(maxMinorVersion, t.version().minorVersion());
147 types << t;
148 } else {
149 types << QQmlType();
150 }
151
152 metaObject = metaObject->superClass();
153 }
154
155 const QTypeRevision maxVersion = QTypeRevision::fromVersion(combinedVersion.majorVersion(),
156 maxMinorVersion);
157 if (auto pc = propertyCacheForVersion(type.index(), maxVersion)) {
158 setPropertyCacheForVersion(type.index(), maxVersion, pc);
159 return pc;
160 }
161
162 QQmlPropertyCache::ConstPtr raw = propertyCache(type.metaObject(), combinedVersion);
163 QQmlPropertyCache::Ptr copied;
164
165 for (int ii = 0; ii < types.size(); ++ii) {
166 const QQmlType &currentType = types.at(ii);
167 if (!currentType.isValid())
168 continue;
169
170 QTypeRevision rev = currentType.metaObjectRevision();
171 int moIndex = types.size() - 1 - ii;
172
173 if (raw->allowedRevision(moIndex) != rev) {
174 if (copied.isNull()) {
175 copied = raw->copy();
176 raw = copied;
177 }
178 copied->setAllowedRevision(moIndex, rev);
179 }
180 }
181
182 // Test revision compatibility - the basic rule is:
183 // * Anything that is excluded, cannot overload something that is not excluded *
184
185 // Signals override:
186 // * other signals and methods of the same name.
187 // * properties named on<Signal Name>
188 // * automatic <property name>Changed notify signals
189
190 // Methods override:
191 // * other methods of the same name
192
193 // Properties override:
194 // * other elements of the same name
195
196#if 0
197 bool overloadError = false;
198 QString overloadName;
199
200 for (QQmlPropertyCache::StringCache::ConstIterator iter = raw->stringCache.begin();
201 !overloadError && iter != raw->stringCache.end();
202 ++iter) {
203
204 const QQmlPropertyData *d = *iter;
205 if (raw->isAllowedInRevision(d))
206 continue; // Not excluded - no problems
207
208 // check that a regular "name" overload isn't happening
209 const QQmlPropertyData *current = d;
210 while (!overloadError && current) {
211 current = d->overrideData(current);
212 if (current && raw->isAllowedInRevision(current))
213 overloadError = true;
214 }
215 }
216
217 if (overloadError) {
218 if (hasCopied) raw->release();
219
220 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."));
221 return 0;
222 }
223#endif
224
225 setPropertyCacheForVersion(type.index(), version, raw);
226
227 if (version != maxVersion)
228 setPropertyCacheForVersion(type.index(), maxVersion, raw);
229
230 return raw;
231}
232
233QQmlPropertyCache::ConstPtr QQmlMetaTypeData::propertyCacheForPotentialInlineComponentType(
234 QMetaType t, const QQmlMetaTypeData::CompositeTypes::const_iterator &iter) {
235 if (t != (*iter)->metaType()) {
236 // this is an inline component, and what we have in the iterator is currently the parent compilation unit
237 for (auto &&icDatum: (*iter)->inlineComponentData)
238 if (icDatum.qmlType.typeId() == t)
239 return (*iter)->propertyCaches.at(icDatum.objectIndex);
240 }
241 return (*iter)->rootPropertyCache();
242}
243
245{
246 // Last inserted
247 auto iter = compositeTypes.constFind(t.iface());
248 return (iter == compositeTypes.constEnd())
249 ? QQmlPropertyCache::ConstPtr()
250 : propertyCacheForPotentialInlineComponentType(t, iter);
251}
252
254{
255 // Unregister all remaining composite types.
256 // Avoid deletion recursion (via QQmlTypePrivate dtor) by moving them out of the way first.
257 CompositeTypes emptyComposites;
258 emptyComposites.swap(compositeTypes);
259
260 // ECMAScript modules can form cycles. Clear the edges first, so that we don't leak memory.
261 for (const auto &cu : std::as_const(emptyComposites))
262 clearCompositeType(cu);
263}
264
266{
267 for (const auto &compositeMetaType : std::as_const(compositeMetaTypes)) {
268 Q_ASSERT(compositeMetaType.type);
269 QMetaType::unregisterMetaType(QMetaType(compositeMetaType.type));
270 delete compositeMetaType.type;
271
272 Q_ASSERT(compositeMetaType.listType);
273 QMetaType::unregisterMetaType(QMetaType(compositeMetaType.listType));
274 delete compositeMetaType.listType;
275 }
276 compositeMetaTypes.clear();
277}
278
279QT_END_NAMESPACE
Combined button and popup list for selecting options.
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 setPropertyCacheForVersion(int index, QTypeRevision version, const QQmlPropertyCache::ConstPtr &cache)