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