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