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