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
qqmltype_p_p.h
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
5#ifndef QQMLTYPE_P_P_H
6#define QQMLTYPE_P_P_H
7
8//
9// W A R N I N G
10// -------------
11//
12// This file is not part of the Qt API. It exists purely as an
13// implementation detail. This header file may change from version to
14// version without notice, or even be removed.
15//
16// We mean it.
17//
18
19#include <private/qqmlengine_p.h>
20#include <private/qqmlmetatype_p.h>
21#include <private/qqmlpropertycache_p.h>
22#include <private/qqmlproxymetaobject_p.h>
23#include <private/qqmlrefcount_p.h>
24#include <private/qqmltype_p.h>
25#include <private/qqmltypeloader_p.h>
26#include <private/qstringhash_p.h>
27#include <private/qv4engine_p.h>
28#include <private/qv4executablecompilationunit_p.h>
29#include <private/qv4resolvedtypereference_p.h>
30
31#include <QAtomicInteger>
32#include <QtCore/qtyperevision.h>
33
34QT_BEGIN_NAMESPACE
35
36class QQmlTypePrivate final : public QQmlRefCounted<QQmlTypePrivate>
37{
38 Q_DISABLE_COPY_MOVE(QQmlTypePrivate)
39public:
40 struct ProxyMetaObjects
41 {
42 ~ProxyMetaObjects()
43 {
44 for (const QQmlProxyMetaObject::ProxyData &metaObject : std::as_const(data))
45 free(metaObject.metaObject);
46 }
47
48 QList<QQmlProxyMetaObject::ProxyData> data;
49 bool containsRevisionedAttributes = false;
50 };
51
52 struct Enums
53 {
54 enum Scoping { Scoped, Unscoped };
55 ~Enums()
56 {
57 qDeleteAll(scopedEnums);
58 qDeleteAll(unscopedEnums);
59 }
60
61 QStringHash<int> enums;
62 QStringHash<int> scopedEnumIndex; // maps from enum name to index in scopedEnums
63 QStringHash<int> unscopedEnumIndex; // maps from enum name to index in unscopedEnums
64 QList<QStringHash<int> *> scopedEnums;
65 QList<QStringHash<int> *> unscopedEnums;
66 };
67
68 QQmlTypePrivate(QQmlType::RegistrationType type);
69
70 const ProxyMetaObjects *init() const;
71
72 QUrl sourceUrl() const
73 {
74 switch (regType) {
75 case QQmlType::CompositeType:
76 return extraData.compositeTypeData;
77 case QQmlType::CompositeSingletonType:
78 return extraData.singletonTypeData->singletonInstanceInfo->url;
79 case QQmlType::InlineComponentType:
80 return extraData.inlineComponentTypeData;
81 case QQmlType::JavaScriptType:
82 return extraData.javaScriptTypeData;
83 default:
84 return QUrl();
85 }
86 }
87
88 const QQmlTypePrivate *attachedPropertiesBase(QQmlTypeLoader *typeLoader) const
89 {
90 for (const QQmlTypePrivate *d = this; d;
91 d = d->resolveCompositeBaseType(typeLoader).d.data()) {
92 if (d->regType == QQmlType::CppType)
93 return d->extraData.cppTypeData->attachedPropertiesType ? d : nullptr;
94
95 if (d->regType != QQmlType::CompositeType)
96 return nullptr;
97 }
98 return nullptr;
99 }
100
101 bool isComposite() const
102 {
103 switch (regType) {
104 case QQmlType::CompositeType:
105 case QQmlType::CompositeSingletonType:
106 case QQmlType::InlineComponentType:
107 return true;
108 default:
109 break;
110 }
111
112 return false;
113 }
114
115 bool isValueType() const
116 {
117 return regType == QQmlType::CppType && !(typeId.flags() & QMetaType::PointerToQObject);
118 }
119
120 QQmlType resolveCompositeBaseType(QQmlTypeLoader *typeLoader) const;
121 QQmlPropertyCache::ConstPtr compositePropertyCache(QQmlTypeLoader *typeLoader) const;
122
123 struct QQmlCppTypeData
124 {
125 int allocationSize;
126 void (*newFunc)(void *, void *);
127 void *userdata = nullptr;
128 QString noCreationReason;
129 QVariant (*createValueTypeFunc)(const QJSValue &);
130 int parserStatusCast;
131 QObject *(*extFunc)(QObject *);
132 const QMetaObject *extMetaObject;
133 QQmlCustomParser *customParser;
134 QQmlAttachedPropertiesFunc attachedPropertiesFunc;
135 const QMetaObject *attachedPropertiesType;
136 int propertyValueSourceCast;
137 int propertyValueInterceptorCast;
138 int finalizerCast;
139 bool registerEnumClassesUnscoped;
140 bool registerEnumsFromRelatedTypes;
141 bool constructValueType;
142 bool populateValueType;
143 };
144
145 struct QQmlSingletonTypeData
146 {
147 QQmlType::SingletonInstanceInfo::ConstPtr singletonInstanceInfo;
148 QObject *(*extFunc)(QObject *);
149 const QMetaObject *extMetaObject;
150 };
151
152 int index = -1;
153
154 union extraData {
155 extraData() {} // QQmlTypePrivate() does the actual construction.
156 ~extraData() {} // ~QQmlTypePrivate() does the actual destruction.
157
158 QQmlCppTypeData *cppTypeData;
159 QQmlSingletonTypeData *singletonTypeData;
160 QUrl compositeTypeData;
161 QUrl javaScriptTypeData;
162 QUrl inlineComponentTypeData;
163 QMetaSequence sequentialContainerTypeData;
164 const char *interfaceTypeData;
165 } extraData;
166 static_assert(sizeof(extraData) == sizeof(void *));
167
168 QHashedString module;
169 QString name;
170 QString elementName;
171 QMetaType typeId;
172 QMetaType listId;
173 QQmlType::RegistrationType regType;
174 QTypeRevision version;
175 QTypeRevision revision = QTypeRevision::zero();
176 const QMetaObject *baseMetaObject = nullptr;
177
178 void setName(const QString &uri, const QString &element);
179
180 template<typename String>
181 static int enumValue(
182 const QQmlRefPointer<const QQmlTypePrivate> &d, QQmlTypeLoader *typeLoader,
183 const String &name, bool *ok)
184 {
185 const auto *rv = doGetEnumOp<const int *>(
186 d, typeLoader, [&](const QQmlTypePrivate::Enums *enums) {
187 return enums->enums.value(name);
188 }, [](const int *p) { return !!p; }, ok);
189 return rv ? *rv : -1;
190 }
191
192 template<Enums::Scoping scoping, typename String>
193 static int enumIndex(
194 const QQmlRefPointer<const QQmlTypePrivate> &d, QQmlTypeLoader *typeLoader,
195 const String &name, bool *ok)
196 {
197 const auto *rv = doGetEnumOp<const int *> (
198 d, typeLoader, [&](const QQmlTypePrivate::Enums *enums) {
199 if constexpr (scoping == Enums::Scoped)
200 return enums->scopedEnumIndex.value(name);
201 else
202 return enums->unscopedEnumIndex.value(name);
203 }, [](const int *p) { return !!p; }, ok);
204 return rv ? *rv : -1;
205 }
206
207 template<Enums::Scoping scoping, typename String>
208 static int enumValue(
209 const QQmlRefPointer<const QQmlTypePrivate> &d, QQmlTypeLoader *typeLoader, int index,
210 const String &name, bool *ok)
211 {
212 const auto *rv = doGetEnumOp<const int *>(
213 d, typeLoader, [&](const QQmlTypePrivate::Enums *enums) {
214 if constexpr (scoping == Enums::Scoped) {
215 Q_ASSERT(index > -1 && index < enums->scopedEnums.size());
216 return enums->scopedEnums.at(index)->value(name);
217 } else {
218 Q_ASSERT(index > -1 && index < enums->unscopedEnums.size());
219 return enums->unscopedEnums.at(index)->value(name);
220 }
221 }, [](const int *p) { return !!p; }, ok);
222 return rv ? *rv : -1;
223 }
224
225 template<Enums::Scoping scoping, typename String1, typename String2>
226 static int enumValue(
227 const QQmlRefPointer<const QQmlTypePrivate> &d, QQmlTypeLoader *typeLoader,
228 const String1 &scopedEnumName, const String2 &name, bool *ok)
229 {
230 const auto *rv = doGetEnumOp<const int *>(
231 d, typeLoader, [&](const QQmlTypePrivate::Enums *enums) {
232 const QStringHash<int> *enumIndex;
233 const QList<QStringHash<int> *> *_enums;
234 if constexpr (scoping == Enums::Scoped) {
235 enumIndex = &enums->scopedEnumIndex;
236 _enums = &enums->scopedEnums;
237 } else {
238 enumIndex = &enums->unscopedEnumIndex;
239 _enums = &enums->unscopedEnums;
240 }
241
242 const int *rv = enumIndex->value(scopedEnumName);
243 if (!rv)
244 return static_cast<int *>(nullptr);
245
246 const int index = *rv;
247 Q_ASSERT(index > -1 && index < _enums->size());
248 return _enums->at(index)->value(name);
249 }, [](const int *p) { return !!p; }, ok);
250 return rv ? *rv : -1;
251 }
252
253 template<Enums::Scoping scoping>
254 static QString enumKey(
255 const QQmlRefPointer<const QQmlTypePrivate> &d, QQmlTypeLoader *typeLoader,
256 int index, int value, bool *ok)
257 {
258 return doGetEnumOp<QString>(d, typeLoader, [&](const QQmlTypePrivate::Enums *enums) {
259 const QList<QStringHash<int> *> *_enums;
260 if constexpr (scoping == Enums::Scoped)
261 _enums = &enums->scopedEnums;
262 else
263 _enums = &enums->unscopedEnums;
264
265 Q_ASSERT(index > -1 && index < _enums->size());
266 const auto hash = _enums->at(index);
267 for (auto it = hash->constBegin(), end = hash->constEnd(); it != end; ++it) {
268 if (it.value() == value)
269 return QString(it.key());
270 }
271 return QString();
272 }, [](const QString &s) { return !s.isEmpty(); }, ok);
273 }
274
275 template<Enums::Scoping scoping>
276 static QStringList enumKeys(
277 const QQmlRefPointer<const QQmlTypePrivate> &d, QQmlTypeLoader *typeLoader,
278 int index, int value, bool *ok)
279 {
280 return doGetEnumOp<QStringList>(d, typeLoader, [&](const QQmlTypePrivate::Enums *enums) {
281 const QList<QStringHash<int> *> *_enums;
282 if constexpr (scoping == Enums::Scoped)
283 _enums = &enums->scopedEnums;
284 else
285 _enums = &enums->unscopedEnums;
286
287 Q_ASSERT(index > -1 && index < _enums->size());
288 QStringList keys;
289 const auto hash = _enums->at(index);
290 for (auto it = hash->constBegin(), end = hash->constEnd(); it != end; ++it) {
291 if (it.value() == value)
292 keys.append(QString(it.key()));
293 }
294 std::reverse(keys.begin(), keys.end());
295 return keys;
296 }, [](const QStringList &l) { return !l.empty(); }, ok);
297 }
298
299 const QMetaObject *metaObject() const
300 {
301 if (isValueType())
302 return metaObjectForValueType();
303
304 const QQmlTypePrivate::ProxyMetaObjects *proxies = init();
305 return proxies->data.isEmpty()
306 ? baseMetaObject
307 : proxies->data.constFirst().metaObject;
308 }
309
310 const QMetaObject *metaObjectForValueType() const
311 {
312 Q_ASSERT(isValueType());
313
314 // Prefer the extension meta object, if any.
315 // Extensions allow registration of non-gadget value types.
316 if (const QMetaObject *extensionMetaObject = extraData.cppTypeData->extMetaObject) {
317 // This may be a namespace even if the original metaType isn't.
318 // You can do such things with QML_FOREIGN declarations.
319 if (extensionMetaObject->metaType().flags() & QMetaType::IsGadget)
320 return extensionMetaObject;
321 }
322
323 if (baseMetaObject) {
324 // This may be a namespace even if the original metaType isn't.
325 // You can do such things with QML_FOREIGN declarations.
326 if (baseMetaObject->metaType().flags() & QMetaType::IsGadget)
327 return baseMetaObject;
328 }
329
330 return nullptr;
331 }
332
333 static QQmlType visibleQmlTypeByName(
334 const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &unit,
335 const QString &elementName, QQmlTypeLoader *typeLoader)
336 {
337 // Invalid speculative inline component types are either rejected at creation time
338 // (if the base type is already registered) or pruned when the base type registers.
339 return unit->typeNameCache->query<QQmlImport::AllowRecursion>(
340 elementName, typeLoader).type;
341 }
342
343 // Tries the base unit's resolvedTypes first. If successful, that is cheap
344 // because it's just a hash. Otherwise falls back to typeNameCache.
345 // typeNameCache is slower because it will do a generic type search on all imports.
346 // This can involve iterating all the types of an import or querying QQmlMetaType for
347 // further details.
348 // TODO: Not all referenced types are pre-resolved when loading. That should be fixed.
349 // In particular, types only used in function signatures are not resolved.
350 static QQmlType visibleQmlTypeByName(
351 const QV4::ExecutableCompilationUnit *unit, int elementNameId,
352 QQmlTypeLoader *typeLoader = nullptr)
353 {
354 const auto &base = unit->baseCompilationUnit();
355 const auto it = base->resolvedTypes.constFind(elementNameId);
356 if (it == base->resolvedTypes.constEnd()) {
357 return visibleQmlTypeByName(
358 base, base->stringAt(elementNameId),
359 typeLoader ? typeLoader : unit->engine->typeLoader());
360 }
361
362 return (*it)->type();
363 }
364
365private:
366 mutable QAtomicPointer<const ProxyMetaObjects> proxyMetaObjects;
367 mutable QAtomicPointer<const Enums> enums;
368
369 ~QQmlTypePrivate();
370 friend class QQmlRefCounted<QQmlTypePrivate>;
371
372 struct EnumInfo {
373 QStringList path;
374 QString metaObjectName;
375 QString enumName;
376 QString enumKey;
377 QString metaEnumScope;
378 bool scoped;
379 };
380
381 template<typename Ret, typename Op, typename Check>
382 static Ret doGetEnumOp(const QQmlRefPointer<const QQmlTypePrivate> &d,
383 QQmlTypeLoader *typeLoader, Op &&op, Check &&check, bool *ok)
384 {
385 Q_ASSERT(ok);
386 if (d) {
387 if (const QQmlTypePrivate::Enums *enums = d->initEnums(typeLoader)) {
388 if (Ret rv = op(enums); check(rv)) {
389 *ok = true;
390 return rv;
391 }
392 }
393 }
394
395 *ok = false;
396 return Ret();
397 }
398
399 const Enums *initEnums(QQmlTypeLoader *typeLoader) const;
400 void insertEnums(Enums *enums, const QMetaObject *metaObject) const;
401 void insertEnumsFromPropertyCache(Enums *enums, const QQmlPropertyCache::ConstPtr &cache) const;
402
403 void createListOfPossibleConflictingItems(const QMetaObject *metaObject, QList<EnumInfo> &enumInfoList, QStringList path) const;
404 void createEnumConflictReport(const QMetaObject *metaObject, const QString &conflictingKey) const;
405};
406
408
409#endif // QQMLTYPE_P_P_H
Combined button and popup list for selecting options.
static bool isPropertyRevisioned(const QMetaObject *mo, int index)
Definition qqmltype.cpp:171