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