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 for (QTypeRevision revision : QList<QTypeRevision>(*revisions)) { // yes, copy
637 // allow any minor version for each explicitly specified past major one
638 if (revision.hasMajorVersion()) {
639 revisionsHaveMajorVersions = true;
640 if (revision.majorVersion() < defaultVersion.majorVersion())
641 revisions->append(QTypeRevision::fromVersion(revision.majorVersion(), 254));
642 }
643 }
644
645 if (revisionsHaveMajorVersions) {
646 if (!added.hasMajorVersion()) {
647 // If added in unspecified major version, assume default one.
648 revisions->append(QTypeRevision::fromVersion(defaultVersion.majorVersion(),
649 added.minorVersion()));
650 } else if (added.majorVersion() < defaultVersion.majorVersion()) {
651 // If added in past major version, add .0 of default version.
652 revisions->append(QTypeRevision::fromVersion(defaultVersion.majorVersion(), 0));
653 }
654 }
655
656 std::sort(revisions->begin(), revisions->end());
657 const auto it = std::unique(revisions->begin(), revisions->end());
658 revisions->erase(it, revisions->end());
659}
660
662 const QQmlPrivate::RegisterSingletonType &type)
663{
664 QQmlType::SingletonInstanceInfo::Ptr siinfo = QQmlType::SingletonInstanceInfo::create();
665 siinfo->scriptCallback = type.scriptApi;
666 siinfo->qobjectCallback = type.qObjectApi;
667 siinfo->typeName = type.typeName;
668 return QQmlType::SingletonInstanceInfo::ConstPtr(
669 siinfo.take(), QQmlType::SingletonInstanceInfo::ConstPtr::Adopt);
670}
671
673 const QQmlPrivate::RegisterCompositeSingletonType &type)
674{
675 QQmlType::SingletonInstanceInfo::Ptr siinfo = QQmlType::SingletonInstanceInfo::create();
676 siinfo->url = QQmlMetaType::normalizedUrl(type.url);
677 siinfo->typeName = type.typeName;
678 return QQmlType::SingletonInstanceInfo::ConstPtr(
679 siinfo.take(), QQmlType::SingletonInstanceInfo::ConstPtr::Adopt);
680}
681
682static int finalizeType(const QQmlType &dtype)
683{
684 if (!dtype.isValid())
685 return -1;
686
687 QQmlMetaType::registerUndeletableType(dtype);
688 return dtype.index();
689}
690
691using ElementNames = QVarLengthArray<const char *, 8>;
692static ElementNames classElementNames(const QMetaObject *metaObject)
693{
694 Q_ASSERT(metaObject);
695 const char *key = "QML.Element";
696
697 const int offset = metaObject->classInfoOffset();
698 const int start = metaObject->classInfoCount() + offset - 1;
699
700 ElementNames elementNames;
701
702 for (int i = start; i >= offset; --i) {
703 const QMetaClassInfo classInfo = metaObject->classInfo(i);
704 if (qstrcmp(key, classInfo.name()) == 0) {
705 const char *elementName = classInfo.value();
706
707 if (qstrcmp(elementName, "auto") == 0) {
708 const char *strippedClassName = metaObject->className();
709 for (const char *c = strippedClassName; *c != '\0'; c++) {
710 if (*c == ':')
711 strippedClassName = c + 1;
712 }
713 elementName = strippedClassName;
714 } else if (qstrcmp(elementName, "anonymous") == 0) {
715 if (elementNames.isEmpty())
716 elementNames.push_back(nullptr);
717 else if (elementNames[0] != nullptr)
718 qWarning() << metaObject->className() << "is both anonymous and named";
719 continue;
720 }
721
722 if (!elementNames.isEmpty() && elementNames[0] == nullptr) {
723 qWarning() << metaObject->className() << "is both anonymous and named";
724 elementNames[0] = elementName;
725 } else {
726 elementNames.push_back(elementName);
727 }
728 }
729 }
730
731 return elementNames;
732}
733
735{
736 AliasRegistrar(const ElementNames *elementNames) : elementNames(elementNames) {}
737
738 void registerAliases(int typeId)
739 {
740 if (elementNames) {
741 for (int i = 1, end = elementNames->length(); i < end; ++i)
742 otherNames.append(QString::fromUtf8(elementNames->at(i)));
743 elementNames = nullptr;
744 }
745
746 for (const QString &otherName : std::as_const(otherNames))
747 QQmlMetaType::registerTypeAlias(typeId, otherName);
748 }
749
750private:
751 const ElementNames *elementNames;
752 QVarLengthArray<QString, 8> otherNames;
753};
754
755
757 const QQmlPrivate::RegisterTypeAndRevisions &type,
758 const ElementNames &elementNames)
759{
760 using namespace QQmlPrivate;
761
762 const bool isValueType = !(type.typeId.flags() & QMetaType::PointerToQObject);
763 const bool creatable = (elementNames[0] != nullptr || isValueType)
764 && boolClassInfo(type.classInfoMetaObject, "QML.Creatable", true);
765
766 QString noCreateReason;
767 ValueTypeCreationMethod creationMethod = ValueTypeCreationMethod::None;
768
769 if (!creatable) {
770 noCreateReason = QString::fromUtf8(
771 classInfo(type.classInfoMetaObject, "QML.UncreatableReason"));
772 if (noCreateReason.isEmpty())
773 noCreateReason = QLatin1String("Type cannot be created in QML.");
774 } else if (isValueType) {
775 const char *method = classInfo(type.classInfoMetaObject, "QML.CreationMethod");
776 if (qstrcmp(method, "structured") == 0)
777 creationMethod = ValueTypeCreationMethod::Structured;
778 else if (qstrcmp(method, "construct") == 0)
779 creationMethod = ValueTypeCreationMethod::Construct;
780 }
781
782 RegisterType typeRevision = {
783 QQmlPrivate::RegisterType::CurrentVersion,
784 type.typeId,
785 type.listId,
786 creatable ? type.objectSize : 0,
787 nullptr,
788 nullptr,
789 noCreateReason,
790 type.createValueType,
791 type.uri,
792 type.version,
793 nullptr,
794 type.metaObject,
795 type.attachedPropertiesFunction,
796 type.attachedPropertiesMetaObject,
797 type.parserStatusCast,
798 type.valueSourceCast,
799 type.valueInterceptorCast,
800 type.extensionObjectCreate,
801 type.extensionMetaObject,
802 nullptr,
803 QTypeRevision(),
804 type.structVersion > 0 ? type.finalizerCast : -1,
805 creationMethod
806 };
807
808 QQmlPrivate::RegisterSequentialContainer sequenceRevision = {
809 0,
810 type.uri,
811 type.version,
812 nullptr,
813 type.listId,
814 type.structVersion > 1 ? type.listMetaSequence : QMetaSequence(),
815 QTypeRevision(),
816 };
817
818 const QTypeRevision added = revisionClassInfo(
819 type.classInfoMetaObject, "QML.AddedInVersion",
820 QTypeRevision::fromVersion(type.version.majorVersion(), 0));
821 const QTypeRevision removed = revisionClassInfo(
822 type.classInfoMetaObject, "QML.RemovedInVersion");
823 const QList<QTypeRevision> furtherRevisions = revisionClassInfos(type.classInfoMetaObject,
824 "QML.ExtraVersion");
825
826 auto revisions = prepareRevisions(type.metaObject, added) + furtherRevisions;
827 if (type.attachedPropertiesMetaObject)
828 revisions += availableRevisions(type.attachedPropertiesMetaObject);
829 uniqueRevisions(&revisions, type.version, added);
830
831 AliasRegistrar aliasRegistrar(&elementNames);
832 for (QTypeRevision revision : std::as_const(revisions)) {
833 if (revision.hasMajorVersion() && revision.majorVersion() > type.version.majorVersion())
834 break;
835
836 assignVersions(&typeRevision, revision, type.version);
837
838 // When removed or before added, we still add revisions, but anonymous ones
839 if (typeRevision.version < added
840 || (removed.isValid() && !(typeRevision.version < removed))) {
841 typeRevision.elementName = nullptr;
842 typeRevision.create = nullptr;
843 typeRevision.userdata = nullptr;
844 } else {
845 typeRevision.elementName = elementNames[0];
846 typeRevision.create = creatable ? type.create : nullptr;
847 typeRevision.userdata = type.userdata;
848 }
849
850 typeRevision.customParser = type.customParserFactory();
851 const int id = qmlregister(TypeRegistration, &typeRevision);
852 if (type.qmlTypeIds)
853 type.qmlTypeIds->append(id);
854
855 if (typeRevision.elementName)
856 aliasRegistrar.registerAliases(id);
857
858 if (sequenceRevision.metaSequence != QMetaSequence()) {
859 sequenceRevision.version = typeRevision.version;
860 sequenceRevision.revision = typeRevision.revision;
861 const int id = QQmlPrivate::qmlregister(
862 QQmlPrivate::SequentialContainerRegistration, &sequenceRevision);
863 if (type.qmlTypeIds)
864 type.qmlTypeIds->append(id);
865 }
866 }
867}
868
870 const QQmlPrivate::RegisterSingletonTypeAndRevisions &type,
871 const ElementNames &elementNames)
872{
873 using namespace QQmlPrivate;
874
875 RegisterSingletonType revisionRegistration = {
876 0,
877 type.uri,
878 type.version,
879 elementNames[0],
880 nullptr,
881 type.qObjectApi,
882 type.instanceMetaObject,
883 type.typeId,
884 type.extensionObjectCreate,
885 type.extensionMetaObject,
886 QTypeRevision()
887 };
888 const QQmlType::SingletonInstanceInfo::ConstPtr siinfo
889 = singletonInstanceInfo(revisionRegistration);
890
891 const QTypeRevision added = revisionClassInfo(
892 type.classInfoMetaObject, "QML.AddedInVersion",
893 QTypeRevision::fromVersion(type.version.majorVersion(), 0));
894 const QTypeRevision removed = revisionClassInfo(
895 type.classInfoMetaObject, "QML.RemovedInVersion");
896 const QList<QTypeRevision> furtherRevisions = revisionClassInfos(type.classInfoMetaObject,
897 "QML.ExtraVersion");
898
899 auto revisions = prepareRevisions(type.instanceMetaObject, added) + furtherRevisions;
900 uniqueRevisions(&revisions, type.version, added);
901
902 AliasRegistrar aliasRegistrar(&elementNames);
903 for (QTypeRevision revision : std::as_const(revisions)) {
904 if (revision.hasMajorVersion() && revision.majorVersion() > type.version.majorVersion())
905 break;
906
907 assignVersions(&revisionRegistration, revision, type.version);
908
909 // When removed or before added, we still add revisions, but anonymous ones
910 if (revisionRegistration.version < added
911 || (removed.isValid() && !(revisionRegistration.version < removed))) {
912 revisionRegistration.typeName = nullptr;
913 revisionRegistration.qObjectApi = nullptr;
914 } else {
915 revisionRegistration.typeName = elementNames[0];
916 revisionRegistration.qObjectApi = type.qObjectApi;
917 }
918
919 const int id = finalizeType(
920 QQmlMetaType::registerSingletonType(revisionRegistration, siinfo));
921 if (type.qmlTypeIds)
922 type.qmlTypeIds->append(id);
923
924 if (revisionRegistration.typeName)
925 aliasRegistrar.registerAliases(id);
926 }
927}
928
929/*
930This method is "over generalized" to allow us to (potentially) register more types of things in
931the future without adding exported symbols.
932*/
933int QQmlPrivate::qmlregister(RegistrationType type, void *data)
934{
935 switch (type) {
936 case AutoParentRegistration:
937 return QQmlMetaType::registerAutoParentFunction(
938 *reinterpret_cast<RegisterAutoParent *>(data));
939 case QmlUnitCacheHookRegistration:
940 return QQmlMetaType::registerUnitCacheHook(
941 *reinterpret_cast<RegisterQmlUnitCacheHook *>(data));
942 case TypeAndRevisionsRegistration: {
943 const RegisterTypeAndRevisions &type = *reinterpret_cast<RegisterTypeAndRevisions *>(data);
944 if (type.structVersion > 1 && type.forceAnonymous) {
945 doRegisterTypeAndRevisions(type, {nullptr});
946 } else {
947 const ElementNames names = classElementNames(type.classInfoMetaObject);
948 if (names.isEmpty()) {
949 qWarning().nospace() << "Missing QML.Element class info for "
950 << type.classInfoMetaObject->className();
951 } else {
952 doRegisterTypeAndRevisions(type, names);
953 }
954
955 }
956 break;
957 }
958 case SingletonAndRevisionsRegistration: {
959 const RegisterSingletonTypeAndRevisions &type
960 = *reinterpret_cast<RegisterSingletonTypeAndRevisions *>(data);
961 const ElementNames names = classElementNames(type.classInfoMetaObject);
962 if (names.isEmpty()) {
963 qWarning().nospace() << "Missing QML.Element class info for "
964 << type.classInfoMetaObject->className();
965 } else {
966 doRegisterSingletonAndRevisions(type, names);
967 }
968 break;
969 }
970 case SequentialContainerAndRevisionsRegistration: {
971 const RegisterSequentialContainerAndRevisions &type
972 = *reinterpret_cast<RegisterSequentialContainerAndRevisions *>(data);
973 RegisterSequentialContainer revisionRegistration = {
974 0,
975 type.uri,
976 type.version,
977 nullptr,
978 type.typeId,
979 type.metaSequence,
980 QTypeRevision()
981 };
982
983 const QTypeRevision added = revisionClassInfo(
984 type.classInfoMetaObject, "QML.AddedInVersion",
985 QTypeRevision::fromMinorVersion(0));
986 QList<QTypeRevision> revisions = revisionClassInfos(
987 type.classInfoMetaObject, "QML.ExtraVersion");
988 revisions.append(added);
989 uniqueRevisions(&revisions, type.version, added);
990
991 for (QTypeRevision revision : std::as_const(revisions)) {
992 if (revision < added)
993 continue;
994 if (revision.hasMajorVersion() && revision.majorVersion() > type.version.majorVersion())
995 break;
996
997 assignVersions(&revisionRegistration, revision, type.version);
998 const int id = qmlregister(SequentialContainerRegistration, &revisionRegistration);
999 if (type.qmlTypeIds)
1000 type.qmlTypeIds->append(id);
1001 }
1002 break;
1003 }
1004 case TypeRegistration:
1005 return finalizeType(
1006 QQmlMetaType::registerType(*reinterpret_cast<RegisterType *>(data)));
1007 case InterfaceRegistration:
1008 return finalizeType(
1009 QQmlMetaType::registerInterface(*reinterpret_cast<RegisterInterface *>(data)));
1010 case SingletonRegistration:
1011 return finalizeType(QQmlMetaType::registerSingletonType(
1012 *reinterpret_cast<RegisterSingletonType *>(data),
1013 singletonInstanceInfo(*reinterpret_cast<RegisterSingletonType *>(data))));
1014 case CompositeRegistration:
1015 return finalizeType(QQmlMetaType::registerCompositeType(
1016 *reinterpret_cast<RegisterCompositeType *>(data)));
1017 case CompositeSingletonRegistration:
1018 return finalizeType(QQmlMetaType::registerCompositeSingletonType(
1019 *reinterpret_cast<RegisterCompositeSingletonType *>(data),
1020 singletonInstanceInfo(*reinterpret_cast<RegisterCompositeSingletonType *>(data))));
1021 case SequentialContainerRegistration:
1022 return finalizeType(QQmlMetaType::registerSequentialContainer(
1023 *reinterpret_cast<RegisterSequentialContainer *>(data)));
1024 default:
1025 return -1;
1026 }
1027
1028 return -1;
1029}
1030
1031void QQmlPrivate::qmlunregister(RegistrationType type, quintptr data)
1032{
1033 switch (type) {
1034 case AutoParentRegistration:
1035 QQmlMetaType::unregisterAutoParentFunction(reinterpret_cast<AutoParentFunction>(data));
1036 break;
1037 case QmlUnitCacheHookRegistration:
1038 QQmlMetaType::removeCachedUnitLookupFunction(
1039 reinterpret_cast<QmlUnitCacheLookupFunction>(data));
1040 break;
1041 case SequentialContainerRegistration:
1042 QQmlMetaType::unregisterSequentialContainer(data);
1043 break;
1044 case TypeRegistration:
1045 case InterfaceRegistration:
1046 case SingletonRegistration:
1047 case CompositeRegistration:
1048 case CompositeSingletonRegistration:
1049 QQmlMetaType::unregisterType(data);
1050 break;
1051 case TypeAndRevisionsRegistration:
1052 case SingletonAndRevisionsRegistration:
1053 case SequentialContainerAndRevisionsRegistration:
1054 // Currently unnecessary. We'd need a special data structure to hold
1055 // URI + majorVersion and then we'd iterate the minor versions, look up the
1056 // associated QQmlType objects by uri/elementName/major/minor and qmlunregister
1057 // each of them.
1058 Q_UNREACHABLE();
1059 break;
1060 }
1061}
1062
1063QList<QTypeRevision> QQmlPrivate::revisionClassInfos(const QMetaObject *metaObject,
1064 const char *key)
1065{
1066 QList<QTypeRevision> revisions;
1067 for (int index = indexOfOwnClassInfo(metaObject, key); index != -1;
1068 index = indexOfOwnClassInfo(metaObject, key, index - 1)) {
1069 revisions.push_back(QTypeRevision::fromEncodedVersion(
1070 QLatin1StringView(metaObject->classInfo(index).value()).toInt()));
1071 }
1072 return revisions;
1073}
1074
1075/*!
1076 \relates <qqml.h>
1077
1078 This function registers a type in the QML system with the name \a qmlName, in the type namespace imported from \a uri having the
1079 version number composed from \a versionMajor and \a versionMinor, but any attempt to instantiate the type
1080 will produce the given error \a message.
1081
1082 Normally, the types exported by a plugin should be fixed. However, if a C++ type is not available, you should
1083 at least "reserve" the QML type name, and give the user of the unavailable type a meaningful error message.
1084
1085 Returns the QML type id.
1086
1087 Example:
1088
1089 \code
1090 #ifdef NO_GAMES_ALLOWED
1091 qmlRegisterTypeNotAvailable("MinehuntCore", 0, 1, "Game", "Get back to work, slacker!");
1092 #else
1093 qmlRegisterType<MinehuntGame>("MinehuntCore", 0, 1, "Game");
1094 #endif
1095 \endcode
1096
1097 This will cause any QML which imports the "MinehuntCore" type namespace and attempts to use the type to produce an error message:
1098 \code
1099 fun.qml: Get back to work, slacker!
1100 Game {
1101 ^
1102 \endcode
1103
1104 Without this, a generic "Game is not a type" message would be given.
1105
1106 \sa QML_UNAVAILABLE, qmlRegisterUncreatableType(),
1107 {Choosing the Correct Integration Method Between C++ and QML}
1108*/
1109int qmlRegisterTypeNotAvailable(
1110 const char *uri, int versionMajor, int versionMinor,
1111 const char *qmlName, const QString &message)
1112{
1113 return qmlRegisterUncreatableType<QQmlTypeNotAvailable>(
1114 uri, versionMajor, versionMinor, qmlName, message);
1115}
1116
1117namespace QQmlPrivate {
1118template<>
1120 const char *uri, int versionMajor, const QMetaObject *classInfoMetaObject,
1121 QList<int> *qmlTypeIds, const QMetaObject *extension, bool)
1122{
1123 using T = QQmlTypeNotAvailable;
1124
1125 RegisterTypeAndRevisions type = {
1126 3,
1127 QmlMetaType<T>::self(),
1128 QmlMetaType<T>::list(),
1129 0,
1130 nullptr,
1131 nullptr,
1132 nullptr,
1133
1134 uri,
1135 QTypeRevision::fromMajorVersion(versionMajor),
1136
1137 &QQmlTypeNotAvailable::staticMetaObject,
1138 classInfoMetaObject,
1139
1140 attachedPropertiesFunc<T>(),
1141 attachedPropertiesMetaObject<T>(),
1142
1143 StaticCastSelector<T, QQmlParserStatus>::cast(),
1144 StaticCastSelector<T, QQmlPropertyValueSource>::cast(),
1145 StaticCastSelector<T, QQmlPropertyValueInterceptor>::cast(),
1146
1147 nullptr,
1148 extension,
1149 qmlCreateCustomParser<T>,
1150 qmlTypeIds,
1151 QQmlPrivate::StaticCastSelector<T, QQmlFinalizerHook>::cast(),
1152 false,
1153 QmlMetaType<T>::sequence(),
1154 };
1155
1156 qmlregister(TypeAndRevisionsRegistration, &type);
1157}
1158
1160
1162{
1163 return static_cast<QV4::MetaTypesStackFrame *>(engine->handle()->currentStackFrame)
1164 ->thisObject();
1165}
1166
1168{
1169 return engine->handle()->qmlEngine();
1170}
1171
1172static QQmlPropertyCapture *propertyCapture(const AOTCompiledContext *aotContext)
1173{
1174 QQmlEngine *engine = aotContext->qmlEngine();
1175 return engine ? QQmlEnginePrivate::get(aotContext->qmlEngine())->propertyCapture : nullptr;
1176}
1177
1183
1189
1194
1196{
1197 if (auto *frame = engine->handle()->currentStackFrame) {
1200 }
1201}
1202
1207
1208static bool markPointer(const QVariant &element, QV4::MarkStack *markStack)
1209{
1210 if (!element.metaType().flags().testFlag(QMetaType::PointerToQObject))
1211 return false;
1212
1213 QV4::QObjectWrapper::markWrapper(
1214 *static_cast<QObject *const *>(element.constData()), markStack);
1215 return true;
1216}
1217
1218static void iterateVariant(const QVariant &element, std::vector<QVariant> *elements)
1219{
1220#define ADD_CASE(Type, id, T)
1221 case QMetaType::Type:
1222
1223 const QMetaType elementMetaType = element.metaType();
1224 switch (elementMetaType.id()) {
1225 case QMetaType::QVariantMap:
1226 for (const QVariant &variant : *static_cast<const QVariantMap *>(element.constData()))
1227 elements->push_back(variant);
1228 return;
1229 case QMetaType::QVariantHash:
1230 for (const QVariant &variant : *static_cast<const QVariantHash *>(element.constData()))
1231 elements->push_back(variant);
1232 return;
1233 case QMetaType::QVariantList:
1234 for (const QVariant &variant : *static_cast<const QVariantList *>(element.constData()))
1235 elements->push_back(variant);
1236 return;
1237 QT_FOR_EACH_STATIC_PRIMITIVE_TYPE(ADD_CASE)
1238 QT_FOR_EACH_STATIC_CORE_CLASS(ADD_CASE)
1239 QT_FOR_EACH_STATIC_GUI_CLASS(ADD_CASE)
1240 case QMetaType::QStringList:
1241 case QMetaType::QByteArrayList:
1242 return;
1243 default:
1244 break;
1245 }
1246
1247 if (elementMetaType == QMetaType::fromType<QJSValue>()
1248 || elementMetaType == QMetaType::fromType<QJSManagedValue>()
1249 || elementMetaType == QMetaType::fromType<QJSPrimitiveValue>()) {
1250 // QJSValue and QJSManagedValue effectively hold persistent values anyway.
1251 // QJSPrimitiveValue can only hold primitives or QString.
1252 return;
1253 }
1254
1255 QMetaSequence::Iterable iterable;
1256 if (!QMetaType::convert(
1257 element.metaType(), element.constData(),
1258 QMetaType::fromType<QMetaSequence::Iterable>(), &iterable)) {
1259 return;
1260 }
1261
1262 switch (iterable.metaContainer().valueMetaType().id()) {
1263 QT_FOR_EACH_STATIC_PRIMITIVE_TYPE(ADD_CASE)
1264 QT_FOR_EACH_STATIC_CORE_CLASS(ADD_CASE)
1265 QT_FOR_EACH_STATIC_GUI_CLASS(ADD_CASE)
1266 case QMetaType::QStringList:
1267 case QMetaType::QByteArrayList:
1268 return;
1269 default:
1270 break;
1271 }
1272
1273 for (auto it = iterable.constBegin(), end = iterable.constEnd(); it != end; ++it)
1274 elements->push_back(*it);
1275
1276#undef ADD_CASE
1277}
1278
1280{
1282 return;
1283
1286
1287 while (!stack.empty()) {
1288 const QVariant element = std::as_const(stack).back();
1289 stack.pop_back();
1292 }
1293}
1294
1305
1316
1317static bool inherits(const QQmlPropertyCache *descendent, const QQmlPropertyCache *ancestor)
1318{
1319 for (const QQmlPropertyCache *cache = descendent; cache; cache = cache->parent().data()) {
1320 if (cache == ancestor)
1321 return true;
1322 }
1323 return false;
1324}
1325
1327
1333
1334template<bool StrictType>
1352
1353template<bool StrictType = false>
1370
1371template<bool StrictType = false>
1381
1388
1390{
1391 // We've just initialized the lookup. So everything must be fine here.
1392
1394
1397
1398 const QMetaObject *metaObject
1399 = reinterpret_cast<const QMetaObject *>(lookup->qobjectFallbackLookup.metaObject - 1);
1401
1402 return {qmlData, metaObject, PropertyResult::OK};
1403}
1404
1424
1437
1449
1460
1473
1485
1486template<bool StrictType, typename Op>
1499
1500template<bool StrictType = false>
1503{
1505 if (property->isResettable()) {
1507 } else {
1508 v4->throwError(
1509 QLatin1String("Cannot assign [undefined] to ") +
1511 }
1512 });
1513}
1514
1515template<bool StrictType = false>
1522
1523template<typename Op>
1537
1539{
1541 lookup, object, [&](const QMetaObject *metaObject, int coreIndex) {
1542 void *args[] = { value, nullptr };
1544 });
1545}
1546
1549{
1551 lookup, object, [&](const QMetaObject *metaObject, int coreIndex) {
1553 void *args[] = { nullptr };
1555 } else {
1556 const QMetaType propType(reinterpret_cast<const QtPrivate::QMetaTypeInterface *>(
1558 v4->throwError(
1559 QLatin1String("Cannot assign [undefined] to ") +
1561 }
1562 });
1563}
1564
1565static bool isEnumUnderlyingType(QMetaType enumType, QMetaType numberType)
1566{
1567 // You can pass the underlying type of an enum.
1568 // We don't want to check for the actual underlying type because
1569 // moc and qmltyperegistrar are not very precise about it. Especially
1570 // the long and longlong types can be ambiguous.
1571
1572 const bool isUnsigned = enumType.flags() & QMetaType::IsUnsignedEnumeration;
1573 switch (enumType.sizeOf()) {
1574 case 1:
1575 return isUnsigned
1576 ? numberType == QMetaType::fromType<quint8>()
1577 : numberType == QMetaType::fromType<qint8>();
1578 case 2:
1579 return isUnsigned
1580 ? numberType == QMetaType::fromType<ushort>()
1581 : numberType == QMetaType::fromType<short>();
1582 case 4:
1583 // The default type, if moc doesn't know the actual enum type, is int.
1584 // However, the compiler can still decide to encode the enum in uint.
1585 // Therefore, we also accept int for uint enums.
1586 // TODO: This is technically UB.
1587 return isUnsigned
1588 ? (numberType == QMetaType::fromType<int>()
1589 || numberType == QMetaType::fromType<uint>())
1590 : numberType == QMetaType::fromType<int>();
1591 case 8:
1592 return isUnsigned
1593 ? numberType == QMetaType::fromType<qulonglong>()
1594 : numberType == QMetaType::fromType<qlonglong>();
1595 }
1596
1597 return false;
1598}
1599
1600static bool canHoldVoid(QMetaType type)
1601{
1602 // We cannot directly store void, but we can put it into QVariant or QJSPrimitiveValue
1603 return !type.isValid()
1604 || type == QMetaType::fromType<QVariant>()
1605 || type == QMetaType::fromType<QJSPrimitiveValue>();
1606}
1607
1608static bool isTypeCompatible(QMetaType source, QMetaType target)
1609{
1610 if (source == target)
1611 return true;
1612
1613 if ((source.flags() & QMetaType::IsQmlList)
1614 && (target.flags() & QMetaType::IsQmlList)) {
1615 // We want to check the value types here, but we cannot easily do it.
1616 // Internally those are all QObject* lists, though.
1617 return true;
1618 }
1619
1620 if (target.flags() & QMetaType::PointerToQObject) {
1621 // We accept any derived class, too
1622
1623 const QMetaObject *targetMetaObject = target.metaObject();
1624 const QMetaObject *sourceMetaObject = source.metaObject();
1625 if (!sourceMetaObject)
1626 sourceMetaObject = QQmlMetaType::metaObjectForType(source).metaObject();
1627
1628 while (sourceMetaObject && sourceMetaObject != targetMetaObject)
1629 sourceMetaObject = sourceMetaObject->superClass();
1630
1631 return sourceMetaObject != nullptr;
1632 }
1633
1634 if (target.flags() & QMetaType::IsEnumeration)
1635 return isEnumUnderlyingType(target, source);
1636
1637 if (source.flags() & QMetaType::IsEnumeration)
1638 return isEnumUnderlyingType(source, target);
1639
1640 if (!source.isValid())
1641 return canHoldVoid(target);
1642
1643 return false;
1644}
1645
1677
1705
1711
1712template<QV4::Lookup::Call FallbackCall>
1714 const AOTCompiledContext *aotContext, QV4::Lookup *lookup, QObject *object)
1715{
1716 QV4::Scope scope(aotContext->engine->handle());
1717 QV4::PropertyKey id = scope.engine->identifierTable->asPropertyKey(
1718 aotContext->compilationUnit->runtimeStrings[lookup->nameIndex]);
1719
1720 Q_ASSERT(id.isString());
1721
1722 QV4::ScopedString name(scope, id.asStringOrSymbol());
1723
1724 Q_ASSERT(!name->equals(scope.engine->id_toString()));
1725 Q_ASSERT(!name->equals(scope.engine->id_destroy()));
1726
1727 QQmlData *ddata = QQmlData::get(object, true);
1728 Q_ASSERT(ddata);
1729 if (ddata->isQueuedForDeletion)
1731
1732 const QQmlPropertyData *property;
1733 if (!ddata->propertyCache) {
1734 property = QQmlPropertyCache::property(object, name, aotContext->qmlContext, nullptr);
1735 } else {
1736 property = ddata->propertyCache->property(
1737 name.getPointer(), object, aotContext->qmlContext);
1738 }
1739
1740 if (!property) {
1741 const QMetaObject *metaObject = object->metaObject();
1742 if (!metaObject)
1744
1745 const int coreIndex = metaObject->indexOfProperty(
1746 name->toQStringNoThrow().toUtf8().constData());
1747 if (coreIndex < 0)
1749
1750 const QMetaProperty property = metaObject->property(coreIndex);
1751
1752 lookup->releasePropertyCache();
1753 // & 1 to tell the gc that this is not heap allocated; see markObjects in qv4lookup_p.h
1754 lookup->qobjectFallbackLookup.metaObject = quintptr(metaObject) + 1;
1755 lookup->qobjectFallbackLookup.metaType = quintptr(property.metaType().iface()) + 1;
1756 lookup->qobjectFallbackLookup.coreIndex = coreIndex;
1757 lookup->qobjectFallbackLookup.notifyIndex =
1758 QMetaObjectPrivate::signalIndex(property.notifySignal());
1759
1760 if constexpr (FallbackCall == QV4::Lookup::Call::ContextGetterScopeObjectPropertyFallback
1761 || FallbackCall == QV4::Lookup::Call::GetterQObjectPropertyFallback) {
1762 lookup->qobjectFallbackLookup.isConstantOrResettable = property.isConstant() ? 1 : 0;
1763 } else if constexpr (FallbackCall == QV4::Lookup::Call::SetterQObjectPropertyFallback) {
1764 lookup->qobjectFallbackLookup.isConstantOrResettable = property.isResettable() ? 1 : 0;
1765 }
1767 }
1768
1769 Q_ASSERT(ddata->propertyCache);
1770
1771 QV4::setupQObjectLookup(lookup, ddata, property);
1772
1774}
1775
1777template<QV4::Lookup::Call ObjectCall, QV4::Lookup::Call FallbackCall, LookupType Type>
1778void initObjectLookup(const AOTCompiledContext *aotContext, uint index, QObject *object)
1779{
1780 QV4::ExecutionEngine *v4 = aotContext->engine->handle();
1781 if (v4->hasException) {
1782 v4->amendException();
1783 return;
1784 }
1785
1786 QV4::Lookup *lookup = aotContext->compilationUnit->runtimeLookups + index;
1787 switch (initObjectLookup<FallbackCall>(aotContext, lookup, object)) {
1789 lookup->call = ObjectCall;
1790 lookup->asVariant = (Type == LookupType::Variant);
1791 break;
1793 lookup->call = FallbackCall;
1794 lookup->asVariant = (Type == LookupType::Variant);
1795 break;
1797 v4->throwTypeError();
1798 break;
1799 }
1800
1801 return;
1802}
1803
1804
1806 QV4::Lookup *lookup, QV4::ExecutableCompilationUnit *compilationUnit,
1807 const QMetaObject *metaObject)
1808{
1809 Q_ASSERT(metaObject);
1810 const QByteArray name = compilationUnit->runtimeStrings[lookup->nameIndex]->toQString().toUtf8();
1811 const int coreIndex = metaObject->indexOfProperty(name.constData());
1812 QMetaType lookupType = metaObject->property(coreIndex).metaType();
1813 lookup->qgadgetLookup.metaObject = quintptr(metaObject) + 1;
1814 lookup->qgadgetLookup.coreIndex = coreIndex;
1815 lookup->qgadgetLookup.metaType = lookupType.iface();
1816}
1817
1846
1870
1876
1878{
1879#if QT_CONFIG(translation)
1881#else
1882 return QString();
1883#endif
1884}
1885
1887{
1889 switch (lookup->call) {
1902 return QMetaType::fromType<QObject *>();
1905 // We can do this because the fallback lookup gets invalidated for every call.
1906 return QMetaType(reinterpret_cast<const QtPrivate::QMetaTypeInterface *>(
1908 }
1914 return QMetaType::fromType<void>();
1916 return QMetaType::fromType<QString>();
1917 default:
1919 }
1920 default:
1921 break;
1922 }
1923
1925}
1926
1927static bool isUndefined(const void *value, QMetaType type)
1928{
1929 if (type == QMetaType::fromType<QVariant>())
1930 return !static_cast<const QVariant *>(value)->isValid();
1931 if (type == QMetaType::fromType<QJSValue>())
1932 return static_cast<const QJSValue *>(value)->isUndefined();
1933 if (type == QMetaType::fromType<QJSPrimitiveValue>()) {
1934 return static_cast<const QJSPrimitiveValue *>(value)->type()
1935 == QJSPrimitiveValue::Undefined;
1936 }
1937 return false;
1938}
1939
1941{
1942 // We don't really use any part of the lookup machinery here.
1943 // The QV4::Lookup is created on the stack to conveniently get the property cache, and through
1944 // the property cache we store a value into the property.
1945
1946 const auto unwrapVariant = [&]() {
1947 if (type == QMetaType::fromType<QVariant>()) {
1948 QVariant *variant = static_cast<QVariant *>(value);
1949 type = variant->metaType();
1950 value = variant->data();
1951 }
1952 };
1953
1954 QV4::Lookup lookup;
1955 memset(&lookup, 0, sizeof(QV4::Lookup));
1957 lookup.forCall = false;
1960
1962 this, &lookup, qmlScopeObject)) {
1963 case ObjectLookupResult::Object: {
1967 } else if (isUndefined(value, type)) {
1968
1969 // NB: In order to have a meaningful reset() here, the type needs to be a wrapper type
1970 // that can hold undefined. For example QVariant. The caller must not unwrap it.
1971
1973 } else {
1974
1975 // Unwrap any QVariant so that we get a meaningful conversion below.
1976 unwrapVariant();
1977
1980 QV4::Scope scope(v4);
1985 }
1986 }
1987
1989 break;
1990 }
1992 propType = QMetaType(reinterpret_cast<const QtPrivate::QMetaTypeInterface *>(
1996 } else if (isUndefined(value, type)) {
1997
1998 // NB: In order to have a meaningful reset() here, the type needs to be a wrapper type
1999 // that can hold undefined. For example QVariant. The caller must not unwrap it.
2001
2002 } else {
2003
2004 // Unwrap any QVariant so that we get a meaningful conversion below.
2005 unwrapVariant();
2006
2009 QV4::Scope scope(v4);
2014 }
2015 }
2016 break;
2017 }
2020 return;
2021 }
2022
2023 switch (storeResult) {
2024 case PropertyResult::NeedsInit: {
2025 const QString error = QLatin1String("Cannot assign ") +
2027 QLatin1String(" to ") +
2030 break;
2031 }
2032 case PropertyResult::Deleted:
2034 QStringLiteral("Value is null and could not be converted to an object"));
2035 break;
2036 case PropertyResult::OK:
2037 break;
2038 }
2039}
2040
2048
2050{
2051 if (wrapper) {
2052 // We have to check this here because you may pass a plain QObject that only
2053 // turns out to be a QQmlLoggingCategoryBase at run time.
2057 *ok = true;
2058 if (!loggingCategory) {
2060 QStringLiteral("A QmlLoggingCatgory was provided without a valid name"));
2061 }
2062 return loggingCategory;
2063 }
2064 }
2065
2066 *ok = false;
2067 return qmlEngine() ? &lcQml() : &lcJs();
2068}
2069
2072{
2074
2076 Q_ASSERT(frame);
2077
2078 const QByteArray source(frame->source().toUtf8());
2082
2083 switch (type) {
2084 case QtDebugMsg:
2086 break;
2087 case QtInfoMsg:
2089 break;
2090 case QtWarningMsg:
2092 break;
2093 case QtCriticalMsg:
2095 break;
2096 default:
2097 break;
2098 }
2099}
2100
2108
2113
2118
2120 double year, double month, double day, double hours,
2121 double minutes, double seconds, double msecs) const
2122{
2125}
2126
2128 const QQmlType &type, const QV4::CompiledData::ParameterType &parameter)
2129{
2130 return parameter.isList() ? type.qListTypeId() : type.typeId();
2131}
2132
2143
2146 QObject *thisObject, void **args, int argc)
2147{
2148 // We need to re-fetch the method on every call because it can be shadowed.
2149
2153
2154 // The getter mustn't reset the isVariant flag
2156
2157 // Since we have an asVariant lookup, the function may have been overridden in the mean time.
2158 if (!function)
2159 return false;
2160
2161 Q_ALLOCA_VAR(QMetaType, types, (argc + 1) * sizeof(QMetaType));
2163
2165 return !scope.hasException();
2166}
2167
2170 QObject *thisObject, void **args, int argc)
2171{
2173
2174 Q_ALLOCA_VAR(QMetaType, types, (argc + 1) * sizeof(QMetaType));
2179 for (int i = 0; i < argc; ++i)
2181
2183 }
2184
2188 switch (method->methodIndex()) {
2190 return method->method_destroy(
2191 engine, thisObject, argc > 0 ? *static_cast<int *>(args[1]) : 0);
2195 thisObject);
2196 if (void *returnValue = args[0])
2197 *static_cast<QString *>(returnValue) = std::move(result);
2198 return true;
2199 }
2200 default:
2201 break;
2202 }
2203 return false;
2204}
2205
2208 QObject *thisObject, void **args, int argc)
2209{
2213
2214 switch (v4Function->kind) {
2215 case QV4::Function::AotCompiled: {
2218 return !engine->hasException;
2219 }
2220 case QV4::Function::JsTyped: {
2224
2225 Q_ALLOCA_VAR(QMetaType, types, (argc + 1) * sizeof(QMetaType));
2228 for (qsizetype i = 0; i != argc; ++i) {
2231 }
2232
2234 return !engine->hasException;
2235 }
2236 case QV4::Function::JsUntyped: {
2237 // We can call untyped functions if we're not expecting a specific return value and don't
2238 // have to pass any arguments. The compiler verifies this.
2239 Q_ASSERT(argc == 0);
2242 return !engine->hasException;
2243 }
2244 case QV4::Function::Eval:
2245 break;
2246 }
2247
2248 Q_UNREACHABLE_RETURN(false);
2249}
2250
2252 const AOTCompiledContext *aotContext, QV4::Lookup *lookup, const QString &object)
2253{
2254 aotContext->engine->handle()->throwTypeError(
2255 QStringLiteral("Property '%1' of object %2 is not a function").arg(
2256 aotContext->compilationUnit->runtimeStrings[lookup->nameIndex]->toQString(),
2257 object));
2258};
2259
2282
2284
2286 QV4::QObjectMethod *method, QV4::Lookup *lookup, int relativeMethodIndex)
2287{
2288 Q_ASSERT(lookup->qobjectMethodLookup.method.get() == method->d());
2289
2290 const auto *d = method->d();
2291 const int methodCount = d->methodCount;
2292
2293 if (relativeMethodIndex == -1 && methodCount == 1) {
2294 // QML-declared signals do not have a meaningful method index and cannot be overloaded.
2295 // They still show up as QObjectMethod rather than ArrowFunction. If they didn't, we
2296 // wouldn't have to care.
2297 Q_ASSERT(d->methods[0].metaMethod().methodType() == QMetaMethod::Signal);
2298 lookup->qobjectMethodLookup.propertyData = d->methods;
2299 return ExactMatch;
2300 }
2301
2302 for (int i = 0, end = d->methodCount; i != end; ++i) {
2303 const QMetaMethod metaMethod = d->methods[i].metaMethod();
2304 if (metaMethod.relativeMethodIndex() != relativeMethodIndex)
2305 continue;
2306
2307 lookup->qobjectMethodLookup.propertyData = d->methods + i;
2308 return ExactMatch;
2309 }
2310
2311 return NoMatch;
2312}
2313
2315{
2316 QV4::Heap::QObjectMethod *d = method->d();
2317 switch (method->methodIndex()) {
2320 return false;
2321 default:
2322 break;
2323 }
2324
2326 return true;
2327}
2328
2360
2362{
2364 int objectId = -1;
2365 QQmlContextData *context = nullptr;
2367
2368 switch (lookup->call) {
2372 break;
2378 if (objectId != -1 && objectId < context->numIdValues())
2379 break;
2380 }
2381 break;
2382 }
2383 default:
2384 return false;
2385 }
2386
2387 Q_ASSERT(objectId >= 0);
2388 Q_ASSERT(context != nullptr);
2392 *static_cast<QObject **>(target) = context->idValue(objectId);
2393 return true;
2394}
2395
2420
2422 uint index, QObject *object, void **args, int argc) const
2423{
2425
2426 if (!object) {
2427 engine->handle()->throwTypeError(QStringLiteral("Cannot call method '%1' of null")
2429 return false;
2430 }
2431
2432 switch (lookup->call) {
2435 return lookup->asVariant
2440 if (lookup->asVariant) {
2441 // If the method can be shadowed, the overridden method can be taken away, too.
2442 // In that case we might end up with a QObjectMethod or random other values instead.
2443 // callQObjectMethodAsVariant is flexible enough to handle that.
2445 }
2446
2447 // Here we always retrieve a fresh ArrowFunction via the getter.
2451
2452 // The getter mustn't touch the asVariant bit
2454
2455 if (function)
2457
2459 }
2460 default:
2461 break;
2462 }
2463
2464 return false;
2465}
2466
2468{
2469 if (engine->hasError()) {
2471 return;
2472 }
2473
2476
2477 const auto *ddata = QQmlData::get(object, false);
2479 // We cannot lookup functions on an object with VME metaobject but no QObjectWrapper
2480 throwIsNotAFunctionError(this, lookup, QStringLiteral("[object Object]"));
2481 return;
2482 }
2483
2486 if (auto *method = function->as<QV4::QObjectMethod>()) {
2488 lookup->asVariant = true;
2489 return;
2490 }
2491
2492 if (function->as<QV4::ArrowFunction>()) {
2493 // Can't have overloads of JavaScript functions.
2494 lookup->asVariant = true;
2495 return;
2496 }
2497
2499}
2500
2503{
2504 if (engine->hasError()) {
2506 return;
2507 }
2508
2511
2512 const auto *ddata = QQmlData::get(object, false);
2514 // We cannot lookup functions on an object with VME metaobject but no QObjectWrapper
2515 throwIsNotAFunctionError(this, lookup, QStringLiteral("[object Object]"));
2516 return;
2517 }
2518
2521 if (auto *method = function->as<QV4::QObjectMethod>()) {
2525 }
2526 return;
2527 }
2528
2529 if (function->as<QV4::ArrowFunction>()) {
2530 // Can't have overloads of JavaScript functions.
2531 return;
2532 }
2533
2535}
2536
2538{
2541 return false;
2545 val,
2548 return false;
2549 }
2550 return true;
2551}
2552
2563
2565{
2567
2568 if (!qmlScopeObject) {
2571 return false;
2572 }
2573
2575 switch (lookup->call) {
2578 break;
2582 break;
2583 default:
2584 return false;
2585 }
2586
2587 switch (result) {
2589 return false;
2590 case PropertyResult::Deleted:
2592 QStringLiteral("Cannot read property '%1' of null")
2594 return false;
2595 case PropertyResult::OK:
2596 return true;
2597 }
2598
2599 Q_UNREACHABLE_RETURN(false);
2600}
2601
2603{
2605
2607 switch (lookup->call) {
2610 break;
2614 break;
2615 default:
2616 return false;
2617 }
2618
2619 switch (result) {
2621 return false;
2622 case PropertyResult::Deleted: // Silently omit the write back. Same as interpreter
2623 case PropertyResult::OK:
2624 return true;
2625 }
2626
2627 Q_UNREACHABLE_RETURN(false);
2628}
2629
2630
2631
2639
2641{
2644
2648
2649 // We don't handle non-QObject singletons (as those can't be declared in qmltypes anyway)
2651 *static_cast<QObject **>(target) = wrapper->object();
2652 return true;
2653 }
2654
2655 return false;
2656}
2657
2660
2661template<QV4::Lookup::Call call>
2662static void initTypeWrapperLookup(
2663 const AOTCompiledContext *context, QV4::Lookup *lookup, uint importNamespace)
2664{
2665 Q_ASSERT(!context->engine->hasError());
2666 if (importNamespace != AOTCompiledContext::InvalidStringId) {
2667 QV4::Scope scope(context->engine->handle());
2668 QV4::ScopedString import(scope, context->compilationUnit->runtimeStrings[importNamespace]);
2669
2670 QQmlTypeLoader *typeLoader = scope.engine->typeLoader();
2671 Q_ASSERT(typeLoader);
2672 if (const QQmlImportRef *importRef
2673 = context->qmlContext->imports()->query(import, typeLoader).importNamespace) {
2674
2675 QV4::Scoped<QV4::QQmlTypeWrapper> wrapper(
2676 scope, QV4::QQmlTypeWrapper::create(
2677 scope.engine, nullptr, context->qmlContext->imports(), importRef));
2678
2679 // This is not a contextGetter since we actually load from the namespace.
2680 wrapper = lookup->getter(context->engine->handle(), wrapper);
2681
2682 // In theory, the getter may have populated the lookup's property cache.
2683 lookup->releasePropertyCache();
2684
2685 lookup->call = call;
2686 switch (call) {
2687 case QV4::Lookup::Call::ContextGetterSingleton:
2688 lookup->qmlContextSingletonLookup.singletonObject.set(scope.engine, wrapper->heapObject());
2689 break;
2690 case QV4::Lookup::Call::ContextGetterType:
2691 lookup->qmlTypeLookup.qmlTypeWrapper.set(scope.engine, wrapper->heapObject());
2692 break;
2693 default:
2694 break;
2695 }
2696 return;
2697 }
2698 scope.engine->throwTypeError();
2699 } else {
2700 QV4::ExecutionEngine *v4 = context->engine->handle();
2701 lookup->contextGetter(v4, nullptr);
2702 if (lookup->call != call) {
2703 const QString error
2704 = QLatin1String(call == QV4::Lookup::Call::ContextGetterSingleton
2705 ? "%1 was a singleton at compile time, "
2706 "but is not a singleton anymore."
2707 : "%1 was not a singleton at compile time, "
2708 "but is a singleton now.")
2709 .arg(context->compilationUnit->runtimeStrings[lookup->nameIndex]->toQString());
2710 v4->throwTypeError(error);
2711 }
2712 }
2713}
2719}
2733}
2766}
2769{
2772 return false;
2773
2774 const QV4::Heap::QQmlTypeWrapper *typeWrapper = static_cast<const QV4::Heap::QQmlTypeWrapper *>(
2776
2778 *static_cast<const QMetaObject **>(target)
2780 return true;
2781}
2787}
2790{
2792 const auto doThrow = [&]() {
2794 QStringLiteral("Cannot read property '%1' of null")
2796 return false;
2797 };
2798
2799 if (!object)
2800 return doThrow();
2801
2803 switch (lookup->call) {
2808 break;
2814 break;
2815 default:
2816 return false;
2817 }
2818
2819 switch (result) {
2820 case PropertyResult::Deleted:
2821 return doThrow();
2823 return false;
2824 case PropertyResult::OK:
2825 return true;
2826 }
2827
2828 Q_UNREACHABLE_RETURN(false);
2829}
2832{
2834 if (!object)
2835 return true;
2836
2838 switch (lookup->call) {
2843 break;
2849 break;
2850 default:
2851 return false;
2852 }
2853
2854 switch (result) {
2856 return false;
2857 case PropertyResult::Deleted: // Silently omit the write back
2858 case PropertyResult::OK:
2859 return true;
2860 }
2861
2862 Q_UNREACHABLE_RETURN(false);
2863}
2871}
2879}
2881bool AOTCompiledContext::getValueLookup(uint index, void *value, void *target) const
2882{
2883 Q_ASSERT(value);
2884
2887 return false;
2888
2889 const QMetaObject *metaObject
2890 = reinterpret_cast<const QMetaObject *>(lookup->qgadgetLookup.metaObject - 1);
2892
2893 void *args[] = { target, nullptr };
2895 reinterpret_cast<QObject*>(value), QMetaObject::ReadProperty,
2897 return true;
2898}
2901{
2902 Q_ASSERT(value);
2903
2906 return false;
2907
2908 const QMetaObject *metaObject
2909 = reinterpret_cast<const QMetaObject *>(lookup->qgadgetLookup.metaObject - 1);
2911
2912 void *args[] = { source, nullptr };
2914 reinterpret_cast<QObject*>(value), QMetaObject::WriteProperty,
2916 return true;
2917}
2925}
2928{
2931 return false;
2932 const bool isUnsigned
2936 case 1:
2937 if (isUnsigned)
2938 *static_cast<quint8 *>(target) = encoded;
2939 else
2940 *static_cast<qint8 *>(target) = encoded;
2941 return true;
2942 case 2:
2943 if (isUnsigned)
2944 *static_cast<quint16 *>(target) = encoded;
2945 else
2946 *static_cast<qint16 *>(target) = encoded;
2947 return true;
2948 case 4:
2949 if (isUnsigned)
2950 *static_cast<quint32 *>(target) = encoded;
2951 else
2952 *static_cast<qint32 *>(target) = encoded;
2953 return true;
2954 case 8:
2955 if (isUnsigned)
2956 *static_cast<quint64 *>(target) = encoded;
2957 else
2958 *static_cast<qint64 *>(target) = encoded;
2959 return true;
2960 default:
2961 break;
2962 }
2963
2964 return false;
2965}
2984}
2987{
2988 const auto doThrow = [&]() {
2990 QStringLiteral("Value is null and could not be converted to an object"));
2991 return false;
2992 };
2993
2994 if (!object)
2995 return doThrow();
2996
2999 switch (lookup->call) {
3004 break;
3010 break;
3011 default:
3012 return false;
3013 }
3014
3015 switch (result) {
3016 case PropertyResult::Deleted:
3017 return doThrow();
3019 return false;
3020 case PropertyResult::OK:
3021 return true;
3022 }
3023
3024 Q_UNREACHABLE_RETURN(false);
3025}
3033}
3041}
3043static PropertyResult storeValueProperty(
3044 QV4::Lookup *lookup, const QMetaObject *metaObject, void *target, void *value)
3045{
3046 void *args[] = { value, nullptr };
3047 metaObject->d.static_metacall(
3048 reinterpret_cast<QObject *>(target), QMetaObject::WriteProperty,
3049 lookup->qgadgetLookup.coreIndex, args);
3050 return PropertyResult::OK;
3051}
3053static PropertyResult resetValueProperty(
3054 QV4::Lookup *lookup, const QMetaObject *metaObject, void *target, QV4::ExecutionEngine *v4)
3055{
3056 const QMetaProperty property = metaObject->property(lookup->qgadgetLookup.coreIndex);
3057 if (property.isResettable()) {
3058 void *args[] = { nullptr };
3059 metaObject->d.static_metacall(
3060 reinterpret_cast<QObject *>(target), QMetaObject::ResetProperty,
3061 lookup->qgadgetLookup.coreIndex, args);
3062 } else {
3063 v4->throwError(
3064 QLatin1String("Cannot assign [undefined] to ") +
3065 QLatin1String(property.metaType().name()));
3066 }
3067
3068 return PropertyResult::OK;
3069}
3071static PropertyResult storeValueAsVariant(
3072 QV4::ExecutionEngine *v4, QV4::Lookup *lookup, const QMetaObject *metaObject,
3073 void *target, void *value)
3074{
3075 QVariant *variant = static_cast<QVariant *>(value);
3076 const QMetaType propType = metaObject->property(lookup->qgadgetLookup.coreIndex).metaType();
3077 if (propType == QMetaType::fromType<QVariant>())
3078 return storeValueProperty(lookup, metaObject, target, variant);
3079
3080 if (!variant->isValid())
3081 return resetValueProperty(lookup, metaObject, target, v4);
3082
3083 if (isTypeCompatible(variant->metaType(), propType))
3084 return storeValueProperty(lookup, metaObject, target, variant->data());
3085
3086 QVariant converted(propType);
3087 QV4::Scope scope(v4);
3088 QV4::ScopedValue val(scope, v4->fromVariant(*variant));
3089 if (v4->metaTypeFromJS(val, propType, converted.data())
3090 || QMetaType::convert(
3091 variant->metaType(), variant->constData(), propType, converted.data())) {
3092 return storeValueProperty(lookup, metaObject, target, converted.data());
3093 }
3094
3095 v4->throwError(
3096 QLatin1String("Cannot assign ") + QLatin1String(variant->metaType().name())
3097 + QLatin1String(" to ") + QLatin1String(propType.name()));
3098
3100}
3103 uint index, void *target, void *value) const
3104{
3107 return false;
3108
3109 const QMetaObject *metaObject
3110 = reinterpret_cast<const QMetaObject *>(lookup->qgadgetLookup.metaObject - 1);
3111
3115
3116 switch (result) {
3117 case PropertyResult::OK:
3118 return true;
3120 return false;
3121 case PropertyResult::Deleted:
3122 Q_UNREACHABLE();
3123 }
3124
3125 return false;
3126}
3127
3128template<LookupType Type>
3129void initValueLookup(
3130 const AOTCompiledContext *aotContext, uint index, const QMetaObject *metaObject)
3131{
3132 QV4::ExecutionEngine *v4 = aotContext->engine->handle();
3133 if (v4->hasException) {
3134 v4->amendException();
3135 return;
3136 }
3137
3138 QV4::Lookup *lookup = aotContext->compilationUnit->runtimeLookups + index;
3139 initValueLookup(lookup, aotContext->compilationUnit, metaObject);
3140 lookup->call = QV4::Lookup::Call::SetterValueTypeProperty;
3141 lookup->asVariant = (Type == LookupType::Variant);
3142}
3147}
3153}
3155bool AOTCompiledContext::callValueLookup(uint index, void *target, void **args, int argc) const
3156{
3157 Q_UNUSED(argc);
3158
3161 return false;
3162
3164
3165 const QMetaObject *metaObject
3166 = reinterpret_cast<const QMetaObject *>(lookup->qgadgetLookup.metaObject - 1);
3167
3169 reinterpret_cast<QObject *>(target), QMetaObject::InvokeMetaMethod,
3171
3172 return true;
3173}
3190}
3197}
3198
3199} // namespace QQmlPrivate
3200
3201/*!
3202 \macro QML_DECLARE_TYPE()
3203 \relates <qqml.h>
3204
3205 Equivalent to \c Q_DECLARE_METATYPE(TYPE *) and \c Q_DECLARE_METATYPE(QQmlListProperty<TYPE>)
3206*/
3207
3208/*!
3209 \macro QML_DECLARE_TYPEINFO(Type,Flags)
3210 \relates <qqml.h>
3211
3212 Declares additional properties of the given \a Type as described by the
3213 specified \a Flags.
3214
3215 Current the only supported type info is \c QML_HAS_ATTACHED_PROPERTIES which
3216 declares that the \a Type supports \l {Attached Properties and Attached Signal Handlers}
3217 {attached properties}. QML_DECLARE_TYPEINFO() is not necessary if \a Type contains the
3218 QML_ATTACHED macro.
3219*/
3220
3221/*!
3222 \fn template <typename T> int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const char *qmlName)
3223 \relates <qqml.h>
3224
3225 This template function registers the C++ type in the QML system with
3226 the name \a qmlName, in the library imported from \a uri having the
3227 version number composed from \a versionMajor and \a versionMinor.
3228
3229 Returns the QML type id.
3230
3231 There are two forms of this template function:
3232
3233 \code
3234 template<typename T>
3235 int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const char *qmlName);
3236
3237 template<typename T, int metaObjectRevision>
3238 int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const char *qmlName);
3239 \endcode
3240
3241 The former is the standard form which registers the type \e T as a new type.
3242 The latter allows a particular revision of a class to be registered in
3243 a specified version (see \l {Type Revisions and Versions}).
3244
3245
3246 For example, this registers a C++ class \c MySliderItem as a QML type
3247 named \c Slider for version 1.0 of a type namespace called
3248 "com.mycompany.qmlcomponents":
3249
3250 \code
3251 qmlRegisterType<MySliderItem>("com.mycompany.qmlcomponents", 1, 0, "Slider");
3252 \endcode
3253
3254 Once this is registered, the type can be used in QML by importing the
3255 specified type namespace and version number:
3256
3257 \qml
3258 import com.mycompany.qmlcomponents 1.0
3259
3260 Slider {
3261 // ...
3262 }
3263 \endqml
3264
3265 Note that it's perfectly reasonable for a library to register types to older versions
3266 than the actual version of the library. Indeed, it is normal for the new library to allow
3267 QML written to previous versions to continue to work, even if more advanced versions of
3268 some of its types are available.
3269
3270 \sa QML_ELEMENT, QML_NAMED_ELEMENT(),
3271 {Choosing the Correct Integration Method Between C++ and QML}
3272*/
3273
3274/*!
3275 \fn template<typename T, int metaObjectRevision> int qmlRegisterRevision(const char *uri, int versionMajor, int versionMinor)
3276 \relates <qqml.h>
3277
3278 This template function registers the C++ type \a T at the specified revision
3279 \a metaObjectRevision in the QML system with the library imported from \a uri
3280 having the version number composed from \a versionMajor and \a versionMinor.
3281
3282 Returns the QML type id.
3283
3284 \code
3285 template<typename T, int metaObjectRevision>
3286 int qmlRegisterRevision(const char *uri, int versionMajor, int versionMinor);
3287 \endcode
3288
3289 This function is typically used to register the revision of a base class to
3290 use for the specified version of the type (see \l {Type Revisions and Versions}).
3291*/
3292
3293/*!
3294 \fn template <typename T> int qmlRegisterUncreatableType(const char *uri, int versionMajor, int versionMinor, const char *qmlName, const QString& message)
3295 \relates <qqml.h>
3296
3297 This template function registers the C++ type in the QML system with
3298 the name \a qmlName, in the library imported from \a uri having the
3299 version number composed from \a versionMajor and \a versionMinor.
3300
3301 While the type has a name and a type, it cannot be created, and the
3302 given error \a message will result if creation is attempted.
3303
3304 This is useful where the type is only intended for providing attached properties or enum values.
3305
3306 Returns the QML type id.
3307
3308 \sa QML_UNCREATABLE(), qmlRegisterTypeNotAvailable(),
3309 {Choosing the Correct Integration Method Between C++ and QML}
3310*/
3311
3312/*!
3313 \fn template <typename T, typename E> int qmlRegisterExtendedType(const char *uri, int versionMajor, int versionMinor, const char *qmlName)
3314 \relates <qqml.h>
3315
3316 This template function registers the C++ type and its extension object in the
3317 QML system with the name \a qmlName in the library imported from \a uri having
3318 version number composed from \a versionMajor and \a versionMinor. Properties
3319 not available in the main type will be searched for in the extension object.
3320
3321 Returns the QML type id.
3322
3323 \sa QML_EXTENDED(), qmlRegisterType(), {Registering Extension Objects}
3324*/
3325
3326/*!
3327 \fn template <typename T, typename E> int qmlRegisterExtendedUncreatableType(const char *uri, int versionMajor, int versionMinor, const char *qmlName, const QString& reason)
3328 \relates <qqml.h>
3329
3330 This template function registers the C++ type and its extension
3331 in the QML system with the name \a qmlName in the library imported
3332 from \a uri having version number composed from \a versionMajor and
3333 \a versionMinor.
3334
3335 While the type has a name and a type, it cannot be created. An error
3336 message with the given \a reason is printed if the user attempts to
3337 create an instance of this type.
3338
3339 This is useful where the type is only intended for providing attached
3340 properties, enum values or an abstract base class with its extension.
3341
3342 Returns the QML type id.
3343
3344 \sa QML_EXTENDED(), QML_UNCREATABLE(), qmlRegisterUncreatableType()
3345*/
3346
3347/*!
3348 \fn int qmlRegisterCustomExtendedType(const char *uri, int versionMajor, int versionMinor, const char *qmlName, QQmlCustomParser *parser)
3349 \relates <qqml.h>
3350 \internal
3351
3352 This template function registers the C++ type and its extension
3353 in the QML system with the name \a qmlName in the library imported
3354 from \a uri having version number composed from \a versionMajor and
3355 \a versionMinor. Properties from the C++ type or its extension that
3356 cannot be resolved directly by the QML system will be resolved using
3357 the \a parser provided.
3358
3359 Returns the QML type id.
3360
3361 \sa QML_ELEMENT, QML_NAMED_ELEMENT(), QML_EXTENDED()
3362*/
3363
3364/*!
3365 \fn template <typename T> int qmlRegisterAnonymousType(const char *uri, int versionMajor)
3366 \relates <qqml.h>
3367
3368 This template function registers the C++ type in the QML system as an anonymous type. The
3369 resulting QML type does not have a name. Therefore, instances of this type cannot be created from
3370 the QML system. You can, however, access instances of the type when they are exposed as properties
3371 of other types.
3372
3373 Use this function when the type will not be referenced by name, specifically for C++ types that
3374 are used on the left-hand side of a property binding. To indicate to which module the type belongs
3375 use \a uri and \a versionMajor.
3376
3377 For example, consider the following two classes:
3378
3379 //! Workaround for MOC not respecting comments and triggering an error on certain Qt macros.
3380 \code Q
3381 class Bar : public QObject
3382 {
3383 \1_OBJECT
3384 Q_PROPERTY(QString baz READ baz WRITE setBaz NOTIFY bazChanged)
3385
3386 public:
3387 Bar() {}
3388
3389 QString baz() const { return mBaz; }
3390
3391 void setBaz(const QString &baz)
3392 {
3393 if (baz == mBaz)
3394 return;
3395
3396 mBaz = baz;
3397 emit bazChanged();
3398 }
3399
3400 signals:
3401 void bazChanged();
3402
3403 private:
3404 QString mBaz;
3405 };
3406
3407 class Foo : public QObject
3408 {
3409 \1_OBJECT
3410 Q_PROPERTY(Bar *bar READ bar CONSTANT FINAL)
3411
3412 public:
3413 Foo() {}
3414
3415 Bar *bar() { return &mBar; }
3416
3417 private:
3418 Bar mBar;
3419 };
3420 \endcode
3421
3422 In QML, we assign a string to the \c baz property of \c bar:
3423
3424 \code
3425 Foo {
3426 bar.baz: "abc"
3427 Component.onCompleted: print(bar.baz)
3428 }
3429 \endcode
3430
3431 For the QML engine to know that the \c Bar type has a \c baz property,
3432 we have to make \c Bar known:
3433
3434 \code
3435 qmlRegisterType<Foo>("App", 1, 0, "Foo");
3436 qmlRegisterAnonymousType<Bar>("App", 1);
3437 \endcode
3438
3439 As the \c Foo type is instantiated in QML, it must be registered
3440 with the version of \l qmlRegisterType() that takes an element name.
3441
3442 Returns the QML type id.
3443
3444 \since 5.14
3445 \sa QML_ANONYMOUS, {Choosing the Correct Integration Method Between C++ and QML}
3446*/
3447
3448/*!
3449 \fn int qmlRegisterInterface(const char *typeName)
3450 \relates <qqml.h>
3451
3452 This template function registers the C++ type in the QML system
3453 under the name \a typeName.
3454
3455 Types registered as an interface with the engine should also
3456 declare themselves as an interface with the
3457 \l {The Meta-Object System}{meta object system}. For example:
3458
3459 \code
3460 struct FooInterface
3461 {
3462 public:
3463 virtual ~FooInterface();
3464 virtual void doSomething() = 0;
3465 };
3466
3467 Q_DECLARE_INTERFACE(FooInterface, "org.foo.FooInterface")
3468 \endcode
3469
3470 When registered with the QML engine in this way, they can be used as
3471 property types:
3472
3473 Q_PROPERTY(FooInterface *foo READ foo WRITE setFoo)
3474
3475 When you assign a \l QObject sub-class to this property, the QML engine does
3476 the interface cast to \c FooInterface* automatically.
3477
3478 Returns the QML type id.
3479
3480 \sa QML_INTERFACE
3481*/
3482
3483/*!
3484 \fn int qmlRegisterSingletonType(const char *uri, int versionMajor, int versionMinor, const char *typeName, std::function<QJSValue(QQmlEngine *, QJSEngine *)> callback)
3485 \relates <qqml.h>
3486
3487 This function may be used to register a singleton type provider \a callback in a particular \a uri
3488 and \a typeName with a version specified in \a versionMajor and \a versionMinor.
3489
3490 Installing a singleton type allows developers to provide arbitrary functionality
3491 (methods and properties) to a client without requiring individual instances of the type to
3492 be instantiated by the client.
3493
3494 A singleton type may be either a QObject or a QJSValue.
3495 This function should be used to register a singleton type provider function which returns a QJSValue as a singleton type.
3496
3497 \b{NOTE:} QJSValue singleton type properties will \b{not} trigger binding re-evaluation if changed.
3498
3499 Usage:
3500 \code
3501 // First, define the singleton type provider function (callback).
3502 static QJSValue example_qjsvalue_singletontype_provider(QQmlEngine *engine, QJSEngine *scriptEngine)
3503 {
3504 Q_UNUSED(engine)
3505
3506 static int seedValue = 5;
3507 QJSValue example = scriptEngine->newObject();
3508 example.setProperty("someProperty", seedValue++);
3509 return example;
3510 }
3511
3512 // Second, register the singleton type provider with QML by calling this function in an initialization function.
3513 qmlRegisterSingletonType("Qt.example.qjsvalueApi", 1, 0, "MyApi", example_qjsvalue_singletontype_provider);
3514 \endcode
3515
3516 Alternatively, you can use a C++11 lambda:
3517
3518 \code
3519 qmlRegisterSingletonType("Qt.example.qjsvalueApi", 1, 0, "MyApi", [](QQmlEngine *engine, QJSEngine *scriptEngine) -> QJSValue {
3520 Q_UNUSED(engine)
3521
3522 static int seedValue = 5;
3523 QJSValue example = scriptEngine->newObject();
3524 example.setProperty("someProperty", seedValue++);
3525 return example;
3526 });
3527 \endcode
3528
3529 In order to use the registered singleton type in QML, you must import the singleton type.
3530 \qml
3531 import QtQuick 2.0
3532 import Qt.example.qjsvalueApi 1.0 as ExampleApi
3533 Item {
3534 id: root
3535 property int someValue: ExampleApi.MyApi.someProperty
3536 }
3537 \endqml
3538
3539 \sa QML_SINGLETON, {Choosing the Correct Integration Method Between C++ and QML}
3540*/
3541
3542/*!
3543 \fn template<typename T> QObject *qmlAttachedPropertiesObject(const QObject *attachee, bool createIfMissing)
3544 \relates <qqml.h>
3545
3546 The form of this template function is:
3547
3548 \code
3549 template<typename T> QObject *qmlAttachedPropertiesObject(const QObject *attachee, bool createIfMissing = true)
3550 \endcode
3551
3552 This returns the attached object instance that has been attached to the specified
3553 \a attachee by the attaching type \e T.
3554
3555 If \a attachee is \nullptr, returns \nullptr.
3556
3557 If an existing attached object instance of type \e T exists, it will return
3558 it. Otherwise, it will return a newly created instance if
3559 \a createIfMissing is \c true and \e T is a valid attaching type, or
3560 \nullptr if it's not.
3561
3562 \sa QML_ATTACHED(), {Providing Attached Properties}
3563*/
3564
3565/*!
3566 \fn template <typename T> int qmlRegisterSingletonType(const char *uri, int versionMajor, int versionMinor, const char *typeName, std::function<QObject*(QQmlEngine *, QJSEngine *)> callback)
3567 \relates <qqml.h>
3568
3569 This function may be used to register a singleton type provider \a callback in a particular \a uri
3570 and \a typeName with a version specified in \a versionMajor and \a versionMinor.
3571
3572 Installing a singleton type into a uri allows developers to provide arbitrary functionality
3573 (methods and properties) to clients without requiring individual instances ot the type to be
3574 instantiated by the client.
3575
3576 A singleton type may be either a QObject or a QJSValue.
3577 This function should be used to register a singleton type provider function which returns a QObject
3578 of the given type T as a singleton type.
3579
3580 A QObject singleton type may be referenced via the type name with which it was registered, and this
3581 typename may be used as the target in a \l Connections type or otherwise used as any other type id would.
3582 One exception to this is that a QObject singleton type property may not be aliased.
3583
3584 \b{NOTE:} A QObject singleton type instance returned from a singleton type provider is owned by
3585 the QML engine unless the object has explicit QQmlEngine::CppOwnership flag set.
3586
3587 Usage:
3588 //! Workaround for MOC not respecting comments and triggering an error on certain Qt macros.
3589 \code Q
3590 // First, define your QObject which provides the functionality.
3591 class SingletonTypeExample : public QObject
3592 {
3593 \1_OBJECT
3594 Q_PROPERTY (int someProperty READ someProperty WRITE setSomeProperty NOTIFY somePropertyChanged)
3595
3596 public:
3597 SingletonTypeExample(QObject *parent = nullptr)
3598 : QObject(parent), m_someProperty(0)
3599 {
3600 }
3601
3602 ~SingletonTypeExample() {}
3603
3604 Q_INVOKABLE int doSomething() { setSomeProperty(5); return m_someProperty; }
3605
3606 int someProperty() const { return m_someProperty; }
3607 void setSomeProperty(int val) { m_someProperty = val; emit somePropertyChanged(val); }
3608
3609 signals:
3610 void somePropertyChanged(int newValue);
3611
3612 private:
3613 int m_someProperty;
3614 };
3615
3616 // Second, define the singleton type provider function (callback).
3617 static QObject *example_qobject_singletontype_provider(QQmlEngine *engine, QJSEngine *scriptEngine)
3618 {
3619 Q_UNUSED(engine)
3620 Q_UNUSED(scriptEngine)
3621
3622 SingletonTypeExample *example = new SingletonTypeExample();
3623 return example;
3624 }
3625
3626 // Third, register the singleton type provider with QML by calling this function in an initialization function.
3627 qmlRegisterSingletonType<SingletonTypeExample>("Qt.example.qobjectSingleton", 1, 0, "MyApi", example_qobject_singletontype_provider);
3628 \endcode
3629
3630 Alternatively, you can use a C++11 lambda:
3631
3632 \code
3633 qmlRegisterSingletonType<SingletonTypeExample>("Qt.example.qobjectSingleton", 1, 0, "MyApi", [](QQmlEngine *engine, QJSEngine *scriptEngine) -> QObject * {
3634 Q_UNUSED(engine)
3635 Q_UNUSED(scriptEngine)
3636
3637 SingletonTypeExample *example = new SingletonTypeExample();
3638 return example;
3639 });
3640 \endcode
3641
3642 In order to use the registered singleton type in QML, you must import the singleton type.
3643 \qml
3644 import QtQuick 2.0
3645 import Qt.example.qobjectSingleton 1.0
3646 Item {
3647 id: root
3648 property int someValue: MyApi.someProperty
3649
3650 Component.onCompleted: {
3651 someValue = MyApi.doSomething()
3652 }
3653 }
3654 \endqml
3655
3656 \sa QML_SINGLETON, {Choosing the Correct Integration Method Between C++ and QML}
3657*/
3658
3659/*!
3660 \fn int qmlRegisterSingletonType(const QUrl &url, const char *uri, int versionMajor, int versionMinor, const char *qmlName)
3661 \relates <qqml.h>
3662
3663 This function may be used to register a singleton type with the name \a qmlName, in the library imported from \a uri having
3664 the version number composed from \a versionMajor and \a versionMinor. The type is defined by the QML file located at \a url.
3665 The url must be an absolute URL, i.e. url.isRelative() == false.
3666
3667 In addition the type's QML file must have pragma Singleton statement among its import statements.
3668
3669 A singleton type may be referenced via the type name with which it was registered, and this typename may be used as the
3670 target in a \l Connections type or otherwise used as any other type id would. One exception to this is that a singleton
3671 type property may not be aliased (because the singleton type name does not identify an object within the same component
3672 as any other item).
3673
3674 Usage:
3675 \qml
3676 // First, define your QML singleton type which provides the functionality.
3677 pragma Singleton
3678 import QtQuick 2.0
3679 Item {
3680 property int testProp1: 125
3681 }
3682 \endqml
3683
3684 \code
3685 // Second, register the QML singleton type by calling this function in an initialization function.
3686 qmlRegisterSingletonType(QUrl("file:///absolute/path/SingletonType.qml"), "Qt.example.qobjectSingleton", 1, 0, "RegisteredSingleton");
3687 \endcode
3688
3689 In order to use the registered singleton type in QML, you must import the singleton type.
3690 \qml
3691 import QtQuick 2.0
3692 import Qt.example.qobjectSingleton 1.0
3693 Item {
3694 id: root
3695 property int someValue: RegisteredSingleton.testProp1
3696 }
3697 \endqml
3698
3699 It is also possible to have QML singleton types registered without using the qmlRegisterSingletonType function.
3700 That can be done by adding a pragma Singleton statement among the imports of the type's QML file. In addition
3701 the type must be defined in a qmldir file with a singleton keyword and the qmldir must be imported by the QML
3702 files using the singleton.
3703
3704 \sa QML_SINGLETON
3705*/
3706
3707/*!
3708 \fn int qmlRegisterSingletonInstance(const char *uri, int versionMajor, int versionMinor, const char *typeName, QObject *cppObject)
3709 \relates <qqml.h>
3710 \since 5.14
3711
3712 This function is used to register a singleton object \a cppObject, with a
3713 particular \a uri and \a typeName. Its version is a combination of \a
3714 versionMajor and \a versionMinor.
3715
3716 Installing a singleton type into a URI allows you to provide arbitrary
3717 functionality (methods and properties) to QML code without requiring
3718 individual instances of the type to be instantiated by the client.
3719
3720 Use this function to register an object of the given type T as a singleton
3721 type.
3722
3723 A QObject singleton type may be referenced via the type name with which it
3724 was registered; in turn this type name may be used as the target in a \l
3725 Connections type, or like any other type ID. However, there's one
3726 exception: a QObject singleton type property can't be aliased because the
3727 singleton type name does not identify an object within the same component
3728 as any other item.
3729
3730 \note \a cppObject must outlive the QML engine in which it is used.
3731 Moreover, \cppObject must have the same thread affinity as the engine. If
3732 you want separate singleton instances for multiple engines, you need to use
3733 \l {qmlRegisterSingletonType}. See \l{Threads and QObjects} for more
3734 information about thread safety.
3735
3736 \b{NOTE:} qmlRegisterSingleton can only be used when all types of that module are registered procedurally.
3737
3738 Usage:
3739 //! Workaround for MOC not respecting comments and triggering an error on certain Qt macros.
3740 \code Q
3741 // First, define your QObject which provides the functionality.
3742 class SingletonTypeExample : public QObject
3743 {
3744 \1_OBJECT
3745 Q_PROPERTY(int someProperty READ someProperty WRITE setSomeProperty NOTIFY somePropertyChanged)
3746
3747 public:
3748 explicit SingletonTypeExample(QObject* parent = nullptr) : QObject(parent) {}
3749
3750 Q_INVOKABLE int doSomething()
3751 {
3752 setSomeProperty(5);
3753 return m_someProperty;
3754 }
3755
3756 int someProperty() const { return m_someProperty; }
3757 void setSomeProperty(int val) {
3758 if (m_someProperty != val) {
3759 m_someProperty = val;
3760 emit somePropertyChanged(val);
3761 }
3762 }
3763
3764 signals:
3765 void somePropertyChanged(int newValue);
3766
3767 private:
3768 int m_someProperty = 0;
3769 };
3770 \endcode
3771
3772 \code
3773 // Second, create an instance of the object
3774
3775 // allocate example before the engine to ensure that it outlives it
3776 QScopedPointer<SingletonTypeExample> example(new SingletonTypeExample);
3777 QQmlEngine engine;
3778
3779 // Third, register the singleton type provider with QML by calling this
3780 // function in an initialization function.
3781 qmlRegisterSingletonInstance("Qt.example.qobjectSingleton", 1, 0, "MyApi", example.get());
3782 \endcode
3783
3784
3785 In order to use the registered singleton type in QML, you must import the
3786 URI with the corresponding version.
3787 \qml
3788 import QtQuick 2.0
3789 import Qt.example.qobjectSingleton 1.0
3790 Item {
3791 id: root
3792 property int someValue: MyApi.someProperty
3793
3794 Component.onCompleted: {
3795 console.log(MyApi.doSomething())
3796 }
3797 }
3798 \endqml
3799
3800 \sa QML_SINGLETON, qmlRegisterSingletonType
3801 */
3802
3803/*!
3804 \fn int qmlRegisterType(const QUrl &url, const char *uri, int versionMajor, int versionMinor, const char *qmlName);
3805 \relates <qqml.h>
3806
3807 This function registers a type in the QML system with the name \a qmlName, in the library imported from \a uri having the
3808 version number composed from \a versionMajor and \a versionMinor. The type is defined by the QML file located at \a url. The
3809 url must be an absolute URL, i.e. url.isRelative() == false.
3810
3811 Normally QML files can be loaded as types directly from other QML files, or using a qmldir file. This function allows
3812 registration of files to types from C++ code, such as when the type mapping needs to be procedurally determined at startup.
3813
3814 Returns -1 if the registration was not successful.
3815*/
3816
3817QT_END_NAMESPACE
PropertyResult loadFallbackAsVariant(QV4::Lookup *lookup, QObject *object, void *target, const AOTCompiledContext *aotContext)
Definition qqml.cpp:1461
static ObjectLookupResult initObjectLookup(const AOTCompiledContext *aotContext, QV4::Lookup *lookup, QObject *object)
Definition qqml.cpp:1713
void qmlRegisterTypeAndRevisions< QQmlTypeNotAvailable, void >(const char *uri, int versionMajor, const QMetaObject *classInfoMetaObject, QList< int > *qmlTypeIds, const QMetaObject *extension, bool)
Definition qqml.cpp:1119
PropertyResult writeBackObjectAsVariant(QV4::Lookup *lookup, QObject *object, void *source)
Definition qqml.cpp:1450
static PropertyResult writeBackFallbackProperty(QV4::Lookup *lookup, QObject *object, void *source)
Definition qqml.cpp:1425
static PropertyResult changeFallbackProperty(QV4::Lookup *lookup, QObject *object, Op op)
Definition qqml.cpp:1524
static FallbackPropertyQmlData findFallbackPropertyQmlData(QV4::Lookup *lookup, QObject *object)
Definition qqml.cpp:1389
static void throwIsNotAFunctionError(const AOTCompiledContext *aotContext, QV4::Lookup *lookup, const QString &object)
Definition qqml.cpp:2251
static bool markPointer(const QVariant &element, QV4::MarkStack *markStack)
Definition qqml.cpp:1208
PropertyResult loadObjectProperty(QV4::Lookup *lookup, QObject *object, void *target, const AOTCompiledContext *aotContext)
Definition qqml.cpp:1354
static bool isEnumUnderlyingType(QMetaType enumType, QMetaType numberType)
Definition qqml.cpp:1565
static PropertyResult storeFallbackAsVariant(QV4::ExecutionEngine *v4, QV4::Lookup *lookup, QObject *object, void *value)
Definition qqml.cpp:1678
static void iterateVariant(const QVariant &element, std::vector< QVariant > *elements)
Definition qqml.cpp:1218
static PropertyResult changeObjectProperty(QV4::Lookup *lookup, QObject *object, Op op)
Definition qqml.cpp:1487
static PropertyResult storeObjectProperty(QV4::Lookup *lookup, QObject *object, void *value)
Definition qqml.cpp:1516
PropertyResult loadObjectAsVariant(QV4::Lookup *lookup, QObject *object, void *target, const AOTCompiledContext *aotContext)
Definition qqml.cpp:1438
static bool callQObjectMethod(QV4::ExecutionEngine *engine, QV4::Lookup *lookup, QObject *thisObject, void **args, int argc)
Definition qqml.cpp:2168
ObjectPropertyQmlData findObjectPropertyQmlData(QV4::Lookup *lookup, QObject *object)
Definition qqml.cpp:1335
static void captureFallbackProperty(QObject *object, int coreIndex, int notifyIndex, bool isConstant, const AOTCompiledContext *aotContext)
Definition qqml.cpp:1295
static void initValueLookup(QV4::Lookup *lookup, QV4::ExecutableCompilationUnit *compilationUnit, const QMetaObject *metaObject)
Definition qqml.cpp:1805
static bool inherits(const QQmlPropertyCache *descendent, const QQmlPropertyCache *ancestor)
Definition qqml.cpp:1317
static bool canHoldVoid(QMetaType type)
Definition qqml.cpp:1600
static bool tryEnsureMethodsCache(QV4::QObjectMethod *method, QObject *object)
Definition qqml.cpp:2314
static void captureObjectProperty(QObject *object, const QQmlPropertyCache *propertyCache, const QQmlPropertyData *property, const AOTCompiledContext *aotContext)
Definition qqml.cpp:1306
PropertyResult writeBackFallbackAsVariant(QV4::Lookup *lookup, QObject *object, void *source)
Definition qqml.cpp:1474
static PropertyResult storeFallbackProperty(QV4::Lookup *lookup, QObject *object, void *value)
Definition qqml.cpp:1538
static bool isUndefined(const void *value, QMetaType type)
Definition qqml.cpp:1927
static bool callQObjectMethodAsVariant(QV4::ExecutionEngine *engine, QV4::Lookup *lookup, QObject *thisObject, void **args, int argc)
Definition qqml.cpp:2144
static QMetaType jsTypedFunctionArgument(const QQmlType &type, const QV4::CompiledData::ParameterType &parameter)
Definition qqml.cpp:2127
static PropertyResult resetFallbackProperty(QV4::Lookup *lookup, QObject *object, QV4::ExecutionEngine *v4)
Definition qqml.cpp:1547
static PropertyResult loadFallbackProperty(QV4::Lookup *lookup, QObject *object, void *target, const AOTCompiledContext *aotContext)
Definition qqml.cpp:1405
static bool callArrowFunction(QV4::ExecutionEngine *engine, QV4::ArrowFunction *function, QObject *thisObject, void **args, int argc)
Definition qqml.cpp:2206
static PropertyResult resetObjectProperty(QV4::Lookup *lookup, QObject *object, QV4::ExecutionEngine *v4)
Definition qqml.cpp:1501
static PropertyResult storeObjectAsVariant(QV4::ExecutionEngine *v4, QV4::Lookup *lookup, QObject *object, void *value)
Definition qqml.cpp:1646
static bool callQObjectMethodWithTypes(QV4::ExecutionEngine *engine, QV4::Lookup *lookup, QObject *thisObject, void **args, QMetaType *types, int argc)
Definition qqml.cpp:2133
static bool isTypeCompatible(QMetaType source, QMetaType target)
Definition qqml.cpp:1608
PropertyResult writeBackObjectProperty(QV4::Lookup *lookup, QObject *object, void *source)
Definition qqml.cpp:1372
void initObjectLookup(const AOTCompiledContext *aotContext, uint index, QObject *object)
Definition qqml.cpp:1778
static QQmlPropertyCapture * propertyCapture(const AOTCompiledContext *aotContext)
Definition qqml.cpp:1172
static MatchScore resolveQObjectMethodOverload(QV4::QObjectMethod *method, QV4::Lookup *lookup, int relativeMethodIndex)
Definition qqml.cpp:2285
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:869
static ElementNames classElementNames(const QMetaObject *metaObject)
Definition qqml.cpp:692
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:682
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:756
static QTypeRevision resolveModuleVersion(int moduleMajor)
Definition qqml.cpp:382
static QQmlType::SingletonInstanceInfo::ConstPtr singletonInstanceInfo(const QQmlPrivate::RegisterSingletonType &type)
Definition qqml.cpp:661
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:736
void registerAliases(int typeId)
Definition qqml.cpp:738
const QMetaObject * metaObject
Definition qqml.cpp:1385