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/qmetasequence.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 QList<QTypeRevision> availableRevisions(const QMetaObject *metaObject)
582{
583 QList<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 QList<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(QList<QTypeRevision> *revisions, QTypeRevision defaultVersion,
630 QTypeRevision added)
631{
632 bool revisionsHaveMajorVersions = false;
633 for (QTypeRevision revision : QList<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 : std::as_const(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 QList<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 const QMetaType elementMetaType = element.metaType();
1221 switch (elementMetaType.id()) {
1222 case QMetaType::QVariantMap:
1223 for (const QVariant &variant : *static_cast<const QVariantMap *>(element.constData()))
1224 elements->push_back(variant);
1225 return;
1226 case QMetaType::QVariantHash:
1227 for (const QVariant &variant : *static_cast<const QVariantHash *>(element.constData()))
1228 elements->push_back(variant);
1229 return;
1230 case QMetaType::QVariantList:
1231 for (const QVariant &variant : *static_cast<const QVariantList *>(element.constData()))
1232 elements->push_back(variant);
1233 return;
1234 QT_FOR_EACH_STATIC_PRIMITIVE_TYPE(ADD_CASE)
1235 QT_FOR_EACH_STATIC_CORE_CLASS(ADD_CASE)
1236 QT_FOR_EACH_STATIC_GUI_CLASS(ADD_CASE)
1237 case QMetaType::QStringList:
1238 case QMetaType::QByteArrayList:
1239 return;
1240 default:
1241 break;
1242 }
1243
1244 if (elementMetaType == QMetaType::fromType<QJSValue>()
1245 || elementMetaType == QMetaType::fromType<QJSManagedValue>()
1246 || elementMetaType == QMetaType::fromType<QJSPrimitiveValue>()) {
1247 // QJSValue and QJSManagedValue effectively hold persistent values anyway.
1248 // QJSPrimitiveValue can only hold primitives or QString.
1249 return;
1250 }
1251
1252 QMetaSequence::Iterable iterable;
1253 if (!QMetaType::convert(
1254 element.metaType(), element.constData(),
1255 QMetaType::fromType<QMetaSequence::Iterable>(), &iterable)) {
1256 return;
1257 }
1258
1259 switch (iterable.metaContainer().valueMetaType().id()) {
1260 QT_FOR_EACH_STATIC_PRIMITIVE_TYPE(ADD_CASE)
1261 QT_FOR_EACH_STATIC_CORE_CLASS(ADD_CASE)
1262 QT_FOR_EACH_STATIC_GUI_CLASS(ADD_CASE)
1263 case QMetaType::QStringList:
1264 case QMetaType::QByteArrayList:
1265 return;
1266 default:
1267 break;
1268 }
1269
1270 for (auto it = iterable.constBegin(), end = iterable.constEnd(); it != end; ++it)
1271 elements->push_back(*it);
1272
1273#undef ADD_CASE
1274}
1275
1277{
1279 return;
1280
1283
1284 while (!stack.empty()) {
1285 const QVariant element = std::as_const(stack).back();
1286 stack.pop_back();
1289 }
1290}
1291
1302
1313
1314static bool inherits(const QQmlPropertyCache *descendent, const QQmlPropertyCache *ancestor)
1315{
1316 for (const QQmlPropertyCache *cache = descendent; cache; cache = cache->parent().data()) {
1317 if (cache == ancestor)
1318 return true;
1319 }
1320 return false;
1321}
1322
1324
1330
1331template<bool StrictType>
1349
1350template<bool StrictType = false>
1367
1368template<bool StrictType = false>
1378
1385
1387{
1388 // We've just initialized the lookup. So everything must be fine here.
1389
1391
1394
1395 const QMetaObject *metaObject
1396 = reinterpret_cast<const QMetaObject *>(lookup->qobjectFallbackLookup.metaObject - 1);
1398
1399 return {qmlData, metaObject, PropertyResult::OK};
1400}
1401
1421
1434
1446
1457
1470
1482
1483template<bool StrictType, typename Op>
1496
1497template<bool StrictType = false>
1500{
1502 if (property->isResettable()) {
1504 } else {
1505 v4->throwError(
1506 QLatin1String("Cannot assign [undefined] to ") +
1508 }
1509 });
1510}
1511
1512template<bool StrictType = false>
1519
1520template<typename Op>
1534
1536{
1538 lookup, object, [&](const QMetaObject *metaObject, int coreIndex) {
1539 void *args[] = { value, nullptr };
1541 });
1542}
1543
1546{
1548 lookup, object, [&](const QMetaObject *metaObject, int coreIndex) {
1550 void *args[] = { nullptr };
1552 } else {
1553 const QMetaType propType(reinterpret_cast<const QtPrivate::QMetaTypeInterface *>(
1555 v4->throwError(
1556 QLatin1String("Cannot assign [undefined] to ") +
1558 }
1559 });
1560}
1561
1562static bool isEnumUnderlyingType(QMetaType enumType, QMetaType numberType)
1563{
1564 // You can pass the underlying type of an enum.
1565 // We don't want to check for the actual underlying type because
1566 // moc and qmltyperegistrar are not very precise about it. Especially
1567 // the long and longlong types can be ambiguous.
1568
1569 const bool isUnsigned = enumType.flags() & QMetaType::IsUnsignedEnumeration;
1570 switch (enumType.sizeOf()) {
1571 case 1:
1572 return isUnsigned
1573 ? numberType == QMetaType::fromType<quint8>()
1574 : numberType == QMetaType::fromType<qint8>();
1575 case 2:
1576 return isUnsigned
1577 ? numberType == QMetaType::fromType<ushort>()
1578 : numberType == QMetaType::fromType<short>();
1579 case 4:
1580 // The default type, if moc doesn't know the actual enum type, is int.
1581 // However, the compiler can still decide to encode the enum in uint.
1582 // Therefore, we also accept int for uint enums.
1583 // TODO: This is technically UB.
1584 return isUnsigned
1585 ? (numberType == QMetaType::fromType<int>()
1586 || numberType == QMetaType::fromType<uint>())
1587 : numberType == QMetaType::fromType<int>();
1588 case 8:
1589 return isUnsigned
1590 ? numberType == QMetaType::fromType<qulonglong>()
1591 : numberType == QMetaType::fromType<qlonglong>();
1592 }
1593
1594 return false;
1595}
1596
1597static bool canHoldVoid(QMetaType type)
1598{
1599 // We cannot directly store void, but we can put it into QVariant or QJSPrimitiveValue
1600 return !type.isValid()
1601 || type == QMetaType::fromType<QVariant>()
1602 || type == QMetaType::fromType<QJSPrimitiveValue>();
1603}
1604
1605static bool isTypeCompatible(QMetaType source, QMetaType target)
1606{
1607 if (source == target)
1608 return true;
1609
1610 if ((source.flags() & QMetaType::IsQmlList)
1611 && (target.flags() & QMetaType::IsQmlList)) {
1612 // We want to check the value types here, but we cannot easily do it.
1613 // Internally those are all QObject* lists, though.
1614 return true;
1615 }
1616
1617 if (target.flags() & QMetaType::PointerToQObject) {
1618 // We accept any derived class, too
1619
1620 const QMetaObject *targetMetaObject = target.metaObject();
1621 const QMetaObject *sourceMetaObject = source.metaObject();
1622 if (!sourceMetaObject)
1623 sourceMetaObject = QQmlMetaType::metaObjectForType(source).metaObject();
1624
1625 while (sourceMetaObject && sourceMetaObject != targetMetaObject)
1626 sourceMetaObject = sourceMetaObject->superClass();
1627
1628 return sourceMetaObject != nullptr;
1629 }
1630
1631 if (target.flags() & QMetaType::IsEnumeration)
1632 return isEnumUnderlyingType(target, source);
1633
1634 if (source.flags() & QMetaType::IsEnumeration)
1635 return isEnumUnderlyingType(source, target);
1636
1637 if (!source.isValid())
1638 return canHoldVoid(target);
1639
1640 return false;
1641}
1642
1674
1702
1708
1709template<QV4::Lookup::Call FallbackCall>
1711 const AOTCompiledContext *aotContext, QV4::Lookup *lookup, QObject *object)
1712{
1713 QV4::Scope scope(aotContext->engine->handle());
1714 QV4::PropertyKey id = scope.engine->identifierTable->asPropertyKey(
1715 aotContext->compilationUnit->runtimeStrings[lookup->nameIndex]);
1716
1717 Q_ASSERT(id.isString());
1718
1719 QV4::ScopedString name(scope, id.asStringOrSymbol());
1720
1721 Q_ASSERT(!name->equals(scope.engine->id_toString()));
1722 Q_ASSERT(!name->equals(scope.engine->id_destroy()));
1723
1724 QQmlData *ddata = QQmlData::get(object, true);
1725 Q_ASSERT(ddata);
1726 if (ddata->isQueuedForDeletion)
1728
1729 const QQmlPropertyData *property;
1730 if (!ddata->propertyCache) {
1731 property = QQmlPropertyCache::property(object, name, aotContext->qmlContext, nullptr);
1732 } else {
1733 property = ddata->propertyCache->property(
1734 name.getPointer(), object, aotContext->qmlContext);
1735 }
1736
1737 if (!property) {
1738 const QMetaObject *metaObject = object->metaObject();
1739 if (!metaObject)
1741
1742 const int coreIndex = metaObject->indexOfProperty(
1743 name->toQStringNoThrow().toUtf8().constData());
1744 if (coreIndex < 0)
1746
1747 const QMetaProperty property = metaObject->property(coreIndex);
1748
1749 lookup->releasePropertyCache();
1750 // & 1 to tell the gc that this is not heap allocated; see markObjects in qv4lookup_p.h
1751 lookup->qobjectFallbackLookup.metaObject = quintptr(metaObject) + 1;
1752 lookup->qobjectFallbackLookup.metaType = quintptr(property.metaType().iface()) + 1;
1753 lookup->qobjectFallbackLookup.coreIndex = coreIndex;
1754 lookup->qobjectFallbackLookup.notifyIndex =
1755 QMetaObjectPrivate::signalIndex(property.notifySignal());
1756
1757 if constexpr (FallbackCall == QV4::Lookup::Call::ContextGetterScopeObjectPropertyFallback
1758 || FallbackCall == QV4::Lookup::Call::GetterQObjectPropertyFallback) {
1759 lookup->qobjectFallbackLookup.isConstantOrResettable = property.isConstant() ? 1 : 0;
1760 } else if constexpr (FallbackCall == QV4::Lookup::Call::SetterQObjectPropertyFallback) {
1761 lookup->qobjectFallbackLookup.isConstantOrResettable = property.isResettable() ? 1 : 0;
1762 }
1764 }
1765
1766 Q_ASSERT(ddata->propertyCache);
1767
1768 QV4::setupQObjectLookup(lookup, ddata, property);
1769
1771}
1772
1774template<QV4::Lookup::Call ObjectCall, QV4::Lookup::Call FallbackCall, LookupType Type>
1775void initObjectLookup(const AOTCompiledContext *aotContext, uint index, QObject *object)
1776{
1777 QV4::ExecutionEngine *v4 = aotContext->engine->handle();
1778 if (v4->hasException) {
1779 v4->amendException();
1780 return;
1781 }
1782
1783 QV4::Lookup *lookup = aotContext->compilationUnit->runtimeLookups + index;
1784 switch (initObjectLookup<FallbackCall>(aotContext, lookup, object)) {
1786 lookup->call = ObjectCall;
1787 lookup->asVariant = (Type == LookupType::Variant);
1788 break;
1790 lookup->call = FallbackCall;
1791 lookup->asVariant = (Type == LookupType::Variant);
1792 break;
1794 v4->throwTypeError();
1795 break;
1796 }
1797
1798 return;
1799}
1800
1801
1803 QV4::Lookup *lookup, QV4::ExecutableCompilationUnit *compilationUnit,
1804 const QMetaObject *metaObject)
1805{
1806 Q_ASSERT(metaObject);
1807 const QByteArray name = compilationUnit->runtimeStrings[lookup->nameIndex]->toQString().toUtf8();
1808 const int coreIndex = metaObject->indexOfProperty(name.constData());
1809 QMetaType lookupType = metaObject->property(coreIndex).metaType();
1810 lookup->qgadgetLookup.metaObject = quintptr(metaObject) + 1;
1811 lookup->qgadgetLookup.coreIndex = coreIndex;
1812 lookup->qgadgetLookup.metaType = lookupType.iface();
1813}
1814
1843
1867
1873
1875{
1876#if QT_CONFIG(translation)
1878#else
1879 return QString();
1880#endif
1881}
1882
1884{
1886 switch (lookup->call) {
1899 return QMetaType::fromType<QObject *>();
1902 // We can do this because the fallback lookup gets invalidated for every call.
1903 return QMetaType(reinterpret_cast<const QtPrivate::QMetaTypeInterface *>(
1905 }
1911 return QMetaType::fromType<void>();
1913 return QMetaType::fromType<QString>();
1914 default:
1916 }
1917 default:
1918 break;
1919 }
1920
1922}
1923
1924static bool isUndefined(const void *value, QMetaType type)
1925{
1926 if (type == QMetaType::fromType<QVariant>())
1927 return !static_cast<const QVariant *>(value)->isValid();
1928 if (type == QMetaType::fromType<QJSValue>())
1929 return static_cast<const QJSValue *>(value)->isUndefined();
1930 if (type == QMetaType::fromType<QJSPrimitiveValue>()) {
1931 return static_cast<const QJSPrimitiveValue *>(value)->type()
1932 == QJSPrimitiveValue::Undefined;
1933 }
1934 return false;
1935}
1936
1938{
1939 // We don't really use any part of the lookup machinery here.
1940 // The QV4::Lookup is created on the stack to conveniently get the property cache, and through
1941 // the property cache we store a value into the property.
1942
1943 const auto unwrapVariant = [&]() {
1944 if (type == QMetaType::fromType<QVariant>()) {
1945 QVariant *variant = static_cast<QVariant *>(value);
1946 type = variant->metaType();
1947 value = variant->data();
1948 }
1949 };
1950
1951 QV4::Lookup lookup;
1952 memset(&lookup, 0, sizeof(QV4::Lookup));
1954 lookup.forCall = false;
1957
1959 this, &lookup, qmlScopeObject)) {
1960 case ObjectLookupResult::Object: {
1964 } else if (isUndefined(value, type)) {
1965
1966 // NB: In order to have a meaningful reset() here, the type needs to be a wrapper type
1967 // that can hold undefined. For example QVariant. The caller must not unwrap it.
1968
1970 } else {
1971
1972 // Unwrap any QVariant so that we get a meaningful conversion below.
1973 unwrapVariant();
1974
1977 QV4::Scope scope(v4);
1982 }
1983 }
1984
1986 break;
1987 }
1989 propType = QMetaType(reinterpret_cast<const QtPrivate::QMetaTypeInterface *>(
1993 } else if (isUndefined(value, type)) {
1994
1995 // NB: In order to have a meaningful reset() here, the type needs to be a wrapper type
1996 // that can hold undefined. For example QVariant. The caller must not unwrap it.
1998
1999 } else {
2000
2001 // Unwrap any QVariant so that we get a meaningful conversion below.
2002 unwrapVariant();
2003
2006 QV4::Scope scope(v4);
2011 }
2012 }
2013 break;
2014 }
2017 return;
2018 }
2019
2020 switch (storeResult) {
2021 case PropertyResult::NeedsInit: {
2022 const QString error = QLatin1String("Cannot assign ") +
2024 QLatin1String(" to ") +
2027 break;
2028 }
2029 case PropertyResult::Deleted:
2031 QStringLiteral("Value is null and could not be converted to an object"));
2032 break;
2033 case PropertyResult::OK:
2034 break;
2035 }
2036}
2037
2045
2047{
2048 if (wrapper) {
2049 // We have to check this here because you may pass a plain QObject that only
2050 // turns out to be a QQmlLoggingCategoryBase at run time.
2054 *ok = true;
2055 if (!loggingCategory) {
2057 QStringLiteral("A QmlLoggingCatgory was provided without a valid name"));
2058 }
2059 return loggingCategory;
2060 }
2061 }
2062
2063 *ok = false;
2064 return qmlEngine() ? &lcQml() : &lcJs();
2065}
2066
2069{
2071
2073 Q_ASSERT(frame);
2074
2075 const QByteArray source(frame->source().toUtf8());
2079
2080 switch (type) {
2081 case QtDebugMsg:
2083 break;
2084 case QtInfoMsg:
2086 break;
2087 case QtWarningMsg:
2089 break;
2090 case QtCriticalMsg:
2092 break;
2093 default:
2094 break;
2095 }
2096}
2097
2105
2110
2115
2117 double year, double month, double day, double hours,
2118 double minutes, double seconds, double msecs) const
2119{
2122}
2123
2125 const QQmlType &type, const QV4::CompiledData::ParameterType &parameter)
2126{
2127 return parameter.isList() ? type.qListTypeId() : type.typeId();
2128}
2129
2140
2143 QObject *thisObject, void **args, int argc)
2144{
2145 // We need to re-fetch the method on every call because it can be shadowed.
2146
2150
2151 // The getter mustn't reset the isVariant flag
2153
2154 // Since we have an asVariant lookup, the function may have been overridden in the mean time.
2155 if (!function)
2156 return false;
2157
2158 Q_ALLOCA_VAR(QMetaType, types, (argc + 1) * sizeof(QMetaType));
2160
2162 return !scope.hasException();
2163}
2164
2167 QObject *thisObject, void **args, int argc)
2168{
2170
2171 Q_ALLOCA_VAR(QMetaType, types, (argc + 1) * sizeof(QMetaType));
2176 for (int i = 0; i < argc; ++i)
2178
2180 }
2181
2185 switch (method->methodIndex()) {
2187 return method->method_destroy(
2188 engine, thisObject, argc > 0 ? *static_cast<int *>(args[1]) : 0);
2192 thisObject);
2193 if (void *returnValue = args[0])
2194 *static_cast<QString *>(returnValue) = std::move(result);
2195 return true;
2196 }
2197 default:
2198 break;
2199 }
2200 return false;
2201}
2202
2205 QObject *thisObject, void **args, int argc)
2206{
2210
2211 switch (v4Function->kind) {
2212 case QV4::Function::AotCompiled: {
2215 return !engine->hasException;
2216 }
2217 case QV4::Function::JsTyped: {
2221
2222 Q_ALLOCA_VAR(QMetaType, types, (argc + 1) * sizeof(QMetaType));
2225 for (qsizetype i = 0; i != argc; ++i) {
2228 }
2229
2231 return !engine->hasException;
2232 }
2233 case QV4::Function::JsUntyped: {
2234 // We can call untyped functions if we're not expecting a specific return value and don't
2235 // have to pass any arguments. The compiler verifies this.
2236 Q_ASSERT(argc == 0);
2239 return !engine->hasException;
2240 }
2241 case QV4::Function::Eval:
2242 break;
2243 }
2244
2245 Q_UNREACHABLE_RETURN(false);
2246}
2247
2249 const AOTCompiledContext *aotContext, QV4::Lookup *lookup, const QString &object)
2250{
2251 aotContext->engine->handle()->throwTypeError(
2252 QStringLiteral("Property '%1' of object %2 is not a function").arg(
2253 aotContext->compilationUnit->runtimeStrings[lookup->nameIndex]->toQString(),
2254 object));
2255};
2256
2279
2281
2283 QV4::QObjectMethod *method, QV4::Lookup *lookup, int relativeMethodIndex)
2284{
2285 Q_ASSERT(lookup->qobjectMethodLookup.method.get() == method->d());
2286
2287 const auto *d = method->d();
2288 const int methodCount = d->methodCount;
2289
2290 if (relativeMethodIndex == -1 && methodCount == 1) {
2291 // QML-declared signals do not have a meaningful method index and cannot be overloaded.
2292 // They still show up as QObjectMethod rather than ArrowFunction. If they didn't, we
2293 // wouldn't have to care.
2294 Q_ASSERT(d->methods[0].metaMethod().methodType() == QMetaMethod::Signal);
2295 lookup->qobjectMethodLookup.propertyData = d->methods;
2296 return ExactMatch;
2297 }
2298
2299 for (int i = 0, end = d->methodCount; i != end; ++i) {
2300 const QMetaMethod metaMethod = d->methods[i].metaMethod();
2301 if (metaMethod.relativeMethodIndex() != relativeMethodIndex)
2302 continue;
2303
2304 lookup->qobjectMethodLookup.propertyData = d->methods + i;
2305 return ExactMatch;
2306 }
2307
2308 return NoMatch;
2309}
2310
2312{
2313 QV4::Heap::QObjectMethod *d = method->d();
2314 switch (method->methodIndex()) {
2317 return false;
2318 default:
2319 break;
2320 }
2321
2323 return true;
2324}
2325
2357
2359{
2361 int objectId = -1;
2362 QQmlContextData *context = nullptr;
2364
2365 switch (lookup->call) {
2369 break;
2375 if (objectId != -1 && objectId < context->numIdValues())
2376 break;
2377 }
2378 break;
2379 }
2380 default:
2381 return false;
2382 }
2383
2384 Q_ASSERT(objectId >= 0);
2385 Q_ASSERT(context != nullptr);
2389 *static_cast<QObject **>(target) = context->idValue(objectId);
2390 return true;
2391}
2392
2417
2419 uint index, QObject *object, void **args, int argc) const
2420{
2422
2423 if (!object) {
2424 engine->handle()->throwTypeError(QStringLiteral("Cannot call method '%1' of null")
2426 return false;
2427 }
2428
2429 switch (lookup->call) {
2432 return lookup->asVariant
2437 if (lookup->asVariant) {
2438 // If the method can be shadowed, the overridden method can be taken away, too.
2439 // In that case we might end up with a QObjectMethod or random other values instead.
2440 // callQObjectMethodAsVariant is flexible enough to handle that.
2442 }
2443
2444 // Here we always retrieve a fresh ArrowFunction via the getter.
2448
2449 // The getter mustn't touch the asVariant bit
2451
2452 if (function)
2454
2456 }
2457 default:
2458 break;
2459 }
2460
2461 return false;
2462}
2463
2465{
2466 if (engine->hasError()) {
2468 return;
2469 }
2470
2473
2474 const auto *ddata = QQmlData::get(object, false);
2476 // We cannot lookup functions on an object with VME metaobject but no QObjectWrapper
2477 throwIsNotAFunctionError(this, lookup, QStringLiteral("[object Object]"));
2478 return;
2479 }
2480
2483 if (auto *method = function->as<QV4::QObjectMethod>()) {
2485 lookup->asVariant = true;
2486 return;
2487 }
2488
2489 if (function->as<QV4::ArrowFunction>()) {
2490 // Can't have overloads of JavaScript functions.
2491 lookup->asVariant = true;
2492 return;
2493 }
2494
2496}
2497
2500{
2501 if (engine->hasError()) {
2503 return;
2504 }
2505
2508
2509 const auto *ddata = QQmlData::get(object, false);
2511 // We cannot lookup functions on an object with VME metaobject but no QObjectWrapper
2512 throwIsNotAFunctionError(this, lookup, QStringLiteral("[object Object]"));
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;
2579 break;
2580 default:
2581 return false;
2582 }
2583
2584 switch (result) {
2586 return false;
2587 case PropertyResult::Deleted:
2589 QStringLiteral("Cannot read property '%1' of null")
2591 return false;
2592 case PropertyResult::OK:
2593 return true;
2594 }
2595
2596 Q_UNREACHABLE_RETURN(false);
2597}
2598
2600{
2602
2604 switch (lookup->call) {
2607 break;
2611 break;
2612 default:
2613 return false;
2614 }
2615
2616 switch (result) {
2618 return false;
2619 case PropertyResult::Deleted: // Silently omit the write back. Same as interpreter
2620 case PropertyResult::OK:
2621 return true;
2622 }
2623
2624 Q_UNREACHABLE_RETURN(false);
2625}
2626
2627
2628
2636
2638{
2641
2645
2646 // We don't handle non-QObject singletons (as those can't be declared in qmltypes anyway)
2648 *static_cast<QObject **>(target) = wrapper->object();
2649 return true;
2650 }
2651
2652 return false;
2653}
2654
2657
2658template<QV4::Lookup::Call call>
2659static void initTypeWrapperLookup(
2660 const AOTCompiledContext *context, QV4::Lookup *lookup, uint importNamespace)
2661{
2662 Q_ASSERT(!context->engine->hasError());
2663 if (importNamespace != AOTCompiledContext::InvalidStringId) {
2664 QV4::Scope scope(context->engine->handle());
2665 QV4::ScopedString import(scope, context->compilationUnit->runtimeStrings[importNamespace]);
2666
2667 QQmlTypeLoader *typeLoader = scope.engine->typeLoader();
2668 Q_ASSERT(typeLoader);
2669 if (const QQmlImportRef *importRef
2670 = context->qmlContext->imports()->query(import, typeLoader).importNamespace) {
2671
2672 QV4::Scoped<QV4::QQmlTypeWrapper> wrapper(
2673 scope, QV4::QQmlTypeWrapper::create(
2674 scope.engine, nullptr, context->qmlContext->imports(), importRef));
2675
2676 // This is not a contextGetter since we actually load from the namespace.
2677 wrapper = lookup->getter(context->engine->handle(), wrapper);
2678
2679 // In theory, the getter may have populated the lookup's property cache.
2680 lookup->releasePropertyCache();
2681
2682 lookup->call = call;
2683 switch (call) {
2684 case QV4::Lookup::Call::ContextGetterSingleton:
2685 lookup->qmlContextSingletonLookup.singletonObject.set(scope.engine, wrapper->heapObject());
2686 break;
2687 case QV4::Lookup::Call::ContextGetterType:
2688 lookup->qmlTypeLookup.qmlTypeWrapper.set(scope.engine, wrapper->heapObject());
2689 break;
2690 default:
2691 break;
2692 }
2693 return;
2694 }
2695 scope.engine->throwTypeError();
2696 } else {
2697 QV4::ExecutionEngine *v4 = context->engine->handle();
2698 lookup->contextGetter(v4, nullptr);
2699 if (lookup->call != call) {
2700 const QString error
2701 = QLatin1String(call == QV4::Lookup::Call::ContextGetterSingleton
2702 ? "%1 was a singleton at compile time, "
2703 "but is not a singleton anymore."
2704 : "%1 was not a singleton at compile time, "
2705 "but is a singleton now.")
2706 .arg(context->compilationUnit->runtimeStrings[lookup->nameIndex]->toQString());
2707 v4->throwTypeError(error);
2708 }
2709 }
2710}
2716}
2730}
2763}
2766{
2769 return false;
2770
2771 const QV4::Heap::QQmlTypeWrapper *typeWrapper = static_cast<const QV4::Heap::QQmlTypeWrapper *>(
2773
2775 *static_cast<const QMetaObject **>(target)
2777 return true;
2778}
2784}
2787{
2789 const auto doThrow = [&]() {
2791 QStringLiteral("Cannot read property '%1' of null")
2793 return false;
2794 };
2795
2796 if (!object)
2797 return doThrow();
2798
2800 switch (lookup->call) {
2805 break;
2811 break;
2812 default:
2813 return false;
2814 }
2815
2816 switch (result) {
2817 case PropertyResult::Deleted:
2818 return doThrow();
2820 return false;
2821 case PropertyResult::OK:
2822 return true;
2823 }
2824
2825 Q_UNREACHABLE_RETURN(false);
2826}
2829{
2831 if (!object)
2832 return true;
2833
2835 switch (lookup->call) {
2840 break;
2846 break;
2847 default:
2848 return false;
2849 }
2850
2851 switch (result) {
2853 return false;
2854 case PropertyResult::Deleted: // Silently omit the write back
2855 case PropertyResult::OK:
2856 return true;
2857 }
2858
2859 Q_UNREACHABLE_RETURN(false);
2860}
2868}
2876}
2878bool AOTCompiledContext::getValueLookup(uint index, void *value, void *target) const
2879{
2880 Q_ASSERT(value);
2881
2884 return false;
2885
2886 const QMetaObject *metaObject
2887 = reinterpret_cast<const QMetaObject *>(lookup->qgadgetLookup.metaObject - 1);
2889
2890 void *args[] = { target, nullptr };
2892 reinterpret_cast<QObject*>(value), QMetaObject::ReadProperty,
2894 return true;
2895}
2898{
2899 Q_ASSERT(value);
2900
2903 return false;
2904
2905 const QMetaObject *metaObject
2906 = reinterpret_cast<const QMetaObject *>(lookup->qgadgetLookup.metaObject - 1);
2908
2909 void *args[] = { source, nullptr };
2911 reinterpret_cast<QObject*>(value), QMetaObject::WriteProperty,
2913 return true;
2914}
2922}
2925{
2928 return false;
2929 const bool isUnsigned
2933 case 1:
2934 if (isUnsigned)
2935 *static_cast<quint8 *>(target) = encoded;
2936 else
2937 *static_cast<qint8 *>(target) = encoded;
2938 return true;
2939 case 2:
2940 if (isUnsigned)
2941 *static_cast<quint16 *>(target) = encoded;
2942 else
2943 *static_cast<qint16 *>(target) = encoded;
2944 return true;
2945 case 4:
2946 if (isUnsigned)
2947 *static_cast<quint32 *>(target) = encoded;
2948 else
2949 *static_cast<qint32 *>(target) = encoded;
2950 return true;
2951 case 8:
2952 if (isUnsigned)
2953 *static_cast<quint64 *>(target) = encoded;
2954 else
2955 *static_cast<qint64 *>(target) = encoded;
2956 return true;
2957 default:
2958 break;
2959 }
2960
2961 return false;
2962}
2981}
2984{
2985 const auto doThrow = [&]() {
2987 QStringLiteral("Value is null and could not be converted to an object"));
2988 return false;
2989 };
2990
2991 if (!object)
2992 return doThrow();
2993
2996 switch (lookup->call) {
3001 break;
3007 break;
3008 default:
3009 return false;
3010 }
3011
3012 switch (result) {
3013 case PropertyResult::Deleted:
3014 return doThrow();
3016 return false;
3017 case PropertyResult::OK:
3018 return true;
3019 }
3020
3021 Q_UNREACHABLE_RETURN(false);
3022}
3030}
3038}
3040static PropertyResult storeValueProperty(
3041 QV4::Lookup *lookup, const QMetaObject *metaObject, void *target, void *value)
3042{
3043 void *args[] = { value, nullptr };
3044 metaObject->d.static_metacall(
3045 reinterpret_cast<QObject *>(target), QMetaObject::WriteProperty,
3046 lookup->qgadgetLookup.coreIndex, args);
3047 return PropertyResult::OK;
3048}
3050static PropertyResult resetValueProperty(
3051 QV4::Lookup *lookup, const QMetaObject *metaObject, void *target, QV4::ExecutionEngine *v4)
3052{
3053 const QMetaProperty property = metaObject->property(lookup->qgadgetLookup.coreIndex);
3054 if (property.isResettable()) {
3055 void *args[] = { nullptr };
3056 metaObject->d.static_metacall(
3057 reinterpret_cast<QObject *>(target), QMetaObject::ResetProperty,
3058 lookup->qgadgetLookup.coreIndex, args);
3059 } else {
3060 v4->throwError(
3061 QLatin1String("Cannot assign [undefined] to ") +
3062 QLatin1String(property.metaType().name()));
3063 }
3064
3065 return PropertyResult::OK;
3066}
3068static PropertyResult storeValueAsVariant(
3069 QV4::ExecutionEngine *v4, QV4::Lookup *lookup, const QMetaObject *metaObject,
3070 void *target, void *value)
3071{
3072 QVariant *variant = static_cast<QVariant *>(value);
3073 const QMetaType propType = metaObject->property(lookup->qgadgetLookup.coreIndex).metaType();
3074 if (propType == QMetaType::fromType<QVariant>())
3075 return storeValueProperty(lookup, metaObject, target, variant);
3076
3077 if (!variant->isValid())
3078 return resetValueProperty(lookup, metaObject, target, v4);
3079
3080 if (isTypeCompatible(variant->metaType(), propType))
3081 return storeValueProperty(lookup, metaObject, target, variant->data());
3082
3083 QVariant converted(propType);
3084 QV4::Scope scope(v4);
3085 QV4::ScopedValue val(scope, v4->fromVariant(*variant));
3086 if (v4->metaTypeFromJS(val, propType, converted.data())
3087 || QMetaType::convert(
3088 variant->metaType(), variant->constData(), propType, converted.data())) {
3089 return storeValueProperty(lookup, metaObject, target, converted.data());
3090 }
3091
3092 v4->throwError(
3093 QLatin1String("Cannot assign ") + QLatin1String(variant->metaType().name())
3094 + QLatin1String(" to ") + QLatin1String(propType.name()));
3095
3097}
3100 uint index, void *target, void *value) const
3101{
3104 return false;
3105
3106 const QMetaObject *metaObject
3107 = reinterpret_cast<const QMetaObject *>(lookup->qgadgetLookup.metaObject - 1);
3108
3112
3113 switch (result) {
3114 case PropertyResult::OK:
3115 return true;
3117 return false;
3118 case PropertyResult::Deleted:
3119 Q_UNREACHABLE();
3120 }
3121
3122 return false;
3123}
3124
3125template<LookupType Type>
3126void initValueLookup(
3127 const AOTCompiledContext *aotContext, uint index, const QMetaObject *metaObject)
3128{
3129 QV4::ExecutionEngine *v4 = aotContext->engine->handle();
3130 if (v4->hasException) {
3131 v4->amendException();
3132 return;
3133 }
3134
3135 QV4::Lookup *lookup = aotContext->compilationUnit->runtimeLookups + index;
3136 initValueLookup(lookup, aotContext->compilationUnit, metaObject);
3137 lookup->call = QV4::Lookup::Call::SetterValueTypeProperty;
3138 lookup->asVariant = (Type == LookupType::Variant);
3139}
3144}
3150}
3152bool AOTCompiledContext::callValueLookup(uint index, void *target, void **args, int argc) const
3153{
3154 Q_UNUSED(argc);
3155
3158 return false;
3159
3161
3162 const QMetaObject *metaObject
3163 = reinterpret_cast<const QMetaObject *>(lookup->qgadgetLookup.metaObject - 1);
3164
3166 reinterpret_cast<QObject *>(target), QMetaObject::InvokeMetaMethod,
3168
3169 return true;
3170}
3187}
3194}
3195
3196} // namespace QQmlPrivate
3197
3198/*!
3199 \macro QML_DECLARE_TYPE()
3200 \relates <qqml.h>
3201
3202 Equivalent to \c Q_DECLARE_METATYPE(TYPE *) and \c Q_DECLARE_METATYPE(QQmlListProperty<TYPE>)
3203*/
3204
3205/*!
3206 \macro QML_DECLARE_TYPEINFO(Type,Flags)
3207 \relates <qqml.h>
3208
3209 Declares additional properties of the given \a Type as described by the
3210 specified \a Flags.
3211
3212 Current the only supported type info is \c QML_HAS_ATTACHED_PROPERTIES which
3213 declares that the \a Type supports \l {Attached Properties and Attached Signal Handlers}
3214 {attached properties}. QML_DECLARE_TYPEINFO() is not necessary if \a Type contains the
3215 QML_ATTACHED macro.
3216*/
3217
3218/*!
3219 \fn template <typename T> int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const char *qmlName)
3220 \relates <qqml.h>
3221
3222 This template function registers the C++ type in the QML system with
3223 the name \a qmlName, in the library imported from \a uri having the
3224 version number composed from \a versionMajor and \a versionMinor.
3225
3226 Returns the QML type id.
3227
3228 There are two forms of this template function:
3229
3230 \code
3231 template<typename T>
3232 int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const char *qmlName);
3233
3234 template<typename T, int metaObjectRevision>
3235 int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const char *qmlName);
3236 \endcode
3237
3238 The former is the standard form which registers the type \e T as a new type.
3239 The latter allows a particular revision of a class to be registered in
3240 a specified version (see \l {Type Revisions and Versions}).
3241
3242
3243 For example, this registers a C++ class \c MySliderItem as a QML type
3244 named \c Slider for version 1.0 of a type namespace called
3245 "com.mycompany.qmlcomponents":
3246
3247 \code
3248 qmlRegisterType<MySliderItem>("com.mycompany.qmlcomponents", 1, 0, "Slider");
3249 \endcode
3250
3251 Once this is registered, the type can be used in QML by importing the
3252 specified type namespace and version number:
3253
3254 \qml
3255 import com.mycompany.qmlcomponents 1.0
3256
3257 Slider {
3258 // ...
3259 }
3260 \endqml
3261
3262 Note that it's perfectly reasonable for a library to register types to older versions
3263 than the actual version of the library. Indeed, it is normal for the new library to allow
3264 QML written to previous versions to continue to work, even if more advanced versions of
3265 some of its types are available.
3266
3267 \sa QML_ELEMENT, QML_NAMED_ELEMENT(),
3268 {Choosing the Correct Integration Method Between C++ and QML}
3269*/
3270
3271/*!
3272 \fn template<typename T, int metaObjectRevision> int qmlRegisterRevision(const char *uri, int versionMajor, int versionMinor)
3273 \relates <qqml.h>
3274
3275 This template function registers the C++ type \a T at the specified revision
3276 \a metaObjectRevision in the QML system with the library imported from \a uri
3277 having the version number composed from \a versionMajor and \a versionMinor.
3278
3279 Returns the QML type id.
3280
3281 \code
3282 template<typename T, int metaObjectRevision>
3283 int qmlRegisterRevision(const char *uri, int versionMajor, int versionMinor);
3284 \endcode
3285
3286 This function is typically used to register the revision of a base class to
3287 use for the specified version of the type (see \l {Type Revisions and Versions}).
3288*/
3289
3290/*!
3291 \fn template <typename T> int qmlRegisterUncreatableType(const char *uri, int versionMajor, int versionMinor, const char *qmlName, const QString& message)
3292 \relates <qqml.h>
3293
3294 This template function registers the C++ type in the QML system with
3295 the name \a qmlName, in the library imported from \a uri having the
3296 version number composed from \a versionMajor and \a versionMinor.
3297
3298 While the type has a name and a type, it cannot be created, and the
3299 given error \a message will result if creation is attempted.
3300
3301 This is useful where the type is only intended for providing attached properties or enum values.
3302
3303 Returns the QML type id.
3304
3305 \sa QML_UNCREATABLE(), qmlRegisterTypeNotAvailable(),
3306 {Choosing the Correct Integration Method Between C++ and QML}
3307*/
3308
3309/*!
3310 \fn template <typename T, typename E> int qmlRegisterExtendedType(const char *uri, int versionMajor, int versionMinor, const char *qmlName)
3311 \relates <qqml.h>
3312
3313 This template function registers the C++ type and its extension object in the
3314 QML system with the name \a qmlName in the library imported from \a uri having
3315 version number composed from \a versionMajor and \a versionMinor. Properties
3316 not available in the main type will be searched for in the extension object.
3317
3318 Returns the QML type id.
3319
3320 \sa QML_EXTENDED(), qmlRegisterType(), {Registering Extension Objects}
3321*/
3322
3323/*!
3324 \fn template <typename T, typename E> int qmlRegisterExtendedUncreatableType(const char *uri, int versionMajor, int versionMinor, const char *qmlName, const QString& reason)
3325 \relates <qqml.h>
3326
3327 This template function registers the C++ type and its extension
3328 in the QML system with the name \a qmlName in the library imported
3329 from \a uri having version number composed from \a versionMajor and
3330 \a versionMinor.
3331
3332 While the type has a name and a type, it cannot be created. An error
3333 message with the given \a reason is printed if the user attempts to
3334 create an instance of this type.
3335
3336 This is useful where the type is only intended for providing attached
3337 properties, enum values or an abstract base class with its extension.
3338
3339 Returns the QML type id.
3340
3341 \sa QML_EXTENDED(), QML_UNCREATABLE(), qmlRegisterUncreatableType()
3342*/
3343
3344/*!
3345 \fn int qmlRegisterCustomExtendedType(const char *uri, int versionMajor, int versionMinor, const char *qmlName, QQmlCustomParser *parser)
3346 \relates <qqml.h>
3347 \internal
3348
3349 This template function registers the C++ type and its extension
3350 in the QML system with the name \a qmlName in the library imported
3351 from \a uri having version number composed from \a versionMajor and
3352 \a versionMinor. Properties from the C++ type or its extension that
3353 cannot be resolved directly by the QML system will be resolved using
3354 the \a parser provided.
3355
3356 Returns the QML type id.
3357
3358 \sa QML_ELEMENT, QML_NAMED_ELEMENT(), QML_EXTENDED()
3359*/
3360
3361/*!
3362 \fn template <typename T> int qmlRegisterAnonymousType(const char *uri, int versionMajor)
3363 \relates <qqml.h>
3364
3365 This template function registers the C++ type in the QML system as an anonymous type. The
3366 resulting QML type does not have a name. Therefore, instances of this type cannot be created from
3367 the QML system. You can, however, access instances of the type when they are exposed as properties
3368 of other types.
3369
3370 Use this function when the type will not be referenced by name, specifically for C++ types that
3371 are used on the left-hand side of a property binding. To indicate to which module the type belongs
3372 use \a uri and \a versionMajor.
3373
3374 For example, consider the following two classes:
3375
3376 //! Workaround for MOC not respecting comments and triggering an error on certain Qt macros.
3377 \code Q
3378 class Bar : public QObject
3379 {
3380 \1_OBJECT
3381 Q_PROPERTY(QString baz READ baz WRITE setBaz NOTIFY bazChanged)
3382
3383 public:
3384 Bar() {}
3385
3386 QString baz() const { return mBaz; }
3387
3388 void setBaz(const QString &baz)
3389 {
3390 if (baz == mBaz)
3391 return;
3392
3393 mBaz = baz;
3394 emit bazChanged();
3395 }
3396
3397 signals:
3398 void bazChanged();
3399
3400 private:
3401 QString mBaz;
3402 };
3403
3404 class Foo : public QObject
3405 {
3406 \1_OBJECT
3407 Q_PROPERTY(Bar *bar READ bar CONSTANT FINAL)
3408
3409 public:
3410 Foo() {}
3411
3412 Bar *bar() { return &mBar; }
3413
3414 private:
3415 Bar mBar;
3416 };
3417 \endcode
3418
3419 In QML, we assign a string to the \c baz property of \c bar:
3420
3421 \code
3422 Foo {
3423 bar.baz: "abc"
3424 Component.onCompleted: print(bar.baz)
3425 }
3426 \endcode
3427
3428 For the QML engine to know that the \c Bar type has a \c baz property,
3429 we have to make \c Bar known:
3430
3431 \code
3432 qmlRegisterType<Foo>("App", 1, 0, "Foo");
3433 qmlRegisterAnonymousType<Bar>("App", 1);
3434 \endcode
3435
3436 As the \c Foo type is instantiated in QML, it must be registered
3437 with the version of \l qmlRegisterType() that takes an element name.
3438
3439 Returns the QML type id.
3440
3441 \since 5.14
3442 \sa QML_ANONYMOUS, {Choosing the Correct Integration Method Between C++ and QML}
3443*/
3444
3445/*!
3446 \fn int qmlRegisterInterface(const char *typeName)
3447 \relates <qqml.h>
3448
3449 This template function registers the C++ type in the QML system
3450 under the name \a typeName.
3451
3452 Types registered as an interface with the engine should also
3453 declare themselves as an interface with the
3454 \l {The Meta-Object System}{meta object system}. For example:
3455
3456 \code
3457 struct FooInterface
3458 {
3459 public:
3460 virtual ~FooInterface();
3461 virtual void doSomething() = 0;
3462 };
3463
3464 Q_DECLARE_INTERFACE(FooInterface, "org.foo.FooInterface")
3465 \endcode
3466
3467 When registered with the QML engine in this way, they can be used as
3468 property types:
3469
3470 Q_PROPERTY(FooInterface *foo READ foo WRITE setFoo)
3471
3472 When you assign a \l QObject sub-class to this property, the QML engine does
3473 the interface cast to \c FooInterface* automatically.
3474
3475 Returns the QML type id.
3476
3477 \sa QML_INTERFACE
3478*/
3479
3480/*!
3481 \fn int qmlRegisterSingletonType(const char *uri, int versionMajor, int versionMinor, const char *typeName, std::function<QJSValue(QQmlEngine *, QJSEngine *)> callback)
3482 \relates <qqml.h>
3483
3484 This function may be used to register a singleton type provider \a callback in a particular \a uri
3485 and \a typeName with a version specified in \a versionMajor and \a versionMinor.
3486
3487 Installing a singleton type allows developers to provide arbitrary functionality
3488 (methods and properties) to a client without requiring individual instances of the type to
3489 be instantiated by the client.
3490
3491 A singleton type may be either a QObject or a QJSValue.
3492 This function should be used to register a singleton type provider function which returns a QJSValue as a singleton type.
3493
3494 \b{NOTE:} QJSValue singleton type properties will \b{not} trigger binding re-evaluation if changed.
3495
3496 Usage:
3497 \code
3498 // First, define the singleton type provider function (callback).
3499 static QJSValue example_qjsvalue_singletontype_provider(QQmlEngine *engine, QJSEngine *scriptEngine)
3500 {
3501 Q_UNUSED(engine)
3502
3503 static int seedValue = 5;
3504 QJSValue example = scriptEngine->newObject();
3505 example.setProperty("someProperty", seedValue++);
3506 return example;
3507 }
3508
3509 // Second, register the singleton type provider with QML by calling this function in an initialization function.
3510 qmlRegisterSingletonType("Qt.example.qjsvalueApi", 1, 0, "MyApi", example_qjsvalue_singletontype_provider);
3511 \endcode
3512
3513 Alternatively, you can use a C++11 lambda:
3514
3515 \code
3516 qmlRegisterSingletonType("Qt.example.qjsvalueApi", 1, 0, "MyApi", [](QQmlEngine *engine, QJSEngine *scriptEngine) -> QJSValue {
3517 Q_UNUSED(engine)
3518
3519 static int seedValue = 5;
3520 QJSValue example = scriptEngine->newObject();
3521 example.setProperty("someProperty", seedValue++);
3522 return example;
3523 });
3524 \endcode
3525
3526 In order to use the registered singleton type in QML, you must import the singleton type.
3527 \qml
3528 import QtQuick 2.0
3529 import Qt.example.qjsvalueApi 1.0 as ExampleApi
3530 Item {
3531 id: root
3532 property int someValue: ExampleApi.MyApi.someProperty
3533 }
3534 \endqml
3535
3536 \sa QML_SINGLETON, {Choosing the Correct Integration Method Between C++ and QML}
3537*/
3538
3539/*!
3540 \fn template<typename T> QObject *qmlAttachedPropertiesObject(const QObject *attachee, bool createIfMissing)
3541 \relates <qqml.h>
3542
3543 The form of this template function is:
3544
3545 \code
3546 template<typename T> QObject *qmlAttachedPropertiesObject(const QObject *attachee, bool createIfMissing = true)
3547 \endcode
3548
3549 This returns the attached object instance that has been attached to the specified
3550 \a attachee by the attaching type \e T.
3551
3552 If \a attachee is \nullptr, returns \nullptr.
3553
3554 If an existing attached object instance of type \e T exists, it will return
3555 it. Otherwise, it will return a newly created instance if
3556 \a createIfMissing is \c true and \e T is a valid attaching type, or
3557 \nullptr if it's not.
3558
3559 \sa QML_ATTACHED(), {Providing Attached Properties}
3560*/
3561
3562/*!
3563 \fn template <typename T> int qmlRegisterSingletonType(const char *uri, int versionMajor, int versionMinor, const char *typeName, std::function<QObject*(QQmlEngine *, QJSEngine *)> callback)
3564 \relates <qqml.h>
3565
3566 This function may be used to register a singleton type provider \a callback in a particular \a uri
3567 and \a typeName with a version specified in \a versionMajor and \a versionMinor.
3568
3569 Installing a singleton type into a uri allows developers to provide arbitrary functionality
3570 (methods and properties) to clients without requiring individual instances ot the type to be
3571 instantiated by the client.
3572
3573 A singleton type may be either a QObject or a QJSValue.
3574 This function should be used to register a singleton type provider function which returns a QObject
3575 of the given type T as a singleton type.
3576
3577 A QObject singleton type may be referenced via the type name with which it was registered, and this
3578 typename may be used as the target in a \l Connections type or otherwise used as any other type id would.
3579 One exception to this is that a QObject singleton type property may not be aliased.
3580
3581 \b{NOTE:} A QObject singleton type instance returned from a singleton type provider is owned by
3582 the QML engine unless the object has explicit QQmlEngine::CppOwnership flag set.
3583
3584 Usage:
3585 //! Workaround for MOC not respecting comments and triggering an error on certain Qt macros.
3586 \code Q
3587 // First, define your QObject which provides the functionality.
3588 class SingletonTypeExample : public QObject
3589 {
3590 \1_OBJECT
3591 Q_PROPERTY (int someProperty READ someProperty WRITE setSomeProperty NOTIFY somePropertyChanged)
3592
3593 public:
3594 SingletonTypeExample(QObject *parent = nullptr)
3595 : QObject(parent), m_someProperty(0)
3596 {
3597 }
3598
3599 ~SingletonTypeExample() {}
3600
3601 Q_INVOKABLE int doSomething() { setSomeProperty(5); return m_someProperty; }
3602
3603 int someProperty() const { return m_someProperty; }
3604 void setSomeProperty(int val) { m_someProperty = val; emit somePropertyChanged(val); }
3605
3606 signals:
3607 void somePropertyChanged(int newValue);
3608
3609 private:
3610 int m_someProperty;
3611 };
3612
3613 // Second, define the singleton type provider function (callback).
3614 static QObject *example_qobject_singletontype_provider(QQmlEngine *engine, QJSEngine *scriptEngine)
3615 {
3616 Q_UNUSED(engine)
3617 Q_UNUSED(scriptEngine)
3618
3619 SingletonTypeExample *example = new SingletonTypeExample();
3620 return example;
3621 }
3622
3623 // Third, register the singleton type provider with QML by calling this function in an initialization function.
3624 qmlRegisterSingletonType<SingletonTypeExample>("Qt.example.qobjectSingleton", 1, 0, "MyApi", example_qobject_singletontype_provider);
3625 \endcode
3626
3627 Alternatively, you can use a C++11 lambda:
3628
3629 \code
3630 qmlRegisterSingletonType<SingletonTypeExample>("Qt.example.qobjectSingleton", 1, 0, "MyApi", [](QQmlEngine *engine, QJSEngine *scriptEngine) -> QObject * {
3631 Q_UNUSED(engine)
3632 Q_UNUSED(scriptEngine)
3633
3634 SingletonTypeExample *example = new SingletonTypeExample();
3635 return example;
3636 });
3637 \endcode
3638
3639 In order to use the registered singleton type in QML, you must import the singleton type.
3640 \qml
3641 import QtQuick 2.0
3642 import Qt.example.qobjectSingleton 1.0
3643 Item {
3644 id: root
3645 property int someValue: MyApi.someProperty
3646
3647 Component.onCompleted: {
3648 someValue = MyApi.doSomething()
3649 }
3650 }
3651 \endqml
3652
3653 \sa QML_SINGLETON, {Choosing the Correct Integration Method Between C++ and QML}
3654*/
3655
3656/*!
3657 \fn int qmlRegisterSingletonType(const QUrl &url, const char *uri, int versionMajor, int versionMinor, const char *qmlName)
3658 \relates <qqml.h>
3659
3660 This function may be used to register a singleton type with the name \a qmlName, in the library imported from \a uri having
3661 the version number composed from \a versionMajor and \a versionMinor. The type is defined by the QML file located at \a url.
3662 The url must be an absolute URL, i.e. url.isRelative() == false.
3663
3664 In addition the type's QML file must have pragma Singleton statement among its import statements.
3665
3666 A singleton type may be referenced via the type name with which it was registered, and this typename may be used as the
3667 target in a \l Connections type or otherwise used as any other type id would. One exception to this is that a singleton
3668 type property may not be aliased (because the singleton type name does not identify an object within the same component
3669 as any other item).
3670
3671 Usage:
3672 \qml
3673 // First, define your QML singleton type which provides the functionality.
3674 pragma Singleton
3675 import QtQuick 2.0
3676 Item {
3677 property int testProp1: 125
3678 }
3679 \endqml
3680
3681 \code
3682 // Second, register the QML singleton type by calling this function in an initialization function.
3683 qmlRegisterSingletonType(QUrl("file:///absolute/path/SingletonType.qml"), "Qt.example.qobjectSingleton", 1, 0, "RegisteredSingleton");
3684 \endcode
3685
3686 In order to use the registered singleton type in QML, you must import the singleton type.
3687 \qml
3688 import QtQuick 2.0
3689 import Qt.example.qobjectSingleton 1.0
3690 Item {
3691 id: root
3692 property int someValue: RegisteredSingleton.testProp1
3693 }
3694 \endqml
3695
3696 It is also possible to have QML singleton types registered without using the qmlRegisterSingletonType function.
3697 That can be done by adding a pragma Singleton statement among the imports of the type's QML file. In addition
3698 the type must be defined in a qmldir file with a singleton keyword and the qmldir must be imported by the QML
3699 files using the singleton.
3700
3701 \sa QML_SINGLETON
3702*/
3703
3704/*!
3705 \fn int qmlRegisterSingletonInstance(const char *uri, int versionMajor, int versionMinor, const char *typeName, QObject *cppObject)
3706 \relates <qqml.h>
3707 \since 5.14
3708
3709 This function is used to register a singleton object \a cppObject, with a
3710 particular \a uri and \a typeName. Its version is a combination of \a
3711 versionMajor and \a versionMinor.
3712
3713 Installing a singleton type into a URI allows you to provide arbitrary
3714 functionality (methods and properties) to QML code without requiring
3715 individual instances of the type to be instantiated by the client.
3716
3717 Use this function to register an object of the given type T as a singleton
3718 type.
3719
3720 A QObject singleton type may be referenced via the type name with which it
3721 was registered; in turn this type name may be used as the target in a \l
3722 Connections type, or like any other type ID. However, there's one
3723 exception: a QObject singleton type property can't be aliased because the
3724 singleton type name does not identify an object within the same component
3725 as any other item.
3726
3727 \note \a cppObject must outlive the QML engine in which it is used.
3728 Moreover, \cppObject must have the same thread affinity as the engine. If
3729 you want separate singleton instances for multiple engines, you need to use
3730 \l {qmlRegisterSingletonType}. See \l{Threads and QObjects} for more
3731 information about thread safety.
3732
3733 \b{NOTE:} qmlRegisterSingleton can only be used when all types of that module are registered procedurally.
3734
3735 Usage:
3736 //! Workaround for MOC not respecting comments and triggering an error on certain Qt macros.
3737 \code Q
3738 // First, define your QObject which provides the functionality.
3739 class SingletonTypeExample : public QObject
3740 {
3741 \1_OBJECT
3742 Q_PROPERTY(int someProperty READ someProperty WRITE setSomeProperty NOTIFY somePropertyChanged)
3743
3744 public:
3745 explicit SingletonTypeExample(QObject* parent = nullptr) : QObject(parent) {}
3746
3747 Q_INVOKABLE int doSomething()
3748 {
3749 setSomeProperty(5);
3750 return m_someProperty;
3751 }
3752
3753 int someProperty() const { return m_someProperty; }
3754 void setSomeProperty(int val) {
3755 if (m_someProperty != val) {
3756 m_someProperty = val;
3757 emit somePropertyChanged(val);
3758 }
3759 }
3760
3761 signals:
3762 void somePropertyChanged(int newValue);
3763
3764 private:
3765 int m_someProperty = 0;
3766 };
3767 \endcode
3768
3769 \code
3770 // Second, create an instance of the object
3771
3772 // allocate example before the engine to ensure that it outlives it
3773 QScopedPointer<SingletonTypeExample> example(new SingletonTypeExample);
3774 QQmlEngine engine;
3775
3776 // Third, register the singleton type provider with QML by calling this
3777 // function in an initialization function.
3778 qmlRegisterSingletonInstance("Qt.example.qobjectSingleton", 1, 0, "MyApi", example.get());
3779 \endcode
3780
3781
3782 In order to use the registered singleton type in QML, you must import the
3783 URI with the corresponding version.
3784 \qml
3785 import QtQuick 2.0
3786 import Qt.example.qobjectSingleton 1.0
3787 Item {
3788 id: root
3789 property int someValue: MyApi.someProperty
3790
3791 Component.onCompleted: {
3792 console.log(MyApi.doSomething())
3793 }
3794 }
3795 \endqml
3796
3797 \sa QML_SINGLETON, qmlRegisterSingletonType
3798 */
3799
3800/*!
3801 \fn int qmlRegisterType(const QUrl &url, const char *uri, int versionMajor, int versionMinor, const char *qmlName);
3802 \relates <qqml.h>
3803
3804 This function registers a type in the QML system with the name \a qmlName, in the library imported from \a uri having the
3805 version number composed from \a versionMajor and \a versionMinor. The type is defined by the QML file located at \a url. The
3806 url must be an absolute URL, i.e. url.isRelative() == false.
3807
3808 Normally QML files can be loaded as types directly from other QML files, or using a qmldir file. This function allows
3809 registration of files to types from C++ code, such as when the type mapping needs to be procedurally determined at startup.
3810
3811 Returns -1 if the registration was not successful.
3812*/
3813
3814QT_END_NAMESPACE
PropertyResult loadFallbackAsVariant(QV4::Lookup *lookup, QObject *object, void *target, const AOTCompiledContext *aotContext)
Definition qqml.cpp:1458
static ObjectLookupResult initObjectLookup(const AOTCompiledContext *aotContext, QV4::Lookup *lookup, QObject *object)
Definition qqml.cpp:1710
void qmlRegisterTypeAndRevisions< QQmlTypeNotAvailable, void >(const char *uri, int versionMajor, const QMetaObject *classInfoMetaObject, QList< int > *qmlTypeIds, const QMetaObject *extension, bool)
Definition qqml.cpp:1116
PropertyResult writeBackObjectAsVariant(QV4::Lookup *lookup, QObject *object, void *source)
Definition qqml.cpp:1447
static PropertyResult writeBackFallbackProperty(QV4::Lookup *lookup, QObject *object, void *source)
Definition qqml.cpp:1422
static PropertyResult changeFallbackProperty(QV4::Lookup *lookup, QObject *object, Op op)
Definition qqml.cpp:1521
static FallbackPropertyQmlData findFallbackPropertyQmlData(QV4::Lookup *lookup, QObject *object)
Definition qqml.cpp:1386
static void throwIsNotAFunctionError(const AOTCompiledContext *aotContext, QV4::Lookup *lookup, const QString &object)
Definition qqml.cpp:2248
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:1351
static bool isEnumUnderlyingType(QMetaType enumType, QMetaType numberType)
Definition qqml.cpp:1562
static PropertyResult storeFallbackAsVariant(QV4::ExecutionEngine *v4, QV4::Lookup *lookup, QObject *object, void *value)
Definition qqml.cpp:1675
static void iterateVariant(const QVariant &element, std::vector< QVariant > *elements)
Definition qqml.cpp:1215
static PropertyResult changeObjectProperty(QV4::Lookup *lookup, QObject *object, Op op)
Definition qqml.cpp:1484
static PropertyResult storeObjectProperty(QV4::Lookup *lookup, QObject *object, void *value)
Definition qqml.cpp:1513
PropertyResult loadObjectAsVariant(QV4::Lookup *lookup, QObject *object, void *target, const AOTCompiledContext *aotContext)
Definition qqml.cpp:1435
static bool callQObjectMethod(QV4::ExecutionEngine *engine, QV4::Lookup *lookup, QObject *thisObject, void **args, int argc)
Definition qqml.cpp:2165
ObjectPropertyQmlData findObjectPropertyQmlData(QV4::Lookup *lookup, QObject *object)
Definition qqml.cpp:1332
static void captureFallbackProperty(QObject *object, int coreIndex, int notifyIndex, bool isConstant, const AOTCompiledContext *aotContext)
Definition qqml.cpp:1292
static void initValueLookup(QV4::Lookup *lookup, QV4::ExecutableCompilationUnit *compilationUnit, const QMetaObject *metaObject)
Definition qqml.cpp:1802
static bool inherits(const QQmlPropertyCache *descendent, const QQmlPropertyCache *ancestor)
Definition qqml.cpp:1314
static bool canHoldVoid(QMetaType type)
Definition qqml.cpp:1597
static bool tryEnsureMethodsCache(QV4::QObjectMethod *method, QObject *object)
Definition qqml.cpp:2311
static void captureObjectProperty(QObject *object, const QQmlPropertyCache *propertyCache, const QQmlPropertyData *property, const AOTCompiledContext *aotContext)
Definition qqml.cpp:1303
PropertyResult writeBackFallbackAsVariant(QV4::Lookup *lookup, QObject *object, void *source)
Definition qqml.cpp:1471
static PropertyResult storeFallbackProperty(QV4::Lookup *lookup, QObject *object, void *value)
Definition qqml.cpp:1535
static bool isUndefined(const void *value, QMetaType type)
Definition qqml.cpp:1924
static bool callQObjectMethodAsVariant(QV4::ExecutionEngine *engine, QV4::Lookup *lookup, QObject *thisObject, void **args, int argc)
Definition qqml.cpp:2141
static QMetaType jsTypedFunctionArgument(const QQmlType &type, const QV4::CompiledData::ParameterType &parameter)
Definition qqml.cpp:2124
static PropertyResult resetFallbackProperty(QV4::Lookup *lookup, QObject *object, QV4::ExecutionEngine *v4)
Definition qqml.cpp:1544
static PropertyResult loadFallbackProperty(QV4::Lookup *lookup, QObject *object, void *target, const AOTCompiledContext *aotContext)
Definition qqml.cpp:1402
static bool callArrowFunction(QV4::ExecutionEngine *engine, QV4::ArrowFunction *function, QObject *thisObject, void **args, int argc)
Definition qqml.cpp:2203
static PropertyResult resetObjectProperty(QV4::Lookup *lookup, QObject *object, QV4::ExecutionEngine *v4)
Definition qqml.cpp:1498
static PropertyResult storeObjectAsVariant(QV4::ExecutionEngine *v4, QV4::Lookup *lookup, QObject *object, void *value)
Definition qqml.cpp:1643
static bool callQObjectMethodWithTypes(QV4::ExecutionEngine *engine, QV4::Lookup *lookup, QObject *thisObject, void **args, QMetaType *types, int argc)
Definition qqml.cpp:2130
static bool isTypeCompatible(QMetaType source, QMetaType target)
Definition qqml.cpp:1605
PropertyResult writeBackObjectProperty(QV4::Lookup *lookup, QObject *object, void *source)
Definition qqml.cpp:1369
void initObjectLookup(const AOTCompiledContext *aotContext, uint index, QObject *object)
Definition qqml.cpp:1775
static QQmlPropertyCapture * propertyCapture(const AOTCompiledContext *aotContext)
Definition qqml.cpp:1169
static MatchScore resolveQObjectMethodOverload(QV4::QObjectMethod *method, QV4::Lookup *lookup, int relativeMethodIndex)
Definition qqml.cpp:2282
Combined button and popup list for selecting options.
QQmlAttachedPropertiesFunc qmlAttachedPropertiesFunction(QObject *object, const QMetaObject *attachedMetaObject)
Definition qqml.cpp:116
static QList< QTypeRevision > availableRevisions(const QMetaObject *metaObject)
Definition qqml.cpp:581
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
static void uniqueRevisions(QList< QTypeRevision > *revisions, QTypeRevision defaultVersion, QTypeRevision added)
Definition qqml.cpp:629
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
QQmlContext * qmlContext(const QObject *obj)
Definition qqml.cpp:85
static QObject * resolveAttachedProperties(QQmlAttachedPropertiesFunc pf, QQmlData *data, QObject *object, bool create)
Definition qqml.cpp:98
QT_BEGIN_NAMESPACE void qmlExecuteDeferred(QObject *object)
\inmodule QtQml \title Functions to register C++ types to QML
Definition qqml.cpp:59
static QList< QTypeRevision > prepareRevisions(const QMetaObject *metaObject, QTypeRevision added)
Definition qqml.cpp:622
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 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:1382