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
qqml.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
5#include "qqml.h"
6
7#include <private/qjsvalue_p.h>
8#include <private/qqmlbuiltinfunctions_p.h>
9#include <private/qqmlcomponent_p.h>
10#include <private/qqmlengine_p.h>
11#include <private/qqmlfinalizer_p.h>
12#include <private/qqmlloggingcategorybase_p.h>
13#include <private/qqmlmetatype_p.h>
14#include <private/qqmlmetatypedata_p.h>
15#include <private/qqmltype_p_p.h>
16#include <private/qqmltypemodule_p.h>
17#include <private/qqmltypewrapper_p.h>
18#include <private/qqmlvaluetypewrapper_p.h>
19#include <private/qv4alloca_p.h>
20#include <private/qv4dateobject_p.h>
21#include <private/qv4errorobject_p.h>
22#include <private/qv4identifiertable_p.h>
23#include <private/qv4lookup_p.h>
24#include <private/qv4qobjectwrapper_p.h>
25
26#include <QtQml/qqmlprivate.h>
27
28#include <QtCore/qmutex.h>
29#include <QtCore/qmetasequence.h>
30
32
33/*!
34 \headerfile <qqml.h>
35 \inmodule QtQml
36 \title Functions to register C++ types to QML
37
38 This header provides a collection of functions that allow the registration of
39 C++ types to QML.
40
41 \sa {Overview - QML and C++ Integration}, qqmlintegration.h, qmltyperegistrar
42*/
43
44/*!
45 \internal
46
47 This method completes the setup of all deferred properties of \a object.
48 Deferred properties are declared with
49 Q_CLASSINFO("DeferredPropertyNames", "comma,separated,property,list");
50
51 Any binding to a deferred property is not executed when the object is instantiated,
52 but only when completion is requested with qmlExecuteDeferred, or by manually
53 calling QQmlComponentPrivate::beginDeferred and completeDeferred.
54
55 \sa QV4::CompiledData::Binding::IsDeferredBinding,
56 QV4::CompiledData::Object::HasDeferredBindings,
57 QQmlData::deferData,
58 QQmlObjectCreator::setupBindings
59*/
60void qmlExecuteDeferred(QObject *object)
61{
62 QQmlData *data = QQmlData::get(object);
63
64 if (!data
65 || !data->context
66 || !data->context->engine()
67 || data->deferredData.isEmpty()
68 || data->wasDeleted(object)) {
69 return;
70 }
71
72 if (!data->propertyCache)
73 data->propertyCache = QQmlMetaType::propertyCache(object->metaObject());
74
75 QQmlEnginePrivate *ep = QQmlEnginePrivate::get(data->context->engine());
76
77 QQmlComponentPrivate::DeferredState state;
78 QQmlComponentPrivate::beginDeferred(ep, object, &state);
79
80 // Release the reference for the deferral action (we still have one from construction)
81 data->releaseDeferredData();
82
83 QQmlComponentPrivate::completeDeferred(ep, &state);
84}
85
86QQmlContext *qmlContext(const QObject *obj)
87{
88 return QQmlEngine::contextForObject(obj);
89}
90
91QQmlEngine *qmlEngine(const QObject *obj)
92{
93 QQmlData *data = QQmlData::get(obj);
94 if (!data || !data->context)
95 return nullptr;
96 return data->context->engine();
97}
98
99static QObject *resolveAttachedProperties(QQmlAttachedPropertiesFunc pf, QQmlData *data,
100 QObject *object, bool create)
101{
102 if (!pf)
103 return nullptr;
104
105 QObject *rv = data->hasExtendedData() ? data->attachedProperties()->value(pf) : 0;
106 if (rv || !create)
107 return rv;
108
109 rv = pf(object);
110
111 if (rv)
112 data->attachedProperties()->insert(pf, rv);
113
114 return rv;
115}
116
118 const QMetaObject *attachedMetaObject)
119{
120 QQmlEngine *engine = object ? qmlEngine(object) : nullptr;
121 return QQmlMetaType::attachedPropertiesFunc(
122 engine ? QQmlTypeLoader::get(engine) : nullptr, attachedMetaObject);
123}
124
125QObject *qmlAttachedPropertiesObject(QObject *object, QQmlAttachedPropertiesFunc func, bool createIfMissing)
126{
127 if (!object)
128 return nullptr;
129
130 QQmlData *data = QQmlData::get(object, createIfMissing);
131
132 // Attached properties are only on objects created by QML,
133 // unless explicitly requested (create==true)
134 if (!data)
135 return nullptr;
136
137 return resolveAttachedProperties(func, data, object, createIfMissing);
138}
139
140/*!
141 \relates <qqml.h>
142
143 This function returns the extension object that belongs to \a base, if there is any.
144 Otherwise it returns \c nullptr.
145
146 \sa QML_EXTENDED
147*/
148QObject *qmlExtendedObject(QObject *base)
149{
150 return QQmlPrivate::qmlExtendedObject(base, 0);
151}
152
153QObject *QQmlPrivate::qmlExtendedObject(QObject *object, int index)
154{
155 if (!object)
156 return nullptr;
157
158 void *result = nullptr;
159 QObjectPrivate *d = QObjectPrivate::get(object);
160 if (!d->metaObject)
161 return nullptr;
162
163 const int id = d->metaObject->metaCall(
164 object, QMetaObject::CustomCall,
165 QQmlProxyMetaObject::extensionObjectId(index), &result);
166 if (id != QQmlProxyMetaObject::extensionObjectId(index))
167 return nullptr;
168
169 return static_cast<QObject *>(result);
170}
171
172void QQmlPrivate::qmlRegistrationWarning(
173 QQmlPrivate::QmlRegistrationWarning warning, QMetaType metaType)
174{
175 switch (warning) {
176 case UnconstructibleType:
177 qWarning().nospace()
178 << metaType.name()
179 << " is neither a default constructible QObject, nor a default- "
180 << "and copy-constructible Q_GADGET, nor a QObject marked as uncreatable.\n"
181 << "You should not use it as a QML type.";
182 break;
183 case UnconstructibleSingleton:
184 qWarning()
185 << "Singleton" << metaType.name()
186 << "needs to be a concrete class with either a default constructor"
187 << "or, when adding a default constructor is infeasible, a public static"
188 << "create(QQmlEngine *, QJSEngine *) method.";
189 break;
190 case NonQObjectWithAtached:
191 qWarning()
192 << metaType.name()
193 << "is not a QObject, but has attached properties. This won't work.";
194 break;
195 }
196}
197
198QMetaType QQmlPrivate::compositeMetaType(
199 QV4::ExecutableCompilationUnit *unit, int elementNameId)
200{
201 return QQmlTypePrivate::visibleQmlTypeByName(unit, elementNameId).typeId();
202}
203
204QMetaType QQmlPrivate::compositeMetaType(
205 QV4::ExecutableCompilationUnit *unit, const QString &elementName)
206{
207 return QQmlTypePrivate::visibleQmlTypeByName(
208 unit->baseCompilationUnit(), elementName, unit->engine->typeLoader())
209 .typeId();
210}
211
212QMetaType QQmlPrivate::compositeListMetaType(
213 QV4::ExecutableCompilationUnit *unit, int elementNameId)
214{
215 return QQmlTypePrivate::visibleQmlTypeByName(unit, elementNameId).qListTypeId();
216}
217
218QMetaType QQmlPrivate::compositeListMetaType(
219 QV4::ExecutableCompilationUnit *unit, const QString &elementName)
220{
221 return QQmlTypePrivate::visibleQmlTypeByName(
222 unit->baseCompilationUnit(), elementName, unit->engine->typeLoader())
223 .qListTypeId();
224}
225
226/*!
227 \relates <qqml.h>
228 \since 5.8
229
230 This function registers the \a staticMetaObject and its extension
231 in the QML system with the name \a qmlName in the library imported
232 from \a uri having version number composed from \a versionMajor and
233 \a versionMinor.
234
235 An instance of the meta object cannot be created. An error message with
236 the given \a reason is printed if the user attempts to create it.
237
238 This function is useful for registering Q_NAMESPACE namespaces.
239
240 Returns the QML type id.
241
242 For example:
243
244 //! Workaround for MOC not respecting comments and triggering an error on certain Qt macros.
245 \code Q
246 namespace MyNamespace {
247 \1_NAMESPACE
248 enum MyEnum {
249 Key1,
250 Key2,
251 };
252 \1_ENUM_NS(MyEnum)
253 }
254
255 //...
256 qmlRegisterUncreatableMetaObject(MyNamespace::staticMetaObject, "io.qt", 1, 0, "MyNamespace", "Access to enums & flags only");
257 \endcode
258
259 On the QML side, you can now use the registered enums:
260 \code
261 Component.onCompleted: console.log(MyNamespace.Key2)
262 \endcode
263
264 \sa QML_ELEMENT, QML_NAMED_ELEMENT(), QML_UNCREATABLE()
265*/
266int qmlRegisterUncreatableMetaObject(const QMetaObject &staticMetaObject,
267 const char *uri, int versionMajor,
268 int versionMinor, const char *qmlName,
269 const QString& reason)
270{
271 QQmlPrivate::RegisterType type = {
272 QQmlPrivate::RegisterType::CurrentVersion,
273 QMetaType(),
274 QMetaType(),
275 0,
276 nullptr,
277 nullptr,
278 reason,
279 nullptr,
280
281 uri, QTypeRevision::fromVersion(versionMajor, versionMinor), qmlName, &staticMetaObject,
282
283 QQmlAttachedPropertiesFunc(),
284 nullptr,
285
286 -1,
287 -1,
288 -1,
289
290 nullptr, nullptr,
291
292 nullptr,
293 QTypeRevision::zero(),
294 -1,
295 QQmlPrivate::ValueTypeCreationMethod::None
296 };
297
298 return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
299}
300
301/*!
302 \relates <qqml.h>
303
304 Clears all stored type registrations, such as those produced with \l qmlRegisterType().
305
306 Do not call this function while a QQmlEngine exists or behavior will be undefined.
307 Any existing QQmlEngines must be deleted before calling this function. This function
308 only affects the application global cache. Delete the QQmlEngine to clear all cached
309 data relating to that engine.
310*/
311void qmlClearTypeRegistrations() // Declared in qqml.h
312{
313 QQmlMetaType::clearTypeRegistrations();
314 QQmlEnginePrivate::baseModulesUninitialized = true; //So the engine re-registers its types
315 qmlClearEnginePlugins();
316}
317
318/*!
319 \relates <qqml.h>
320
321 This function protects a module from further modification. This can be used
322 to prevent other plugins from injecting types into your module. It can also
323 be a performance improvement, as it allows the engine to skip checking for
324 the possibility of new types or plugins when this import is reached.
325
326 Once qmlProtectModule has been called, a QML engine will not search for a new
327 \c qmldir file to load the module anymore. It will re-use any \c qmldir files
328 it has loaded before, though. Therefore, types present at this point continue
329 to work. Mind that different QML engines may load different modules. The
330 module protection, however, is global and affects all engines. The overhead
331 of locating \c qmldir files and loading plugins may be noticeable with slow file
332 systems. Therefore, protecting a module once you are sure you won't need to
333 load it anymore can be a good optimization. Mind also that the module lock
334 not only affects plugins but also any other qmldir directives, like \c import
335 or \c prefer, as well as any composite types or scripts declared in a \c qmldir
336 file.
337
338 In addition, after this function is called, any attempt to register C++ types
339 into this uri, major version combination will lead to a runtime error.
340
341 Returns true if the module with \a uri as a \l{Identified Modules}
342 {module identifier} and \a majVersion as a major version number was found
343 and locked, otherwise returns false. The module must contain exported types
344 in order to be found.
345*/
346bool qmlProtectModule(const char *uri, int majVersion)
347{
348 return QQmlMetaType::protectModule(QString::fromUtf8(uri),
349 QTypeRevision::fromMajorVersion(majVersion));
350}
351
352/*!
353 \since 5.9
354 \relates <qqml.h>
355
356 This function registers a module in a particular \a uri with a version specified
357 in \a versionMajor and \a versionMinor.
358
359 This can be used to make a certain module version available, even if no types
360 are registered for that version. This is particularly useful for keeping the
361 versions of related modules in sync.
362*/
363
364void qmlRegisterModule(const char *uri, int versionMajor, int versionMinor)
365{
366 QQmlMetaType::registerModule(uri, QTypeRevision::fromVersion(versionMajor, versionMinor));
367}
368
369static QQmlDirParser::Import resolveImport(const QString &uri, int importMajor, int importMinor)
370{
371 if (importMajor == QQmlModuleImportAuto)
372 return QQmlDirParser::Import(uri, QTypeRevision(), QQmlDirParser::Import::Auto);
373 else if (importMajor == QQmlModuleImportLatest)
374 return QQmlDirParser::Import(uri, QTypeRevision(), QQmlDirParser::Import::Default);
375 else if (importMinor == QQmlModuleImportLatest)
376 return QQmlDirParser::Import(uri, QTypeRevision::fromMajorVersion(importMajor), QQmlDirParser::Import::Default);
377 return QQmlDirParser::Import(uri, QTypeRevision::fromVersion(importMajor, importMinor), QQmlDirParser::Import::Default);
378}
379
380static QTypeRevision resolveModuleVersion(int moduleMajor)
381{
382 return moduleMajor == QQmlModuleImportModuleAny
383 ? QTypeRevision()
384 : QTypeRevision::fromMajorVersion(moduleMajor);
385}
386
387/*!
388 * \enum QQmlModuleImportSpecialVersions
389 * \relates <qqml.h>
390 *
391 * Defines some special values that can be passed to the version arguments of
392 * qmlRegisterModuleImport() and qmlUnregisterModuleImport().
393 *
394 * \value QQmlModuleImportModuleAny When passed as majorVersion of the base
395 * module, signifies that the import is to be
396 * applied to any version of the module.
397 * \value QQmlModuleImportLatest When passed as major or minor version of
398 * the imported module, signifies that the
399 * latest overall, or latest minor version
400 * of a specified major version shall be
401 * imported.
402 * \value QQmlModuleImportAuto When passed as major version of the imported
403 * module, signifies that the version of the
404 * base module shall be forwarded.
405 */
406
407/*!
408 * \relates <qqml.h>
409 * Registers a qmldir-import for module \a uri of major version \a moduleMajor.
410 *
411 * This has the same effect as an \c import statement in a qmldir file: Whenever
412 * \a uri of version \a moduleMajor is imported, \a import of version
413 * \a importMajor. \a importMinor is automatically imported, too. If
414 * \a importMajor is \l QQmlModuleImportLatest the latest version
415 * available of that module is imported, and \a importMinor does not matter. If
416 * \a importMinor is \l QQmlModuleImportLatest the latest minor version of a
417 * \a importMajor is chosen. If \a importMajor is \l QQmlModuleImportAuto the
418 * version of \a import is version of \a uri being imported, and \a importMinor
419 * does not matter. If \a moduleMajor is \l QQmlModuleImportModuleAny the module
420 * import is applied for any major version of \a uri. For example, you may
421 * specify that whenever any version of MyModule is imported, the latest version
422 * of MyOtherModule should be imported. Then, the following call would be
423 * appropriate:
424 *
425 * \code
426 * qmlRegisterModuleImport("MyModule", QQmlModuleImportModuleAny,
427 * "MyOtherModule", QQmlModuleImportLatest);
428 * \endcode
429 *
430 * Or, you may specify that whenever major version 5 of "MyModule" is imported,
431 * then version 3.14 of "MyOtherModule" should be imported:
432 *
433 * \code
434 * qmlRegisterModuleImport("MyModule", 5, "MyOtherModule", 3, 14);
435 * \endcode
436 *
437 * Finally, if you always want the same version of "MyOtherModule" to be
438 * imported whenever "MyModule" is imported, specify the following:
439 *
440 * \code
441 * qmlRegisterModuleImport("MyModule", QQmlModuleImportModuleAny,
442 * "MyOtherModule", QQmlModuleImportAuto);
443 * \endcode
444 *
445 * \sa qmlUnregisterModuleImport()
446 */
447void qmlRegisterModuleImport(const char *uri, int moduleMajor,
448 const char *import, int importMajor, int importMinor)
449{
450 QQmlMetaType::registerModuleImport(
451 QString::fromUtf8(uri), resolveModuleVersion(moduleMajor),
452 resolveImport(QString::fromUtf8(import), importMajor, importMinor));
453}
454
455
456/*!
457 * \relates <qqml.h>
458 * Removes a module import previously registered with qmlRegisterModuleImport()
459 *
460 * Calling this function makes sure that \a import of version
461 * \a{importMajor}.\a{importMinor} is not automatically imported anymore when
462 * \a uri of version \a moduleMajor is. The version resolution works the same
463 * way as with \l qmlRegisterModuleImport().
464 *
465 * \sa qmlRegisterModuleImport()
466 */
467void qmlUnregisterModuleImport(const char *uri, int moduleMajor,
468 const char *import, int importMajor, int importMinor)
469{
470 QQmlMetaType::unregisterModuleImport(
471 QString::fromUtf8(uri), resolveModuleVersion(moduleMajor),
472 resolveImport(QString::fromUtf8(import), importMajor, importMinor));
473}
474
475/*!
476 \since 5.12
477 \relates <qqml.h>
478
479 Returns the QML type id of a type that was registered with the
480 name \a qmlName in a particular \a uri and a version specified in \a
481 versionMajor and \a versionMinor.
482
483 This function returns the same value as the QML type registration functions
484 such as qmlRegisterType() and qmlRegisterSingletonType().
485
486 If \a qmlName, \a uri and \a versionMajor match a registered type, but the
487 specified minor version in \a versionMinor is higher, then the id of the type
488 with the closest minor version is returned.
489
490 Returns -1 if no matching type was found or one of the given parameters
491 was invalid.
492
493 \note: qmlTypeId tries to make modules available, even if they were not accessed by any
494 engine yet. This can introduce overhead the first time a module is accessed. Trying to
495 find types from a module which does not exist always introduces this overhead.
496
497 \sa QML_ELEMENT, QML_NAMED_ELEMENT, QML_SINGLETON, qmlRegisterType(), qmlRegisterSingletonType()
498*/
499int qmlTypeId(const char *uri, int versionMajor, int versionMinor, const char *qmlName)
500{
501 auto revision = QTypeRevision::fromVersion(versionMajor, versionMinor);
502 int id = QQmlMetaType::typeId(uri, revision, qmlName);
503 if (id != -1)
504 return id;
505 /* If the module hasn't been imported yet, we might not have the id of a
506 singleton at this point. To obtain it, we need an engine in order to
507 to do the resolution steps.
508 This is expensive, but we assume that users don't constantly query invalid
509 Types; internal code should use QQmlMetaType API.
510 */
511 QQmlEngine engine;
512 QQmlTypeLoader *typeLoader = QQmlTypeLoader::get(&engine);
513 auto loadHelper = QQml::makeRefPointer<LoadHelper>(
514 typeLoader, uri, qmlName, QQmlTypeLoader::Synchronous);
515 const QQmlType type = loadHelper->type();
516 if (type.availableInVersion(revision))
517 return type.index();
518 else
519 return -1;
520}
521
522static bool checkSingletonInstance(QQmlEngine *engine, QObject *instance)
523{
524 if (!instance) {
525 QQmlError error;
526 error.setDescription(QStringLiteral("The registered singleton has already been deleted. "
527 "Ensure that it outlives the engine."));
528 QQmlEnginePrivate::get(engine)->warning(engine, error);
529 return false;
530 }
531
532 if (engine->thread() != instance->thread()) {
533 QQmlError error;
534 error.setDescription(QStringLiteral("Registered object must live in the same thread "
535 "as the engine it was registered with"));
536 QQmlEnginePrivate::get(engine)->warning(engine, error);
537 return false;
538 }
539
540 return true;
541}
542
543// From qqmlprivate.h
544#if QT_DEPRECATED_SINCE(6, 3)
545QObject *QQmlPrivate::SingletonFunctor::operator()(QQmlEngine *qeng, QJSEngine *)
546{
547 if (!checkSingletonInstance(qeng, m_object))
548 return nullptr;
549
550 if (alreadyCalled) {
551 QQmlError error;
552 error.setDescription(QStringLiteral("Singleton registered by registerSingletonInstance "
553 "must only be accessed from one engine"));
554 QQmlEnginePrivate::get(qeng)->warning(qeng, error);
555 return nullptr;
556 }
557
558 alreadyCalled = true;
559 QJSEngine::setObjectOwnership(m_object, QQmlEngine::CppOwnership);
560 return m_object;
561};
562#endif
563
564QObject *QQmlPrivate::SingletonInstanceFunctor::operator()(QQmlEngine *qeng, QJSEngine *)
565{
566 if (!checkSingletonInstance(qeng, m_object))
567 return nullptr;
568
569 if (!m_engine) {
570 m_engine = qeng;
571 QJSEngine::setObjectOwnership(m_object, QQmlEngine::CppOwnership);
572 } else if (m_engine != qeng) {
573 QQmlError error;
574 error.setDescription(QLatin1String("Singleton registered by registerSingletonInstance must only be accessed from one engine"));
575 QQmlEnginePrivate::get(qeng)->warning(qeng, error);
576 return nullptr;
577 }
578
579 return m_object;
580};
581
582static QList<QTypeRevision> availableRevisions(const QMetaObject *metaObject)
583{
584 QList<QTypeRevision> revisions;
585 if (!metaObject)
586 return revisions;
587 const int propertyOffset = metaObject->propertyOffset();
588 const int propertyCount = metaObject->propertyCount();
589 for (int coreIndex = propertyOffset, propertyEnd = propertyOffset + propertyCount;
590 coreIndex < propertyEnd; ++coreIndex) {
591 const QMetaProperty property = metaObject->property(coreIndex);
592 if (int revision = property.revision())
593 revisions.append(QTypeRevision::fromEncodedVersion(revision));
594 }
595 const int methodOffset = metaObject->methodOffset();
596 const int methodCount = metaObject->methodCount();
597 for (int methodIndex = methodOffset, methodEnd = methodOffset + methodCount;
598 methodIndex < methodEnd; ++methodIndex) {
599 const QMetaMethod method = metaObject->method(methodIndex);
600 if (int revision = method.revision())
601 revisions.append(QTypeRevision::fromEncodedVersion(revision));
602 }
603
604 // Need to also check parent meta objects, as their revisions are inherited.
605 if (const QMetaObject *superMeta = metaObject->superClass())
606 revisions += availableRevisions(superMeta);
607
608 return revisions;
609}
610
611template<typename Registration>
612void assignVersions(Registration *registration, QTypeRevision revision,
613 QTypeRevision defaultVersion)
614{
615 const quint8 majorVersion = revision.hasMajorVersion() ? revision.majorVersion()
616 : defaultVersion.majorVersion();
617 registration->version = revision.hasMinorVersion()
618 ? QTypeRevision::fromVersion(majorVersion, revision.minorVersion())
619 : QTypeRevision::fromMajorVersion(majorVersion);
620 registration->revision = revision;
621}
622
623static QList<QTypeRevision> prepareRevisions(const QMetaObject *metaObject, QTypeRevision added)
624{
625 auto revisions = availableRevisions(metaObject);
626 revisions.append(added);
627 return revisions;
628}
629
630static void uniqueRevisions(QList<QTypeRevision> *revisions, QTypeRevision defaultVersion,
631 QTypeRevision added)
632{
633 bool revisionsHaveMajorVersions = false;
634 for (QTypeRevision revision : QList<QTypeRevision>(*revisions)) { // yes, copy
635 // allow any minor version for each explicitly specified past major one
636 if (revision.hasMajorVersion()) {
637 revisionsHaveMajorVersions = true;
638 if (revision.majorVersion() < defaultVersion.majorVersion())
639 revisions->append(QTypeRevision::fromVersion(revision.majorVersion(), 254));
640 }
641 }
642
643 if (revisionsHaveMajorVersions) {
644 if (!added.hasMajorVersion()) {
645 // If added in unspecified major version, assume default one.
646 revisions->append(QTypeRevision::fromVersion(defaultVersion.majorVersion(),
647 added.minorVersion()));
648 } else if (added.majorVersion() < defaultVersion.majorVersion()) {
649 // If added in past major version, add .0 of default version.
650 revisions->append(QTypeRevision::fromVersion(defaultVersion.majorVersion(), 0));
651 }
652 }
653
654 std::sort(revisions->begin(), revisions->end());
655 const auto it = std::unique(revisions->begin(), revisions->end());
656 revisions->erase(it, revisions->end());
657}
658
660 const QQmlPrivate::RegisterSingletonType &type)
661{
662 QQmlType::SingletonInstanceInfo::Ptr siinfo = QQmlType::SingletonInstanceInfo::create();
663 siinfo->scriptCallback = type.scriptApi;
664 siinfo->qobjectCallback = type.qObjectApi;
665 siinfo->typeName = type.typeName;
666 return QQmlType::SingletonInstanceInfo::ConstPtr(
667 siinfo.take(), QQmlType::SingletonInstanceInfo::ConstPtr::Adopt);
668}
669
671 const QQmlPrivate::RegisterCompositeSingletonType &type)
672{
673 QQmlType::SingletonInstanceInfo::Ptr siinfo = QQmlType::SingletonInstanceInfo::create();
674 siinfo->url = QQmlMetaType::normalizedUrl(type.url);
675 siinfo->typeName = type.typeName;
676 return QQmlType::SingletonInstanceInfo::ConstPtr(
677 siinfo.take(), QQmlType::SingletonInstanceInfo::ConstPtr::Adopt);
678}
679
680static int finalizeType(const QQmlType &dtype)
681{
682 if (!dtype.isValid())
683 return -1;
684
685 QQmlMetaType::registerUndeletableType(dtype);
686 return dtype.index();
687}
688
689using ElementNames = QVarLengthArray<const char *, 8>;
690static ElementNames classElementNames(const QMetaObject *metaObject)
691{
692 Q_ASSERT(metaObject);
693 const char *key = "QML.Element";
694
695 const int offset = metaObject->classInfoOffset();
696 const int start = metaObject->classInfoCount() + offset - 1;
697
698 ElementNames elementNames;
699
700 for (int i = start; i >= offset; --i) {
701 const QMetaClassInfo classInfo = metaObject->classInfo(i);
702 if (qstrcmp(key, classInfo.name()) == 0) {
703 const char *elementName = classInfo.value();
704
705 if (qstrcmp(elementName, "auto") == 0) {
706 const char *strippedClassName = metaObject->className();
707 for (const char *c = strippedClassName; *c != '\0'; c++) {
708 if (*c == ':')
709 strippedClassName = c + 1;
710 }
711 elementName = strippedClassName;
712 } else if (qstrcmp(elementName, "anonymous") == 0) {
713 if (elementNames.isEmpty())
714 elementNames.push_back(nullptr);
715 else if (elementNames[0] != nullptr)
716 qWarning() << metaObject->className() << "is both anonymous and named";
717 continue;
718 }
719
720 if (!elementNames.isEmpty() && elementNames[0] == nullptr) {
721 qWarning() << metaObject->className() << "is both anonymous and named";
722 elementNames[0] = elementName;
723 } else {
724 elementNames.push_back(elementName);
725 }
726 }
727 }
728
729 return elementNames;
730}
731
733{
734 AliasRegistrar(const ElementNames *elementNames) : elementNames(elementNames) {}
735
736 void registerAliases(int typeId)
737 {
738 if (elementNames) {
739 for (int i = 1, end = elementNames->length(); i < end; ++i)
740 otherNames.append(QString::fromUtf8(elementNames->at(i)));
741 elementNames = nullptr;
742 }
743
744 for (const QString &otherName : std::as_const(otherNames))
745 QQmlMetaType::registerTypeAlias(typeId, otherName);
746 }
747
748private:
749 const ElementNames *elementNames;
750 QVarLengthArray<QString, 8> otherNames;
751};
752
753
755 const QQmlPrivate::RegisterTypeAndRevisions &type,
756 const ElementNames &elementNames)
757{
758 using namespace QQmlPrivate;
759
760 const bool isValueType = !(type.typeId.flags() & QMetaType::PointerToQObject);
761 const bool creatable = (elementNames[0] != nullptr || isValueType)
762 && boolClassInfo(type.classInfoMetaObject, "QML.Creatable", true);
763
764 QString noCreateReason;
765 ValueTypeCreationMethod creationMethod = ValueTypeCreationMethod::None;
766
767 if (!creatable) {
768 noCreateReason = QString::fromUtf8(
769 classInfo(type.classInfoMetaObject, "QML.UncreatableReason"));
770 if (noCreateReason.isEmpty())
771 noCreateReason = QLatin1String("Type cannot be created in QML.");
772 } else if (isValueType) {
773 const char *method = classInfo(type.classInfoMetaObject, "QML.CreationMethod");
774 if (qstrcmp(method, "structured") == 0)
775 creationMethod = ValueTypeCreationMethod::Structured;
776 else if (qstrcmp(method, "construct") == 0)
777 creationMethod = ValueTypeCreationMethod::Construct;
778 }
779
780 RegisterType typeRevision = {
781 QQmlPrivate::RegisterType::CurrentVersion,
782 type.typeId,
783 type.listId,
784 creatable ? type.objectSize : 0,
785 nullptr,
786 nullptr,
787 noCreateReason,
788 type.createValueType,
789 type.uri,
790 type.version,
791 nullptr,
792 type.metaObject,
793 type.attachedPropertiesFunction,
794 type.attachedPropertiesMetaObject,
795 type.parserStatusCast,
796 type.valueSourceCast,
797 type.valueInterceptorCast,
798 type.extensionObjectCreate,
799 type.extensionMetaObject,
800 nullptr,
801 QTypeRevision(),
802 type.structVersion > 0 ? type.finalizerCast : -1,
803 creationMethod
804 };
805
806 QQmlPrivate::RegisterSequentialContainer sequenceRevision = {
807 0,
808 type.uri,
809 type.version,
810 nullptr,
811 type.listId,
812 type.structVersion > 1 ? type.listMetaSequence : QMetaSequence(),
813 QTypeRevision(),
814 };
815
816 const QTypeRevision added = revisionClassInfo(
817 type.classInfoMetaObject, "QML.AddedInVersion",
818 QTypeRevision::fromVersion(type.version.majorVersion(), 0));
819 const QTypeRevision removed = revisionClassInfo(
820 type.classInfoMetaObject, "QML.RemovedInVersion");
821 const QList<QTypeRevision> furtherRevisions = revisionClassInfos(type.classInfoMetaObject,
822 "QML.ExtraVersion");
823
824 auto revisions = prepareRevisions(type.metaObject, added) + furtherRevisions;
825 if (type.attachedPropertiesMetaObject)
826 revisions += availableRevisions(type.attachedPropertiesMetaObject);
827 uniqueRevisions(&revisions, type.version, added);
828
829 AliasRegistrar aliasRegistrar(&elementNames);
830 for (QTypeRevision revision : std::as_const(revisions)) {
831 if (revision.hasMajorVersion() && revision.majorVersion() > type.version.majorVersion())
832 break;
833
834 assignVersions(&typeRevision, revision, type.version);
835
836 // When removed or before added, we still add revisions, but anonymous ones
837 if (typeRevision.version < added
838 || (removed.isValid() && !(typeRevision.version < removed))) {
839 typeRevision.elementName = nullptr;
840 typeRevision.create = nullptr;
841 typeRevision.userdata = nullptr;
842 } else {
843 typeRevision.elementName = elementNames[0];
844 typeRevision.create = creatable ? type.create : nullptr;
845 typeRevision.userdata = type.userdata;
846 }
847
848 typeRevision.customParser = type.customParserFactory();
849 const int id = qmlregister(TypeRegistration, &typeRevision);
850 if (type.qmlTypeIds)
851 type.qmlTypeIds->append(id);
852
853 if (typeRevision.elementName)
854 aliasRegistrar.registerAliases(id);
855
856 if (sequenceRevision.metaSequence != QMetaSequence()) {
857 sequenceRevision.version = typeRevision.version;
858 sequenceRevision.revision = typeRevision.revision;
859 const int id = QQmlPrivate::qmlregister(
860 QQmlPrivate::SequentialContainerRegistration, &sequenceRevision);
861 if (type.qmlTypeIds)
862 type.qmlTypeIds->append(id);
863 }
864 }
865}
866
868 const QQmlPrivate::RegisterSingletonTypeAndRevisions &type,
869 const ElementNames &elementNames)
870{
871 using namespace QQmlPrivate;
872
873 RegisterSingletonType revisionRegistration = {
874 0,
875 type.uri,
876 type.version,
877 elementNames[0],
878 nullptr,
879 type.qObjectApi,
880 type.instanceMetaObject,
881 type.typeId,
882 type.extensionObjectCreate,
883 type.extensionMetaObject,
884 QTypeRevision()
885 };
886 const QQmlType::SingletonInstanceInfo::ConstPtr siinfo
887 = singletonInstanceInfo(revisionRegistration);
888
889 const QTypeRevision added = revisionClassInfo(
890 type.classInfoMetaObject, "QML.AddedInVersion",
891 QTypeRevision::fromVersion(type.version.majorVersion(), 0));
892 const QTypeRevision removed = revisionClassInfo(
893 type.classInfoMetaObject, "QML.RemovedInVersion");
894 const QList<QTypeRevision> furtherRevisions = revisionClassInfos(type.classInfoMetaObject,
895 "QML.ExtraVersion");
896
897 auto revisions = prepareRevisions(type.instanceMetaObject, added) + furtherRevisions;
898 uniqueRevisions(&revisions, type.version, added);
899
900 AliasRegistrar aliasRegistrar(&elementNames);
901 for (QTypeRevision revision : std::as_const(revisions)) {
902 if (revision.hasMajorVersion() && revision.majorVersion() > type.version.majorVersion())
903 break;
904
905 assignVersions(&revisionRegistration, revision, type.version);
906
907 // When removed or before added, we still add revisions, but anonymous ones
908 if (revisionRegistration.version < added
909 || (removed.isValid() && !(revisionRegistration.version < removed))) {
910 revisionRegistration.typeName = nullptr;
911 revisionRegistration.qObjectApi = nullptr;
912 } else {
913 revisionRegistration.typeName = elementNames[0];
914 revisionRegistration.qObjectApi = type.qObjectApi;
915 }
916
917 const int id = finalizeType(
918 QQmlMetaType::registerSingletonType(revisionRegistration, siinfo));
919 if (type.qmlTypeIds)
920 type.qmlTypeIds->append(id);
921
922 if (revisionRegistration.typeName)
923 aliasRegistrar.registerAliases(id);
924 }
925}
926
927/*
928This method is "over generalized" to allow us to (potentially) register more types of things in
929the future without adding exported symbols.
930*/
931int QQmlPrivate::qmlregister(RegistrationType type, void *data)
932{
933 switch (type) {
934 case AutoParentRegistration:
935 return QQmlMetaType::registerAutoParentFunction(
936 *reinterpret_cast<RegisterAutoParent *>(data));
937 case QmlUnitCacheHookRegistration:
938 return QQmlMetaType::registerUnitCacheHook(
939 *reinterpret_cast<RegisterQmlUnitCacheHook *>(data));
940 case TypeAndRevisionsRegistration: {
941 const RegisterTypeAndRevisions &type = *reinterpret_cast<RegisterTypeAndRevisions *>(data);
942 if (type.structVersion > 1 && type.forceAnonymous) {
943 doRegisterTypeAndRevisions(type, {nullptr});
944 } else {
945 const ElementNames names = classElementNames(type.classInfoMetaObject);
946 if (names.isEmpty()) {
947 qWarning().nospace() << "Missing QML.Element class info for "
948 << type.classInfoMetaObject->className();
949 } else {
950 doRegisterTypeAndRevisions(type, names);
951 }
952
953 }
954 break;
955 }
956 case SingletonAndRevisionsRegistration: {
957 const RegisterSingletonTypeAndRevisions &type
958 = *reinterpret_cast<RegisterSingletonTypeAndRevisions *>(data);
959 const ElementNames names = classElementNames(type.classInfoMetaObject);
960 if (names.isEmpty()) {
961 qWarning().nospace() << "Missing QML.Element class info for "
962 << type.classInfoMetaObject->className();
963 } else {
964 doRegisterSingletonAndRevisions(type, names);
965 }
966 break;
967 }
968 case SequentialContainerAndRevisionsRegistration: {
969 const RegisterSequentialContainerAndRevisions &type
970 = *reinterpret_cast<RegisterSequentialContainerAndRevisions *>(data);
971 RegisterSequentialContainer revisionRegistration = {
972 0,
973 type.uri,
974 type.version,
975 nullptr,
976 type.typeId,
977 type.metaSequence,
978 QTypeRevision()
979 };
980
981 const QTypeRevision added = revisionClassInfo(
982 type.classInfoMetaObject, "QML.AddedInVersion",
983 QTypeRevision::fromMinorVersion(0));
984 QList<QTypeRevision> revisions = revisionClassInfos(
985 type.classInfoMetaObject, "QML.ExtraVersion");
986 revisions.append(added);
987 uniqueRevisions(&revisions, type.version, added);
988
989 for (QTypeRevision revision : std::as_const(revisions)) {
990 if (revision < added)
991 continue;
992 if (revision.hasMajorVersion() && revision.majorVersion() > type.version.majorVersion())
993 break;
994
995 assignVersions(&revisionRegistration, revision, type.version);
996 const int id = qmlregister(SequentialContainerRegistration, &revisionRegistration);
997 if (type.qmlTypeIds)
998 type.qmlTypeIds->append(id);
999 }
1000 break;
1001 }
1002 case TypeRegistration:
1003 return finalizeType(
1004 QQmlMetaType::registerType(*reinterpret_cast<RegisterType *>(data)));
1005 case InterfaceRegistration:
1006 return finalizeType(
1007 QQmlMetaType::registerInterface(*reinterpret_cast<RegisterInterface *>(data)));
1008 case SingletonRegistration:
1009 return finalizeType(QQmlMetaType::registerSingletonType(
1010 *reinterpret_cast<RegisterSingletonType *>(data),
1011 singletonInstanceInfo(*reinterpret_cast<RegisterSingletonType *>(data))));
1012 case CompositeRegistration:
1013 return finalizeType(QQmlMetaType::registerCompositeType(
1014 *reinterpret_cast<RegisterCompositeType *>(data)));
1015 case CompositeSingletonRegistration:
1016 return finalizeType(QQmlMetaType::registerCompositeSingletonType(
1017 *reinterpret_cast<RegisterCompositeSingletonType *>(data),
1018 singletonInstanceInfo(*reinterpret_cast<RegisterCompositeSingletonType *>(data))));
1019 case SequentialContainerRegistration:
1020 return finalizeType(QQmlMetaType::registerSequentialContainer(
1021 *reinterpret_cast<RegisterSequentialContainer *>(data)));
1022 default:
1023 return -1;
1024 }
1025
1026 return -1;
1027}
1028
1029void QQmlPrivate::qmlunregister(RegistrationType type, quintptr data)
1030{
1031 switch (type) {
1032 case AutoParentRegistration:
1033 QQmlMetaType::unregisterAutoParentFunction(reinterpret_cast<AutoParentFunction>(data));
1034 break;
1035 case QmlUnitCacheHookRegistration:
1036 QQmlMetaType::removeCachedUnitLookupFunction(
1037 reinterpret_cast<QmlUnitCacheLookupFunction>(data));
1038 break;
1039 case SequentialContainerRegistration:
1040 QQmlMetaType::unregisterSequentialContainer(data);
1041 break;
1042 case TypeRegistration:
1043 case InterfaceRegistration:
1044 case SingletonRegistration:
1045 case CompositeRegistration:
1046 case CompositeSingletonRegistration:
1047 QQmlMetaType::unregisterType(data);
1048 break;
1049 case TypeAndRevisionsRegistration:
1050 case SingletonAndRevisionsRegistration:
1051 case SequentialContainerAndRevisionsRegistration:
1052 // Currently unnecessary. We'd need a special data structure to hold
1053 // URI + majorVersion and then we'd iterate the minor versions, look up the
1054 // associated QQmlType objects by uri/elementName/major/minor and qmlunregister
1055 // each of them.
1056 Q_UNREACHABLE();
1057 break;
1058 }
1059}
1060
1061QList<QTypeRevision> QQmlPrivate::revisionClassInfos(const QMetaObject *metaObject,
1062 const char *key)
1063{
1064 QList<QTypeRevision> revisions;
1065 for (int index = indexOfOwnClassInfo(metaObject, key); index != -1;
1066 index = indexOfOwnClassInfo(metaObject, key, index - 1)) {
1067 revisions.push_back(QTypeRevision::fromEncodedVersion(
1068 QLatin1StringView(metaObject->classInfo(index).value()).toInt()));
1069 }
1070 return revisions;
1071}
1072
1073/*!
1074 \relates <qqml.h>
1075
1076 This function registers a type in the QML system with the name \a qmlName, in the type namespace imported from \a uri having the
1077 version number composed from \a versionMajor and \a versionMinor, but any attempt to instantiate the type
1078 will produce the given error \a message.
1079
1080 Normally, the types exported by a plugin should be fixed. However, if a C++ type is not available, you should
1081 at least "reserve" the QML type name, and give the user of the unavailable type a meaningful error message.
1082
1083 Returns the QML type id.
1084
1085 Example:
1086
1087 \code
1088 #ifdef NO_GAMES_ALLOWED
1089 qmlRegisterTypeNotAvailable("MinehuntCore", 0, 1, "Game", "Get back to work, slacker!");
1090 #else
1091 qmlRegisterType<MinehuntGame>("MinehuntCore", 0, 1, "Game");
1092 #endif
1093 \endcode
1094
1095 This will cause any QML which imports the "MinehuntCore" type namespace and attempts to use the type to produce an error message:
1096 \code
1097 fun.qml: Get back to work, slacker!
1098 Game {
1099 ^
1100 \endcode
1101
1102 Without this, a generic "Game is not a type" message would be given.
1103
1104 \sa QML_UNAVAILABLE, qmlRegisterUncreatableType(),
1105 {Choosing the Correct Integration Method Between C++ and QML}
1106*/
1107int qmlRegisterTypeNotAvailable(
1108 const char *uri, int versionMajor, int versionMinor,
1109 const char *qmlName, const QString &message)
1110{
1111 return qmlRegisterUncreatableType<QQmlTypeNotAvailable>(
1112 uri, versionMajor, versionMinor, qmlName, message);
1113}
1114
1115namespace QQmlPrivate {
1116template<>
1118 const char *uri, int versionMajor, const QMetaObject *classInfoMetaObject,
1119 QList<int> *qmlTypeIds, const QMetaObject *extension, bool)
1120{
1121 using T = QQmlTypeNotAvailable;
1122
1123 RegisterTypeAndRevisions type = {
1124 3,
1125 QmlMetaType<T>::self(),
1126 QmlMetaType<T>::list(),
1127 0,
1128 nullptr,
1129 nullptr,
1130 nullptr,
1131
1132 uri,
1133 QTypeRevision::fromMajorVersion(versionMajor),
1134
1135 &QQmlTypeNotAvailable::staticMetaObject,
1136 classInfoMetaObject,
1137
1138 attachedPropertiesFunc<T>(),
1139 attachedPropertiesMetaObject<T>(),
1140
1141 StaticCastSelector<T, QQmlParserStatus>::cast(),
1142 StaticCastSelector<T, QQmlPropertyValueSource>::cast(),
1143 StaticCastSelector<T, QQmlPropertyValueInterceptor>::cast(),
1144
1145 nullptr,
1146 extension,
1147 qmlCreateCustomParser<T>,
1148 qmlTypeIds,
1149 QQmlPrivate::StaticCastSelector<T, QQmlFinalizerHook>::cast(),
1150 false,
1151 QmlMetaType<T>::sequence(),
1152 };
1153
1154 qmlregister(TypeAndRevisionsRegistration, &type);
1155}
1156
1158
1160{
1161 return static_cast<QV4::MetaTypesStackFrame *>(engine->handle()->currentStackFrame)
1162 ->thisObject();
1163}
1164
1166{
1167 return engine->handle()->qmlEngine();
1168}
1169
1170static QQmlPropertyCapture *propertyCapture(const AOTCompiledContext *aotContext)
1171{
1172 QQmlEngine *engine = aotContext->qmlEngine();
1173 return engine ? QQmlEnginePrivate::get(aotContext->qmlEngine())->propertyCapture : nullptr;
1174}
1175
1181
1187
1192
1194{
1195 if (auto *frame = engine->handle()->currentStackFrame) {
1198 }
1199}
1200
1205
1206static bool markPointer(const QVariant &element, QV4::MarkStack *markStack)
1207{
1208 if (!element.metaType().flags().testFlag(QMetaType::PointerToQObject))
1209 return false;
1210
1211 QV4::QObjectWrapper::markWrapper(
1212 *static_cast<QObject *const *>(element.constData()), markStack);
1213 return true;
1214}
1215
1216static void iterateVariant(const QVariant &element, std::vector<QVariant> *elements)
1217{
1218#define ADD_CASE(Type, id, T)
1219 case QMetaType::Type:
1220
1221 const QMetaType elementMetaType = element.metaType();
1222 switch (elementMetaType.id()) {
1223 case QMetaType::QVariantMap:
1224 for (const QVariant &variant : *static_cast<const QVariantMap *>(element.constData()))
1225 elements->push_back(variant);
1226 return;
1227 case QMetaType::QVariantHash:
1228 for (const QVariant &variant : *static_cast<const QVariantHash *>(element.constData()))
1229 elements->push_back(variant);
1230 return;
1231 case QMetaType::QVariantList:
1232 for (const QVariant &variant : *static_cast<const QVariantList *>(element.constData()))
1233 elements->push_back(variant);
1234 return;
1235 QT_FOR_EACH_STATIC_PRIMITIVE_TYPE(ADD_CASE)
1236 QT_FOR_EACH_STATIC_CORE_CLASS(ADD_CASE)
1237 QT_FOR_EACH_STATIC_GUI_CLASS(ADD_CASE)
1238 case QMetaType::QStringList:
1239 case QMetaType::QByteArrayList:
1240 return;
1241 default:
1242 break;
1243 }
1244
1245 if (elementMetaType == QMetaType::fromType<QJSValue>()
1246 || elementMetaType == QMetaType::fromType<QJSManagedValue>()
1247 || elementMetaType == QMetaType::fromType<QJSPrimitiveValue>()) {
1248 // QJSValue and QJSManagedValue effectively hold persistent values anyway.
1249 // QJSPrimitiveValue can only hold primitives or QString.
1250 return;
1251 }
1252
1253 QMetaSequence::Iterable iterable;
1254 if (!QMetaType::convert(
1255 element.metaType(), element.constData(),
1256 QMetaType::fromType<QMetaSequence::Iterable>(), &iterable)) {
1257 return;
1258 }
1259
1260 switch (iterable.metaContainer().valueMetaType().id()) {
1261 QT_FOR_EACH_STATIC_PRIMITIVE_TYPE(ADD_CASE)
1262 QT_FOR_EACH_STATIC_CORE_CLASS(ADD_CASE)
1263 QT_FOR_EACH_STATIC_GUI_CLASS(ADD_CASE)
1264 case QMetaType::QStringList:
1265 case QMetaType::QByteArrayList:
1266 return;
1267 default:
1268 break;
1269 }
1270
1271 for (auto it = iterable.constBegin(), end = iterable.constEnd(); it != end; ++it)
1272 elements->push_back(*it);
1273
1274#undef ADD_CASE
1275}
1276
1278{
1280 return;
1281
1284
1285 while (!stack.empty()) {
1286 const QVariant element = std::as_const(stack).back();
1287 stack.pop_back();
1290 }
1291}
1292
1303
1314
1315static bool inherits(const QQmlPropertyCache *descendent, const QQmlPropertyCache *ancestor)
1316{
1317 for (const QQmlPropertyCache *cache = descendent; cache; cache = cache->parent().data()) {
1318 if (cache == ancestor)
1319 return true;
1320 }
1321 return false;
1322}
1323
1325
1331
1332template<bool StrictType>
1350
1351template<bool StrictType = false>
1368
1369template<bool StrictType = false>
1379
1386
1388{
1389 // We've just initialized the lookup. So everything must be fine here.
1390
1392
1395
1396 const QMetaObject *metaObject
1397 = reinterpret_cast<const QMetaObject *>(lookup->qobjectFallbackLookup.metaObject - 1);
1399
1400 return {qmlData, metaObject, PropertyResult::OK};
1401}
1402
1422
1435
1447
1458
1471
1483
1484template<bool StrictType, typename Op>
1497
1498template<bool StrictType = false>
1501{
1503 if (property->isResettable()) {
1505 } else {
1506 v4->throwError(
1507 QLatin1String("Cannot assign [undefined] to ") +
1509 }
1510 });
1511}
1512
1513template<bool StrictType = false>
1520
1521template<typename Op>
1535
1537{
1539 lookup, object, [&](const QMetaObject *metaObject, int coreIndex) {
1540 void *args[] = { value, nullptr };
1542 });
1543}
1544
1547{
1549 lookup, object, [&](const QMetaObject *metaObject, int coreIndex) {
1551 void *args[] = { nullptr };
1553 } else {
1554 const QMetaType propType(reinterpret_cast<const QtPrivate::QMetaTypeInterface *>(
1556 v4->throwError(
1557 QLatin1String("Cannot assign [undefined] to ") +
1559 }
1560 });
1561}
1562
1563static bool isEnumUnderlyingType(QMetaType enumType, QMetaType numberType)
1564{
1565 // You can pass the underlying type of an enum.
1566 // We don't want to check for the actual underlying type because
1567 // moc and qmltyperegistrar are not very precise about it. Especially
1568 // the long and longlong types can be ambiguous.
1569
1570 const bool isUnsigned = enumType.flags() & QMetaType::IsUnsignedEnumeration;
1571 switch (enumType.sizeOf()) {
1572 case 1:
1573 return isUnsigned
1574 ? numberType == QMetaType::fromType<quint8>()
1575 : numberType == QMetaType::fromType<qint8>();
1576 case 2:
1577 return isUnsigned
1578 ? numberType == QMetaType::fromType<ushort>()
1579 : numberType == QMetaType::fromType<short>();
1580 case 4:
1581 // The default type, if moc doesn't know the actual enum type, is int.
1582 // However, the compiler can still decide to encode the enum in uint.
1583 // Therefore, we also accept int for uint enums.
1584 // TODO: This is technically UB.
1585 return isUnsigned
1586 ? (numberType == QMetaType::fromType<int>()
1587 || numberType == QMetaType::fromType<uint>())
1588 : numberType == QMetaType::fromType<int>();
1589 case 8:
1590 return isUnsigned
1591 ? numberType == QMetaType::fromType<qulonglong>()
1592 : numberType == QMetaType::fromType<qlonglong>();
1593 }
1594
1595 return false;
1596}
1597
1598static bool canHoldVoid(QMetaType type)
1599{
1600 // We cannot directly store void, but we can put it into QVariant or QJSPrimitiveValue
1601 return !type.isValid()
1602 || type == QMetaType::fromType<QVariant>()
1603 || type == QMetaType::fromType<QJSPrimitiveValue>();
1604}
1605
1606static bool isTypeCompatible(QMetaType source, QMetaType target)
1607{
1608 if (source == target)
1609 return true;
1610
1611 if ((source.flags() & QMetaType::IsQmlList)
1612 && (target.flags() & QMetaType::IsQmlList)) {
1613 // We want to check the value types here, but we cannot easily do it.
1614 // Internally those are all QObject* lists, though.
1615 return true;
1616 }
1617
1618 if (target.flags() & QMetaType::PointerToQObject) {
1619 // We accept any derived class, too
1620
1621 const QMetaObject *targetMetaObject = target.metaObject();
1622 const QMetaObject *sourceMetaObject = source.metaObject();
1623 if (!sourceMetaObject)
1624 sourceMetaObject = QQmlMetaType::metaObjectForType(source).metaObject();
1625
1626 while (sourceMetaObject && sourceMetaObject != targetMetaObject)
1627 sourceMetaObject = sourceMetaObject->superClass();
1628
1629 return sourceMetaObject != nullptr;
1630 }
1631
1632 if (target.flags() & QMetaType::IsEnumeration)
1633 return isEnumUnderlyingType(target, source);
1634
1635 if (source.flags() & QMetaType::IsEnumeration)
1636 return isEnumUnderlyingType(source, target);
1637
1638 if (!source.isValid())
1639 return canHoldVoid(target);
1640
1641 return false;
1642}
1643
1675
1703
1709
1710template<QV4::Lookup::Call FallbackCall>
1712 const AOTCompiledContext *aotContext, QV4::Lookup *lookup, QObject *object)
1713{
1714 QV4::Scope scope(aotContext->engine->handle());
1715 QV4::PropertyKey id = scope.engine->identifierTable->asPropertyKey(
1716 aotContext->compilationUnit->runtimeStrings[lookup->nameIndex]);
1717
1718 Q_ASSERT(id.isString());
1719
1720 QV4::ScopedString name(scope, id.asStringOrSymbol());
1721
1722 Q_ASSERT(!name->equals(scope.engine->id_toString()));
1723 Q_ASSERT(!name->equals(scope.engine->id_destroy()));
1724
1725 QQmlData *ddata = QQmlData::get(object, true);
1726 Q_ASSERT(ddata);
1727 if (ddata->isQueuedForDeletion)
1729
1730 const QQmlPropertyData *property;
1731 if (!ddata->propertyCache) {
1732 property = QQmlPropertyCache::property(object, name, aotContext->qmlContext, nullptr);
1733 } else {
1734 property = ddata->propertyCache->property(
1735 name.getPointer(), object, aotContext->qmlContext);
1736 }
1737
1738 if (!property) {
1739 const QMetaObject *metaObject = object->metaObject();
1740 if (!metaObject)
1742
1743 const int coreIndex = metaObject->indexOfProperty(
1744 name->toQStringNoThrow().toUtf8().constData());
1745 if (coreIndex < 0)
1747
1748 const QMetaProperty property = metaObject->property(coreIndex);
1749
1750 lookup->releasePropertyCache();
1751 // & 1 to tell the gc that this is not heap allocated; see markObjects in qv4lookup_p.h
1752 lookup->qobjectFallbackLookup.metaObject = quintptr(metaObject) + 1;
1753 lookup->qobjectFallbackLookup.metaType = quintptr(property.metaType().iface()) + 1;
1754 lookup->qobjectFallbackLookup.coreIndex = coreIndex;
1755 lookup->qobjectFallbackLookup.notifyIndex =
1756 QMetaObjectPrivate::signalIndex(property.notifySignal());
1757
1758 if constexpr (FallbackCall == QV4::Lookup::Call::ContextGetterScopeObjectPropertyFallback
1759 || FallbackCall == QV4::Lookup::Call::GetterQObjectPropertyFallback) {
1760 lookup->qobjectFallbackLookup.isConstantOrResettable = property.isConstant() ? 1 : 0;
1761 } else if constexpr (FallbackCall == QV4::Lookup::Call::SetterQObjectPropertyFallback) {
1762 lookup->qobjectFallbackLookup.isConstantOrResettable = property.isResettable() ? 1 : 0;
1763 }
1765 }
1766
1767 Q_ASSERT(ddata->propertyCache);
1768
1769 QV4::setupQObjectLookup(lookup, ddata, property);
1770
1772}
1773
1775template<QV4::Lookup::Call ObjectCall, QV4::Lookup::Call FallbackCall, LookupType Type>
1776void initObjectLookup(const AOTCompiledContext *aotContext, uint index, QObject *object)
1777{
1778 QV4::ExecutionEngine *v4 = aotContext->engine->handle();
1779 if (v4->hasException) {
1780 v4->amendException();
1781 return;
1782 }
1783
1784 QV4::Lookup *lookup = aotContext->compilationUnit->runtimeLookups + index;
1785 switch (initObjectLookup<FallbackCall>(aotContext, lookup, object)) {
1787 lookup->call = ObjectCall;
1788 lookup->asVariant = (Type == LookupType::Variant);
1789 break;
1791 lookup->call = FallbackCall;
1792 lookup->asVariant = (Type == LookupType::Variant);
1793 break;
1795 v4->throwTypeError();
1796 break;
1797 }
1798
1799 return;
1800}
1801
1802
1804 QV4::Lookup *lookup, QV4::ExecutableCompilationUnit *compilationUnit,
1805 const QMetaObject *metaObject)
1806{
1807 Q_ASSERT(metaObject);
1808 const QByteArray name = compilationUnit->runtimeStrings[lookup->nameIndex]->toQString().toUtf8();
1809 const int coreIndex = metaObject->indexOfProperty(name.constData());
1810 QMetaType lookupType = metaObject->property(coreIndex).metaType();
1811 lookup->qgadgetLookup.metaObject = quintptr(metaObject) + 1;
1812 lookup->qgadgetLookup.coreIndex = coreIndex;
1813 lookup->qgadgetLookup.metaType = lookupType.iface();
1814}
1815
1844
1868
1874
1876{
1877#if QT_CONFIG(translation)
1879#else
1880 return QString();
1881#endif
1882}
1883
1885{
1887 switch (lookup->call) {
1900 return QMetaType::fromType<QObject *>();
1903 // We can do this because the fallback lookup gets invalidated for every call.
1904 return QMetaType(reinterpret_cast<const QtPrivate::QMetaTypeInterface *>(
1906 }
1912 return QMetaType::fromType<void>();
1914 return QMetaType::fromType<QString>();
1915 default:
1917 }
1918 default:
1919 break;
1920 }
1921
1923}
1924
1925static bool isUndefined(const void *value, QMetaType type)
1926{
1927 if (type == QMetaType::fromType<QVariant>())
1928 return !static_cast<const QVariant *>(value)->isValid();
1929 if (type == QMetaType::fromType<QJSValue>())
1930 return static_cast<const QJSValue *>(value)->isUndefined();
1931 if (type == QMetaType::fromType<QJSPrimitiveValue>()) {
1932 return static_cast<const QJSPrimitiveValue *>(value)->type()
1933 == QJSPrimitiveValue::Undefined;
1934 }
1935 return false;
1936}
1937
1939{
1940 // We don't really use any part of the lookup machinery here.
1941 // The QV4::Lookup is created on the stack to conveniently get the property cache, and through
1942 // the property cache we store a value into the property.
1943
1944 const auto unwrapVariant = [&]() {
1945 if (type == QMetaType::fromType<QVariant>()) {
1946 QVariant *variant = static_cast<QVariant *>(value);
1947 type = variant->metaType();
1948 value = variant->data();
1949 }
1950 };
1951
1952 QV4::Lookup lookup;
1953 memset(&lookup, 0, sizeof(QV4::Lookup));
1955 lookup.forCall = false;
1958
1960 this, &lookup, qmlScopeObject)) {
1961 case ObjectLookupResult::Object: {
1965 } else if (isUndefined(value, type)) {
1966
1967 // NB: In order to have a meaningful reset() here, the type needs to be a wrapper type
1968 // that can hold undefined. For example QVariant. The caller must not unwrap it.
1969
1971 } else {
1972
1973 // Unwrap any QVariant so that we get a meaningful conversion below.
1974 unwrapVariant();
1975
1978 QV4::Scope scope(v4);
1983 }
1984 }
1985
1987 break;
1988 }
1990 propType = QMetaType(reinterpret_cast<const QtPrivate::QMetaTypeInterface *>(
1994 } else if (isUndefined(value, type)) {
1995
1996 // NB: In order to have a meaningful reset() here, the type needs to be a wrapper type
1997 // that can hold undefined. For example QVariant. The caller must not unwrap it.
1999
2000 } else {
2001
2002 // Unwrap any QVariant so that we get a meaningful conversion below.
2003 unwrapVariant();
2004
2007 QV4::Scope scope(v4);
2012 }
2013 }
2014 break;
2015 }
2018 return;
2019 }
2020
2021 switch (storeResult) {
2022 case PropertyResult::NeedsInit: {
2023 const QString error = QLatin1String("Cannot assign ") +
2025 QLatin1String(" to ") +
2028 break;
2029 }
2030 case PropertyResult::Deleted:
2032 QStringLiteral("Value is null and could not be converted to an object"));
2033 break;
2034 case PropertyResult::OK:
2035 break;
2036 }
2037}
2038
2046
2048{
2049 if (wrapper) {
2050 // We have to check this here because you may pass a plain QObject that only
2051 // turns out to be a QQmlLoggingCategoryBase at run time.
2055 *ok = true;
2056 if (!loggingCategory) {
2058 QStringLiteral("A QmlLoggingCatgory was provided without a valid name"));
2059 }
2060 return loggingCategory;
2061 }
2062 }
2063
2064 *ok = false;
2065 return qmlEngine() ? &lcQml() : &lcJs();
2066}
2067
2070{
2072
2074 Q_ASSERT(frame);
2075
2076 const QByteArray source(frame->source().toUtf8());
2080
2081 switch (type) {
2082 case QtDebugMsg:
2084 break;
2085 case QtInfoMsg:
2087 break;
2088 case QtWarningMsg:
2090 break;
2091 case QtCriticalMsg:
2093 break;
2094 default:
2095 break;
2096 }
2097}
2098
2106
2111
2116
2118 double year, double month, double day, double hours,
2119 double minutes, double seconds, double msecs) const
2120{
2123}
2124
2126 const QQmlType &type, const QV4::CompiledData::ParameterType &parameter)
2127{
2128 return parameter.isList() ? type.qListTypeId() : type.typeId();
2129}
2130
2141
2144 QObject *thisObject, void **args, int argc)
2145{
2146 // We need to re-fetch the method on every call because it can be shadowed.
2147
2151
2152 // The getter mustn't reset the isVariant flag
2154
2155 // Since we have an asVariant lookup, the function may have been overridden in the mean time.
2156 if (!function)
2157 return false;
2158
2159 Q_ALLOCA_VAR(QMetaType, types, (argc + 1) * sizeof(QMetaType));
2161
2163 return !scope.hasException();
2164}
2165
2168 QObject *thisObject, void **args, int argc)
2169{
2171
2172 Q_ALLOCA_VAR(QMetaType, types, (argc + 1) * sizeof(QMetaType));
2177 for (int i = 0; i < argc; ++i)
2179
2181 }
2182
2186 switch (method->methodIndex()) {
2188 return method->method_destroy(
2189 engine, thisObject, argc > 0 ? *static_cast<int *>(args[1]) : 0);
2193 thisObject);
2194 if (void *returnValue = args[0])
2195 *static_cast<QString *>(returnValue) = std::move(result);
2196 return true;
2197 }
2198 default:
2199 break;
2200 }
2201 return false;
2202}
2203
2206 QObject *thisObject, void **args, int argc)
2207{
2211
2212 switch (v4Function->kind) {
2213 case QV4::Function::AotCompiled: {
2216 return !engine->hasException;
2217 }
2218 case QV4::Function::JsTyped: {
2222
2223 Q_ALLOCA_VAR(QMetaType, types, (argc + 1) * sizeof(QMetaType));
2226 for (qsizetype i = 0; i != argc; ++i) {
2229 }
2230
2232 return !engine->hasException;
2233 }
2234 case QV4::Function::JsUntyped: {
2235 // We can call untyped functions if we're not expecting a specific return value and don't
2236 // have to pass any arguments. The compiler verifies this.
2237 Q_ASSERT(argc == 0);
2240 return !engine->hasException;
2241 }
2242 case QV4::Function::Eval:
2243 break;
2244 }
2245
2246 Q_UNREACHABLE_RETURN(false);
2247}
2248
2250 const AOTCompiledContext *aotContext, QV4::Lookup *lookup, const QString &object)
2251{
2252 aotContext->engine->handle()->throwTypeError(
2253 QStringLiteral("Property '%1' of object %2 is not a function").arg(
2254 aotContext->compilationUnit->runtimeStrings[lookup->nameIndex]->toQString(),
2255 object));
2256};
2257
2280
2282
2284 QV4::QObjectMethod *method, QV4::Lookup *lookup, int relativeMethodIndex)
2285{
2286 Q_ASSERT(lookup->qobjectMethodLookup.method.get() == method->d());
2287
2288 const auto *d = method->d();
2289 const int methodCount = d->methodCount;
2290
2291 if (relativeMethodIndex == -1 && methodCount == 1) {
2292 // QML-declared signals do not have a meaningful method index and cannot be overloaded.
2293 // They still show up as QObjectMethod rather than ArrowFunction. If they didn't, we
2294 // wouldn't have to care.
2295 Q_ASSERT(d->methods[0].metaMethod().methodType() == QMetaMethod::Signal);
2296 lookup->qobjectMethodLookup.propertyData = d->methods;
2297 return ExactMatch;
2298 }
2299
2300 for (int i = 0, end = d->methodCount; i != end; ++i) {
2301 const QMetaMethod metaMethod = d->methods[i].metaMethod();
2302 if (metaMethod.relativeMethodIndex() != relativeMethodIndex)
2303 continue;
2304
2305 lookup->qobjectMethodLookup.propertyData = d->methods + i;
2306 return ExactMatch;
2307 }
2308
2309 return NoMatch;
2310}
2311
2313{
2314 QV4::Heap::QObjectMethod *d = method->d();
2315 switch (method->methodIndex()) {
2318 return false;
2319 default:
2320 break;
2321 }
2322
2324 return true;
2325}
2326
2358
2360{
2362 int objectId = -1;
2363 QQmlContextData *context = nullptr;
2365
2366 switch (lookup->call) {
2370 break;
2376 if (objectId != -1 && objectId < context->numIdValues())
2377 break;
2378 }
2379 break;
2380 }
2381 default:
2382 return false;
2383 }
2384
2385 Q_ASSERT(objectId >= 0);
2386 Q_ASSERT(context != nullptr);
2390 *static_cast<QObject **>(target) = context->idValue(objectId);
2391 return true;
2392}
2393
2418
2420 uint index, QObject *object, void **args, int argc) const
2421{
2423
2424 if (!object) {
2425 engine->handle()->throwTypeError(QStringLiteral("Cannot call method '%1' of null")
2427 return false;
2428 }
2429
2430 switch (lookup->call) {
2433 return lookup->asVariant
2438 if (lookup->asVariant) {
2439 // If the method can be shadowed, the overridden method can be taken away, too.
2440 // In that case we might end up with a QObjectMethod or random other values instead.
2441 // callQObjectMethodAsVariant is flexible enough to handle that.
2443 }
2444
2445 // Here we always retrieve a fresh ArrowFunction via the getter.
2449
2450 // The getter mustn't touch the asVariant bit
2452
2453 if (function)
2455
2457 }
2458 default:
2459 break;
2460 }
2461
2462 return false;
2463}
2464
2466{
2467 if (engine->hasError()) {
2469 return;
2470 }
2471
2474
2475 const auto *ddata = QQmlData::get(object, false);
2477 // We cannot lookup functions on an object with VME metaobject but no QObjectWrapper
2478 throwIsNotAFunctionError(this, lookup, QStringLiteral("[object Object]"));
2479 return;
2480 }
2481
2484 if (auto *method = function->as<QV4::QObjectMethod>()) {
2486 lookup->asVariant = true;
2487 return;
2488 }
2489
2490 if (function->as<QV4::ArrowFunction>()) {
2491 // Can't have overloads of JavaScript functions.
2492 lookup->asVariant = true;
2493 return;
2494 }
2495
2497}
2498
2501{
2502 if (engine->hasError()) {
2504 return;
2505 }
2506
2509
2510 const auto *ddata = QQmlData::get(object, false);
2512 // We cannot lookup functions on an object with VME metaobject but no QObjectWrapper
2513 throwIsNotAFunctionError(this, lookup, QStringLiteral("[object Object]"));
2514 return;
2515 }
2516
2519 if (auto *method = function->as<QV4::QObjectMethod>()) {
2523 }
2524 return;
2525 }
2526
2527 if (function->as<QV4::ArrowFunction>()) {
2528 // Can't have overloads of JavaScript functions.
2529 return;
2530 }
2531
2533}
2534
2536{
2539 return false;
2543 val,
2546 return false;
2547 }
2548 return true;
2549}
2550
2561
2563{
2565
2566 if (!qmlScopeObject) {
2569 return false;
2570 }
2571
2573 switch (lookup->call) {
2576 break;
2580 break;
2581 default:
2582 return false;
2583 }
2584
2585 switch (result) {
2587 return false;
2588 case PropertyResult::Deleted:
2590 QStringLiteral("Cannot read property '%1' of null")
2592 return false;
2593 case PropertyResult::OK:
2594 return true;
2595 }
2596
2597 Q_UNREACHABLE_RETURN(false);
2598}
2599
2601{
2603
2605 switch (lookup->call) {
2608 break;
2612 break;
2613 default:
2614 return false;
2615 }
2616
2617 switch (result) {
2619 return false;
2620 case PropertyResult::Deleted: // Silently omit the write back. Same as interpreter
2621 case PropertyResult::OK:
2622 return true;
2623 }
2624
2625 Q_UNREACHABLE_RETURN(false);
2626}
2627
2628
2629
2637
2639{
2642
2646
2647 // We don't handle non-QObject singletons (as those can't be declared in qmltypes anyway)
2649 *static_cast<QObject **>(target) = wrapper->object();
2650 return true;
2651 }
2652
2653 return false;
2654}
2655
2658
2659template<QV4::Lookup::Call call>
2660static void initTypeWrapperLookup(
2661 const AOTCompiledContext *context, QV4::Lookup *lookup, uint importNamespace)
2662{
2663 Q_ASSERT(!context->engine->hasError());
2664 if (importNamespace != AOTCompiledContext::InvalidStringId) {
2665 QV4::Scope scope(context->engine->handle());
2666 QV4::ScopedString import(scope, context->compilationUnit->runtimeStrings[importNamespace]);
2667
2668 QQmlTypeLoader *typeLoader = scope.engine->typeLoader();
2669 Q_ASSERT(typeLoader);
2670 if (const QQmlImportRef *importRef
2671 = context->qmlContext->imports()->query(import, typeLoader).importNamespace) {
2672
2673 QV4::Scoped<QV4::QQmlTypeWrapper> wrapper(
2674 scope, QV4::QQmlTypeWrapper::create(
2675 scope.engine, nullptr, context->qmlContext->imports(), importRef));
2676
2677 // This is not a contextGetter since we actually load from the namespace.
2678 wrapper = lookup->getter(context->engine->handle(), wrapper);
2679
2680 // In theory, the getter may have populated the lookup's property cache.
2681 lookup->releasePropertyCache();
2682
2683 lookup->call = call;
2684 switch (call) {
2685 case QV4::Lookup::Call::ContextGetterSingleton:
2686 lookup->qmlContextSingletonLookup.singletonObject.set(scope.engine, wrapper->heapObject());
2687 break;
2688 case QV4::Lookup::Call::ContextGetterType:
2689 lookup->qmlTypeLookup.qmlTypeWrapper.set(scope.engine, wrapper->heapObject());
2690 break;
2691 default:
2692 break;
2693 }
2694 return;
2695 }
2696 scope.engine->throwTypeError();
2697 } else {
2698 QV4::ExecutionEngine *v4 = context->engine->handle();
2699 lookup->contextGetter(v4, nullptr);
2700 if (lookup->call != call) {
2701 const QString error
2702 = QLatin1String(call == QV4::Lookup::Call::ContextGetterSingleton
2703 ? "%1 was a singleton at compile time, "
2704 "but is not a singleton anymore."
2705 : "%1 was not a singleton at compile time, "
2706 "but is a singleton now.")
2707 .arg(context->compilationUnit->runtimeStrings[lookup->nameIndex]->toQString());
2708 v4->throwTypeError(error);
2709 }
2710 }
2711}
2717}
2731}
2764}
2767{
2770 return false;
2771
2772 const QV4::Heap::QQmlTypeWrapper *typeWrapper = static_cast<const QV4::Heap::QQmlTypeWrapper *>(
2774
2776 *static_cast<const QMetaObject **>(target)
2778 return true;
2779}
2785}
2788{
2790 const auto doThrow = [&]() {
2792 QStringLiteral("Cannot read property '%1' of null")
2794 return false;
2795 };
2796
2797 if (!object)
2798 return doThrow();
2799
2801 switch (lookup->call) {
2806 break;
2812 break;
2813 default:
2814 return false;
2815 }
2816
2817 switch (result) {
2818 case PropertyResult::Deleted:
2819 return doThrow();
2821 return false;
2822 case PropertyResult::OK:
2823 return true;
2824 }
2825
2826 Q_UNREACHABLE_RETURN(false);
2827}
2830{
2832 if (!object)
2833 return true;
2834
2836 switch (lookup->call) {
2841 break;
2847 break;
2848 default:
2849 return false;
2850 }
2851
2852 switch (result) {
2854 return false;
2855 case PropertyResult::Deleted: // Silently omit the write back
2856 case PropertyResult::OK:
2857 return true;
2858 }
2859
2860 Q_UNREACHABLE_RETURN(false);
2861}
2869}
2877}
2879bool AOTCompiledContext::getValueLookup(uint index, void *value, void *target) const
2880{
2881 Q_ASSERT(value);
2882
2885 return false;
2886
2887 const QMetaObject *metaObject
2888 = reinterpret_cast<const QMetaObject *>(lookup->qgadgetLookup.metaObject - 1);
2890
2891 void *args[] = { target, nullptr };
2893 reinterpret_cast<QObject*>(value), QMetaObject::ReadProperty,
2895 return true;
2896}
2899{
2900 Q_ASSERT(value);
2901
2904 return false;
2905
2906 const QMetaObject *metaObject
2907 = reinterpret_cast<const QMetaObject *>(lookup->qgadgetLookup.metaObject - 1);
2909
2910 void *args[] = { source, nullptr };
2912 reinterpret_cast<QObject*>(value), QMetaObject::WriteProperty,
2914 return true;
2915}
2923}
2926{
2929 return false;
2930 const bool isUnsigned
2934 case 1:
2935 if (isUnsigned)
2936 *static_cast<quint8 *>(target) = encoded;
2937 else
2938 *static_cast<qint8 *>(target) = encoded;
2939 return true;
2940 case 2:
2941 if (isUnsigned)
2942 *static_cast<quint16 *>(target) = encoded;
2943 else
2944 *static_cast<qint16 *>(target) = encoded;
2945 return true;
2946 case 4:
2947 if (isUnsigned)
2948 *static_cast<quint32 *>(target) = encoded;
2949 else
2950 *static_cast<qint32 *>(target) = encoded;
2951 return true;
2952 case 8:
2953 if (isUnsigned)
2954 *static_cast<quint64 *>(target) = encoded;
2955 else
2956 *static_cast<qint64 *>(target) = encoded;
2957 return true;
2958 default:
2959 break;
2960 }
2961
2962 return false;
2963}
2982}
2985{
2986 const auto doThrow = [&]() {
2988 QStringLiteral("Value is null and could not be converted to an object"));
2989 return false;
2990 };
2991
2992 if (!object)
2993 return doThrow();
2994
2997 switch (lookup->call) {
3002 break;
3008 break;
3009 default:
3010 return false;
3011 }
3012
3013 switch (result) {
3014 case PropertyResult::Deleted:
3015 return doThrow();
3017 return false;
3018 case PropertyResult::OK:
3019 return true;
3020 }
3021
3022 Q_UNREACHABLE_RETURN(false);
3023}
3031}
3039}
3041static PropertyResult storeValueProperty(
3042 QV4::Lookup *lookup, const QMetaObject *metaObject, void *target, void *value)
3043{
3044 void *args[] = { value, nullptr };
3045 metaObject->d.static_metacall(
3046 reinterpret_cast<QObject *>(target), QMetaObject::WriteProperty,
3047 lookup->qgadgetLookup.coreIndex, args);
3048 return PropertyResult::OK;
3049}
3051static PropertyResult resetValueProperty(
3052 QV4::Lookup *lookup, const QMetaObject *metaObject, void *target, QV4::ExecutionEngine *v4)
3053{
3054 const QMetaProperty property = metaObject->property(lookup->qgadgetLookup.coreIndex);
3055 if (property.isResettable()) {
3056 void *args[] = { nullptr };
3057 metaObject->d.static_metacall(
3058 reinterpret_cast<QObject *>(target), QMetaObject::ResetProperty,
3059 lookup->qgadgetLookup.coreIndex, args);
3060 } else {
3061 v4->throwError(
3062 QLatin1String("Cannot assign [undefined] to ") +
3063 QLatin1String(property.metaType().name()));
3064 }
3065
3066 return PropertyResult::OK;
3067}
3069static PropertyResult storeValueAsVariant(
3070 QV4::ExecutionEngine *v4, QV4::Lookup *lookup, const QMetaObject *metaObject,
3071 void *target, void *value)
3072{
3073 QVariant *variant = static_cast<QVariant *>(value);
3074 const QMetaType propType = metaObject->property(lookup->qgadgetLookup.coreIndex).metaType();
3075 if (propType == QMetaType::fromType<QVariant>())
3076 return storeValueProperty(lookup, metaObject, target, variant);
3077
3078 if (!variant->isValid())
3079 return resetValueProperty(lookup, metaObject, target, v4);
3080
3081 if (isTypeCompatible(variant->metaType(), propType))
3082 return storeValueProperty(lookup, metaObject, target, variant->data());
3083
3084 QVariant converted(propType);
3085 QV4::Scope scope(v4);
3086 QV4::ScopedValue val(scope, v4->fromVariant(*variant));
3087 if (v4->metaTypeFromJS(val, propType, converted.data())
3088 || QMetaType::convert(
3089 variant->metaType(), variant->constData(), propType, converted.data())) {
3090 return storeValueProperty(lookup, metaObject, target, converted.data());
3091 }
3092
3093 v4->throwError(
3094 QLatin1String("Cannot assign ") + QLatin1String(variant->metaType().name())
3095 + QLatin1String(" to ") + QLatin1String(propType.name()));
3096
3098}
3101 uint index, void *target, void *value) const
3102{
3105 return false;
3106
3107 const QMetaObject *metaObject
3108 = reinterpret_cast<const QMetaObject *>(lookup->qgadgetLookup.metaObject - 1);
3109
3113
3114 switch (result) {
3115 case PropertyResult::OK:
3116 return true;
3118 return false;
3119 case PropertyResult::Deleted:
3120 Q_UNREACHABLE();
3121 }
3122
3123 return false;
3124}
3125
3126template<LookupType Type>
3127void initValueLookup(
3128 const AOTCompiledContext *aotContext, uint index, const QMetaObject *metaObject)
3129{
3130 QV4::ExecutionEngine *v4 = aotContext->engine->handle();
3131 if (v4->hasException) {
3132 v4->amendException();
3133 return;
3134 }
3135
3136 QV4::Lookup *lookup = aotContext->compilationUnit->runtimeLookups + index;
3137 initValueLookup(lookup, aotContext->compilationUnit, metaObject);
3138 lookup->call = QV4::Lookup::Call::SetterValueTypeProperty;
3139 lookup->asVariant = (Type == LookupType::Variant);
3140}
3145}
3151}
3153bool AOTCompiledContext::callValueLookup(uint index, void *target, void **args, int argc) const
3154{
3155 Q_UNUSED(argc);
3156
3159 return false;
3160
3162
3163 const QMetaObject *metaObject
3164 = reinterpret_cast<const QMetaObject *>(lookup->qgadgetLookup.metaObject - 1);
3165
3167 reinterpret_cast<QObject *>(target), QMetaObject::InvokeMetaMethod,
3169
3170 return true;
3171}
3188}
3195}
3196
3197} // namespace QQmlPrivate
3198
3199/*!
3200 \macro QML_DECLARE_TYPE()
3201 \relates <qqml.h>
3202
3203 Equivalent to \c Q_DECLARE_METATYPE(TYPE *) and \c Q_DECLARE_METATYPE(QQmlListProperty<TYPE>)
3204*/
3205
3206/*!
3207 \macro QML_DECLARE_TYPEINFO(Type,Flags)
3208 \relates <qqml.h>
3209
3210 Declares additional properties of the given \a Type as described by the
3211 specified \a Flags.
3212
3213 Current the only supported type info is \c QML_HAS_ATTACHED_PROPERTIES which
3214 declares that the \a Type supports \l {Attached Properties and Attached Signal Handlers}
3215 {attached properties}. QML_DECLARE_TYPEINFO() is not necessary if \a Type contains the
3216 QML_ATTACHED macro.
3217*/
3218
3219/*!
3220 \fn template <typename T> int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const char *qmlName)
3221 \relates <qqml.h>
3222
3223 This template function registers the C++ type in the QML system with
3224 the name \a qmlName, in the library imported from \a uri having the
3225 version number composed from \a versionMajor and \a versionMinor.
3226
3227 Returns the QML type id.
3228
3229 There are two forms of this template function:
3230
3231 \code
3232 template<typename T>
3233 int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const char *qmlName);
3234
3235 template<typename T, int metaObjectRevision>
3236 int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const char *qmlName);
3237 \endcode
3238
3239 The former is the standard form which registers the type \e T as a new type.
3240 The latter allows a particular revision of a class to be registered in
3241 a specified version (see \l {Type Revisions and Versions}).
3242
3243
3244 For example, this registers a C++ class \c MySliderItem as a QML type
3245 named \c Slider for version 1.0 of a type namespace called
3246 "com.mycompany.qmlcomponents":
3247
3248 \code
3249 qmlRegisterType<MySliderItem>("com.mycompany.qmlcomponents", 1, 0, "Slider");
3250 \endcode
3251
3252 Once this is registered, the type can be used in QML by importing the
3253 specified type namespace and version number:
3254
3255 \qml
3256 import com.mycompany.qmlcomponents 1.0
3257
3258 Slider {
3259 // ...
3260 }
3261 \endqml
3262
3263 Note that it's perfectly reasonable for a library to register types to older versions
3264 than the actual version of the library. Indeed, it is normal for the new library to allow
3265 QML written to previous versions to continue to work, even if more advanced versions of
3266 some of its types are available.
3267
3268 \sa QML_ELEMENT, QML_NAMED_ELEMENT(),
3269 {Choosing the Correct Integration Method Between C++ and QML}
3270*/
3271
3272/*!
3273 \fn template<typename T, int metaObjectRevision> int qmlRegisterRevision(const char *uri, int versionMajor, int versionMinor)
3274 \relates <qqml.h>
3275
3276 This template function registers the C++ type \a T at the specified revision
3277 \a metaObjectRevision in the QML system with the library imported from \a uri
3278 having the version number composed from \a versionMajor and \a versionMinor.
3279
3280 Returns the QML type id.
3281
3282 \code
3283 template<typename T, int metaObjectRevision>
3284 int qmlRegisterRevision(const char *uri, int versionMajor, int versionMinor);
3285 \endcode
3286
3287 This function is typically used to register the revision of a base class to
3288 use for the specified version of the type (see \l {Type Revisions and Versions}).
3289*/
3290
3291/*!
3292 \fn template <typename T> int qmlRegisterUncreatableType(const char *uri, int versionMajor, int versionMinor, const char *qmlName, const QString& message)
3293 \relates <qqml.h>
3294
3295 This template function registers the C++ type in the QML system with
3296 the name \a qmlName, in the library imported from \a uri having the
3297 version number composed from \a versionMajor and \a versionMinor.
3298
3299 While the type has a name and a type, it cannot be created, and the
3300 given error \a message will result if creation is attempted.
3301
3302 This is useful where the type is only intended for providing attached properties or enum values.
3303
3304 Returns the QML type id.
3305
3306 \sa QML_UNCREATABLE(), qmlRegisterTypeNotAvailable(),
3307 {Choosing the Correct Integration Method Between C++ and QML}
3308*/
3309
3310/*!
3311 \fn template <typename T, typename E> int qmlRegisterExtendedType(const char *uri, int versionMajor, int versionMinor, const char *qmlName)
3312 \relates <qqml.h>
3313
3314 This template function registers the C++ type and its extension object in the
3315 QML system with the name \a qmlName in the library imported from \a uri having
3316 version number composed from \a versionMajor and \a versionMinor. Properties
3317 not available in the main type will be searched for in the extension object.
3318
3319 Returns the QML type id.
3320
3321 \sa QML_EXTENDED(), qmlRegisterType(), {Registering Extension Objects}
3322*/
3323
3324/*!
3325 \fn template <typename T, typename E> int qmlRegisterExtendedUncreatableType(const char *uri, int versionMajor, int versionMinor, const char *qmlName, const QString& reason)
3326 \relates <qqml.h>
3327
3328 This template function registers the C++ type and its extension
3329 in the QML system with the name \a qmlName in the library imported
3330 from \a uri having version number composed from \a versionMajor and
3331 \a versionMinor.
3332
3333 While the type has a name and a type, it cannot be created. An error
3334 message with the given \a reason is printed if the user attempts to
3335 create an instance of this type.
3336
3337 This is useful where the type is only intended for providing attached
3338 properties, enum values or an abstract base class with its extension.
3339
3340 Returns the QML type id.
3341
3342 \sa QML_EXTENDED(), QML_UNCREATABLE(), qmlRegisterUncreatableType()
3343*/
3344
3345/*!
3346 \fn int qmlRegisterCustomExtendedType(const char *uri, int versionMajor, int versionMinor, const char *qmlName, QQmlCustomParser *parser)
3347 \relates <qqml.h>
3348 \internal
3349
3350 This template function registers the C++ type and its extension
3351 in the QML system with the name \a qmlName in the library imported
3352 from \a uri having version number composed from \a versionMajor and
3353 \a versionMinor. Properties from the C++ type or its extension that
3354 cannot be resolved directly by the QML system will be resolved using
3355 the \a parser provided.
3356
3357 Returns the QML type id.
3358
3359 \sa QML_ELEMENT, QML_NAMED_ELEMENT(), QML_EXTENDED()
3360*/
3361
3362/*!
3363 \fn template <typename T> int qmlRegisterAnonymousType(const char *uri, int versionMajor)
3364 \relates <qqml.h>
3365
3366 This template function registers the C++ type in the QML system as an anonymous type. The
3367 resulting QML type does not have a name. Therefore, instances of this type cannot be created from
3368 the QML system. You can, however, access instances of the type when they are exposed as properties
3369 of other types.
3370
3371 Use this function when the type will not be referenced by name, specifically for C++ types that
3372 are used on the left-hand side of a property binding. To indicate to which module the type belongs
3373 use \a uri and \a versionMajor.
3374
3375 For example, consider the following two classes:
3376
3377 //! Workaround for MOC not respecting comments and triggering an error on certain Qt macros.
3378 \code Q
3379 class Bar : public QObject
3380 {
3381 \1_OBJECT
3382 Q_PROPERTY(QString baz READ baz WRITE setBaz NOTIFY bazChanged)
3383
3384 public:
3385 Bar() {}
3386
3387 QString baz() const { return mBaz; }
3388
3389 void setBaz(const QString &baz)
3390 {
3391 if (baz == mBaz)
3392 return;
3393
3394 mBaz = baz;
3395 emit bazChanged();
3396 }
3397
3398 signals:
3399 void bazChanged();
3400
3401 private:
3402 QString mBaz;
3403 };
3404
3405 class Foo : public QObject
3406 {
3407 \1_OBJECT
3408 Q_PROPERTY(Bar *bar READ bar CONSTANT FINAL)
3409
3410 public:
3411 Foo() {}
3412
3413 Bar *bar() { return &mBar; }
3414
3415 private:
3416 Bar mBar;
3417 };
3418 \endcode
3419
3420 In QML, we assign a string to the \c baz property of \c bar:
3421
3422 \code
3423 Foo {
3424 bar.baz: "abc"
3425 Component.onCompleted: print(bar.baz)
3426 }
3427 \endcode
3428
3429 For the QML engine to know that the \c Bar type has a \c baz property,
3430 we have to make \c Bar known:
3431
3432 \code
3433 qmlRegisterType<Foo>("App", 1, 0, "Foo");
3434 qmlRegisterAnonymousType<Bar>("App", 1);
3435 \endcode
3436
3437 As the \c Foo type is instantiated in QML, it must be registered
3438 with the version of \l qmlRegisterType() that takes an element name.
3439
3440 Returns the QML type id.
3441
3442 \since 5.14
3443 \sa QML_ANONYMOUS, {Choosing the Correct Integration Method Between C++ and QML}
3444*/
3445
3446/*!
3447 \fn int qmlRegisterInterface(const char *typeName)
3448 \relates <qqml.h>
3449
3450 This template function registers the C++ type in the QML system
3451 under the name \a typeName.
3452
3453 Types registered as an interface with the engine should also
3454 declare themselves as an interface with the
3455 \l {The Meta-Object System}{meta object system}. For example:
3456
3457 \code
3458 struct FooInterface
3459 {
3460 public:
3461 virtual ~FooInterface();
3462 virtual void doSomething() = 0;
3463 };
3464
3465 Q_DECLARE_INTERFACE(FooInterface, "org.foo.FooInterface")
3466 \endcode
3467
3468 When registered with the QML engine in this way, they can be used as
3469 property types:
3470
3471 Q_PROPERTY(FooInterface *foo READ foo WRITE setFoo)
3472
3473 When you assign a \l QObject sub-class to this property, the QML engine does
3474 the interface cast to \c FooInterface* automatically.
3475
3476 Returns the QML type id.
3477
3478 \sa QML_INTERFACE
3479*/
3480
3481/*!
3482 \fn int qmlRegisterSingletonType(const char *uri, int versionMajor, int versionMinor, const char *typeName, std::function<QJSValue(QQmlEngine *, QJSEngine *)> callback)
3483 \relates <qqml.h>
3484
3485 This function may be used to register a singleton type provider \a callback in a particular \a uri
3486 and \a typeName with a version specified in \a versionMajor and \a versionMinor.
3487
3488 Installing a singleton type allows developers to provide arbitrary functionality
3489 (methods and properties) to a client without requiring individual instances of the type to
3490 be instantiated by the client.
3491
3492 A singleton type may be either a QObject or a QJSValue.
3493 This function should be used to register a singleton type provider function which returns a QJSValue as a singleton type.
3494
3495 \b{NOTE:} QJSValue singleton type properties will \b{not} trigger binding re-evaluation if changed.
3496
3497 Usage:
3498 \code
3499 // First, define the singleton type provider function (callback).
3500 static QJSValue example_qjsvalue_singletontype_provider(QQmlEngine *engine, QJSEngine *scriptEngine)
3501 {
3502 Q_UNUSED(engine)
3503
3504 static int seedValue = 5;
3505 QJSValue example = scriptEngine->newObject();
3506 example.setProperty("someProperty", seedValue++);
3507 return example;
3508 }
3509
3510 // Second, register the singleton type provider with QML by calling this function in an initialization function.
3511 qmlRegisterSingletonType("Qt.example.qjsvalueApi", 1, 0, "MyApi", example_qjsvalue_singletontype_provider);
3512 \endcode
3513
3514 Alternatively, you can use a C++11 lambda:
3515
3516 \code
3517 qmlRegisterSingletonType("Qt.example.qjsvalueApi", 1, 0, "MyApi", [](QQmlEngine *engine, QJSEngine *scriptEngine) -> QJSValue {
3518 Q_UNUSED(engine)
3519
3520 static int seedValue = 5;
3521 QJSValue example = scriptEngine->newObject();
3522 example.setProperty("someProperty", seedValue++);
3523 return example;
3524 });
3525 \endcode
3526
3527 In order to use the registered singleton type in QML, you must import the singleton type.
3528 \qml
3529 import QtQuick 2.0
3530 import Qt.example.qjsvalueApi 1.0 as ExampleApi
3531 Item {
3532 id: root
3533 property int someValue: ExampleApi.MyApi.someProperty
3534 }
3535 \endqml
3536
3537 \sa QML_SINGLETON, {Choosing the Correct Integration Method Between C++ and QML}
3538*/
3539
3540/*!
3541 \fn template<typename T> QObject *qmlAttachedPropertiesObject(const QObject *attachee, bool createIfMissing)
3542 \relates <qqml.h>
3543
3544 The form of this template function is:
3545
3546 \code
3547 template<typename T> QObject *qmlAttachedPropertiesObject(const QObject *attachee, bool createIfMissing = true)
3548 \endcode
3549
3550 This returns the attached object instance that has been attached to the specified
3551 \a attachee by the attaching type \e T.
3552
3553 If \a attachee is \nullptr, returns \nullptr.
3554
3555 If an existing attached object instance of type \e T exists, it will return
3556 it. Otherwise, it will return a newly created instance if
3557 \a createIfMissing is \c true and \e T is a valid attaching type, or
3558 \nullptr if it's not.
3559
3560 \sa QML_ATTACHED(), {Providing Attached Properties}
3561*/
3562
3563/*!
3564 \fn template <typename T> int qmlRegisterSingletonType(const char *uri, int versionMajor, int versionMinor, const char *typeName, std::function<QObject*(QQmlEngine *, QJSEngine *)> callback)
3565 \relates <qqml.h>
3566
3567 This function may be used to register a singleton type provider \a callback in a particular \a uri
3568 and \a typeName with a version specified in \a versionMajor and \a versionMinor.
3569
3570 Installing a singleton type into a uri allows developers to provide arbitrary functionality
3571 (methods and properties) to clients without requiring individual instances ot the type to be
3572 instantiated by the client.
3573
3574 A singleton type may be either a QObject or a QJSValue.
3575 This function should be used to register a singleton type provider function which returns a QObject
3576 of the given type T as a singleton type.
3577
3578 A QObject singleton type may be referenced via the type name with which it was registered, and this
3579 typename may be used as the target in a \l Connections type or otherwise used as any other type id would.
3580 One exception to this is that a QObject singleton type property may not be aliased.
3581
3582 \b{NOTE:} A QObject singleton type instance returned from a singleton type provider is owned by
3583 the QML engine unless the object has explicit QQmlEngine::CppOwnership flag set.
3584
3585 Usage:
3586 //! Workaround for MOC not respecting comments and triggering an error on certain Qt macros.
3587 \code Q
3588 // First, define your QObject which provides the functionality.
3589 class SingletonTypeExample : public QObject
3590 {
3591 \1_OBJECT
3592 Q_PROPERTY (int someProperty READ someProperty WRITE setSomeProperty NOTIFY somePropertyChanged)
3593
3594 public:
3595 SingletonTypeExample(QObject *parent = nullptr)
3596 : QObject(parent), m_someProperty(0)
3597 {
3598 }
3599
3600 ~SingletonTypeExample() {}
3601
3602 Q_INVOKABLE int doSomething() { setSomeProperty(5); return m_someProperty; }
3603
3604 int someProperty() const { return m_someProperty; }
3605 void setSomeProperty(int val) { m_someProperty = val; emit somePropertyChanged(val); }
3606
3607 signals:
3608 void somePropertyChanged(int newValue);
3609
3610 private:
3611 int m_someProperty;
3612 };
3613
3614 // Second, define the singleton type provider function (callback).
3615 static QObject *example_qobject_singletontype_provider(QQmlEngine *engine, QJSEngine *scriptEngine)
3616 {
3617 Q_UNUSED(engine)
3618 Q_UNUSED(scriptEngine)
3619
3620 SingletonTypeExample *example = new SingletonTypeExample();
3621 return example;
3622 }
3623
3624 // Third, register the singleton type provider with QML by calling this function in an initialization function.
3625 qmlRegisterSingletonType<SingletonTypeExample>("Qt.example.qobjectSingleton", 1, 0, "MyApi", example_qobject_singletontype_provider);
3626 \endcode
3627
3628 Alternatively, you can use a C++11 lambda:
3629
3630 \code
3631 qmlRegisterSingletonType<SingletonTypeExample>("Qt.example.qobjectSingleton", 1, 0, "MyApi", [](QQmlEngine *engine, QJSEngine *scriptEngine) -> QObject * {
3632 Q_UNUSED(engine)
3633 Q_UNUSED(scriptEngine)
3634
3635 SingletonTypeExample *example = new SingletonTypeExample();
3636 return example;
3637 });
3638 \endcode
3639
3640 In order to use the registered singleton type in QML, you must import the singleton type.
3641 \qml
3642 import QtQuick 2.0
3643 import Qt.example.qobjectSingleton 1.0
3644 Item {
3645 id: root
3646 property int someValue: MyApi.someProperty
3647
3648 Component.onCompleted: {
3649 someValue = MyApi.doSomething()
3650 }
3651 }
3652 \endqml
3653
3654 \sa QML_SINGLETON, {Choosing the Correct Integration Method Between C++ and QML}
3655*/
3656
3657/*!
3658 \fn int qmlRegisterSingletonType(const QUrl &url, const char *uri, int versionMajor, int versionMinor, const char *qmlName)
3659 \relates <qqml.h>
3660
3661 This function may be used to register a singleton type with the name \a qmlName, in the library imported from \a uri having
3662 the version number composed from \a versionMajor and \a versionMinor. The type is defined by the QML file located at \a url.
3663 The url must be an absolute URL, i.e. url.isRelative() == false.
3664
3665 In addition the type's QML file must have pragma Singleton statement among its import statements.
3666
3667 A singleton type may be referenced via the type name with which it was registered, and this typename may be used as the
3668 target in a \l Connections type or otherwise used as any other type id would. One exception to this is that a singleton
3669 type property may not be aliased (because the singleton type name does not identify an object within the same component
3670 as any other item).
3671
3672 Usage:
3673 \qml
3674 // First, define your QML singleton type which provides the functionality.
3675 pragma Singleton
3676 import QtQuick 2.0
3677 Item {
3678 property int testProp1: 125
3679 }
3680 \endqml
3681
3682 \code
3683 // Second, register the QML singleton type by calling this function in an initialization function.
3684 qmlRegisterSingletonType(QUrl("file:///absolute/path/SingletonType.qml"), "Qt.example.qobjectSingleton", 1, 0, "RegisteredSingleton");
3685 \endcode
3686
3687 In order to use the registered singleton type in QML, you must import the singleton type.
3688 \qml
3689 import QtQuick 2.0
3690 import Qt.example.qobjectSingleton 1.0
3691 Item {
3692 id: root
3693 property int someValue: RegisteredSingleton.testProp1
3694 }
3695 \endqml
3696
3697 It is also possible to have QML singleton types registered without using the qmlRegisterSingletonType function.
3698 That can be done by adding a pragma Singleton statement among the imports of the type's QML file. In addition
3699 the type must be defined in a qmldir file with a singleton keyword and the qmldir must be imported by the QML
3700 files using the singleton.
3701
3702 \sa QML_SINGLETON
3703*/
3704
3705/*!
3706 \fn int qmlRegisterSingletonInstance(const char *uri, int versionMajor, int versionMinor, const char *typeName, QObject *cppObject)
3707 \relates <qqml.h>
3708 \since 5.14
3709
3710 This function is used to register a singleton object \a cppObject, with a
3711 particular \a uri and \a typeName. Its version is a combination of \a
3712 versionMajor and \a versionMinor.
3713
3714 Installing a singleton type into a URI allows you to provide arbitrary
3715 functionality (methods and properties) to QML code without requiring
3716 individual instances of the type to be instantiated by the client.
3717
3718 Use this function to register an object of the given type T as a singleton
3719 type.
3720
3721 A QObject singleton type may be referenced via the type name with which it
3722 was registered; in turn this type name may be used as the target in a \l
3723 Connections type, or like any other type ID. However, there's one
3724 exception: a QObject singleton type property can't be aliased because the
3725 singleton type name does not identify an object within the same component
3726 as any other item.
3727
3728 \note \a cppObject must outlive the QML engine in which it is used.
3729 Moreover, \cppObject must have the same thread affinity as the engine. If
3730 you want separate singleton instances for multiple engines, you need to use
3731 \l {qmlRegisterSingletonType}. See \l{Threads and QObjects} for more
3732 information about thread safety.
3733
3734 \b{NOTE:} qmlRegisterSingleton can only be used when all types of that module are registered procedurally.
3735
3736 Usage:
3737 //! Workaround for MOC not respecting comments and triggering an error on certain Qt macros.
3738 \code Q
3739 // First, define your QObject which provides the functionality.
3740 class SingletonTypeExample : public QObject
3741 {
3742 \1_OBJECT
3743 Q_PROPERTY(int someProperty READ someProperty WRITE setSomeProperty NOTIFY somePropertyChanged)
3744
3745 public:
3746 explicit SingletonTypeExample(QObject* parent = nullptr) : QObject(parent) {}
3747
3748 Q_INVOKABLE int doSomething()
3749 {
3750 setSomeProperty(5);
3751 return m_someProperty;
3752 }
3753
3754 int someProperty() const { return m_someProperty; }
3755 void setSomeProperty(int val) {
3756 if (m_someProperty != val) {
3757 m_someProperty = val;
3758 emit somePropertyChanged(val);
3759 }
3760 }
3761
3762 signals:
3763 void somePropertyChanged(int newValue);
3764
3765 private:
3766 int m_someProperty = 0;
3767 };
3768 \endcode
3769
3770 \code
3771 // Second, create an instance of the object
3772
3773 // allocate example before the engine to ensure that it outlives it
3774 QScopedPointer<SingletonTypeExample> example(new SingletonTypeExample);
3775 QQmlEngine engine;
3776
3777 // Third, register the singleton type provider with QML by calling this
3778 // function in an initialization function.
3779 qmlRegisterSingletonInstance("Qt.example.qobjectSingleton", 1, 0, "MyApi", example.get());
3780 \endcode
3781
3782
3783 In order to use the registered singleton type in QML, you must import the
3784 URI with the corresponding version.
3785 \qml
3786 import QtQuick 2.0
3787 import Qt.example.qobjectSingleton 1.0
3788 Item {
3789 id: root
3790 property int someValue: MyApi.someProperty
3791
3792 Component.onCompleted: {
3793 console.log(MyApi.doSomething())
3794 }
3795 }
3796 \endqml
3797
3798 \sa QML_SINGLETON, qmlRegisterSingletonType
3799 */
3800
3801/*!
3802 \fn int qmlRegisterType(const QUrl &url, const char *uri, int versionMajor, int versionMinor, const char *qmlName);
3803 \relates <qqml.h>
3804
3805 This function registers a type in the QML system with the name \a qmlName, in the library imported from \a uri having the
3806 version number composed from \a versionMajor and \a versionMinor. The type is defined by the QML file located at \a url. The
3807 url must be an absolute URL, i.e. url.isRelative() == false.
3808
3809 Normally QML files can be loaded as types directly from other QML files, or using a qmldir file. This function allows
3810 registration of files to types from C++ code, such as when the type mapping needs to be procedurally determined at startup.
3811
3812 Returns -1 if the registration was not successful.
3813*/
3814
3815QT_END_NAMESPACE
PropertyResult loadFallbackAsVariant(QV4::Lookup *lookup, QObject *object, void *target, const AOTCompiledContext *aotContext)
Definition qqml.cpp:1459
static ObjectLookupResult initObjectLookup(const AOTCompiledContext *aotContext, QV4::Lookup *lookup, QObject *object)
Definition qqml.cpp:1711
void qmlRegisterTypeAndRevisions< QQmlTypeNotAvailable, void >(const char *uri, int versionMajor, const QMetaObject *classInfoMetaObject, QList< int > *qmlTypeIds, const QMetaObject *extension, bool)
Definition qqml.cpp:1117
PropertyResult writeBackObjectAsVariant(QV4::Lookup *lookup, QObject *object, void *source)
Definition qqml.cpp:1448
static PropertyResult writeBackFallbackProperty(QV4::Lookup *lookup, QObject *object, void *source)
Definition qqml.cpp:1423
static PropertyResult changeFallbackProperty(QV4::Lookup *lookup, QObject *object, Op op)
Definition qqml.cpp:1522
static FallbackPropertyQmlData findFallbackPropertyQmlData(QV4::Lookup *lookup, QObject *object)
Definition qqml.cpp:1387
static void throwIsNotAFunctionError(const AOTCompiledContext *aotContext, QV4::Lookup *lookup, const QString &object)
Definition qqml.cpp:2249
static bool markPointer(const QVariant &element, QV4::MarkStack *markStack)
Definition qqml.cpp:1206
PropertyResult loadObjectProperty(QV4::Lookup *lookup, QObject *object, void *target, const AOTCompiledContext *aotContext)
Definition qqml.cpp:1352
static bool isEnumUnderlyingType(QMetaType enumType, QMetaType numberType)
Definition qqml.cpp:1563
static PropertyResult storeFallbackAsVariant(QV4::ExecutionEngine *v4, QV4::Lookup *lookup, QObject *object, void *value)
Definition qqml.cpp:1676
static void iterateVariant(const QVariant &element, std::vector< QVariant > *elements)
Definition qqml.cpp:1216
static PropertyResult changeObjectProperty(QV4::Lookup *lookup, QObject *object, Op op)
Definition qqml.cpp:1485
static PropertyResult storeObjectProperty(QV4::Lookup *lookup, QObject *object, void *value)
Definition qqml.cpp:1514
PropertyResult loadObjectAsVariant(QV4::Lookup *lookup, QObject *object, void *target, const AOTCompiledContext *aotContext)
Definition qqml.cpp:1436
static bool callQObjectMethod(QV4::ExecutionEngine *engine, QV4::Lookup *lookup, QObject *thisObject, void **args, int argc)
Definition qqml.cpp:2166
ObjectPropertyQmlData findObjectPropertyQmlData(QV4::Lookup *lookup, QObject *object)
Definition qqml.cpp:1333
static void captureFallbackProperty(QObject *object, int coreIndex, int notifyIndex, bool isConstant, const AOTCompiledContext *aotContext)
Definition qqml.cpp:1293
static void initValueLookup(QV4::Lookup *lookup, QV4::ExecutableCompilationUnit *compilationUnit, const QMetaObject *metaObject)
Definition qqml.cpp:1803
static bool inherits(const QQmlPropertyCache *descendent, const QQmlPropertyCache *ancestor)
Definition qqml.cpp:1315
static bool canHoldVoid(QMetaType type)
Definition qqml.cpp:1598
static bool tryEnsureMethodsCache(QV4::QObjectMethod *method, QObject *object)
Definition qqml.cpp:2312
static void captureObjectProperty(QObject *object, const QQmlPropertyCache *propertyCache, const QQmlPropertyData *property, const AOTCompiledContext *aotContext)
Definition qqml.cpp:1304
PropertyResult writeBackFallbackAsVariant(QV4::Lookup *lookup, QObject *object, void *source)
Definition qqml.cpp:1472
static PropertyResult storeFallbackProperty(QV4::Lookup *lookup, QObject *object, void *value)
Definition qqml.cpp:1536
static bool isUndefined(const void *value, QMetaType type)
Definition qqml.cpp:1925
static bool callQObjectMethodAsVariant(QV4::ExecutionEngine *engine, QV4::Lookup *lookup, QObject *thisObject, void **args, int argc)
Definition qqml.cpp:2142
static QMetaType jsTypedFunctionArgument(const QQmlType &type, const QV4::CompiledData::ParameterType &parameter)
Definition qqml.cpp:2125
static PropertyResult resetFallbackProperty(QV4::Lookup *lookup, QObject *object, QV4::ExecutionEngine *v4)
Definition qqml.cpp:1545
static PropertyResult loadFallbackProperty(QV4::Lookup *lookup, QObject *object, void *target, const AOTCompiledContext *aotContext)
Definition qqml.cpp:1403
static bool callArrowFunction(QV4::ExecutionEngine *engine, QV4::ArrowFunction *function, QObject *thisObject, void **args, int argc)
Definition qqml.cpp:2204
static PropertyResult resetObjectProperty(QV4::Lookup *lookup, QObject *object, QV4::ExecutionEngine *v4)
Definition qqml.cpp:1499
static PropertyResult storeObjectAsVariant(QV4::ExecutionEngine *v4, QV4::Lookup *lookup, QObject *object, void *value)
Definition qqml.cpp:1644
static bool callQObjectMethodWithTypes(QV4::ExecutionEngine *engine, QV4::Lookup *lookup, QObject *thisObject, void **args, QMetaType *types, int argc)
Definition qqml.cpp:2131
static bool isTypeCompatible(QMetaType source, QMetaType target)
Definition qqml.cpp:1606
PropertyResult writeBackObjectProperty(QV4::Lookup *lookup, QObject *object, void *source)
Definition qqml.cpp:1370
void initObjectLookup(const AOTCompiledContext *aotContext, uint index, QObject *object)
Definition qqml.cpp:1776
static QQmlPropertyCapture * propertyCapture(const AOTCompiledContext *aotContext)
Definition qqml.cpp:1170
static MatchScore resolveQObjectMethodOverload(QV4::QObjectMethod *method, QV4::Lookup *lookup, int relativeMethodIndex)
Definition qqml.cpp:2283
Combined button and popup list for selecting options.
QQmlAttachedPropertiesFunc qmlAttachedPropertiesFunction(QObject *object, const QMetaObject *attachedMetaObject)
Definition qqml.cpp:117
static QList< QTypeRevision > availableRevisions(const QMetaObject *metaObject)
Definition qqml.cpp:582
static void doRegisterSingletonAndRevisions(const QQmlPrivate::RegisterSingletonTypeAndRevisions &type, const ElementNames &elementNames)
Definition qqml.cpp:867
static ElementNames classElementNames(const QMetaObject *metaObject)
Definition qqml.cpp:690
QObject * qmlAttachedPropertiesObject(QObject *object, QQmlAttachedPropertiesFunc func, bool createIfMissing)
Definition qqml.cpp:125
static void uniqueRevisions(QList< QTypeRevision > *revisions, QTypeRevision defaultVersion, QTypeRevision added)
Definition qqml.cpp:630
void assignVersions(Registration *registration, QTypeRevision revision, QTypeRevision defaultVersion)
Definition qqml.cpp:612
static int finalizeType(const QQmlType &dtype)
Definition qqml.cpp:680
QQmlEngine * qmlEngine(const QObject *obj)
Definition qqml.cpp:91
QQmlContext * qmlContext(const QObject *obj)
Definition qqml.cpp:86
static QObject * resolveAttachedProperties(QQmlAttachedPropertiesFunc pf, QQmlData *data, QObject *object, bool create)
Definition qqml.cpp:99
QT_BEGIN_NAMESPACE void qmlExecuteDeferred(QObject *object)
\inmodule QtQml \title Functions to register C++ types to QML
Definition qqml.cpp:60
static QList< QTypeRevision > prepareRevisions(const QMetaObject *metaObject, QTypeRevision added)
Definition qqml.cpp:623
static QQmlDirParser::Import resolveImport(const QString &uri, int importMajor, int importMinor)
Definition qqml.cpp:369
static bool checkSingletonInstance(QQmlEngine *engine, QObject *instance)
Definition qqml.cpp:522
static void doRegisterTypeAndRevisions(const QQmlPrivate::RegisterTypeAndRevisions &type, const ElementNames &elementNames)
Definition qqml.cpp:754
static QTypeRevision resolveModuleVersion(int moduleMajor)
Definition qqml.cpp:380
static QQmlType::SingletonInstanceInfo::ConstPtr singletonInstanceInfo(const QQmlPrivate::RegisterSingletonType &type)
Definition qqml.cpp:659
Q_QML_EXPORT void qmlRegisterModuleImport(const char *uri, int moduleMajor, const char *import, int importMajor=QQmlModuleImportLatest, int importMinor=QQmlModuleImportLatest)
Q_QML_EXPORT bool qmlProtectModule(const char *uri, int majVersion)
Q_QML_EXPORT void qmlUnregisterModuleImport(const char *uri, int moduleMajor, const char *import, int importMajor=QQmlModuleImportLatest, int importMinor=QQmlModuleImportLatest)
Q_QML_EXPORT void qmlRegisterModule(const char *uri, int versionMajor, int versionMinor)
AliasRegistrar(const ElementNames *elementNames)
Definition qqml.cpp:734
void registerAliases(int typeId)
Definition qqml.cpp:736
const QMetaObject * metaObject
Definition qqml.cpp:1383