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