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 \warning
307 Do not call this function while a QQmlEngine exists or behavior will be undefined.
308 Any existing QQmlEngines must be deleted before calling this function.
309
310 This function only affects the application global cache. Delete the QQmlEngine to clear
311 all cached data relating to that engine.
312*/
313void qmlClearTypeRegistrations() // Declared in qqml.h
314{
315 QQmlMetaType::clearTypeRegistrations();
316 QQmlEnginePrivate::baseModulesUninitialized = true; //So the engine re-registers its types
317 qmlClearEnginePlugins();
318}
319
320/*!
321 \relates <qqml.h>
322
323 This function protects a module from further modification. This can be used
324 to prevent other plugins from injecting types into your module. It can also
325 be a performance improvement, as it allows the engine to skip checking for
326 the possibility of new types or plugins when this import is reached.
327
328 Once qmlProtectModule has been called, a QML engine will not search for a new
329 \c qmldir file to load the module anymore. It will re-use any \c qmldir files
330 it has loaded before, though. Therefore, types present at this point continue
331 to work. Mind that different QML engines may load different modules. The
332 module protection, however, is global and affects all engines. The overhead
333 of locating \c qmldir files and loading plugins may be noticeable with slow file
334 systems. Therefore, protecting a module once you are sure you won't need to
335 load it anymore can be a good optimization. Mind also that the module lock
336 not only affects plugins but also any other qmldir directives, like \c import
337 or \c prefer, as well as any composite types or scripts declared in a \c qmldir
338 file.
339
340 In addition, after this function is called, any attempt to register C++ types
341 into this uri, major version combination will lead to a runtime error.
342
343 Returns true if the module with \a uri as a \l{Identified Modules}
344 {module identifier} and \a majVersion as a major version number was found
345 and locked, otherwise returns false. The module must contain exported types
346 in order to be found.
347*/
348bool qmlProtectModule(const char *uri, int majVersion)
349{
350 return QQmlMetaType::protectModule(QString::fromUtf8(uri),
351 QTypeRevision::fromMajorVersion(majVersion));
352}
353
354/*!
355 \since 5.9
356 \relates <qqml.h>
357
358 This function registers a module in a particular \a uri with a version specified
359 in \a versionMajor and \a versionMinor.
360
361 This can be used to make a certain module version available, even if no types
362 are registered for that version. This is particularly useful for keeping the
363 versions of related modules in sync.
364*/
365
366void qmlRegisterModule(const char *uri, int versionMajor, int versionMinor)
367{
368 QQmlMetaType::registerModule(uri, QTypeRevision::fromVersion(versionMajor, versionMinor));
369}
370
371static QQmlDirParser::Import resolveImport(const QString &uri, int importMajor, int importMinor)
372{
373 if (importMajor == QQmlModuleImportAuto)
374 return QQmlDirParser::Import(uri, QTypeRevision(), QQmlDirParser::Import::Auto);
375 else if (importMajor == QQmlModuleImportLatest)
376 return QQmlDirParser::Import(uri, QTypeRevision(), QQmlDirParser::Import::Default);
377 else if (importMinor == QQmlModuleImportLatest)
378 return QQmlDirParser::Import(uri, QTypeRevision::fromMajorVersion(importMajor), QQmlDirParser::Import::Default);
379 return QQmlDirParser::Import(uri, QTypeRevision::fromVersion(importMajor, importMinor), QQmlDirParser::Import::Default);
380}
381
382static QTypeRevision resolveModuleVersion(int moduleMajor)
383{
384 return moduleMajor == QQmlModuleImportModuleAny
385 ? QTypeRevision()
386 : QTypeRevision::fromMajorVersion(moduleMajor);
387}
388
389/*!
390 * \enum QQmlModuleImportSpecialVersions
391 * \relates <qqml.h>
392 *
393 * Defines some special values that can be passed to the version arguments of
394 * qmlRegisterModuleImport() and qmlUnregisterModuleImport().
395 *
396 * \value QQmlModuleImportModuleAny When passed as majorVersion of the base
397 * module, signifies that the import is to be
398 * applied to any version of the module.
399 * \value QQmlModuleImportLatest When passed as major or minor version of
400 * the imported module, signifies that the
401 * latest overall, or latest minor version
402 * of a specified major version shall be
403 * imported.
404 * \value QQmlModuleImportAuto When passed as major version of the imported
405 * module, signifies that the version of the
406 * base module shall be forwarded.
407 */
408
409/*!
410 * \relates <qqml.h>
411 * Registers a qmldir-import for module \a uri of major version \a moduleMajor.
412 *
413 * This has the same effect as an \c import statement in a qmldir file: Whenever
414 * \a uri of version \a moduleMajor is imported, \a import of version
415 * \a importMajor. \a importMinor is automatically imported, too. If
416 * \a importMajor is \l QQmlModuleImportLatest the latest version
417 * available of that module is imported, and \a importMinor does not matter. If
418 * \a importMinor is \l QQmlModuleImportLatest the latest minor version of a
419 * \a importMajor is chosen. If \a importMajor is \l QQmlModuleImportAuto the
420 * version of \a import is version of \a uri being imported, and \a importMinor
421 * does not matter. If \a moduleMajor is \l QQmlModuleImportModuleAny the module
422 * import is applied for any major version of \a uri. For example, you may
423 * specify that whenever any version of MyModule is imported, the latest version
424 * of MyOtherModule should be imported. Then, the following call would be
425 * appropriate:
426 *
427 * \code
428 * qmlRegisterModuleImport("MyModule", QQmlModuleImportModuleAny,
429 * "MyOtherModule", QQmlModuleImportLatest);
430 * \endcode
431 *
432 * Or, you may specify that whenever major version 5 of "MyModule" is imported,
433 * then version 3.14 of "MyOtherModule" should be imported:
434 *
435 * \code
436 * qmlRegisterModuleImport("MyModule", 5, "MyOtherModule", 3, 14);
437 * \endcode
438 *
439 * Finally, if you always want the same version of "MyOtherModule" to be
440 * imported whenever "MyModule" is imported, specify the following:
441 *
442 * \code
443 * qmlRegisterModuleImport("MyModule", QQmlModuleImportModuleAny,
444 * "MyOtherModule", QQmlModuleImportAuto);
445 * \endcode
446 *
447 * \sa qmlUnregisterModuleImport()
448 */
449void qmlRegisterModuleImport(const char *uri, int moduleMajor,
450 const char *import, int importMajor, int importMinor)
451{
452 QQmlMetaType::registerModuleImport(
453 QString::fromUtf8(uri), resolveModuleVersion(moduleMajor),
454 resolveImport(QString::fromUtf8(import), importMajor, importMinor));
455}
456
457
458/*!
459 * \relates <qqml.h>
460 * Removes a module import previously registered with qmlRegisterModuleImport()
461 *
462 * Calling this function makes sure that \a import of version
463 * \a{importMajor}.\a{importMinor} is not automatically imported anymore when
464 * \a uri of version \a moduleMajor is. The version resolution works the same
465 * way as with \l qmlRegisterModuleImport().
466 *
467 * \sa qmlRegisterModuleImport()
468 */
469void qmlUnregisterModuleImport(const char *uri, int moduleMajor,
470 const char *import, int importMajor, int importMinor)
471{
472 QQmlMetaType::unregisterModuleImport(
473 QString::fromUtf8(uri), resolveModuleVersion(moduleMajor),
474 resolveImport(QString::fromUtf8(import), importMajor, importMinor));
475}
476
477/*!
478 \since 5.12
479 \relates <qqml.h>
480
481 Returns the QML type id of a type that was registered with the
482 name \a qmlName in a particular \a uri and a version specified in \a
483 versionMajor and \a versionMinor.
484
485 This function returns the same value as the QML type registration functions
486 such as qmlRegisterType() and qmlRegisterSingletonType().
487
488 If \a qmlName, \a uri and \a versionMajor match a registered type, but the
489 specified minor version in \a versionMinor is higher, then the id of the type
490 with the closest minor version is returned.
491
492 Returns -1 if no matching type was found or one of the given parameters
493 was invalid.
494
495 \note: qmlTypeId tries to make modules available, even if they were not accessed by any
496 engine yet. This can introduce overhead the first time a module is accessed. Trying to
497 find types from a module which does not exist always introduces this overhead.
498
499 \sa QML_ELEMENT, QML_NAMED_ELEMENT, QML_SINGLETON, qmlRegisterType(), qmlRegisterSingletonType()
500*/
501int qmlTypeId(const char *uri, int versionMajor, int versionMinor, const char *qmlName)
502{
503 auto revision = QTypeRevision::fromVersion(versionMajor, versionMinor);
504 int id = QQmlMetaType::typeId(uri, revision, qmlName);
505 if (id != -1)
506 return id;
507 /* If the module hasn't been imported yet, we might not have the id of a
508 singleton at this point. To obtain it, we need an engine in order to
509 to do the resolution steps.
510 This is expensive, but we assume that users don't constantly query invalid
511 Types; internal code should use QQmlMetaType API.
512 */
513 QQmlEngine engine;
514 QQmlTypeLoader *typeLoader = QQmlTypeLoader::get(&engine);
515 auto loadHelper = QQml::makeRefPointer<LoadHelper>(
516 typeLoader, uri, qmlName, QQmlTypeLoader::Synchronous);
517 const QQmlType type = loadHelper->type();
518 if (type.availableInVersion(revision))
519 return type.index();
520 else
521 return -1;
522}
523
524static bool checkSingletonInstance(QQmlEngine *engine, QObject *instance)
525{
526 if (!instance) {
527 QQmlError error;
528 error.setDescription(QStringLiteral("The registered singleton has already been deleted. "
529 "Ensure that it outlives the engine."));
530 QQmlEnginePrivate::get(engine)->warning(engine, error);
531 return false;
532 }
533
534 if (engine->thread() != instance->thread()) {
535 QQmlError error;
536 error.setDescription(QStringLiteral("Registered object must live in the same thread "
537 "as the engine it was registered with"));
538 QQmlEnginePrivate::get(engine)->warning(engine, error);
539 return false;
540 }
541
542 return true;
543}
544
545// From qqmlprivate.h
546#if QT_DEPRECATED_SINCE(6, 3)
547QObject *QQmlPrivate::SingletonFunctor::operator()(QQmlEngine *qeng, QJSEngine *)
548{
549 if (!checkSingletonInstance(qeng, m_object))
550 return nullptr;
551
552 if (alreadyCalled) {
553 QQmlError error;
554 error.setDescription(QStringLiteral("Singleton registered by registerSingletonInstance "
555 "must only be accessed from one engine"));
556 QQmlEnginePrivate::get(qeng)->warning(qeng, error);
557 return nullptr;
558 }
559
560 alreadyCalled = true;
561 QJSEngine::setObjectOwnership(m_object, QQmlEngine::CppOwnership);
562 return m_object;
563};
564#endif
565
566QObject *QQmlPrivate::SingletonInstanceFunctor::operator()(QQmlEngine *qeng, QJSEngine *)
567{
568 if (!checkSingletonInstance(qeng, m_object))
569 return nullptr;
570
571 if (!m_engine) {
572 m_engine = qeng;
573 QJSEngine::setObjectOwnership(m_object, QQmlEngine::CppOwnership);
574 } else if (m_engine != qeng) {
575 QQmlError error;
576 error.setDescription(QLatin1String("Singleton registered by registerSingletonInstance must only be accessed from one engine"));
577 QQmlEnginePrivate::get(qeng)->warning(qeng, error);
578 return nullptr;
579 }
580
581 return m_object;
582};
583
584static QList<QTypeRevision> availableRevisions(const QMetaObject *metaObject)
585{
586 QList<QTypeRevision> revisions;
587 if (!metaObject)
588 return revisions;
589 const int propertyOffset = metaObject->propertyOffset();
590 const int propertyCount = metaObject->propertyCount();
591 for (int coreIndex = propertyOffset, propertyEnd = propertyOffset + propertyCount;
592 coreIndex < propertyEnd; ++coreIndex) {
593 const QMetaProperty property = metaObject->property(coreIndex);
594 if (int revision = property.revision())
595 revisions.append(QTypeRevision::fromEncodedVersion(revision));
596 }
597 const int methodOffset = metaObject->methodOffset();
598 const int methodCount = metaObject->methodCount();
599 for (int methodIndex = methodOffset, methodEnd = methodOffset + methodCount;
600 methodIndex < methodEnd; ++methodIndex) {
601 const QMetaMethod method = metaObject->method(methodIndex);
602 if (int revision = method.revision())
603 revisions.append(QTypeRevision::fromEncodedVersion(revision));
604 }
605
606 // Need to also check parent meta objects, as their revisions are inherited.
607 if (const QMetaObject *superMeta = metaObject->superClass())
608 revisions += availableRevisions(superMeta);
609
610 return revisions;
611}
612
613template<typename Registration>
614void assignVersions(Registration *registration, QTypeRevision revision,
615 QTypeRevision defaultVersion)
616{
617 const quint8 majorVersion = revision.hasMajorVersion() ? revision.majorVersion()
618 : defaultVersion.majorVersion();
619 registration->version = revision.hasMinorVersion()
620 ? QTypeRevision::fromVersion(majorVersion, revision.minorVersion())
621 : QTypeRevision::fromMajorVersion(majorVersion);
622 registration->revision = revision;
623}
624
625static QList<QTypeRevision> prepareRevisions(const QMetaObject *metaObject, QTypeRevision added)
626{
627 auto revisions = availableRevisions(metaObject);
628 revisions.append(added);
629 return revisions;
630}
631
632static void uniqueRevisions(QList<QTypeRevision> *revisions, QTypeRevision defaultVersion,
633 QTypeRevision added)
634{
635 bool revisionsHaveMajorVersions = false;
636
637 // copy because we modify revisions in the loop
638 const QList<QTypeRevision> origRevisions = *revisions;
639 for (QTypeRevision revision : origRevisions) {
640 // allow any minor version for each explicitly specified past major one
641 if (revision.hasMajorVersion()) {
642 revisionsHaveMajorVersions = true;
643 if (revision.majorVersion() < defaultVersion.majorVersion())
644 revisions->append(QTypeRevision::fromVersion(revision.majorVersion(), 254));
645 }
646 }
647
648 if (revisionsHaveMajorVersions) {
649 if (!added.hasMajorVersion()) {
650 // If added in unspecified major version, assume default one.
651 revisions->append(QTypeRevision::fromVersion(defaultVersion.majorVersion(),
652 added.minorVersion()));
653 } else if (added.majorVersion() < defaultVersion.majorVersion()) {
654 // If added in past major version, add .0 of default version.
655 revisions->append(QTypeRevision::fromVersion(defaultVersion.majorVersion(), 0));
656 }
657 }
658
659 std::sort(revisions->begin(), revisions->end());
660 const auto it = std::unique(revisions->begin(), revisions->end());
661 revisions->erase(it, revisions->end());
662}
663
665 const QQmlPrivate::RegisterSingletonType &type)
666{
667 QQmlType::SingletonInstanceInfo::Ptr siinfo = QQmlType::SingletonInstanceInfo::create();
668 siinfo->scriptCallback = type.scriptApi;
669 siinfo->qobjectCallback = type.qObjectApi;
670 siinfo->typeName = type.typeName;
671 return QQmlType::SingletonInstanceInfo::ConstPtr(
672 siinfo.take(), QQmlType::SingletonInstanceInfo::ConstPtr::Adopt);
673}
674
676 const QQmlPrivate::RegisterCompositeSingletonType &type)
677{
678 QQmlType::SingletonInstanceInfo::Ptr siinfo = QQmlType::SingletonInstanceInfo::create();
679 siinfo->url = QQmlMetaType::normalizedUrl(type.url);
680 siinfo->typeName = type.typeName;
681 return QQmlType::SingletonInstanceInfo::ConstPtr(
682 siinfo.take(), QQmlType::SingletonInstanceInfo::ConstPtr::Adopt);
683}
684
685static int finalizeType(const QQmlType &dtype)
686{
687 if (!dtype.isValid())
688 return -1;
689
690 QQmlMetaType::registerUndeletableType(dtype);
691 return dtype.index();
692}
693
694using ElementNames = QVarLengthArray<const char *, 8>;
695static ElementNames classElementNames(const QMetaObject *metaObject)
696{
697 Q_ASSERT(metaObject);
698 const char *key = "QML.Element";
699
700 const int offset = metaObject->classInfoOffset();
701 const int start = metaObject->classInfoCount() + offset - 1;
702
703 ElementNames elementNames;
704
705 for (int i = start; i >= offset; --i) {
706 const QMetaClassInfo classInfo = metaObject->classInfo(i);
707 if (qstrcmp(key, classInfo.name()) == 0) {
708 const char *elementName = classInfo.value();
709
710 if (qstrcmp(elementName, "auto") == 0) {
711 const char *strippedClassName = metaObject->className();
712 for (const char *c = strippedClassName; *c != '\0'; c++) {
713 if (*c == ':')
714 strippedClassName = c + 1;
715 }
716 elementName = strippedClassName;
717 } else if (qstrcmp(elementName, "anonymous") == 0) {
718 if (elementNames.isEmpty())
719 elementNames.push_back(nullptr);
720 else if (elementNames[0] != nullptr)
721 qWarning() << metaObject->className() << "is both anonymous and named";
722 continue;
723 }
724
725 if (!elementNames.isEmpty() && elementNames[0] == nullptr) {
726 qWarning() << metaObject->className() << "is both anonymous and named";
727 elementNames[0] = elementName;
728 } else {
729 elementNames.push_back(elementName);
730 }
731 }
732 }
733
734 return elementNames;
735}
736
738{
739 AliasRegistrar(const ElementNames *elementNames) : elementNames(elementNames) {}
740
741 void registerAliases(int typeId)
742 {
743 if (elementNames) {
744 for (int i = 1, end = elementNames->length(); i < end; ++i)
745 otherNames.append(QString::fromUtf8(elementNames->at(i)));
746 elementNames = nullptr;
747 }
748
749 for (const QString &otherName : std::as_const(otherNames))
750 QQmlMetaType::registerTypeAlias(typeId, otherName);
751 }
752
753private:
754 const ElementNames *elementNames;
755 QVarLengthArray<QString, 8> otherNames;
756};
757
758
760 const QQmlPrivate::RegisterTypeAndRevisions &type,
761 const ElementNames &elementNames)
762{
763 using namespace QQmlPrivate;
764
765 const bool isValueType = !(type.typeId.flags() & QMetaType::PointerToQObject);
766 const bool creatable = (elementNames[0] != nullptr || isValueType)
767 && boolClassInfo(type.classInfoMetaObject, "QML.Creatable", true);
768
769 QString noCreateReason;
770 ValueTypeCreationMethod creationMethod = ValueTypeCreationMethod::None;
771
772 if (!creatable) {
773 noCreateReason = QString::fromUtf8(
774 classInfo(type.classInfoMetaObject, "QML.UncreatableReason"));
775 if (noCreateReason.isEmpty())
776 noCreateReason = QLatin1String("Type cannot be created in QML.");
777 } else if (isValueType) {
778 const char *method = classInfo(type.classInfoMetaObject, "QML.CreationMethod");
779 if (qstrcmp(method, "structured") == 0)
780 creationMethod = ValueTypeCreationMethod::Structured;
781 else if (qstrcmp(method, "construct") == 0)
782 creationMethod = ValueTypeCreationMethod::Construct;
783 }
784
785 RegisterType typeRevision = {
786 QQmlPrivate::RegisterType::CurrentVersion,
787 type.typeId,
788 type.listId,
789 creatable ? type.objectSize : 0,
790 nullptr,
791 nullptr,
792 noCreateReason,
793 type.createValueType,
794 type.uri,
795 type.version,
796 nullptr,
797 type.metaObject,
798 type.attachedPropertiesFunction,
799 type.attachedPropertiesMetaObject,
800 type.parserStatusCast,
801 type.valueSourceCast,
802 type.valueInterceptorCast,
803 type.extensionObjectCreate,
804 type.extensionMetaObject,
805 nullptr,
806 QTypeRevision(),
807 type.structVersion > 0 ? type.finalizerCast : -1,
808 creationMethod
809 };
810
811 QQmlPrivate::RegisterSequentialContainer sequenceRevision = {
812 0,
813 type.uri,
814 type.version,
815 nullptr,
816 type.listId,
817 type.structVersion > 1 ? type.listMetaSequence : QMetaSequence(),
818 QTypeRevision(),
819 };
820
821 const QTypeRevision added = revisionClassInfo(
822 type.classInfoMetaObject, "QML.AddedInVersion",
823 QTypeRevision::fromVersion(type.version.majorVersion(), 0));
824 const QTypeRevision removed = revisionClassInfo(
825 type.classInfoMetaObject, "QML.RemovedInVersion");
826 const QList<QTypeRevision> furtherRevisions = revisionClassInfos(type.classInfoMetaObject,
827 "QML.ExtraVersion");
828
829 auto revisions = prepareRevisions(type.metaObject, added) + furtherRevisions;
830 if (type.attachedPropertiesMetaObject)
831 revisions += availableRevisions(type.attachedPropertiesMetaObject);
832 uniqueRevisions(&revisions, type.version, added);
833
834 AliasRegistrar aliasRegistrar(&elementNames);
835 for (QTypeRevision revision : std::as_const(revisions)) {
836 if (revision.hasMajorVersion() && revision.majorVersion() > type.version.majorVersion())
837 break;
838
839 assignVersions(&typeRevision, revision, type.version);
840
841 // When removed or before added, we still add revisions, but anonymous ones
842 if (typeRevision.version < added
843 || (removed.isValid() && !(typeRevision.version < removed))) {
844 typeRevision.elementName = nullptr;
845 typeRevision.create = nullptr;
846 typeRevision.userdata = nullptr;
847 } else {
848 typeRevision.elementName = elementNames[0];
849 typeRevision.create = creatable ? type.create : nullptr;
850 typeRevision.userdata = type.userdata;
851 }
852
853 typeRevision.customParser = type.customParserFactory();
854 const int id = qmlregister(TypeRegistration, &typeRevision);
855 if (type.qmlTypeIds)
856 type.qmlTypeIds->append(id);
857
858 if (typeRevision.elementName)
859 aliasRegistrar.registerAliases(id);
860
861 if (sequenceRevision.metaSequence != QMetaSequence()) {
862 sequenceRevision.version = typeRevision.version;
863 sequenceRevision.revision = typeRevision.revision;
864 const int id = QQmlPrivate::qmlregister(
865 QQmlPrivate::SequentialContainerRegistration, &sequenceRevision);
866 if (type.qmlTypeIds)
867 type.qmlTypeIds->append(id);
868 }
869 }
870}
871
873 const QQmlPrivate::RegisterSingletonTypeAndRevisions &type,
874 const ElementNames &elementNames)
875{
876 using namespace QQmlPrivate;
877
878 RegisterSingletonType revisionRegistration = {
879 0,
880 type.uri,
881 type.version,
882 elementNames[0],
883 nullptr,
884 type.qObjectApi,
885 type.instanceMetaObject,
886 type.typeId,
887 type.extensionObjectCreate,
888 type.extensionMetaObject,
889 QTypeRevision()
890 };
891 const QQmlType::SingletonInstanceInfo::ConstPtr siinfo
892 = singletonInstanceInfo(revisionRegistration);
893
894 const QTypeRevision added = revisionClassInfo(
895 type.classInfoMetaObject, "QML.AddedInVersion",
896 QTypeRevision::fromVersion(type.version.majorVersion(), 0));
897 const QTypeRevision removed = revisionClassInfo(
898 type.classInfoMetaObject, "QML.RemovedInVersion");
899 const QList<QTypeRevision> furtherRevisions = revisionClassInfos(type.classInfoMetaObject,
900 "QML.ExtraVersion");
901
902 auto revisions = prepareRevisions(type.instanceMetaObject, added) + furtherRevisions;
903 uniqueRevisions(&revisions, type.version, added);
904
905 AliasRegistrar aliasRegistrar(&elementNames);
906 for (QTypeRevision revision : std::as_const(revisions)) {
907 if (revision.hasMajorVersion() && revision.majorVersion() > type.version.majorVersion())
908 break;
909
910 assignVersions(&revisionRegistration, revision, type.version);
911
912 // When removed or before added, we still add revisions, but anonymous ones
913 if (revisionRegistration.version < added
914 || (removed.isValid() && !(revisionRegistration.version < removed))) {
915 revisionRegistration.typeName = nullptr;
916 revisionRegistration.qObjectApi = nullptr;
917 } else {
918 revisionRegistration.typeName = elementNames[0];
919 revisionRegistration.qObjectApi = type.qObjectApi;
920 }
921
922 const int id = finalizeType(
923 QQmlMetaType::registerSingletonType(revisionRegistration, siinfo));
924 if (type.qmlTypeIds)
925 type.qmlTypeIds->append(id);
926
927 if (revisionRegistration.typeName)
928 aliasRegistrar.registerAliases(id);
929 }
930}
931
932/*
933This method is "over generalized" to allow us to (potentially) register more types of things in
934the future without adding exported symbols.
935*/
936int QQmlPrivate::qmlregister(RegistrationType type, void *data)
937{
938 switch (type) {
939 case AutoParentRegistration:
940 return QQmlMetaType::registerAutoParentFunction(
941 *reinterpret_cast<RegisterAutoParent *>(data));
942 case QmlUnitCacheHookRegistration:
943 return QQmlMetaType::registerUnitCacheHook(
944 *reinterpret_cast<RegisterQmlUnitCacheHook *>(data));
945 case TypeAndRevisionsRegistration: {
946 const RegisterTypeAndRevisions &type = *reinterpret_cast<RegisterTypeAndRevisions *>(data);
947 if (type.structVersion > 1 && type.forceAnonymous) {
948 doRegisterTypeAndRevisions(type, {nullptr});
949 } else {
950 const ElementNames names = classElementNames(type.classInfoMetaObject);
951 if (names.isEmpty()) {
952 qWarning().nospace() << "Missing QML.Element class info for "
953 << type.classInfoMetaObject->className();
954 } else {
955 doRegisterTypeAndRevisions(type, names);
956 }
957
958 }
959 break;
960 }
961 case SingletonAndRevisionsRegistration: {
962 const RegisterSingletonTypeAndRevisions &type
963 = *reinterpret_cast<RegisterSingletonTypeAndRevisions *>(data);
964 const ElementNames names = classElementNames(type.classInfoMetaObject);
965 if (names.isEmpty()) {
966 qWarning().nospace() << "Missing QML.Element class info for "
967 << type.classInfoMetaObject->className();
968 } else {
969 doRegisterSingletonAndRevisions(type, names);
970 }
971 break;
972 }
973 case SequentialContainerAndRevisionsRegistration: {
974 const RegisterSequentialContainerAndRevisions &type
975 = *reinterpret_cast<RegisterSequentialContainerAndRevisions *>(data);
976 RegisterSequentialContainer revisionRegistration = {
977 0,
978 type.uri,
979 type.version,
980 nullptr,
981 type.typeId,
982 type.metaSequence,
983 QTypeRevision()
984 };
985
986 const QTypeRevision added = revisionClassInfo(
987 type.classInfoMetaObject, "QML.AddedInVersion",
988 QTypeRevision::fromMinorVersion(0));
989 QList<QTypeRevision> revisions = revisionClassInfos(
990 type.classInfoMetaObject, "QML.ExtraVersion");
991 revisions.append(added);
992 uniqueRevisions(&revisions, type.version, added);
993
994 for (QTypeRevision revision : std::as_const(revisions)) {
995 if (revision < added)
996 continue;
997 if (revision.hasMajorVersion() && revision.majorVersion() > type.version.majorVersion())
998 break;
999
1000 assignVersions(&revisionRegistration, revision, type.version);
1001 const int id = qmlregister(SequentialContainerRegistration, &revisionRegistration);
1002 if (type.qmlTypeIds)
1003 type.qmlTypeIds->append(id);
1004 }
1005 break;
1006 }
1007 case TypeRegistration:
1008 return finalizeType(
1009 QQmlMetaType::registerType(*reinterpret_cast<RegisterType *>(data)));
1010 case InterfaceRegistration:
1011 return finalizeType(
1012 QQmlMetaType::registerInterface(*reinterpret_cast<RegisterInterface *>(data)));
1013 case SingletonRegistration:
1014 return finalizeType(QQmlMetaType::registerSingletonType(
1015 *reinterpret_cast<RegisterSingletonType *>(data),
1016 singletonInstanceInfo(*reinterpret_cast<RegisterSingletonType *>(data))));
1017 case CompositeRegistration:
1018 return finalizeType(QQmlMetaType::registerCompositeType(
1019 *reinterpret_cast<RegisterCompositeType *>(data)));
1020 case CompositeSingletonRegistration:
1021 return finalizeType(QQmlMetaType::registerCompositeSingletonType(
1022 *reinterpret_cast<RegisterCompositeSingletonType *>(data),
1023 singletonInstanceInfo(*reinterpret_cast<RegisterCompositeSingletonType *>(data))));
1024 case SequentialContainerRegistration:
1025 return finalizeType(QQmlMetaType::registerSequentialContainer(
1026 *reinterpret_cast<RegisterSequentialContainer *>(data)));
1027 default:
1028 return -1;
1029 }
1030
1031 return -1;
1032}
1033
1034void QQmlPrivate::qmlunregister(RegistrationType type, quintptr data)
1035{
1036 switch (type) {
1037 case AutoParentRegistration:
1038 QQmlMetaType::unregisterAutoParentFunction(reinterpret_cast<AutoParentFunction>(data));
1039 break;
1040 case QmlUnitCacheHookRegistration:
1041 QQmlMetaType::removeCachedUnitLookupFunction(
1042 reinterpret_cast<QmlUnitCacheLookupFunction>(data));
1043 break;
1044 case SequentialContainerRegistration:
1045 QQmlMetaType::unregisterSequentialContainer(data);
1046 break;
1047 case TypeRegistration:
1048 case InterfaceRegistration:
1049 case SingletonRegistration:
1050 case CompositeRegistration:
1051 case CompositeSingletonRegistration:
1052 QQmlMetaType::unregisterType(data);
1053 break;
1054 case TypeAndRevisionsRegistration:
1055 case SingletonAndRevisionsRegistration:
1056 case SequentialContainerAndRevisionsRegistration:
1057 // Currently unnecessary. We'd need a special data structure to hold
1058 // URI + majorVersion and then we'd iterate the minor versions, look up the
1059 // associated QQmlType objects by uri/elementName/major/minor and qmlunregister
1060 // each of them.
1061 Q_UNREACHABLE();
1062 break;
1063 }
1064}
1065
1066QList<QTypeRevision> QQmlPrivate::revisionClassInfos(const QMetaObject *metaObject,
1067 const char *key)
1068{
1069 QList<QTypeRevision> revisions;
1070 for (int index = indexOfOwnClassInfo(metaObject, key); index != -1;
1071 index = indexOfOwnClassInfo(metaObject, key, index - 1)) {
1072 revisions.push_back(QTypeRevision::fromEncodedVersion(
1073 QLatin1StringView(metaObject->classInfo(index).value()).toInt()));
1074 }
1075 return revisions;
1076}
1077
1078/*!
1079 \relates <qqml.h>
1080
1081 This function registers a type in the QML system with the name \a qmlName, in the type namespace imported from \a uri having the
1082 version number composed from \a versionMajor and \a versionMinor, but any attempt to instantiate the type
1083 will produce the given error \a message.
1084
1085 Normally, the types exported by a plugin should be fixed. However, if a C++ type is not available, you should
1086 at least "reserve" the QML type name, and give the user of the unavailable type a meaningful error message.
1087
1088 Returns the QML type id.
1089
1090 Example:
1091
1092 \code
1093 #ifdef NO_GAMES_ALLOWED
1094 qmlRegisterTypeNotAvailable("MinehuntCore", 0, 1, "Game", "Get back to work, slacker!");
1095 #else
1096 qmlRegisterType<MinehuntGame>("MinehuntCore", 0, 1, "Game");
1097 #endif
1098 \endcode
1099
1100 This will cause any QML which imports the "MinehuntCore" type namespace and attempts to use the type to produce an error message:
1101 \code
1102 fun.qml: Get back to work, slacker!
1103 Game {
1104 ^
1105 \endcode
1106
1107 Without this, a generic "Game is not a type" message would be given.
1108
1109 \sa QML_UNAVAILABLE, qmlRegisterUncreatableType(),
1110 {Choosing the Correct Integration Method Between C++ and QML}
1111*/
1112int qmlRegisterTypeNotAvailable(
1113 const char *uri, int versionMajor, int versionMinor,
1114 const char *qmlName, const QString &message)
1115{
1116 return qmlRegisterUncreatableType<QQmlTypeNotAvailable>(
1117 uri, versionMajor, versionMinor, qmlName, message);
1118}
1119
1120namespace QQmlPrivate {
1121template<>
1123 const char *uri, int versionMajor, const QMetaObject *classInfoMetaObject,
1124 QList<int> *qmlTypeIds, const QMetaObject *extension, bool)
1125{
1126 using T = QQmlTypeNotAvailable;
1127
1128 RegisterTypeAndRevisions type = {
1129 3,
1130 QmlMetaType<T>::self(),
1131 QmlMetaType<T>::list(),
1132 0,
1133 nullptr,
1134 nullptr,
1135 nullptr,
1136
1137 uri,
1138 QTypeRevision::fromMajorVersion(versionMajor),
1139
1140 &QQmlTypeNotAvailable::staticMetaObject,
1141 classInfoMetaObject,
1142
1143 attachedPropertiesFunc<T>(),
1144 attachedPropertiesMetaObject<T>(),
1145
1146 StaticCastSelector<T, QQmlParserStatus>::cast(),
1147 StaticCastSelector<T, QQmlPropertyValueSource>::cast(),
1148 StaticCastSelector<T, QQmlPropertyValueInterceptor>::cast(),
1149
1150 nullptr,
1151 extension,
1152 qmlCreateCustomParser<T>,
1153 qmlTypeIds,
1154 QQmlPrivate::StaticCastSelector<T, QQmlFinalizerHook>::cast(),
1155 false,
1156 QmlMetaType<T>::sequence(),
1157 };
1158
1159 qmlregister(TypeAndRevisionsRegistration, &type);
1160}
1161
1163
1165{
1166 return static_cast<QV4::MetaTypesStackFrame *>(engine->handle()->currentStackFrame)
1167 ->thisObject();
1168}
1169
1171{
1172 return engine->handle()->qmlEngine();
1173}
1174
1175static QQmlPropertyCapture *propertyCapture(const AOTCompiledContext *aotContext)
1176{
1177 QQmlEngine *engine = aotContext->qmlEngine();
1178 return engine ? QQmlEnginePrivate::get(aotContext->qmlEngine())->propertyCapture : nullptr;
1179}
1180
1186
1192
1197
1199{
1200 if (auto *frame = engine->handle()->currentStackFrame) {
1203 }
1204}
1205
1210
1211static bool markPointer(const QVariant &element, QV4::MarkStack *markStack)
1212{
1213 if (!element.metaType().flags().testFlag(QMetaType::PointerToQObject))
1214 return false;
1215
1216 QV4::QObjectWrapper::markWrapper(
1217 *static_cast<QObject *const *>(element.constData()), markStack);
1218 return true;
1219}
1220
1221static void iterateVariant(const QVariant &element, std::vector<QVariant> *elements)
1222{
1223#define ADD_CASE(Type, id, T)
1224 case QMetaType::Type:
1225
1226 const QMetaType elementMetaType = element.metaType();
1227 switch (elementMetaType.id()) {
1228 case QMetaType::QVariantMap:
1229 for (const QVariant &variant : *static_cast<const QVariantMap *>(element.constData()))
1230 elements->push_back(variant);
1231 return;
1232 case QMetaType::QVariantHash:
1233 for (const QVariant &variant : *static_cast<const QVariantHash *>(element.constData()))
1234 elements->push_back(variant);
1235 return;
1236 case QMetaType::QVariantList:
1237 for (const QVariant &variant : *static_cast<const QVariantList *>(element.constData()))
1238 elements->push_back(variant);
1239 return;
1240 QT_FOR_EACH_STATIC_PRIMITIVE_TYPE(ADD_CASE)
1241 QT_FOR_EACH_STATIC_CORE_CLASS(ADD_CASE)
1242 QT_FOR_EACH_STATIC_GUI_CLASS(ADD_CASE)
1243 case QMetaType::QStringList:
1244 case QMetaType::QByteArrayList:
1245 return;
1246 default:
1247 break;
1248 }
1249
1250 if (elementMetaType == QMetaType::fromType<QJSValue>()
1251 || elementMetaType == QMetaType::fromType<QJSManagedValue>()
1252 || elementMetaType == QMetaType::fromType<QJSPrimitiveValue>()) {
1253 // QJSValue and QJSManagedValue effectively hold persistent values anyway.
1254 // QJSPrimitiveValue can only hold primitives or QString.
1255 return;
1256 }
1257
1258 QMetaSequence::Iterable iterable;
1259 if (!QMetaType::convert(
1260 element.metaType(), element.constData(),
1261 QMetaType::fromType<QMetaSequence::Iterable>(), &iterable)) {
1262 return;
1263 }
1264
1265 switch (iterable.metaContainer().valueMetaType().id()) {
1266 QT_FOR_EACH_STATIC_PRIMITIVE_TYPE(ADD_CASE)
1267 QT_FOR_EACH_STATIC_CORE_CLASS(ADD_CASE)
1268 QT_FOR_EACH_STATIC_GUI_CLASS(ADD_CASE)
1269 case QMetaType::QStringList:
1270 case QMetaType::QByteArrayList:
1271 return;
1272 default:
1273 break;
1274 }
1275
1276 for (auto it = iterable.constBegin(), end = iterable.constEnd(); it != end; ++it)
1277 elements->push_back(*it);
1278
1279#undef ADD_CASE
1280}
1281
1283{
1285 return;
1286
1289
1290 while (!stack.empty()) {
1291 const QVariant element = std::as_const(stack).back();
1292 stack.pop_back();
1295 }
1296}
1297
1308
1319
1320static bool inherits(const QQmlPropertyCache *descendent, const QQmlPropertyCache *ancestor)
1321{
1322 for (const QQmlPropertyCache *cache = descendent; cache; cache = cache->parent().data()) {
1323 if (cache == ancestor)
1324 return true;
1325 }
1326 return false;
1327}
1328
1330
1336
1337template<bool StrictType>
1355
1356template<bool StrictType = false>
1373
1374template<bool StrictType = false>
1384
1391
1393{
1394 // We've just initialized the lookup. So everything must be fine here.
1395
1397
1400
1401 const QMetaObject *metaObject
1402 = reinterpret_cast<const QMetaObject *>(lookup->qobjectFallbackLookup.metaObject - 1);
1404
1405 return {qmlData, metaObject, PropertyResult::OK};
1406}
1407
1427
1440
1452
1463
1476
1488
1489template<bool StrictType, typename Op>
1502
1503template<bool StrictType = false>
1506{
1508 if (property->isResettable()) {
1510 } else {
1511 v4->throwError(
1512 QLatin1String("Cannot assign [undefined] to ") +
1514 }
1515 });
1516}
1517
1518template<bool StrictType = false>
1525
1526template<typename Op>
1540
1542{
1544 lookup, object, [&](const QMetaObject *metaObject, int coreIndex) {
1545 void *args[] = { value, nullptr };
1547 });
1548}
1549
1552{
1554 lookup, object, [&](const QMetaObject *metaObject, int coreIndex) {
1556 void *args[] = { nullptr };
1558 } else {
1559 const QMetaType propType(reinterpret_cast<const QtPrivate::QMetaTypeInterface *>(
1561 v4->throwError(
1562 QLatin1String("Cannot assign [undefined] to ") +
1564 }
1565 });
1566}
1567
1568static bool isEnumUnderlyingType(QMetaType enumType, QMetaType numberType)
1569{
1570 // You can pass the underlying type of an enum.
1571 // We don't want to check for the actual underlying type because
1572 // moc and qmltyperegistrar are not very precise about it. Especially
1573 // the long and longlong types can be ambiguous.
1574
1575 const bool isUnsigned = enumType.flags() & QMetaType::IsUnsignedEnumeration;
1576 switch (enumType.sizeOf()) {
1577 case 1:
1578 return isUnsigned
1579 ? numberType == QMetaType::fromType<quint8>()
1580 : numberType == QMetaType::fromType<qint8>();
1581 case 2:
1582 return isUnsigned
1583 ? numberType == QMetaType::fromType<ushort>()
1584 : numberType == QMetaType::fromType<short>();
1585 case 4:
1586 // The default type, if moc doesn't know the actual enum type, is int.
1587 // However, the compiler can still decide to encode the enum in uint.
1588 // Therefore, we also accept int for uint enums.
1589 // TODO: This is technically UB.
1590 return isUnsigned
1591 ? (numberType == QMetaType::fromType<int>()
1592 || numberType == QMetaType::fromType<uint>())
1593 : numberType == QMetaType::fromType<int>();
1594 case 8:
1595 return isUnsigned
1596 ? numberType == QMetaType::fromType<qulonglong>()
1597 : numberType == QMetaType::fromType<qlonglong>();
1598 }
1599
1600 return false;
1601}
1602
1603static bool canHoldVoid(QMetaType type)
1604{
1605 // We cannot directly store void, but we can put it into QVariant or QJSPrimitiveValue
1606 return !type.isValid()
1607 || type == QMetaType::fromType<QVariant>()
1608 || type == QMetaType::fromType<QJSPrimitiveValue>();
1609}
1610
1611static bool isTypeCompatible(QMetaType source, QMetaType target)
1612{
1613 if (source == target)
1614 return true;
1615
1616 if ((source.flags() & QMetaType::IsQmlList)
1617 && (target.flags() & QMetaType::IsQmlList)) {
1618 // We want to check the value types here, but we cannot easily do it.
1619 // Internally those are all QObject* lists, though.
1620 return true;
1621 }
1622
1623 if (target.flags() & QMetaType::PointerToQObject) {
1624 // We accept any derived class, too
1625
1626 const QMetaObject *targetMetaObject = target.metaObject();
1627 const QMetaObject *sourceMetaObject = source.metaObject();
1628 if (!sourceMetaObject)
1629 sourceMetaObject = QQmlMetaType::metaObjectForType(source).metaObject();
1630
1631 while (sourceMetaObject && sourceMetaObject != targetMetaObject)
1632 sourceMetaObject = sourceMetaObject->superClass();
1633
1634 return sourceMetaObject != nullptr;
1635 }
1636
1637 if (target.flags() & QMetaType::IsEnumeration)
1638 return isEnumUnderlyingType(target, source);
1639
1640 if (source.flags() & QMetaType::IsEnumeration)
1641 return isEnumUnderlyingType(source, target);
1642
1643 if (!source.isValid())
1644 return canHoldVoid(target);
1645
1646 return false;
1647}
1648
1680
1708
1714
1715template<QV4::Lookup::Call FallbackCall>
1717 const AOTCompiledContext *aotContext, QV4::Lookup *lookup, QObject *object)
1718{
1719 QV4::Scope scope(aotContext->engine->handle());
1720 QV4::PropertyKey id = scope.engine->identifierTable->asPropertyKey(
1721 aotContext->compilationUnit->runtimeStrings[lookup->nameIndex]);
1722
1723 Q_ASSERT(id.isString());
1724
1725 QV4::ScopedString name(scope, id.asStringOrSymbol());
1726
1727 Q_ASSERT(!name->equals(scope.engine->id_toString()));
1728 Q_ASSERT(!name->equals(scope.engine->id_destroy()));
1729
1730 QQmlData *ddata = QQmlData::get(object, true);
1731 Q_ASSERT(ddata);
1732 if (ddata->isQueuedForDeletion)
1734
1735 const QQmlPropertyData *property;
1736 if (!ddata->propertyCache) {
1737 property = QQmlPropertyCache::property(object, name, aotContext->qmlContext, nullptr);
1738 } else {
1739 property = ddata->propertyCache->property(
1740 name.getPointer(), object, aotContext->qmlContext);
1741 }
1742
1743 if (!property) {
1744 const QMetaObject *metaObject = object->metaObject();
1745 if (!metaObject)
1747
1748 const int coreIndex = metaObject->indexOfProperty(
1749 name->toQStringNoThrow().toUtf8().constData());
1750 if (coreIndex < 0)
1752
1753 const QMetaProperty property = metaObject->property(coreIndex);
1754
1755 lookup->releasePropertyCache();
1756 // & 1 to tell the gc that this is not heap allocated; see markObjects in qv4lookup_p.h
1757 lookup->qobjectFallbackLookup.metaObject = quintptr(metaObject) + 1;
1758 lookup->qobjectFallbackLookup.metaType = quintptr(property.metaType().iface()) + 1;
1759 lookup->qobjectFallbackLookup.coreIndex = coreIndex;
1760 lookup->qobjectFallbackLookup.notifyIndex =
1761 QMetaObjectPrivate::signalIndex(property.notifySignal());
1762
1763 if constexpr (FallbackCall == QV4::Lookup::Call::ContextGetterScopeObjectPropertyFallback
1764 || FallbackCall == QV4::Lookup::Call::GetterQObjectPropertyFallback) {
1765 lookup->qobjectFallbackLookup.isConstantOrResettable = property.isConstant() ? 1 : 0;
1766 } else if constexpr (FallbackCall == QV4::Lookup::Call::SetterQObjectPropertyFallback) {
1767 lookup->qobjectFallbackLookup.isConstantOrResettable = property.isResettable() ? 1 : 0;
1768 }
1770 }
1771
1772 Q_ASSERT(ddata->propertyCache);
1773
1774 QV4::setupQObjectLookup(lookup, ddata, property);
1775
1777}
1778
1780template<QV4::Lookup::Call ObjectCall, QV4::Lookup::Call FallbackCall, LookupType Type>
1781void initObjectLookup(const AOTCompiledContext *aotContext, uint index, QObject *object)
1782{
1783 QV4::ExecutionEngine *v4 = aotContext->engine->handle();
1784 if (v4->hasException) {
1785 v4->amendException();
1786 return;
1787 }
1788
1789 QV4::Lookup *lookup = aotContext->compilationUnit->runtimeLookups + index;
1790 switch (initObjectLookup<FallbackCall>(aotContext, lookup, object)) {
1792 lookup->call = ObjectCall;
1793 lookup->asVariant = (Type == LookupType::Variant);
1794 break;
1796 lookup->call = FallbackCall;
1797 lookup->asVariant = (Type == LookupType::Variant);
1798 break;
1800 v4->throwTypeError();
1801 break;
1802 }
1803
1804 return;
1805}
1806
1807
1809 QV4::Lookup *lookup, QV4::ExecutableCompilationUnit *compilationUnit,
1810 const QMetaObject *metaObject)
1811{
1812 Q_ASSERT(metaObject);
1813 const QByteArray name = compilationUnit->runtimeStrings[lookup->nameIndex]->toQString().toUtf8();
1814 const int coreIndex = metaObject->indexOfProperty(name.constData());
1815 QMetaType lookupType = metaObject->property(coreIndex).metaType();
1816 lookup->qgadgetLookup.metaObject = quintptr(metaObject) + 1;
1817 lookup->qgadgetLookup.coreIndex = coreIndex;
1818 lookup->qgadgetLookup.metaType = lookupType.iface();
1819}
1820
1849
1873
1879
1881{
1882#if QT_CONFIG(translation)
1884#else
1885 return QString();
1886#endif
1887}
1888
1890{
1892 switch (lookup->call) {
1905 return QMetaType::fromType<QObject *>();
1908 // We can do this because the fallback lookup gets invalidated for every call.
1909 return QMetaType(reinterpret_cast<const QtPrivate::QMetaTypeInterface *>(
1911 }
1917 return QMetaType::fromType<void>();
1919 return QMetaType::fromType<QString>();
1920 default:
1922 }
1923 default:
1924 break;
1925 }
1926
1928}
1929
1930static bool isUndefined(const void *value, QMetaType type)
1931{
1932 if (type == QMetaType::fromType<QVariant>())
1933 return !static_cast<const QVariant *>(value)->isValid();
1934 if (type == QMetaType::fromType<QJSValue>())
1935 return static_cast<const QJSValue *>(value)->isUndefined();
1936 if (type == QMetaType::fromType<QJSPrimitiveValue>()) {
1937 return static_cast<const QJSPrimitiveValue *>(value)->type()
1938 == QJSPrimitiveValue::Undefined;
1939 }
1940 return false;
1941}
1942
1944{
1945 // We don't really use any part of the lookup machinery here.
1946 // The QV4::Lookup is created on the stack to conveniently get the property cache, and through
1947 // the property cache we store a value into the property.
1948
1949 const auto unwrapVariant = [&]() {
1950 if (type == QMetaType::fromType<QVariant>()) {
1951 QVariant *variant = static_cast<QVariant *>(value);
1952 type = variant->metaType();
1953 value = variant->data();
1954 }
1955 };
1956
1957 QV4::Lookup lookup;
1958 memset(&lookup, 0, sizeof(QV4::Lookup));
1960 lookup.forCall = false;
1963
1965 this, &lookup, qmlScopeObject)) {
1966 case ObjectLookupResult::Object: {
1970 } else if (isUndefined(value, type)) {
1971
1972 // NB: In order to have a meaningful reset() here, the type needs to be a wrapper type
1973 // that can hold undefined. For example QVariant. The caller must not unwrap it.
1974
1976 } else {
1977
1978 // Unwrap any QVariant so that we get a meaningful conversion below.
1979 unwrapVariant();
1980
1983 QV4::Scope scope(v4);
1988 }
1989 }
1990
1992 break;
1993 }
1995 propType = QMetaType(reinterpret_cast<const QtPrivate::QMetaTypeInterface *>(
1999 } else if (isUndefined(value, type)) {
2000
2001 // NB: In order to have a meaningful reset() here, the type needs to be a wrapper type
2002 // that can hold undefined. For example QVariant. The caller must not unwrap it.
2004
2005 } else {
2006
2007 // Unwrap any QVariant so that we get a meaningful conversion below.
2008 unwrapVariant();
2009
2012 QV4::Scope scope(v4);
2017 }
2018 }
2019 break;
2020 }
2023 return;
2024 }
2025
2026 switch (storeResult) {
2027 case PropertyResult::NeedsInit: {
2028 const QString error = QLatin1String("Cannot assign ") +
2030 QLatin1String(" to ") +
2033 break;
2034 }
2035 case PropertyResult::Deleted:
2037 QStringLiteral("Value is null and could not be converted to an object"));
2038 break;
2039 case PropertyResult::OK:
2040 break;
2041 }
2042}
2043
2051
2053{
2054 if (wrapper) {
2055 // We have to check this here because you may pass a plain QObject that only
2056 // turns out to be a QQmlLoggingCategoryBase at run time.
2060 *ok = true;
2061 if (!loggingCategory) {
2063 QStringLiteral("A QmlLoggingCatgory was provided without a valid name"));
2064 }
2065 return loggingCategory;
2066 }
2067 }
2068
2069 *ok = false;
2070 return qmlEngine() ? &lcQml() : &lcJs();
2071}
2072
2075{
2077
2079 Q_ASSERT(frame);
2080
2081 const QByteArray source(frame->source().toUtf8());
2085
2086 switch (type) {
2087 case QtDebugMsg:
2089 break;
2090 case QtInfoMsg:
2092 break;
2093 case QtWarningMsg:
2095 break;
2096 case QtCriticalMsg:
2098 break;
2099 default:
2100 break;
2101 }
2102}
2103
2111
2116
2121
2123 double year, double month, double day, double hours,
2124 double minutes, double seconds, double msecs) const
2125{
2128}
2129
2131 const QQmlType &type, const QV4::CompiledData::ParameterType &parameter)
2132{
2133 return parameter.isList() ? type.qListTypeId() : type.typeId();
2134}
2135
2146
2149 QObject *thisObject, void **args, int argc)
2150{
2151 Q_ALLOCA_INIT();
2152 // We need to re-fetch the method on every call because it can be shadowed.
2153
2157
2158 // The getter mustn't reset the isVariant flag
2160
2161 // Since we have an asVariant lookup, the function may have been overridden in the mean time.
2162 if (!function)
2163 return false;
2164
2165 Q_ALLOCA_VAR(QMetaType, types, (argc + 1) * sizeof(QMetaType));
2167
2169 return !scope.hasException();
2170}
2171
2174 QObject *thisObject, void **args, int argc)
2175{
2177
2178 Q_ALLOCA_INIT();
2179 Q_ALLOCA_VAR(QMetaType, types, (argc + 1) * sizeof(QMetaType));
2184 for (int i = 0; i < argc; ++i)
2186
2188 }
2189
2193 switch (method->methodIndex()) {
2195 return method->method_destroy(
2196 engine, thisObject, argc > 0 ? *static_cast<int *>(args[1]) : 0);
2200 thisObject);
2201 if (void *returnValue = args[0])
2202 *static_cast<QString *>(returnValue) = std::move(result);
2203 return true;
2204 }
2205 default:
2206 break;
2207 }
2208 return false;
2209}
2210
2213 QObject *thisObject, void **args, int argc)
2214{
2215 Q_ALLOCA_INIT();
2219
2220 switch (v4Function->kind) {
2221 case QV4::Function::AotCompiled: {
2224 return !engine->hasException;
2225 }
2226 case QV4::Function::JsTyped: {
2230
2231 Q_ALLOCA_VAR(QMetaType, types, (argc + 1) * sizeof(QMetaType));
2234 for (qsizetype i = 0; i != argc; ++i) {
2237 }
2238
2240 return !engine->hasException;
2241 }
2242 case QV4::Function::JsUntyped: {
2243 // We can call untyped functions if we're not expecting a specific return value and don't
2244 // have to pass any arguments. The compiler verifies this.
2245 Q_ASSERT(argc == 0);
2248 return !engine->hasException;
2249 }
2250 case QV4::Function::Eval:
2251 break;
2252 }
2253
2254 Q_UNREACHABLE_RETURN(false);
2255}
2256
2258 const AOTCompiledContext *aotContext, QV4::Lookup *lookup, const QString &object)
2259{
2260 aotContext->engine->handle()->throwTypeError(
2261 QStringLiteral("Property '%1' of object %2 is not a function").arg(
2262 aotContext->compilationUnit->runtimeStrings[lookup->nameIndex]->toQString(),
2263 object));
2264};
2265
2288
2290 QV4::QObjectMethod *method, QV4::Lookup *lookup, int relativeMethodIndex)
2291{
2292 Q_ASSERT(lookup->qobjectMethodLookup.method.get() == method->d());
2293
2294 const auto *d = method->d();
2295 const int methodCount = d->methodCount;
2296
2297 if (methodCount == 1) {
2298 // No need to resolve the overload if there's only one method.
2299 // This can be:
2300 // 1. A QML-declared signal where the relativeMethodIndex is -1.
2301 // 2. A QML-declared function in an object compiled via qmltc where the
2302 // relativeMethodIndex isn't actually the metaobject index.
2303 // NB: QML-declared functions can't be overloaded, so there is no
2304 // ambiguity here.
2305 // 3. A C++-declared invokable. In that case this is an optimization.
2306 lookup->qobjectMethodLookup.propertyData = d->methods;
2307 return;
2308 }
2309
2310 for (int i = 0, end = d->methodCount; i != end; ++i) {
2311 const QMetaMethod metaMethod = d->methods[i].metaMethod();
2312 if (metaMethod.relativeMethodIndex() != relativeMethodIndex)
2313 continue;
2314
2315 lookup->qobjectMethodLookup.propertyData = d->methods + i;
2316 return;
2317 }
2318
2319 Q_UNREACHABLE();
2320}
2321
2323{
2324 QV4::Heap::QObjectMethod *d = method->d();
2325 switch (method->methodIndex()) {
2328 return false;
2329 default:
2330 break;
2331 }
2332
2334 return true;
2335}
2336
2366
2368{
2370 int objectId = -1;
2371 QQmlContextData *context = nullptr;
2373
2374 switch (lookup->call) {
2378 break;
2384 if (objectId != -1 && objectId < context->numIdValues())
2385 break;
2386 }
2387 break;
2388 }
2389 default:
2390 return false;
2391 }
2392
2393 Q_ASSERT(objectId >= 0);
2394 Q_ASSERT(context != nullptr);
2398 *static_cast<QObject **>(target) = context->idValue(objectId);
2399 return true;
2400}
2401
2426
2428 uint index, QObject *object, void **args, int argc) const
2429{
2431
2432 if (!object) {
2433 engine->handle()->throwTypeError(QStringLiteral("Cannot call method '%1' of null")
2435 return false;
2436 }
2437
2438 switch (lookup->call) {
2441 return lookup->asVariant
2446 if (lookup->asVariant) {
2447 // If the method can be shadowed, the overridden method can be taken away, too.
2448 // In that case we might end up with a QObjectMethod or random other values instead.
2449 // callQObjectMethodAsVariant is flexible enough to handle that.
2451 }
2452
2453 // Here we always retrieve a fresh ArrowFunction via the getter.
2457
2458 // The getter mustn't touch the asVariant bit
2460
2461 if (function)
2463
2465 }
2466 default:
2467 break;
2468 }
2469
2470 return false;
2471}
2472
2474{
2475 if (engine->hasError()) {
2477 return;
2478 }
2479
2482
2483 const auto *ddata = QQmlData::get(object, false);
2485 // We cannot lookup functions on an object with VME metaobject but no QObjectWrapper
2486 throwIsNotAFunctionError(this, lookup, QStringLiteral("[object Object]"));
2487 return;
2488 }
2489
2492 if (auto *method = function->as<QV4::QObjectMethod>()) {
2494 lookup->asVariant = true;
2495 return;
2496 }
2497
2498 if (function->as<QV4::ArrowFunction>()) {
2499 // Can't have overloads of JavaScript functions.
2500 lookup->asVariant = true;
2501 return;
2502 }
2503
2505}
2506
2509{
2510 if (engine->hasError()) {
2512 return;
2513 }
2514
2517
2518 const auto *ddata = QQmlData::get(object, false);
2520 // We cannot lookup functions on an object with VME metaobject but no QObjectWrapper
2521 throwIsNotAFunctionError(this, lookup, QStringLiteral("[object Object]"));
2522 return;
2523 }
2524
2527 if (auto *method = function->as<QV4::QObjectMethod>()) {
2530 return;
2531 }
2532
2533 if (function->as<QV4::ArrowFunction>()) {
2534 // Can't have overloads of JavaScript functions.
2535 return;
2536 }
2537
2539}
2540
2542{
2545 return false;
2549 val,
2552 return false;
2553 }
2554 return true;
2555}
2556
2567
2569{
2571
2572 if (!qmlScopeObject) {
2575 return false;
2576 }
2577
2579 switch (lookup->call) {
2582 break;
2586 break;
2587 default:
2588 return false;
2589 }
2590
2591 switch (result) {
2593 return false;
2594 case PropertyResult::Deleted:
2596 QStringLiteral("Cannot read property '%1' of null")
2598 return false;
2599 case PropertyResult::OK:
2600 return true;
2601 }
2602
2603 Q_UNREACHABLE_RETURN(false);
2604}
2605
2607{
2609
2611 switch (lookup->call) {
2614 break;
2618 break;
2619 default:
2620 return false;
2621 }
2622
2623 switch (result) {
2625 return false;
2626 case PropertyResult::Deleted: // Silently omit the write back. Same as interpreter
2627 case PropertyResult::OK:
2628 return true;
2629 }
2630
2631 Q_UNREACHABLE_RETURN(false);
2632}
2633
2634
2635
2643
2645{
2648
2652
2653 // We don't handle non-QObject singletons (as those can't be declared in qmltypes anyway)
2655 *static_cast<QObject **>(target) = wrapper->object();
2656 return true;
2657 }
2658
2659 return false;
2660}
2661
2664
2665template<QV4::Lookup::Call call>
2666static void initTypeWrapperLookup(
2667 const AOTCompiledContext *context, QV4::Lookup *lookup, uint importNamespace)
2668{
2669 Q_ASSERT(!context->engine->hasError());
2670 if (importNamespace != AOTCompiledContext::InvalidStringId) {
2671 QV4::Scope scope(context->engine->handle());
2672 QV4::ScopedString import(scope, context->compilationUnit->runtimeStrings[importNamespace]);
2673
2674 QQmlTypeLoader *typeLoader = scope.engine->typeLoader();
2675 Q_ASSERT(typeLoader);
2676 if (const QQmlImportRef *importRef
2677 = context->qmlContext->imports()->query(import, typeLoader).importNamespace) {
2678
2679 QV4::Scoped<QV4::QQmlTypeWrapper> wrapper(
2680 scope, QV4::QQmlTypeWrapper::create(
2681 scope.engine, nullptr, context->qmlContext->imports(), importRef));
2682
2683 // This is not a contextGetter since we actually load from the namespace.
2684 wrapper = lookup->getter(context->engine->handle(), wrapper);
2685
2686 // In theory, the getter may have populated the lookup's property cache.
2687 lookup->releasePropertyCache();
2688
2689 lookup->call = call;
2690 switch (call) {
2691 case QV4::Lookup::Call::ContextGetterSingleton:
2692 lookup->qmlContextSingletonLookup.singletonObject.set(scope.engine, wrapper->heapObject());
2693 break;
2694 case QV4::Lookup::Call::ContextGetterType:
2695 lookup->qmlTypeLookup.qmlTypeWrapper.set(scope.engine, wrapper->heapObject());
2696 break;
2697 default:
2698 break;
2699 }
2700 return;
2701 }
2702 scope.engine->throwTypeError();
2703 } else {
2704 QV4::ExecutionEngine *v4 = context->engine->handle();
2705 lookup->contextGetter(v4, nullptr);
2706 if (lookup->call != call) {
2707 const QString error
2708 = QLatin1String(call == QV4::Lookup::Call::ContextGetterSingleton
2709 ? "%1 was a singleton at compile time, "
2710 "but is not a singleton anymore."
2711 : "%1 was not a singleton at compile time, "
2712 "but is a singleton now.")
2713 .arg(context->compilationUnit->runtimeStrings[lookup->nameIndex]->toQString());
2714 v4->throwTypeError(error);
2715 }
2716 }
2717}
2723}
2737}
2770}
2773{
2776 return false;
2777
2778 const QV4::Heap::QQmlTypeWrapper *typeWrapper = static_cast<const QV4::Heap::QQmlTypeWrapper *>(
2780
2782 *static_cast<const QMetaObject **>(target)
2784 return true;
2785}
2791}
2794{
2796 const auto doThrow = [&]() {
2798 QStringLiteral("Cannot read property '%1' of null")
2800 return false;
2801 };
2802
2803 if (!object)
2804 return doThrow();
2805
2807 switch (lookup->call) {
2812 break;
2818 break;
2819 default:
2820 return false;
2821 }
2822
2823 switch (result) {
2824 case PropertyResult::Deleted:
2825 return doThrow();
2827 return false;
2828 case PropertyResult::OK:
2829 return true;
2830 }
2831
2832 Q_UNREACHABLE_RETURN(false);
2833}
2836{
2838 if (!object)
2839 return true;
2840
2842 switch (lookup->call) {
2847 break;
2853 break;
2854 default:
2855 return false;
2856 }
2857
2858 switch (result) {
2860 return false;
2861 case PropertyResult::Deleted: // Silently omit the write back
2862 case PropertyResult::OK:
2863 return true;
2864 }
2865
2866 Q_UNREACHABLE_RETURN(false);
2867}
2875}
2883}
2885bool AOTCompiledContext::getValueLookup(uint index, void *value, void *target) const
2886{
2887 Q_ASSERT(value);
2888
2891 return false;
2892
2893 const QMetaObject *metaObject
2894 = reinterpret_cast<const QMetaObject *>(lookup->qgadgetLookup.metaObject - 1);
2896
2897 void *args[] = { target, nullptr };
2899 reinterpret_cast<QObject*>(value), QMetaObject::ReadProperty,
2901 return true;
2902}
2905{
2906 Q_ASSERT(value);
2907
2910 return false;
2911
2912 const QMetaObject *metaObject
2913 = reinterpret_cast<const QMetaObject *>(lookup->qgadgetLookup.metaObject - 1);
2915
2916 void *args[] = { source, nullptr };
2918 reinterpret_cast<QObject*>(value), QMetaObject::WriteProperty,
2920 return true;
2921}
2929}
2932{
2935 return false;
2936 const bool isUnsigned
2940 case 1:
2941 if (isUnsigned)
2942 *static_cast<quint8 *>(target) = encoded;
2943 else
2944 *static_cast<qint8 *>(target) = encoded;
2945 return true;
2946 case 2:
2947 if (isUnsigned)
2948 *static_cast<quint16 *>(target) = encoded;
2949 else
2950 *static_cast<qint16 *>(target) = encoded;
2951 return true;
2952 case 4:
2953 if (isUnsigned)
2954 *static_cast<quint32 *>(target) = encoded;
2955 else
2956 *static_cast<qint32 *>(target) = encoded;
2957 return true;
2958 case 8:
2959 if (isUnsigned)
2960 *static_cast<quint64 *>(target) = encoded;
2961 else
2962 *static_cast<qint64 *>(target) = encoded;
2963 return true;
2964 default:
2965 break;
2966 }
2967
2968 return false;
2969}
2988}
2991{
2992 const auto doThrow = [&]() {
2994 QStringLiteral("Value is null and could not be converted to an object"));
2995 return false;
2996 };
2997
2998 if (!object)
2999 return doThrow();
3000
3003 switch (lookup->call) {
3008 break;
3014 break;
3015 default:
3016 return false;
3017 }
3018
3019 switch (result) {
3020 case PropertyResult::Deleted:
3021 return doThrow();
3023 return false;
3024 case PropertyResult::OK:
3025 return true;
3026 }
3027
3028 Q_UNREACHABLE_RETURN(false);
3029}
3037}
3045}
3047static PropertyResult storeValueProperty(
3048 QV4::Lookup *lookup, const QMetaObject *metaObject, void *target, void *value)
3049{
3050 void *args[] = { value, nullptr };
3051 metaObject->d.static_metacall(
3052 reinterpret_cast<QObject *>(target), QMetaObject::WriteProperty,
3053 lookup->qgadgetLookup.coreIndex, args);
3054 return PropertyResult::OK;
3055}
3057static PropertyResult resetValueProperty(
3058 QV4::Lookup *lookup, const QMetaObject *metaObject, void *target, QV4::ExecutionEngine *v4)
3059{
3060 const QMetaProperty property = metaObject->property(lookup->qgadgetLookup.coreIndex);
3061 if (property.isResettable()) {
3062 void *args[] = { nullptr };
3063 metaObject->d.static_metacall(
3064 reinterpret_cast<QObject *>(target), QMetaObject::ResetProperty,
3065 lookup->qgadgetLookup.coreIndex, args);
3066 } else {
3067 v4->throwError(
3068 QLatin1String("Cannot assign [undefined] to ") +
3069 QLatin1String(property.metaType().name()));
3070 }
3071
3072 return PropertyResult::OK;
3073}
3075static PropertyResult storeValueAsVariant(
3076 QV4::ExecutionEngine *v4, QV4::Lookup *lookup, const QMetaObject *metaObject,
3077 void *target, void *value)
3078{
3079 QVariant *variant = static_cast<QVariant *>(value);
3080 const QMetaType propType = metaObject->property(lookup->qgadgetLookup.coreIndex).metaType();
3081 if (propType == QMetaType::fromType<QVariant>())
3082 return storeValueProperty(lookup, metaObject, target, variant);
3083
3084 if (!variant->isValid())
3085 return resetValueProperty(lookup, metaObject, target, v4);
3086
3087 if (isTypeCompatible(variant->metaType(), propType))
3088 return storeValueProperty(lookup, metaObject, target, variant->data());
3089
3090 QVariant converted(propType);
3091 QV4::Scope scope(v4);
3092 QV4::ScopedValue val(scope, v4->fromVariant(*variant));
3093 if (v4->metaTypeFromJS(val, propType, converted.data())
3094 || QMetaType::convert(
3095 variant->metaType(), variant->constData(), propType, converted.data())) {
3096 return storeValueProperty(lookup, metaObject, target, converted.data());
3097 }
3098
3099 v4->throwError(
3100 QLatin1String("Cannot assign ") + QLatin1String(variant->metaType().name())
3101 + QLatin1String(" to ") + QLatin1String(propType.name()));
3102
3104}
3107 uint index, void *target, void *value) const
3108{
3111 return false;
3112
3113 const QMetaObject *metaObject
3114 = reinterpret_cast<const QMetaObject *>(lookup->qgadgetLookup.metaObject - 1);
3115
3119
3120 switch (result) {
3121 case PropertyResult::OK:
3122 return true;
3124 return false;
3125 case PropertyResult::Deleted:
3126 Q_UNREACHABLE();
3127 }
3128
3129 return false;
3130}
3131
3132template<LookupType Type>
3133void initValueLookup(
3134 const AOTCompiledContext *aotContext, uint index, const QMetaObject *metaObject)
3135{
3136 QV4::ExecutionEngine *v4 = aotContext->engine->handle();
3137 if (v4->hasException) {
3138 v4->amendException();
3139 return;
3140 }
3141
3142 QV4::Lookup *lookup = aotContext->compilationUnit->runtimeLookups + index;
3143 initValueLookup(lookup, aotContext->compilationUnit, metaObject);
3144 lookup->call = QV4::Lookup::Call::SetterValueTypeProperty;
3145 lookup->asVariant = (Type == LookupType::Variant);
3146}
3151}
3157}
3159bool AOTCompiledContext::callValueLookup(uint index, void *target, void **args, int argc) const
3160{
3161 Q_UNUSED(argc);
3162
3165 return false;
3166
3168
3169 const QMetaObject *metaObject
3170 = reinterpret_cast<const QMetaObject *>(lookup->qgadgetLookup.metaObject - 1);
3171
3173 reinterpret_cast<QObject *>(target), QMetaObject::InvokeMetaMethod,
3175
3176 return true;
3177}
3194}
3201}
3202
3203} // namespace QQmlPrivate
3204
3205/*!
3206 \macro QML_DECLARE_TYPE()
3207 \relates <qqml.h>
3208
3209 Equivalent to \c Q_DECLARE_METATYPE(TYPE *) and \c Q_DECLARE_METATYPE(QQmlListProperty<TYPE>)
3210*/
3211
3212/*!
3213 \macro QML_DECLARE_TYPEINFO(Type,Flags)
3214 \relates <qqml.h>
3215
3216 Declares additional properties of the given \a Type as described by the
3217 specified \a Flags.
3218
3219 Current the only supported type info is \c QML_HAS_ATTACHED_PROPERTIES which
3220 declares that the \a Type supports \l {Attached Properties and Attached Signal Handlers}
3221 {attached properties}. QML_DECLARE_TYPEINFO() is not necessary if \a Type contains the
3222 QML_ATTACHED macro.
3223*/
3224
3225/*!
3226 \fn template <typename T> int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const char *qmlName)
3227 \relates <qqml.h>
3228
3229 This template function registers the C++ type in the QML system with
3230 the name \a qmlName, in the library imported from \a uri having the
3231 version number composed from \a versionMajor and \a versionMinor.
3232
3233 Returns the QML type id.
3234
3235 There are two forms of this template function:
3236
3237 \code
3238 template<typename T>
3239 int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const char *qmlName);
3240
3241 template<typename T, int metaObjectRevision>
3242 int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const char *qmlName);
3243 \endcode
3244
3245 The former is the standard form which registers the type \e T as a new type.
3246 The latter allows a particular revision of a class to be registered in
3247 a specified version (see \l {Type Revisions and Versions}).
3248
3249
3250 For example, this registers a C++ class \c MySliderItem as a QML type
3251 named \c Slider for version 1.0 of a type namespace called
3252 "com.mycompany.qmlcomponents":
3253
3254 \code
3255 qmlRegisterType<MySliderItem>("com.mycompany.qmlcomponents", 1, 0, "Slider");
3256 \endcode
3257
3258 Once this is registered, the type can be used in QML by importing the
3259 specified type namespace and version number:
3260
3261 \qml
3262 import com.mycompany.qmlcomponents 1.0
3263
3264 Slider {
3265 // ...
3266 }
3267 \endqml
3268
3269 Note that it's perfectly reasonable for a library to register types to older versions
3270 than the actual version of the library. Indeed, it is normal for the new library to allow
3271 QML written to previous versions to continue to work, even if more advanced versions of
3272 some of its types are available.
3273
3274 \sa QML_ELEMENT, QML_NAMED_ELEMENT(),
3275 {Choosing the Correct Integration Method Between C++ and QML}
3276*/
3277
3278/*!
3279 \fn template<typename T, int metaObjectRevision> int qmlRegisterRevision(const char *uri, int versionMajor, int versionMinor)
3280 \relates <qqml.h>
3281
3282 This template function registers the C++ type \a T at the specified revision
3283 \a metaObjectRevision in the QML system with the library imported from \a uri
3284 having the version number composed from \a versionMajor and \a versionMinor.
3285
3286 Returns the QML type id.
3287
3288 \code
3289 template<typename T, int metaObjectRevision>
3290 int qmlRegisterRevision(const char *uri, int versionMajor, int versionMinor);
3291 \endcode
3292
3293 This function is typically used to register the revision of a base class to
3294 use for the specified version of the type (see \l {Type Revisions and Versions}).
3295*/
3296
3297/*!
3298 \fn template <typename T> int qmlRegisterUncreatableType(const char *uri, int versionMajor, int versionMinor, const char *qmlName, const QString& message)
3299 \relates <qqml.h>
3300
3301 This template function registers the C++ type in the QML system with
3302 the name \a qmlName, in the library imported from \a uri having the
3303 version number composed from \a versionMajor and \a versionMinor.
3304
3305 While the type has a name and a type, it cannot be created, and the
3306 given error \a message will result if creation is attempted.
3307
3308 This is useful where the type is only intended for providing attached properties or enum values.
3309
3310 Returns the QML type id.
3311
3312 \sa QML_UNCREATABLE(), qmlRegisterTypeNotAvailable(),
3313 {Choosing the Correct Integration Method Between C++ and QML}
3314*/
3315
3316/*!
3317 \fn template <typename T, typename E> int qmlRegisterExtendedType(const char *uri, int versionMajor, int versionMinor, const char *qmlName)
3318 \relates <qqml.h>
3319
3320 This template function registers the C++ type and its extension object in the
3321 QML system with the name \a qmlName in the library imported from \a uri having
3322 version number composed from \a versionMajor and \a versionMinor. Properties
3323 not available in the main type will be searched for in the extension object.
3324
3325 Returns the QML type id.
3326
3327 \sa QML_EXTENDED(), qmlRegisterType(), {Registering Extension Objects}
3328*/
3329
3330/*!
3331 \fn template <typename T, typename E> int qmlRegisterExtendedUncreatableType(const char *uri, int versionMajor, int versionMinor, const char *qmlName, const QString& reason)
3332 \relates <qqml.h>
3333
3334 This template function registers the C++ type and its extension
3335 in the QML system with the name \a qmlName in the library imported
3336 from \a uri having version number composed from \a versionMajor and
3337 \a versionMinor.
3338
3339 While the type has a name and a type, it cannot be created. An error
3340 message with the given \a reason is printed if the user attempts to
3341 create an instance of this type.
3342
3343 This is useful where the type is only intended for providing attached
3344 properties, enum values or an abstract base class with its extension.
3345
3346 Returns the QML type id.
3347
3348 \sa QML_EXTENDED(), QML_UNCREATABLE(), qmlRegisterUncreatableType()
3349*/
3350
3351/*!
3352 \fn int qmlRegisterCustomExtendedType(const char *uri, int versionMajor, int versionMinor, const char *qmlName, QQmlCustomParser *parser)
3353 \relates <qqml.h>
3354 \internal
3355
3356 This template function registers the C++ type and its extension
3357 in the QML system with the name \a qmlName in the library imported
3358 from \a uri having version number composed from \a versionMajor and
3359 \a versionMinor. Properties from the C++ type or its extension that
3360 cannot be resolved directly by the QML system will be resolved using
3361 the \a parser provided.
3362
3363 Returns the QML type id.
3364
3365 \sa QML_ELEMENT, QML_NAMED_ELEMENT(), QML_EXTENDED()
3366*/
3367
3368/*!
3369 \fn template <typename T> int qmlRegisterAnonymousType(const char *uri, int versionMajor)
3370 \relates <qqml.h>
3371
3372 This template function registers the C++ type in the QML system as an anonymous type. The
3373 resulting QML type does not have a name. Therefore, instances of this type cannot be created from
3374 the QML system. You can, however, access instances of the type when they are exposed as properties
3375 of other types.
3376
3377 Use this function when the type will not be referenced by name, specifically for C++ types that
3378 are used on the left-hand side of a property binding. To indicate to which module the type belongs
3379 use \a uri and \a versionMajor.
3380
3381 For example, consider the following two classes:
3382
3383 //! Workaround for MOC not respecting comments and triggering an error on certain Qt macros.
3384 \code Q
3385 class Bar : public QObject
3386 {
3387 \1_OBJECT
3388 Q_PROPERTY(QString baz READ baz WRITE setBaz NOTIFY bazChanged)
3389
3390 public:
3391 Bar() {}
3392
3393 QString baz() const { return mBaz; }
3394
3395 void setBaz(const QString &baz)
3396 {
3397 if (baz == mBaz)
3398 return;
3399
3400 mBaz = baz;
3401 emit bazChanged();
3402 }
3403
3404 signals:
3405 void bazChanged();
3406
3407 private:
3408 QString mBaz;
3409 };
3410
3411 class Foo : public QObject
3412 {
3413 \1_OBJECT
3414 Q_PROPERTY(Bar *bar READ bar CONSTANT FINAL)
3415
3416 public:
3417 Foo() {}
3418
3419 Bar *bar() { return &mBar; }
3420
3421 private:
3422 Bar mBar;
3423 };
3424 \endcode
3425
3426 In QML, we assign a string to the \c baz property of \c bar:
3427
3428 \code
3429 Foo {
3430 bar.baz: "abc"
3431 Component.onCompleted: print(bar.baz)
3432 }
3433 \endcode
3434
3435 For the QML engine to know that the \c Bar type has a \c baz property,
3436 we have to make \c Bar known:
3437
3438 \code
3439 qmlRegisterType<Foo>("App", 1, 0, "Foo");
3440 qmlRegisterAnonymousType<Bar>("App", 1);
3441 \endcode
3442
3443 As the \c Foo type is instantiated in QML, it must be registered
3444 with the version of \l qmlRegisterType() that takes an element name.
3445
3446 Returns the QML type id.
3447
3448 \since 5.14
3449 \sa QML_ANONYMOUS, {Choosing the Correct Integration Method Between C++ and QML}
3450*/
3451
3452/*!
3453 \fn int qmlRegisterInterface(const char *typeName)
3454 \relates <qqml.h>
3455
3456 This template function registers the C++ type in the QML system
3457 under the name \a typeName.
3458
3459 Types registered as an interface with the engine should also
3460 declare themselves as an interface with the
3461 \l {The Meta-Object System}{meta object system}. For example:
3462
3463 \code
3464 struct FooInterface
3465 {
3466 public:
3467 virtual ~FooInterface();
3468 virtual void doSomething() = 0;
3469 };
3470
3471 Q_DECLARE_INTERFACE(FooInterface, "org.foo.FooInterface")
3472 \endcode
3473
3474 When registered with the QML engine in this way, they can be used as
3475 property types:
3476
3477 Q_PROPERTY(FooInterface *foo READ foo WRITE setFoo)
3478
3479 When you assign a \l QObject sub-class to this property, the QML engine does
3480 the interface cast to \c FooInterface* automatically.
3481
3482 Returns the QML type id.
3483
3484 \sa QML_INTERFACE
3485*/
3486
3487/*!
3488 \fn int qmlRegisterSingletonType(const char *uri, int versionMajor, int versionMinor, const char *typeName, std::function<QJSValue(QQmlEngine *, QJSEngine *)> callback)
3489 \relates <qqml.h>
3490
3491 This function may be used to register a singleton type provider \a callback in a particular \a uri
3492 and \a typeName with a version specified in \a versionMajor and \a versionMinor.
3493
3494 Installing a singleton type allows developers to provide arbitrary functionality
3495 (methods and properties) to a client without requiring individual instances of the type to
3496 be instantiated by the client.
3497
3498 A singleton type may be either a QObject or a QJSValue.
3499 This function should be used to register a singleton type provider function which returns a QJSValue as a singleton type.
3500
3501 \b{NOTE:} QJSValue singleton type properties will \b{not} trigger binding re-evaluation if changed.
3502
3503 Usage:
3504 \code
3505 // First, define the singleton type provider function (callback).
3506 static QJSValue example_qjsvalue_singletontype_provider(QQmlEngine *engine, QJSEngine *scriptEngine)
3507 {
3508 Q_UNUSED(engine)
3509
3510 static int seedValue = 5;
3511 QJSValue example = scriptEngine->newObject();
3512 example.setProperty("someProperty", seedValue++);
3513 return example;
3514 }
3515
3516 // Second, register the singleton type provider with QML by calling this function in an initialization function.
3517 qmlRegisterSingletonType("Qt.example.qjsvalueApi", 1, 0, "MyApi", example_qjsvalue_singletontype_provider);
3518 \endcode
3519
3520 Alternatively, you can use a C++11 lambda:
3521
3522 \code
3523 qmlRegisterSingletonType("Qt.example.qjsvalueApi", 1, 0, "MyApi", [](QQmlEngine *engine, QJSEngine *scriptEngine) -> QJSValue {
3524 Q_UNUSED(engine)
3525
3526 static int seedValue = 5;
3527 QJSValue example = scriptEngine->newObject();
3528 example.setProperty("someProperty", seedValue++);
3529 return example;
3530 });
3531 \endcode
3532
3533 In order to use the registered singleton type in QML, you must import the singleton type.
3534 \qml
3535 import QtQuick 2.0
3536 import Qt.example.qjsvalueApi 1.0 as ExampleApi
3537 Item {
3538 id: root
3539 property int someValue: ExampleApi.MyApi.someProperty
3540 }
3541 \endqml
3542
3543 \sa QML_SINGLETON, {Choosing the Correct Integration Method Between C++ and QML}
3544*/
3545
3546/*!
3547 \fn template<typename T> QObject *qmlAttachedPropertiesObject(const QObject *attachee, bool createIfMissing)
3548 \relates <qqml.h>
3549
3550 The form of this template function is:
3551
3552 \code
3553 template<typename T> QObject *qmlAttachedPropertiesObject(const QObject *attachee, bool createIfMissing = true)
3554 \endcode
3555
3556 This returns the attached object instance that has been attached to the specified
3557 \a attachee by the attaching type \e T.
3558
3559 If \a attachee is \nullptr, returns \nullptr.
3560
3561 If an existing attached object instance of type \e T exists, it will return
3562 it. Otherwise, it will return a newly created instance if
3563 \a createIfMissing is \c true and \e T is a valid attaching type, or
3564 \nullptr if it's not.
3565
3566 \sa QML_ATTACHED(), {Providing Attached Properties}
3567*/
3568
3569/*!
3570 \fn template <typename T> int qmlRegisterSingletonType(const char *uri, int versionMajor, int versionMinor, const char *typeName, std::function<QObject*(QQmlEngine *, QJSEngine *)> callback)
3571 \relates <qqml.h>
3572
3573 This function may be used to register a singleton type provider \a callback in a particular \a uri
3574 and \a typeName with a version specified in \a versionMajor and \a versionMinor.
3575
3576 Installing a singleton type into a uri allows developers to provide arbitrary functionality
3577 (methods and properties) to clients without requiring individual instances ot the type to be
3578 instantiated by the client.
3579
3580 A singleton type may be either a QObject or a QJSValue.
3581 This function should be used to register a singleton type provider function which returns a QObject
3582 of the given type T as a singleton type.
3583
3584 A QObject singleton type may be referenced via the type name with which it was registered, and this
3585 typename may be used as the target in a \l Connections type or otherwise used as any other type id would.
3586 One exception to this is that a QObject singleton type property may not be aliased.
3587
3588 \b{NOTE:} A QObject singleton type instance returned from a singleton type provider is owned by
3589 the QML engine unless the object has explicit QQmlEngine::CppOwnership flag set.
3590
3591 Usage:
3592 //! Workaround for MOC not respecting comments and triggering an error on certain Qt macros.
3593 \code Q
3594 // First, define your QObject which provides the functionality.
3595 class SingletonTypeExample : public QObject
3596 {
3597 \1_OBJECT
3598 Q_PROPERTY (int someProperty READ someProperty WRITE setSomeProperty NOTIFY somePropertyChanged)
3599
3600 public:
3601 SingletonTypeExample(QObject *parent = nullptr)
3602 : QObject(parent), m_someProperty(0)
3603 {
3604 }
3605
3606 ~SingletonTypeExample() {}
3607
3608 Q_INVOKABLE int doSomething() { setSomeProperty(5); return m_someProperty; }
3609
3610 int someProperty() const { return m_someProperty; }
3611 void setSomeProperty(int val) { m_someProperty = val; emit somePropertyChanged(val); }
3612
3613 signals:
3614 void somePropertyChanged(int newValue);
3615
3616 private:
3617 int m_someProperty;
3618 };
3619
3620 // Second, define the singleton type provider function (callback).
3621 static QObject *example_qobject_singletontype_provider(QQmlEngine *engine, QJSEngine *scriptEngine)
3622 {
3623 Q_UNUSED(engine)
3624 Q_UNUSED(scriptEngine)
3625
3626 SingletonTypeExample *example = new SingletonTypeExample();
3627 return example;
3628 }
3629
3630 // Third, register the singleton type provider with QML by calling this function in an initialization function.
3631 qmlRegisterSingletonType<SingletonTypeExample>("Qt.example.qobjectSingleton", 1, 0, "MyApi", example_qobject_singletontype_provider);
3632 \endcode
3633
3634 Alternatively, you can use a C++11 lambda:
3635
3636 \code
3637 qmlRegisterSingletonType<SingletonTypeExample>("Qt.example.qobjectSingleton", 1, 0, "MyApi", [](QQmlEngine *engine, QJSEngine *scriptEngine) -> QObject * {
3638 Q_UNUSED(engine)
3639 Q_UNUSED(scriptEngine)
3640
3641 SingletonTypeExample *example = new SingletonTypeExample();
3642 return example;
3643 });
3644 \endcode
3645
3646 In order to use the registered singleton type in QML, you must import the singleton type.
3647 \qml
3648 import QtQuick 2.0
3649 import Qt.example.qobjectSingleton 1.0
3650 Item {
3651 id: root
3652 property int someValue: MyApi.someProperty
3653
3654 Component.onCompleted: {
3655 someValue = MyApi.doSomething()
3656 }
3657 }
3658 \endqml
3659
3660 \sa QML_SINGLETON, {Choosing the Correct Integration Method Between C++ and QML}
3661*/
3662
3663/*!
3664 \fn int qmlRegisterSingletonType(const QUrl &url, const char *uri, int versionMajor, int versionMinor, const char *qmlName)
3665 \relates <qqml.h>
3666
3667 This function may be used to register a singleton type with the name \a qmlName, in the library imported from \a uri having
3668 the version number composed from \a versionMajor and \a versionMinor. The type is defined by the QML file located at \a url.
3669 The url must be an absolute URL, i.e. url.isRelative() == false.
3670
3671 In addition the type's QML file must have pragma Singleton statement among its import statements.
3672
3673 A singleton type may be referenced via the type name with which it was registered, and this typename may be used as the
3674 target in a \l Connections type or otherwise used as any other type id would. One exception to this is that a singleton
3675 type property may not be aliased (because the singleton type name does not identify an object within the same component
3676 as any other item).
3677
3678 Usage:
3679 \qml
3680 // First, define your QML singleton type which provides the functionality.
3681 pragma Singleton
3682 import QtQuick 2.0
3683 Item {
3684 property int testProp1: 125
3685 }
3686 \endqml
3687
3688 \code
3689 // Second, register the QML singleton type by calling this function in an initialization function.
3690 qmlRegisterSingletonType(QUrl("file:///absolute/path/SingletonType.qml"), "Qt.example.qobjectSingleton", 1, 0, "RegisteredSingleton");
3691 \endcode
3692
3693 In order to use the registered singleton type in QML, you must import the singleton type.
3694 \qml
3695 import QtQuick 2.0
3696 import Qt.example.qobjectSingleton 1.0
3697 Item {
3698 id: root
3699 property int someValue: RegisteredSingleton.testProp1
3700 }
3701 \endqml
3702
3703 It is also possible to have QML singleton types registered without using the qmlRegisterSingletonType function.
3704 That can be done by adding a pragma Singleton statement among the imports of the type's QML file. In addition
3705 the type must be defined in a qmldir file with a singleton keyword and the qmldir must be imported by the QML
3706 files using the singleton.
3707
3708 \sa QML_SINGLETON
3709*/
3710
3711/*!
3712 \fn int qmlRegisterSingletonInstance(const char *uri, int versionMajor, int versionMinor, const char *typeName, QObject *cppObject)
3713 \relates <qqml.h>
3714 \since 5.14
3715
3716 This function is used to register a singleton object \a cppObject, with a
3717 particular \a uri and \a typeName. Its version is a combination of \a
3718 versionMajor and \a versionMinor.
3719
3720 Installing a singleton type into a URI allows you to provide arbitrary
3721 functionality (methods and properties) to QML code without requiring
3722 individual instances of the type to be instantiated by the client.
3723
3724 Use this function to register an object of the given type T as a singleton
3725 type.
3726
3727 A QObject singleton type may be referenced via the type name with which it
3728 was registered; in turn this type name may be used as the target in a \l
3729 Connections type, or like any other type ID. However, there's one
3730 exception: a QObject singleton type property can't be aliased because the
3731 singleton type name does not identify an object within the same component
3732 as any other item.
3733
3734 \note \a cppObject must outlive the QML engine in which it is used.
3735 Moreover, \cppObject must have the same thread affinity as the engine. If
3736 you want separate singleton instances for multiple engines, you need to use
3737 \l {qmlRegisterSingletonType}. See \l{Threads and QObjects} for more
3738 information about thread safety.
3739
3740 \b{NOTE:} qmlRegisterSingleton can only be used when all types of that module are registered procedurally.
3741
3742 Usage:
3743 //! Workaround for MOC not respecting comments and triggering an error on certain Qt macros.
3744 \code Q
3745 // First, define your QObject which provides the functionality.
3746 class SingletonTypeExample : public QObject
3747 {
3748 \1_OBJECT
3749 Q_PROPERTY(int someProperty READ someProperty WRITE setSomeProperty NOTIFY somePropertyChanged)
3750
3751 public:
3752 explicit SingletonTypeExample(QObject* parent = nullptr) : QObject(parent) {}
3753
3754 Q_INVOKABLE int doSomething()
3755 {
3756 setSomeProperty(5);
3757 return m_someProperty;
3758 }
3759
3760 int someProperty() const { return m_someProperty; }
3761 void setSomeProperty(int val) {
3762 if (m_someProperty != val) {
3763 m_someProperty = val;
3764 emit somePropertyChanged(val);
3765 }
3766 }
3767
3768 signals:
3769 void somePropertyChanged(int newValue);
3770
3771 private:
3772 int m_someProperty = 0;
3773 };
3774 \endcode
3775
3776 \code
3777 // Second, create an instance of the object
3778
3779 // allocate example before the engine to ensure that it outlives it
3780 QScopedPointer<SingletonTypeExample> example(new SingletonTypeExample);
3781 QQmlEngine engine;
3782
3783 // Third, register the singleton type provider with QML by calling this
3784 // function in an initialization function.
3785 qmlRegisterSingletonInstance("Qt.example.qobjectSingleton", 1, 0, "MyApi", example.get());
3786 \endcode
3787
3788
3789 In order to use the registered singleton type in QML, you must import the
3790 URI with the corresponding version.
3791 \qml
3792 import QtQuick 2.0
3793 import Qt.example.qobjectSingleton 1.0
3794 Item {
3795 id: root
3796 property int someValue: MyApi.someProperty
3797
3798 Component.onCompleted: {
3799 console.log(MyApi.doSomething())
3800 }
3801 }
3802 \endqml
3803
3804 \sa QML_SINGLETON, qmlRegisterSingletonType
3805 */
3806
3807/*!
3808 \fn int qmlRegisterType(const QUrl &url, const char *uri, int versionMajor, int versionMinor, const char *qmlName);
3809 \relates <qqml.h>
3810
3811 This function registers a type in the QML system with the name \a qmlName, in the library imported from \a uri having the
3812 version number composed from \a versionMajor and \a versionMinor. The type is defined by the QML file located at \a url. The
3813 url must be an absolute URL, i.e. url.isRelative() == false.
3814
3815 Normally QML files can be loaded as types directly from other QML files, or using a qmldir file. This function allows
3816 registration of files to types from C++ code, such as when the type mapping needs to be procedurally determined at startup.
3817
3818 Returns -1 if the registration was not successful.
3819*/
3820
3821QT_END_NAMESPACE
PropertyResult loadFallbackAsVariant(QV4::Lookup *lookup, QObject *object, void *target, const AOTCompiledContext *aotContext)
Definition qqml.cpp:1464
static ObjectLookupResult initObjectLookup(const AOTCompiledContext *aotContext, QV4::Lookup *lookup, QObject *object)
Definition qqml.cpp:1716
void qmlRegisterTypeAndRevisions< QQmlTypeNotAvailable, void >(const char *uri, int versionMajor, const QMetaObject *classInfoMetaObject, QList< int > *qmlTypeIds, const QMetaObject *extension, bool)
Definition qqml.cpp:1122
PropertyResult writeBackObjectAsVariant(QV4::Lookup *lookup, QObject *object, void *source)
Definition qqml.cpp:1453
static PropertyResult writeBackFallbackProperty(QV4::Lookup *lookup, QObject *object, void *source)
Definition qqml.cpp:1428
static PropertyResult changeFallbackProperty(QV4::Lookup *lookup, QObject *object, Op op)
Definition qqml.cpp:1527
static FallbackPropertyQmlData findFallbackPropertyQmlData(QV4::Lookup *lookup, QObject *object)
Definition qqml.cpp:1392
static void throwIsNotAFunctionError(const AOTCompiledContext *aotContext, QV4::Lookup *lookup, const QString &object)
Definition qqml.cpp:2257
static bool markPointer(const QVariant &element, QV4::MarkStack *markStack)
Definition qqml.cpp:1211
PropertyResult loadObjectProperty(QV4::Lookup *lookup, QObject *object, void *target, const AOTCompiledContext *aotContext)
Definition qqml.cpp:1357
static bool isEnumUnderlyingType(QMetaType enumType, QMetaType numberType)
Definition qqml.cpp:1568
static PropertyResult storeFallbackAsVariant(QV4::ExecutionEngine *v4, QV4::Lookup *lookup, QObject *object, void *value)
Definition qqml.cpp:1681
static void iterateVariant(const QVariant &element, std::vector< QVariant > *elements)
Definition qqml.cpp:1221
static PropertyResult changeObjectProperty(QV4::Lookup *lookup, QObject *object, Op op)
Definition qqml.cpp:1490
static PropertyResult storeObjectProperty(QV4::Lookup *lookup, QObject *object, void *value)
Definition qqml.cpp:1519
PropertyResult loadObjectAsVariant(QV4::Lookup *lookup, QObject *object, void *target, const AOTCompiledContext *aotContext)
Definition qqml.cpp:1441
static bool callQObjectMethod(QV4::ExecutionEngine *engine, QV4::Lookup *lookup, QObject *thisObject, void **args, int argc)
Definition qqml.cpp:2172
ObjectPropertyQmlData findObjectPropertyQmlData(QV4::Lookup *lookup, QObject *object)
Definition qqml.cpp:1338
static void captureFallbackProperty(QObject *object, int coreIndex, int notifyIndex, bool isConstant, const AOTCompiledContext *aotContext)
Definition qqml.cpp:1298
static void initValueLookup(QV4::Lookup *lookup, QV4::ExecutableCompilationUnit *compilationUnit, const QMetaObject *metaObject)
Definition qqml.cpp:1808
static bool inherits(const QQmlPropertyCache *descendent, const QQmlPropertyCache *ancestor)
Definition qqml.cpp:1320
static bool canHoldVoid(QMetaType type)
Definition qqml.cpp:1603
static bool tryEnsureMethodsCache(QV4::QObjectMethod *method, QObject *object)
Definition qqml.cpp:2322
static void captureObjectProperty(QObject *object, const QQmlPropertyCache *propertyCache, const QQmlPropertyData *property, const AOTCompiledContext *aotContext)
Definition qqml.cpp:1309
PropertyResult writeBackFallbackAsVariant(QV4::Lookup *lookup, QObject *object, void *source)
Definition qqml.cpp:1477
static PropertyResult storeFallbackProperty(QV4::Lookup *lookup, QObject *object, void *value)
Definition qqml.cpp:1541
static bool isUndefined(const void *value, QMetaType type)
Definition qqml.cpp:1930
static bool callQObjectMethodAsVariant(QV4::ExecutionEngine *engine, QV4::Lookup *lookup, QObject *thisObject, void **args, int argc)
Definition qqml.cpp:2147
static QMetaType jsTypedFunctionArgument(const QQmlType &type, const QV4::CompiledData::ParameterType &parameter)
Definition qqml.cpp:2130
static PropertyResult resetFallbackProperty(QV4::Lookup *lookup, QObject *object, QV4::ExecutionEngine *v4)
Definition qqml.cpp:1550
static void resolveQObjectMethodOverload(QV4::QObjectMethod *method, QV4::Lookup *lookup, int relativeMethodIndex)
Definition qqml.cpp:2289
static PropertyResult loadFallbackProperty(QV4::Lookup *lookup, QObject *object, void *target, const AOTCompiledContext *aotContext)
Definition qqml.cpp:1408
static bool callArrowFunction(QV4::ExecutionEngine *engine, QV4::ArrowFunction *function, QObject *thisObject, void **args, int argc)
Definition qqml.cpp:2211
static PropertyResult resetObjectProperty(QV4::Lookup *lookup, QObject *object, QV4::ExecutionEngine *v4)
Definition qqml.cpp:1504
static PropertyResult storeObjectAsVariant(QV4::ExecutionEngine *v4, QV4::Lookup *lookup, QObject *object, void *value)
Definition qqml.cpp:1649
static bool callQObjectMethodWithTypes(QV4::ExecutionEngine *engine, QV4::Lookup *lookup, QObject *thisObject, void **args, QMetaType *types, int argc)
Definition qqml.cpp:2136
static bool isTypeCompatible(QMetaType source, QMetaType target)
Definition qqml.cpp:1611
PropertyResult writeBackObjectProperty(QV4::Lookup *lookup, QObject *object, void *source)
Definition qqml.cpp:1375
void initObjectLookup(const AOTCompiledContext *aotContext, uint index, QObject *object)
Definition qqml.cpp:1781
static QQmlPropertyCapture * propertyCapture(const AOTCompiledContext *aotContext)
Definition qqml.cpp:1175
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:584
static void doRegisterSingletonAndRevisions(const QQmlPrivate::RegisterSingletonTypeAndRevisions &type, const ElementNames &elementNames)
Definition qqml.cpp:872
static ElementNames classElementNames(const QMetaObject *metaObject)
Definition qqml.cpp:695
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:632
void assignVersions(Registration *registration, QTypeRevision revision, QTypeRevision defaultVersion)
Definition qqml.cpp:614
static int finalizeType(const QQmlType &dtype)
Definition qqml.cpp:685
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:625
static QQmlDirParser::Import resolveImport(const QString &uri, int importMajor, int importMinor)
Definition qqml.cpp:371
static bool checkSingletonInstance(QQmlEngine *engine, QObject *instance)
Definition qqml.cpp:524
static void doRegisterTypeAndRevisions(const QQmlPrivate::RegisterTypeAndRevisions &type, const ElementNames &elementNames)
Definition qqml.cpp:759
static QTypeRevision resolveModuleVersion(int moduleMajor)
Definition qqml.cpp:382
static QQmlType::SingletonInstanceInfo::ConstPtr singletonInstanceInfo(const QQmlPrivate::RegisterSingletonType &type)
Definition qqml.cpp:664
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:739
void registerAliases(int typeId)
Definition qqml.cpp:741
const QMetaObject * metaObject
Definition qqml.cpp:1388