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
qqmlobjectcreator.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 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
6
7#include <private/qjsvalue_p.h>
8#include <private/qqmlanybinding_p.h>
9#include <private/qqmlbinding_p.h>
10#include <private/qqmlboundsignal_p.h>
11#include <private/qqmlcomponent_p.h>
12#include <private/qqmlcomponentattached_p.h>
13#include <private/qqmlcustomparser_p.h>
14#include <private/qqmldebugconnector_p.h>
15#include <private/qqmldebugserviceinterfaces_p.h>
16#include <private/qqmlengine_p.h>
17#include <private/qqmlpropertybinding_p.h>
18#include <private/qqmlpropertyvalueinterceptor_p.h>
19#include <private/qqmlscriptdata_p.h>
20#include <private/qqmlscriptstring_p.h>
21#include <private/qqmlsourcecoordinate_p.h>
22#include <private/qqmlstringconverters_p.h>
23#include <private/qqmlvaluetypeproxybinding_p.h>
24#include <private/qqmlvme_p.h>
25#include <private/qqmlvmemetaobject_p.h>
26#include <private/qv4function_p.h>
27#include <private/qv4functionobject_p.h>
28#include <private/qv4generatorobject_p.h>
29#include <private/qv4qobjectwrapper_p.h>
30#include <private/qv4referenceobject_p.h>
31#include <private/qv4resolvedtypereference_p.h>
32
33#include <qtqml_tracepoints_p.h>
34
35#include <QtCore/qscopedvaluerollback.h>
36#include <QtCore/qloggingcategory.h>
37
38Q_STATIC_LOGGING_CATEGORY(lcQmlDefaultMethod, "qt.qml.defaultmethod")
39
40QT_USE_NAMESPACE
41
42Q_TRACE_PREFIX(qtqml,
43"namespace QV4 {" \
44"struct ExecutionEngine;"\
45"class ExecutableCompilationUnit;"\
46"namespace CompiledData {"\
47"struct Object;"\
48"}}"\
49"class QQmlEngine;"
50)
51
52Q_TRACE_POINT(qtqml, QQmlObjectCreator_createInstance_entry, const QV4::ExecutableCompilationUnit *compilationUnit, const QV4::CompiledData::Object *object, const QUrl &url)
53Q_TRACE_POINT(qtqml, QQmlObjectCreator_createInstance_exit, const QString &typeName)
54
55QQmlObjectCreator::QQmlObjectCreator(
56 const QQmlRefPointer<QQmlContextData> &parentContext,
57 const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit,
58 const QQmlRefPointer<QQmlContextData> &creationContext,
59 const QString &inlineComponentName,
60 QQmlIncubatorPrivate *incubator)
61 : phase(Startup)
62 , m_inlineComponentName(inlineComponentName)
63 , compilationUnit(compilationUnit)
64 , propertyCaches(compilationUnit->propertyCachesPtr())
65 , sharedState(new QQmlObjectCreatorSharedState, QQmlRefPointer<QQmlObjectCreatorSharedState>::Adopt)
66 , topLevelCreator(true)
67 , isContextObject(true)
68 , incubator(incubator)
69{
70 init(parentContext);
71
72 sharedState->componentAttached = nullptr;
73 sharedState->allJavaScriptObjects = ObjectInCreationGCAnchorList();
74 sharedState->creationContext = creationContext;
75 sharedState->rootContext.reset();
76 sharedState->hadTopLevelRequiredProperties = false;
77
78 if (auto profiler = QQmlEnginePrivate::get(engine)->profiler) {
79 Q_QML_PROFILE_IF_ENABLED(QQmlProfilerDefinitions::ProfileCreating, profiler,
80 sharedState->profiler.init(profiler));
81 } else {
82 Q_UNUSED(profiler);
83 }
84}
85
86QQmlObjectCreator::QQmlObjectCreator(const QQmlRefPointer<QQmlContextData> &parentContext,
87 const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, const QString inlineComponentName,
88 QQmlObjectCreatorSharedState *inheritedSharedState, bool isContextObject)
89 : phase(Startup)
90 , m_inlineComponentName(inlineComponentName)
91 , compilationUnit(compilationUnit)
92 , propertyCaches(compilationUnit->propertyCachesPtr())
93 , sharedState(inheritedSharedState)
94 , topLevelCreator(false)
95 , isContextObject(isContextObject)
96 , incubator(nullptr)
97{
98 init(parentContext);
99}
100
101void QQmlObjectCreator::init(const QQmlRefPointer<QQmlContextData> &providedParentContext)
102{
103 parentContext = providedParentContext;
104 engine = parentContext->engine();
105 v4 = engine->handle();
106
107 Q_ASSERT(compilationUnit);
108 Q_ASSERT(compilationUnit->engine == v4);
109 if (!compilationUnit->runtimeStrings)
110 compilationUnit->populate();
111
112 qmlUnit = compilationUnit->unitData();
113 _qobject = nullptr;
114 _scopeObject = nullptr;
115 _bindingTarget = nullptr;
116 _valueTypeProperty = nullptr;
117 _compiledObject = nullptr;
118 _compiledObjectIndex = -1;
119 _ddata = nullptr;
120 _vmeMetaObject = nullptr;
121 _qmlContext = nullptr;
122}
123
124QQmlObjectCreator::~QQmlObjectCreator()
125{
126 if (topLevelCreator) {
127 {
128 // This signals to other methods further up the stack that we have
129 // "recursed" and they should be aborted.
130 QQmlObjectCreatorRecursionWatcher watcher(this);
131 }
132 while (sharedState->componentAttached) {
133 QQmlComponentAttached *a = sharedState->componentAttached;
134 a->removeFromList();
135 }
136 }
137}
138
139QObject *QQmlObjectCreator::create(int subComponentIndex, QObject *parent, QQmlInstantiationInterrupt *interrupt, int flags)
140{
141 if (phase == CreatingObjectsPhase2) {
142 phase = ObjectsCreated;
143 return context->contextObject();
144 }
145 Q_ASSERT(phase == Startup);
146 phase = CreatingObjects;
147
148 int objectToCreate;
149 bool isComponentRoot = false; // either a "real" component of or an inline component
150
151 if (subComponentIndex == -1) {
152 objectToCreate = /*root object*/0;
153 isComponentRoot = true;
154 } else {
155 Q_ASSERT(subComponentIndex >= 0);
156 if (flags & CreationFlags::InlineComponent) {
157 if (compilationUnit->componentsAreBound()
158 && compilationUnit != parentContext->typeCompilationUnit()) {
159 recordError({}, tr("Cannot instantiate bound inline component in different file"));
160 phase = ObjectsCreated;
161 return nullptr;
162 }
163 objectToCreate = subComponentIndex;
164 isComponentRoot = true;
165 } else {
166 Q_ASSERT(flags & CreationFlags::NormalObject);
167 if (compilationUnit->componentsAreBound()
168 && sharedState->creationContext != parentContext) {
169 recordError({}, tr("Cannot instantiate bound component "
170 "outside its creation context"));
171 phase = ObjectsCreated;
172 return nullptr;
173 }
174 if (subComponentIndex < compilationUnit->objectCount()) {
175 const QV4::CompiledData::Object *compObj
176 = compilationUnit->objectAt(subComponentIndex);
177 objectToCreate = compObj->bindingTable()->value.objectIndex;
178 } else {
179 // Implicit component wrappers have index >= objectCount().
180 // Read child index from the property cache instead of the CU object.
181 objectToCreate = compilationUnit->resolvedIndex(subComponentIndex);
182 }
183 }
184 }
185
186 QQmlEnginePrivate *enginePriv = QQmlEnginePrivate::get(engine);
187 context = isComponentRoot
188 ? enginePriv->createComponentRootContext(compilationUnit, parentContext,
189 subComponentIndex)
190 : enginePriv->createBareContext(compilationUnit, parentContext, subComponentIndex);
191
192 if (!sharedState->rootContext) {
193 sharedState->rootContext = context;
194 sharedState->rootContext->setIncubator(incubator);
195 sharedState->rootContext->setRootObjectInCreation(true);
196 }
197
198 QV4::Scope scope(v4);
199
200 Q_ASSERT(sharedState->allJavaScriptObjects.canTrack() || topLevelCreator);
201 if (topLevelCreator)
202 sharedState->allJavaScriptObjects = ObjectInCreationGCAnchorList(scope);
203
204 if (!isComponentRoot && sharedState->creationContext) {
205 // otherwise QQmlEnginePrivate::createComponentRootContext() handles it
206 QV4::ScopedValue scripts(scope, sharedState->creationContext->importedScripts());
207 context->setImportedScripts(v4, scripts);
208 }
209
210 QObject *instance = createInstance(objectToCreate, parent, /*isContextObject*/true);
211 if (instance) {
212 QQmlData *ddata = QQmlData::get(instance);
213 Q_ASSERT(ddata);
214 ddata->compilationUnit = compilationUnit;
215 }
216
217 if (topLevelCreator)
218 sharedState->allJavaScriptObjects = ObjectInCreationGCAnchorList();
219
220 phase = CreatingObjectsPhase2;
221
222 if (interrupt && interrupt->shouldInterrupt())
223 return nullptr;
224
225 phase = ObjectsCreated;
226
227 if (instance) {
228 if (QQmlEngineDebugService *service
229 = QQmlDebugConnector::service<QQmlEngineDebugService>()) {
230 if (!parentContext->isInternal())
231 parentContext->asQQmlContextPrivate()->appendInstance(instance);
232 service->objectCreated(engine, instance);
233 } else if (!parentContext->isInternal() && QQmlDebugConnector::service<QV4DebugService>()) {
234 parentContext->asQQmlContextPrivate()->appendInstance(instance);
235 }
236 }
237
238 return instance;
239}
240
241void QQmlObjectCreator::beginPopulateDeferred(const QQmlRefPointer<QQmlContextData> &newContext)
242{
243 context = newContext;
244 sharedState->rootContext = newContext;
245
246 Q_ASSERT(topLevelCreator);
247 Q_ASSERT(!sharedState->allJavaScriptObjects.canTrack());
248
249 // FIXME (QTBUG-122956): allocating from the short lived scope does not make any sense
250 QV4::Scope valueScope(v4);
251 sharedState->allJavaScriptObjects = ObjectInCreationGCAnchorList(valueScope);
252}
253
254void QQmlObjectCreator::populateDeferred(QObject *instance, int deferredIndex,
255 const QQmlPropertyPrivate *qmlProperty,
256 const QV4::CompiledData::Binding *binding)
257{
258 doPopulateDeferred(instance, deferredIndex, [this, qmlProperty, binding]() {
259 Q_ASSERT(qmlProperty);
260 Q_ASSERT(binding->hasFlag(QV4::CompiledData::Binding::IsDeferredBinding));
261
262 QQmlListProperty<QObject> savedList;
263 qSwap(_currentList, savedList);
264
265 const QQmlPropertyData &property = qmlProperty->core;
266
267 if (property.propType().flags().testFlag(QMetaType::IsQmlList)) {
268 void *argv[1] = { (void*)&_currentList };
269 QMetaObject::metacall(_qobject, QMetaObject::ReadProperty, property.coreIndex(), argv);
270 } else if (_currentList.object) {
271 _currentList = QQmlListProperty<QObject>();
272 }
273
274 setPropertyBinding(&property, binding);
275
276 qSwap(_currentList, savedList);
277 });
278}
279
280void QQmlObjectCreator::populateDeferred(QObject *instance, int deferredIndex)
281{
282 doPopulateDeferred(instance, deferredIndex, [this]() { setupBindings(ApplyDeferred); });
283}
284
285bool QQmlObjectCreator::populateDeferredProperties(QObject *instance,
286 const QQmlData::DeferredData *deferredData)
287{
288 beginPopulateDeferred(deferredData->context);
289 populateDeferred(instance, deferredData->deferredIdx);
290 finalizePopulateDeferred();
291 return errors.isEmpty();
292}
293
294void QQmlObjectCreator::populateDeferredBinding(const QQmlProperty &qmlProperty, int deferredIndex,
295 const QV4::CompiledData::Binding *binding)
296{
297 if (binding) {
298 populateDeferred(qmlProperty.object(), deferredIndex, QQmlPropertyPrivate::get(qmlProperty),
299 binding);
300 } else {
301 populateDeferred(qmlProperty.object(), deferredIndex);
302 }
303}
304
305void QQmlObjectCreator::populateDeferredInstance(
306 QObject *outerObject, int deferredIndex, int index, QObject *instance,
307 QObject *bindingTarget, const QQmlPropertyData *valueTypeProperty,
308 const QV4::CompiledData::Binding *binding)
309{
310 doPopulateDeferred(outerObject, deferredIndex, [&]() {
311 populateInstance(index, instance, bindingTarget, valueTypeProperty, binding);
312 });
313}
314
315void QQmlObjectCreator::finalizePopulateDeferred()
316{
317 phase = ObjectsCreated;
318}
319
320void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const QV4::CompiledData::Binding *binding)
321{
322 QQmlPropertyData::WriteFlags propertyWriteFlags = QQmlPropertyData::BypassInterceptor | QQmlPropertyData::RemoveBindingOnAliasWrite;
323 QV4::Scope scope(v4);
324
325 QMetaType propertyType = property->propType();
326
327 if (property->isEnum()) {
328 if (binding->hasFlag(QV4::CompiledData::Binding::IsResolvedEnum) ||
329 // TODO: For historical reasons you can assign any number to an enum property alias
330 // This can be fixed with an opt-out mechanism, for example a pragma.
331 (property->isAlias() && binding->isNumberBinding())) {
332 propertyType = property->propType().underlyingType();
333 } else {
334 // ### This should be resolved earlier at compile time and the binding value should be changed accordingly.
335 QVariant value = compilationUnit->bindingValueAsString(binding);
336 bool ok = QQmlPropertyPrivate::write(_qobject, *property, value, context);
337 Q_ASSERT(ok);
338 Q_UNUSED(ok);
339 return;
340 }
341 }
342
343 auto assertOrNull = [&](bool ok)
344 {
345 Q_ASSERT(ok || binding->type() == QV4::CompiledData::Binding::Type_Null);
346 Q_UNUSED(ok);
347 };
348
349 auto assertType = [&](QV4::CompiledData::Binding::Type type)
350 {
351 Q_ASSERT(binding->type()== type || binding->type() == QV4::CompiledData::Binding::Type_Null);
352 Q_UNUSED(type);
353 };
354
355 if (property->isQObject()) {
356 if (binding->type() == QV4::CompiledData::Binding::Type_Null) {
357 QObject *value = nullptr;
358 const bool ok = property->writeProperty(_qobject, &value, propertyWriteFlags);
359 Q_ASSERT(ok);
360 Q_UNUSED(ok);
361 return;
362 }
363 }
364
365 switch (propertyType.id()) {
366 case QMetaType::QVariant: {
367 if (binding->type() == QV4::CompiledData::Binding::Type_Number) {
368 double n = compilationUnit->bindingValueAsNumber(binding);
369 if (double(int(n)) == n) {
370 if (property->isVarProperty()) {
371 _vmeMetaObject->setVMEProperty(property->coreIndex(), QV4::Value::fromInt32(int(n)));
372 } else {
373 int i = int(n);
374 QVariant value(i);
375 property->writeProperty(_qobject, &value, propertyWriteFlags);
376 }
377 } else {
378 if (property->isVarProperty()) {
379 _vmeMetaObject->setVMEProperty(property->coreIndex(), QV4::Value::fromDouble(n));
380 } else {
381 QVariant value(n);
382 property->writeProperty(_qobject, &value, propertyWriteFlags);
383 }
384 }
385 } else if (binding->type() == QV4::CompiledData::Binding::Type_Boolean) {
386 if (property->isVarProperty()) {
387 _vmeMetaObject->setVMEProperty(property->coreIndex(), QV4::Value::fromBoolean(binding->valueAsBoolean()));
388 } else {
389 QVariant value(binding->valueAsBoolean());
390 property->writeProperty(_qobject, &value, propertyWriteFlags);
391 }
392 } else if (binding->type() == QV4::CompiledData::Binding::Type_Null) {
393 if (property->isVarProperty()) {
394 _vmeMetaObject->setVMEProperty(property->coreIndex(), QV4::Value::nullValue());
395 } else {
396 QVariant nullValue = QVariant::fromValue(nullptr);
397 property->writeProperty(_qobject, &nullValue, propertyWriteFlags);
398 }
399 } else {
400 QString stringValue = compilationUnit->bindingValueAsString(binding);
401 if (property->isVarProperty()) {
402 QV4::ScopedString s(scope, v4->newString(stringValue));
403 _vmeMetaObject->setVMEProperty(property->coreIndex(), s);
404 } else {
405 QVariant value = stringValue;
406 property->writeProperty(_qobject, &value, propertyWriteFlags);
407 }
408 }
409 }
410 break;
411 case QMetaType::QString: {
412 assertOrNull(binding->evaluatesToString());
413 QString value = compilationUnit->bindingValueAsString(binding);
414 property->writeProperty(_qobject, &value, propertyWriteFlags);
415 }
416 break;
417 case QMetaType::QStringList: {
418 assertOrNull(binding->evaluatesToString());
419 QStringList value(compilationUnit->bindingValueAsString(binding));
420 property->writeProperty(_qobject, &value, propertyWriteFlags);
421 }
422 break;
423 case QMetaType::QByteArray: {
424 assertType(QV4::CompiledData::Binding::Type_String);
425 QByteArray value(compilationUnit->bindingValueAsString(binding).toUtf8());
426 property->writeProperty(_qobject, &value, propertyWriteFlags);
427 }
428 break;
429 case QMetaType::QUrl: {
430 assertType(QV4::CompiledData::Binding::Type_String);
431 const QString string = compilationUnit->bindingValueAsString(binding);
432 QUrl value = (!string.isEmpty() && QQmlPropertyPrivate::resolveUrlsOnAssignment())
433 ? compilationUnit->finalUrl().resolved(QUrl(string))
434 : QUrl(string);
435 property->writeProperty(_qobject, &value, propertyWriteFlags);
436 }
437 break;
438 case QMetaType::UInt: {
439 assertType(QV4::CompiledData::Binding::Type_Number);
440 double d = compilationUnit->bindingValueAsNumber(binding);
441 uint value = uint(d);
442 property->writeProperty(_qobject, &value, propertyWriteFlags);
443 break;
444 }
445 break;
446 case QMetaType::Int: {
447 assertType(QV4::CompiledData::Binding::Type_Number);
448 double d = compilationUnit->bindingValueAsNumber(binding);
449 int value = int(d);
450 property->writeProperty(_qobject, &value, propertyWriteFlags);
451 break;
452 }
453 break;
454 case QMetaType::SChar: {
455 assertType(QV4::CompiledData::Binding::Type_Number);
456 double d = compilationUnit->bindingValueAsNumber(binding);
457 qint8 value = qint8(d);
458 property->writeProperty(_qobject, &value, propertyWriteFlags);
459 break;
460 }
461 case QMetaType::UChar: {
462 assertType(QV4::CompiledData::Binding::Type_Number);
463 double d = compilationUnit->bindingValueAsNumber(binding);
464 quint8 value = quint8(d);
465 property->writeProperty(_qobject, &value, propertyWriteFlags);
466 break;
467 }
468 case QMetaType::Short: {
469 assertType(QV4::CompiledData::Binding::Type_Number);
470 double d = compilationUnit->bindingValueAsNumber(binding);
471 qint16 value = qint16(d);
472 property->writeProperty(_qobject, &value, propertyWriteFlags);
473 break;
474 }
475 case QMetaType::UShort: {
476 assertType(QV4::CompiledData::Binding::Type_Number);
477 double d = compilationUnit->bindingValueAsNumber(binding);
478 quint16 value = quint16(d);
479 property->writeProperty(_qobject, &value, propertyWriteFlags);
480 break;
481 }
482 case QMetaType::LongLong: {
483 assertType(QV4::CompiledData::Binding::Type_Number);
484 double d = compilationUnit->bindingValueAsNumber(binding);
485 qint64 value = qint64(d);
486 property->writeProperty(_qobject, &value, propertyWriteFlags);
487 break;
488 }
489 case QMetaType::ULongLong: {
490 assertType(QV4::CompiledData::Binding::Type_Number);
491 double d = compilationUnit->bindingValueAsNumber(binding);
492 quint64 value = quint64(d);
493 property->writeProperty(_qobject, &value, propertyWriteFlags);
494 break;
495 }
496 break;
497 case QMetaType::Float: {
498 assertType(QV4::CompiledData::Binding::Type_Number);
499 float value = float(compilationUnit->bindingValueAsNumber(binding));
500 property->writeProperty(_qobject, &value, propertyWriteFlags);
501 }
502 break;
503 case QMetaType::Double: {
504 assertType(QV4::CompiledData::Binding::Type_Number);
505 double value = compilationUnit->bindingValueAsNumber(binding);
506 property->writeProperty(_qobject, &value, propertyWriteFlags);
507 }
508 break;
509 case QMetaType::QColor: {
510 bool ok = false;
511 QVariant data = QQmlStringConverters::colorFromString(
512 compilationUnit->bindingValueAsString(binding), &ok);
513 Q_ASSERT(ok); // We've checked this in QQmlPropertyValidator
514 property->writeProperty(_qobject, data.data(), propertyWriteFlags);
515 }
516 break;
517#if QT_CONFIG(datestring)
518 case QMetaType::QDate: {
519 bool ok = false;
520 QDate value = QQmlStringConverters::dateFromString(compilationUnit->bindingValueAsString(binding), &ok);
521 assertOrNull(ok);
522 property->writeProperty(_qobject, &value, propertyWriteFlags);
523 }
524 break;
525 case QMetaType::QTime: {
526 bool ok = false;
527 QTime value = QQmlStringConverters::timeFromString(compilationUnit->bindingValueAsString(binding), &ok);
528 assertOrNull(ok);
529 property->writeProperty(_qobject, &value, propertyWriteFlags);
530 }
531 break;
532 case QMetaType::QDateTime: {
533 bool ok = false;
534 QDateTime value = QQmlStringConverters::dateTimeFromString(
535 compilationUnit->bindingValueAsString(binding), &ok);
536 assertOrNull(ok);
537 property->writeProperty(_qobject, &value, propertyWriteFlags);
538 }
539 break;
540#endif // datestring
541 case QMetaType::QPoint: {
542 bool ok = false;
543 QPoint value = QQmlStringConverters::pointFFromString(compilationUnit->bindingValueAsString(binding), &ok).toPoint();
544 assertOrNull(ok);
545 property->writeProperty(_qobject, &value, propertyWriteFlags);
546 }
547 break;
548 case QMetaType::QPointF: {
549 bool ok = false;
550 QPointF value = QQmlStringConverters::pointFFromString(compilationUnit->bindingValueAsString(binding), &ok);
551 assertOrNull(ok);
552 property->writeProperty(_qobject, &value, propertyWriteFlags);
553 }
554 break;
555 case QMetaType::QSize: {
556 bool ok = false;
557 QSize value = QQmlStringConverters::sizeFFromString(compilationUnit->bindingValueAsString(binding), &ok).toSize();
558 assertOrNull(ok);
559 property->writeProperty(_qobject, &value, propertyWriteFlags);
560 }
561 break;
562 case QMetaType::QSizeF: {
563 bool ok = false;
564 QSizeF value = QQmlStringConverters::sizeFFromString(compilationUnit->bindingValueAsString(binding), &ok);
565 assertOrNull(ok);
566 property->writeProperty(_qobject, &value, propertyWriteFlags);
567 }
568 break;
569 case QMetaType::QRect: {
570 bool ok = false;
571 QRect value = QQmlStringConverters::rectFFromString(compilationUnit->bindingValueAsString(binding), &ok).toRect();
572 assertOrNull(ok);
573 property->writeProperty(_qobject, &value, propertyWriteFlags);
574 }
575 break;
576 case QMetaType::QRectF: {
577 bool ok = false;
578 QRectF value = QQmlStringConverters::rectFFromString(compilationUnit->bindingValueAsString(binding), &ok);
579 assertOrNull(ok);
580 property->writeProperty(_qobject, &value, propertyWriteFlags);
581 }
582 break;
583 case QMetaType::Bool: {
584 assertType(QV4::CompiledData::Binding::Type_Boolean);
585 bool value = binding->valueAsBoolean();
586 property->writeProperty(_qobject, &value, propertyWriteFlags);
587 }
588 break;
589 case QMetaType::QVector2D:
590 case QMetaType::QVector3D:
591 case QMetaType::QVector4D:
592 case QMetaType::QQuaternion: {
593 QVariant result = QQmlValueTypeProvider::createValueType(
594 compilationUnit->bindingValueAsString(binding), propertyType);
595 assertOrNull(result.isValid());
596 property->writeProperty(_qobject, result.data(), propertyWriteFlags);
597 break;
598 }
599 default: {
600 // generate single literal value assignment to a list property if required
601 if (propertyType == QMetaType::fromType<QList<qreal>>()) {
602 assertType(QV4::CompiledData::Binding::Type_Number);
603 QList<qreal> value;
604 value.append(compilationUnit->bindingValueAsNumber(binding));
605 property->writeProperty(_qobject, &value, propertyWriteFlags);
606 break;
607 } else if (propertyType == QMetaType::fromType<QList<int>>()) {
608 assertType(QV4::CompiledData::Binding::Type_Number);
609 double n = compilationUnit->bindingValueAsNumber(binding);
610 QList<int> value;
611 value.append(int(n));
612 property->writeProperty(_qobject, &value, propertyWriteFlags);
613 break;
614 } else if (propertyType == QMetaType::fromType<QList<bool>>()) {
615 assertType(QV4::CompiledData::Binding::Type_Boolean);
616 QList<bool> value;
617 value.append(binding->valueAsBoolean());
618 property->writeProperty(_qobject, &value, propertyWriteFlags);
619 break;
620 } else if (propertyType == QMetaType::fromType<QList<QUrl>>()) {
621 assertType(QV4::CompiledData::Binding::Type_String);
622 const QUrl url(compilationUnit->bindingValueAsString(binding));
623 QList<QUrl> value {
624 QQmlPropertyPrivate::resolveUrlsOnAssignment()
625 ? compilationUnit->finalUrl().resolved(url)
626 : url
627 };
628 property->writeProperty(_qobject, &value, propertyWriteFlags);
629 break;
630 } else if (propertyType == QMetaType::fromType<QList<QString>>()) {
631 assertOrNull(binding->evaluatesToString());
632 QList<QString> value;
633 value.append(compilationUnit->bindingValueAsString(binding));
634 property->writeProperty(_qobject, &value, propertyWriteFlags);
635 break;
636 } else if (propertyType == QMetaType::fromType<QJSValue>()) {
637 QJSValue value;
638 switch (binding->type()) {
639 case QV4::CompiledData::Binding::Type_Boolean:
640 value = QJSValue(binding->valueAsBoolean());
641 break;
642 case QV4::CompiledData::Binding::Type_Number: {
643 const double n = compilationUnit->bindingValueAsNumber(binding);
644 if (double(int(n)) == n)
645 value = QJSValue(int(n));
646 else
647 value = QJSValue(n);
648 break;
649 }
650 case QV4::CompiledData::Binding::Type_Null:
651 value = QJSValue::NullValue;
652 break;
653 default:
654 value = QJSValue(compilationUnit->bindingValueAsString(binding));
655 break;
656 }
657 property->writeProperty(_qobject, &value, propertyWriteFlags);
658 break;
659 } else {
660 QVariant source;
661 switch (binding->type()) {
662 case QV4::CompiledData::Binding::Type_Boolean:
663 source = binding->valueAsBoolean();
664 break;
665 case QV4::CompiledData::Binding::Type_Number: {
666 const double n = compilationUnit->bindingValueAsNumber(binding);
667 if (double(int(n)) == n)
668 source = int(n);
669 else
670 source = n;
671 break;
672 }
673 case QV4::CompiledData::Binding::Type_Null:
674 source = QVariant::fromValue<std::nullptr_t>(nullptr);
675 break;
676 case QV4::CompiledData::Binding::Type_Invalid:
677 break;
678 default:
679 source = compilationUnit->bindingValueAsString(binding);
680 break;
681 }
682
683 QVariant target = QQmlValueTypeProvider::createValueType(
684 source, propertyType, engine->handle());
685 if (target.isValid()) {
686 property->writeProperty(_qobject, target.data(), propertyWriteFlags);
687 break;
688 }
689 }
690
691 // string converters are not exposed, so ending up here indicates an error
692 QString stringValue = compilationUnit->bindingValueAsString(binding);
693 QMetaProperty metaProperty = _qobject->metaObject()->property(property->coreIndex());
694 recordError(binding->location, tr("Cannot assign value %1 to property"
695" %2").arg(stringValue, QString::fromUtf8(metaProperty.name())));
696 }
697 break;
698 }
699}
700
701static QQmlType qmlTypeForObject(QObject *object)
702{
703 QQmlType type;
704 const QMetaObject *mo = object->metaObject();
705 while (mo && !type.isValid()) {
706 type = QQmlMetaType::qmlType(mo);
707 mo = mo->superClass();
708 }
709 return type;
710}
711
712void QQmlObjectCreator::setupBindings(BindingSetupFlags mode)
713{
714 QQmlListProperty<QObject> savedList;
715 qSwap(_currentList, savedList);
716
717 const QV4::CompiledData::BindingPropertyData *propertyData
718 = compilationUnit->bindingPropertyDataPerObjectAt(_compiledObjectIndex);
719
720 if (_compiledObject->idNameIndex) {
721 const QQmlPropertyData *idProperty = propertyData->last();
722 Q_ASSERT(!idProperty || !idProperty->isValid() || idProperty->name(_qobject) == QLatin1String("id"));
723 if (idProperty && idProperty->isValid() && idProperty->isWritable() && idProperty->propType().id() == QMetaType::QString) {
724 QV4::CompiledData::Binding idBinding;
725 idBinding.propertyNameIndex = 0; // Not used
726 idBinding.clearFlags();
727 idBinding.setType(QV4::CompiledData::Binding::Type_String);
728 idBinding.stringIndex = _compiledObject->idNameIndex;
729 idBinding.location = _compiledObject->location; // ###
730 idBinding.value.nullMarker = 0; // zero the value field to make codechecker happy
731 setPropertyValue(idProperty, &idBinding);
732 }
733 }
734
735 // ### this is best done through type-compile-time binding skip lists.
736 if (_valueTypeProperty) {
737 QQmlAbstractBinding *binding = QQmlPropertyPrivate::binding(_bindingTarget, QQmlPropertyIndex(_valueTypeProperty->coreIndex()));
738
739 if (binding && binding->kind() != QQmlAbstractBinding::ValueTypeProxy) {
740 QQmlPropertyPrivate::removeBinding(
741 _bindingTarget, QQmlPropertyIndex(_valueTypeProperty->coreIndex()),
742 QQmlPropertyPrivate::OverrideSticky);
743 } else if (binding) {
744 QQmlValueTypeProxyBinding *proxy = static_cast<QQmlValueTypeProxyBinding *>(binding);
745
746 if (qmlTypeForObject(_bindingTarget).isValid()) {
747 quint32 bindingSkipList = 0;
748
749 const QQmlPropertyData *defaultProperty = _compiledObject->indexOfDefaultPropertyOrAlias != -1 ? _propertyCache->parent()->defaultProperty() : _propertyCache->defaultProperty();
750
751 const QV4::CompiledData::Binding *binding = _compiledObject->bindingTable();
752 for (quint32 i = 0; i < _compiledObject->nBindings; ++i, ++binding) {
753 const QQmlPropertyData *property = binding->propertyNameIndex != 0
754 ? _propertyCache->property(stringAt(binding->propertyNameIndex),
755 _qobject, context)
756 : defaultProperty;
757 if (property)
758 bindingSkipList |= (1 << property->coreIndex());
759 }
760
761 proxy->removeBindings(bindingSkipList);
762 }
763 }
764 }
765
766 const QQmlPropertyData *defaultProperty = _compiledObject->indexOfDefaultPropertyOrAlias != -1
767 ? _propertyCache->parent()->defaultProperty()
768 : _propertyCache->defaultProperty();
769
770 int currentListPropertyIndex = -1;
771
772 // Prepare list property state and call setPropertyBinding for one binding.
773 const auto applyBinding = [&](const QQmlPropertyData *property,
774 const QV4::CompiledData::Binding *binding) -> bool {
775 if (property && property->propType().flags().testFlag(QMetaType::IsQmlList)) {
776 if (property->coreIndex() != currentListPropertyIndex) {
777 void *argv[1] = { (void*)&_currentList };
778 QMetaObject::metacall(_qobject, QMetaObject::ReadProperty, property->coreIndex(), argv);
779 currentListPropertyIndex = property->coreIndex();
780
781 // manage override behavior
782 const QMetaObject *const metaobject = _qobject->metaObject();
783 const int qmlListBehavorClassInfoIndex = metaobject->indexOfClassInfo("QML.ListPropertyAssignBehavior");
784 if (qmlListBehavorClassInfoIndex != -1) { // QML.ListPropertyAssignBehavior class info is set
785 const char *overrideBehavior =
786 metaobject->classInfo(qmlListBehavorClassInfoIndex).value();
787 if (!strcmp(overrideBehavior,
788 "Replace")) {
789 if (_currentList.clear) {
790 _currentList.clear(&_currentList);
791 }
792 } else {
793 bool isDefaultProperty =
794 (property->name(_qobject)
795 == QString::fromUtf8(
796 metaobject
797 ->classInfo(metaobject->indexOfClassInfo(
798 "DefaultProperty"))
799 .value()));
800 if (!isDefaultProperty
801 && (!strcmp(overrideBehavior,
802 "ReplaceIfNotDefault"))) {
803 if (_currentList.clear) {
804 _currentList.clear(&_currentList);
805 }
806 }
807 }
808 }
809 }
810 } else if (_currentList.object) {
811 _currentList = QQmlListProperty<QObject>();
812 currentListPropertyIndex = -1;
813 }
814
815 return setPropertyBinding(property, binding);
816 };
817
818 // Explicit default property bindings (propertyNameIndex != 0 but resolving
819 // to the default property) are deferred during iteration over the prepended
820 // section of the binding list and applied in file-offset order once we reach
821 // the appended implicit default bindings (propertyNameIndex == 0).
822 // NB: They have to be contiguous, so we can flush them all in a row.
823 const QV4::CompiledData::Binding *explicitDefaultPropertyBindings = nullptr;
824 quint32 numExplicitDefaultPropertyBindings = 0;
825
826 const auto applyExplicitDefaultPropertyBindings = [&]() -> bool {
827 for (; numExplicitDefaultPropertyBindings > 0; --numExplicitDefaultPropertyBindings) {
828 if (!applyBinding(defaultProperty, explicitDefaultPropertyBindings++))
829 return false;
830 }
831 return true;
832 };
833
834 const QV4::CompiledData::Binding *binding = _compiledObject->bindingTable();
835 for (quint32 i = 0; i < _compiledObject->nBindings; ++i, ++binding) {
836 const QQmlPropertyData *const property = propertyData->at(i);
837 if (property) {
838 const QQmlPropertyData *targetProperty = property;
839 if (targetProperty->isAlias()) {
840 // follow alias
841 QQmlPropertyIndex originalIndex(targetProperty->coreIndex(),
842 _valueTypeProperty ? _valueTypeProperty->coreIndex()
843 : -1);
844 auto [targetObject, targetIndex] =
845 QQmlPropertyPrivate::findAliasTarget(_bindingTarget, originalIndex);
846 QQmlData *data = QQmlData::get(targetObject);
847 Q_ASSERT(data && data->propertyCache);
848 targetProperty = data->propertyCache->property(targetIndex.coreIndex());
849 sharedState->requiredProperties.remove({ targetObject, targetProperty });
850 }
851 sharedState->requiredProperties.remove({ _bindingTarget, property });
852 }
853
854 if (binding->hasFlag(QV4::CompiledData::Binding::IsCustomParserBinding))
855 continue;
856
857 if (binding->hasFlag(QV4::CompiledData::Binding::IsDeferredBinding)) {
858 if (!(mode & ApplyDeferred))
859 continue;
860 } else if (!(mode & ApplyImmediate)) {
861 continue;
862 }
863
864 // Defer explicit bindings to the default property until we reach the
865 // implicit default bindings, where they will be interleaved by offset.
866 if (binding->propertyNameIndex != quint32(0)
867 && defaultProperty
868 && property == defaultProperty) {
869 if (++numExplicitDefaultPropertyBindings == 1)
870 explicitDefaultPropertyBindings = binding;
871 continue;
872 }
873
874 // Flush deferred explicit default bindings if file offset is <= the
875 // current implicit default binding's offset.
876 if (binding->propertyNameIndex == quint32(0)
877 && numExplicitDefaultPropertyBindings > 0
878 && !(binding->location < explicitDefaultPropertyBindings->location)) {
879 if (!applyExplicitDefaultPropertyBindings())
880 return;
881 }
882
883 if (!applyBinding(property, binding))
884 return;
885 }
886
887 // Flush any remaining deferred explicit default bindings.
888 if (!applyExplicitDefaultPropertyBindings())
889 return;
890 qSwap(_currentList, savedList);
891}
892
893bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProperty, const QV4::CompiledData::Binding *binding)
894{
895 const QV4::CompiledData::Binding::Type bindingType = binding->type();
896 if (bindingType == QV4::CompiledData::Binding::Type_AttachedProperty) {
897 const QV4::CompiledData::Object *obj = compilationUnit->objectAt(binding->value.objectIndex);
898 QQmlObjectCreationProfiler profiler(sharedState->profiler.profiler, obj);
899
900 Q_ASSERT(stringAt(obj->inheritedTypeNameIndex).isEmpty());
901 QV4::ResolvedTypeReference *tr = resolvedType(binding->propertyNameIndex);
902 Q_ASSERT(tr);
903 QQmlType attachedType = tr->type();
904 QQmlTypeLoader *typeLoader = QQmlTypeLoader::get(engine);
905 if (!attachedType.isValid()) {
906 QQmlTypeNameCache::Result res
907 = context->imports()->query(stringAt(binding->propertyNameIndex), typeLoader);
908 if (res.isValid())
909 attachedType = res.type;
910 else
911 return false;
912 }
913
914 Q_QML_OC_PROFILE(
915 sharedState->profiler,
916 profiler.update(compilationUnit.data(), obj, attachedType.qmlTypeName(),
917 context->url()));
918
919 QObject *qmlObject = qmlAttachedPropertiesObject(
920 _qobject, attachedType.attachedPropertiesFunction(typeLoader));
921 if (!qmlObject) {
922 recordError(binding->location,
923 QStringLiteral("Could not create attached properties object '%1'")
924 .arg(QString::fromUtf8(attachedType.typeName())));
925 return false;
926 }
927
928 const size_t objectIndex = sharedState->allCreatedObjects.size();
929 sharedState->allCreatedObjects.push_back(qmlObject);
930 const QQmlType attachedObjectType
931 = QQmlMetaType::qmlType(attachedType.attachedPropertiesType(typeLoader));
932 const int parserStatusCast = attachedObjectType.parserStatusCast();
933 QQmlParserStatus *parserStatus = nullptr;
934 if (parserStatusCast != -1)
935 parserStatus = reinterpret_cast<QQmlParserStatus*>(reinterpret_cast<char *>(qmlObject) + parserStatusCast);
936 if (parserStatus) {
937 parserStatus->classBegin();
938 // we ignore them for profiling, because it doesn't interact well with the logic anyway
939 sharedState->allParserStatusCallbacks.push_back({objectIndex, parserStatusCast});
940 }
941
942 if (!populateInstance(binding->value.objectIndex, qmlObject, qmlObject,
943 /*value type property*/ nullptr, binding))
944 return false;
945 return true;
946 }
947
948 // ### resolve this at compile time
949 if (bindingProperty && bindingProperty->propType() == QMetaType::fromType<QQmlScriptString>()) {
950 QQmlScriptString ss(compilationUnit->bindingValueAsScriptString(binding),
951 context->asQQmlContext(), _scopeObject);
952 ss.d.data()->bindingId = bindingType == QV4::CompiledData::Binding::Type_Script ? binding->value.compiledScriptIndex : (quint32)QQmlBinding::Invalid;
953 ss.d.data()->lineNumber = binding->location.line();
954 ss.d.data()->columnNumber = binding->location.column();
955 ss.d.data()->isStringLiteral = bindingType == QV4::CompiledData::Binding::Type_String;
956 ss.d.data()->isNumberLiteral = bindingType == QV4::CompiledData::Binding::Type_Number;
957 ss.d.data()->numberValue = compilationUnit->bindingValueAsNumber(binding);
958
959 QQmlPropertyData::WriteFlags propertyWriteFlags = QQmlPropertyData::BypassInterceptor |
960 QQmlPropertyData::RemoveBindingOnAliasWrite;
961 int propertyWriteStatus = -1;
962 void *argv[] = { &ss, nullptr, &propertyWriteStatus, &propertyWriteFlags };
963 QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, bindingProperty->coreIndex(), argv);
964 return true;
965 }
966
967 QObject *createdSubObject = nullptr;
968 if (bindingType == QV4::CompiledData::Binding::Type_Object) {
969 // This is not a top level object. Its required properties don't count towards the
970 // top level required properties.
971 QScopedValueRollback topLevelRequired(sharedState->hadTopLevelRequiredProperties);
972 int objectIndex = binding->value.objectIndex;
973 if (const int wrapperIdx = compilationUnit->implicitComponentForObject(objectIndex);
974 wrapperIdx != -1) {
975 // If the child has an implicit component wrapper, redirect to it.
976 objectIndex = wrapperIdx;
977 }
978 createdSubObject = createInstance(objectIndex, _bindingTarget);
979 if (!createdSubObject)
980 return false;
981 }
982
983 if (bindingType == QV4::CompiledData::Binding::Type_GroupProperty) {
984 const QV4::CompiledData::Object *obj = compilationUnit->objectAt(binding->value.objectIndex);
985 if (stringAt(obj->inheritedTypeNameIndex).isEmpty()) {
986
987 QObject *groupObject = nullptr;
988 QQmlGadgetPtrWrapper *valueType = nullptr;
989 const QQmlPropertyData *valueTypeProperty = nullptr;
990 QObject *bindingTarget = _bindingTarget;
991 int groupObjectIndex = binding->value.objectIndex;
992
993 if (!bindingProperty) {
994 for (int i = 0, end = compilationUnit->objectCount(); i != end; ++i) {
995 const QV4::CompiledData::Object *external = compilationUnit->objectAt(i);
996 if (external->idNameIndex == binding->propertyNameIndex) {
997 bindingTarget = groupObject = context->idValue(external->objectId());
998 break;
999 }
1000 }
1001 if (!groupObject)
1002 return true;
1003 } else if (QQmlMetaType::isValueType(bindingProperty->propType())) {
1004 valueType = QQmlGadgetPtrWrapper::instance(engine, bindingProperty->propType());
1005 if (!valueType) {
1006 recordError(binding->location, tr("Cannot set properties on %1 as it is null").arg(stringAt(binding->propertyNameIndex)));
1007 return false;
1008 }
1009
1010 valueType->read(_qobject, bindingProperty->coreIndex());
1011
1012 groupObject = valueType;
1013 valueTypeProperty = bindingProperty;
1014 } else if (bindingProperty->propType().flags() & QMetaType::PointerToQObject) {
1015 void *argv[1] = { &groupObject };
1016 QMetaObject::metacall(_qobject, QMetaObject::ReadProperty, bindingProperty->coreIndex(), argv);
1017 if (!groupObject) {
1018 QQmlPropertyIndex index(bindingProperty->coreIndex());
1019 auto anyBinding = QQmlAnyBinding::ofProperty(_qobject, index);
1020 if (anyBinding) {
1021 // if there is a binding, try to force-evaluate it now
1022 // this might instantiate a necessary part of a grouped property
1023 anyBinding.refresh();
1024 QMetaObject::metacall(_qobject, QMetaObject::ReadProperty, bindingProperty->coreIndex(), argv);
1025 }
1026 if (!groupObject) {
1027 recordError(binding->location, tr("Cannot set properties on %1 as it is null").arg(stringAt(binding->propertyNameIndex)));
1028 return false;
1029 }
1030 }
1031
1032 bindingTarget = groupObject;
1033 } else {
1034 recordError(
1035 binding->location,
1036 tr("Using grouped property syntax on %1 which has no properties")
1037 .arg(stringAt(binding->propertyNameIndex)));
1038 return false;
1039 }
1040
1041 if (!populateInstance(groupObjectIndex, groupObject, bindingTarget, valueTypeProperty,
1042 binding)) {
1043 return false;
1044 }
1045
1046 if (valueType) {
1047 valueType->write(
1048 _qobject, bindingProperty->coreIndex(),
1049 QQmlPropertyData::BypassInterceptor,
1050 QV4::ReferenceObject::AllProperties);
1051 }
1052
1053 return true;
1054 }
1055 }
1056
1057 if (!bindingProperty) // ### error
1058 return true;
1059
1060 const QV4::CompiledData::Binding::Flags bindingFlags = binding->flags();
1061 const bool allowedToRemoveBinding
1062 = !(bindingFlags & QV4::CompiledData::Binding::IsSignalHandlerExpression)
1063 && !(bindingFlags & QV4::CompiledData::Binding::IsOnAssignment)
1064 && !(bindingFlags & QV4::CompiledData::Binding::IsPropertyObserver)
1065 && !_valueTypeProperty;
1066
1067 if (allowedToRemoveBinding) {
1068 if (bindingProperty->acceptsQBinding()) {
1069 removePendingBinding(_bindingTarget, bindingProperty->coreIndex());
1070 } else {
1071 QQmlPropertyPrivate::removeBinding(
1072 _bindingTarget, QQmlPropertyIndex(bindingProperty->coreIndex()),
1073 QQmlPropertyPrivate::OverrideSticky);
1074 }
1075 }
1076
1077 if (bindingType == QV4::CompiledData::Binding::Type_Script || binding->isTranslationBinding()) {
1078 if (bindingFlags & QV4::CompiledData::Binding::IsSignalHandlerExpression
1079 || bindingFlags & QV4::CompiledData::Binding::IsPropertyObserver) {
1080 QV4::Function *runtimeFunction = compilationUnit->runtimeFunctions[binding->value.compiledScriptIndex];
1081 int signalIndex = _propertyCache->methodIndexToSignalIndex(bindingProperty->coreIndex());
1082 QQmlBoundSignalExpression *expr = new QQmlBoundSignalExpression(
1083 _bindingTarget, signalIndex, context,
1084 _scopeObject, runtimeFunction, currentQmlContext());
1085
1086 if (bindingProperty->notifiesViaBindable()) {
1087 auto target = _bindingTarget;
1088 if (bindingProperty->isAlias()) {
1089 // If the property is an alias, we cannot obtain the bindable interface directly with qt_metacall
1090 // so instead, we resolve the alias to obtain the actual target
1091 // This should be faster than doing a detour through the metaobject of the target, and relying on
1092 // QMetaObject::metacall doing the correct resolution
1093 QQmlPropertyIndex originalIndex(bindingProperty->coreIndex(), _valueTypeProperty ? _valueTypeProperty->coreIndex() : -1);
1094 auto [aliasTargetObject, aliasTargetIndex] = QQmlPropertyPrivate::findAliasTarget(target, originalIndex);
1095 target = aliasTargetObject;
1096 QQmlData *data = QQmlData::get(target);
1097 Q_ASSERT(data && data->propertyCache);
1098 bindingProperty = data->propertyCache->property(aliasTargetIndex.coreIndex());
1099 }
1100 auto &observer = QQmlData::get(_scopeObject)->propertyObservers.emplace_back(expr);
1101 QUntypedBindable bindable;
1102 void *argv[] = { &bindable };
1103 target->qt_metacall(QMetaObject::BindableProperty, bindingProperty->coreIndex(), argv);
1104 Q_ASSERT(bindable.isValid());
1105 bindable.observe(&observer);
1106 } else {
1107 QQmlBoundSignal *bs = new QQmlBoundSignal(_bindingTarget, signalIndex, _scopeObject, engine);
1108 bs->takeExpression(expr);
1109 }
1110 } else if (bindingProperty->acceptsQBinding()) {
1111 QUntypedPropertyBinding qmlBinding;
1112 if (binding->isTranslationBinding()) {
1113 qmlBinding = QQmlTranslationPropertyBinding::create(bindingProperty, compilationUnit, binding);
1114 } else {
1115 QV4::Function *runtimeFunction = compilationUnit->runtimeFunctions[binding->value.compiledScriptIndex];
1116 QQmlPropertyIndex index(bindingProperty->coreIndex(), -1);
1117 qmlBinding = QQmlPropertyBinding::create(bindingProperty, runtimeFunction, _scopeObject, context, currentQmlContext(), _bindingTarget, index);
1118 }
1119 sharedState.data()->allQPropertyBindings.push_back(DeferredQPropertyBinding {_bindingTarget, bindingProperty->coreIndex(), qmlBinding });
1120
1121 QQmlData *data = QQmlData::get(_bindingTarget, true);
1122 data->setBindingBit(_bindingTarget, bindingProperty->coreIndex());
1123 } else {
1124 // When writing bindings to grouped properties implemented as value types,
1125 // such as point.x: { someExpression; }, then the binding is installed on
1126 // the point property (_qobjectForBindings) and after evaluating the expression,
1127 // the result is written to a value type virtual property, that contains the sub-index
1128 // of the "x" property.
1129 QQmlBinding::Ptr qmlBinding;
1130 const QQmlPropertyData *targetProperty = bindingProperty;
1131 const QQmlPropertyData *subprop = nullptr;
1132 if (_valueTypeProperty) {
1133 targetProperty = _valueTypeProperty;
1134 subprop = bindingProperty;
1135 }
1136 if (binding->isTranslationBinding()) {
1137 qmlBinding = QQmlBinding::createTranslationBinding(
1138 compilationUnit, binding, _scopeObject, context);
1139 } else {
1140 QV4::Function *runtimeFunction = compilationUnit->runtimeFunctions[binding->value.compiledScriptIndex];
1141 qmlBinding = QQmlBinding::create(targetProperty, runtimeFunction, _scopeObject,
1142 context, currentQmlContext());
1143 }
1144
1145 auto bindingTarget = _bindingTarget;
1146 auto valueTypeProperty = _valueTypeProperty;
1147 auto assignBinding = [qmlBinding, bindingTarget, targetProperty, subprop, bindingProperty, valueTypeProperty](QQmlObjectCreatorSharedState *sharedState) mutable -> bool {
1148 if (!qmlBinding->setTarget(bindingTarget, *targetProperty, subprop) && targetProperty->isAlias())
1149 return false;
1150
1151 sharedState->allCreatedBindings.push_back(qmlBinding);
1152
1153 if (bindingProperty->isAlias()) {
1154 QQmlPropertyPrivate::setBinding(qmlBinding.data(), QQmlPropertyPrivate::DontEnable);
1155 } else {
1156 qmlBinding->addToObject();
1157
1158 if (!valueTypeProperty) {
1159 QQmlData *targetDeclarativeData = QQmlData::get(bindingTarget);
1160 Q_ASSERT(targetDeclarativeData);
1161 targetDeclarativeData->setPendingBindingBit(bindingTarget, bindingProperty->coreIndex());
1162 }
1163 }
1164
1165 return true;
1166 };
1167 if (!assignBinding(sharedState.data()))
1168 pendingAliasBindings.push_back(assignBinding);
1169 }
1170 return true;
1171 }
1172
1173 if (bindingType == QV4::CompiledData::Binding::Type_Object) {
1174 if (bindingFlags & QV4::CompiledData::Binding::IsOnAssignment) {
1175 // ### determine value source and interceptor casts ahead of time.
1176 QQmlType type = qmlTypeForObject(createdSubObject);
1177 Q_ASSERT(type.isValid());
1178
1179 int valueSourceCast = type.propertyValueSourceCast();
1180 if (valueSourceCast != -1) {
1181 QQmlPropertyValueSource *vs = reinterpret_cast<QQmlPropertyValueSource *>(reinterpret_cast<char *>(createdSubObject) + valueSourceCast);
1182 QObject *target = createdSubObject->parent();
1183 QQmlProperty prop;
1184 if (_valueTypeProperty) {
1185 prop = QQmlPropertyPrivate::restore(target, *_valueTypeProperty,
1186 bindingProperty, context);
1187 } else {
1188 prop = QQmlPropertyPrivate::restore(target, *bindingProperty, nullptr, context);
1189 }
1190 vs->setTarget(prop);
1191 return true;
1192 }
1193 int valueInterceptorCast = type.propertyValueInterceptorCast();
1194 if (valueInterceptorCast != -1) {
1195 QQmlPropertyValueInterceptor *vi = reinterpret_cast<QQmlPropertyValueInterceptor *>(reinterpret_cast<char *>(createdSubObject) + valueInterceptorCast);
1196 QObject *target = createdSubObject->parent();
1197
1198 QQmlPropertyIndex propertyIndex;
1199 if (bindingProperty->isAlias()) {
1200 QQmlPropertyIndex originalIndex(bindingProperty->coreIndex(), _valueTypeProperty ? _valueTypeProperty->coreIndex() : -1);
1201 auto aliasTarget = QQmlPropertyPrivate::findAliasTarget(target, originalIndex);
1202 target = aliasTarget.targetObject;
1203 QQmlData *data = QQmlData::get(target);
1204 if (!data || !data->propertyCache) {
1205 qWarning() << "can't resolve property alias for 'on' assignment";
1206 return false;
1207 }
1208
1209 // we can't have aliasses on subproperties of value types, so:
1210 QQmlPropertyData targetPropertyData = *data->propertyCache->property(aliasTarget.targetIndex.coreIndex());
1211 auto prop = QQmlPropertyPrivate::restore(
1212 target, targetPropertyData, nullptr, context);
1213 vi->setTarget(prop);
1214 propertyIndex = QQmlPropertyPrivate::propertyIndex(prop);
1215 } else {
1216 QQmlProperty prop;
1217 if (_valueTypeProperty) {
1218 prop = QQmlPropertyPrivate::restore(
1219 target, *_valueTypeProperty, bindingProperty, context);
1220 } else {
1221 prop = QQmlPropertyPrivate::restore(
1222 target, *bindingProperty, nullptr, context);
1223 }
1224 vi->setTarget(prop);
1225 propertyIndex = QQmlPropertyPrivate::propertyIndex(prop);
1226 }
1227
1228 QQmlInterceptorMetaObject *mo = QQmlInterceptorMetaObject::get(target);
1229 if (!mo)
1230 mo = new QQmlInterceptorMetaObject(target, QQmlData::get(target)->propertyCache);
1231 mo->registerInterceptor(propertyIndex, vi);
1232 return true;
1233 }
1234 return false;
1235 }
1236
1237 // Assigning object to signal property? ### Qt 7: Remove that functionality
1238 if (bindingFlags & QV4::CompiledData::Binding::IsSignalHandlerObject) {
1239 if (!bindingProperty->isFunction()) {
1240 recordError(binding->valueLocation, tr("Cannot assign an object to signal property %1").arg(bindingProperty->name(_qobject)));
1241 return false;
1242 }
1243 QMetaMethod method = QQmlMetaType::defaultMethod(createdSubObject);
1244 if (!method.isValid()) {
1245 recordError(binding->valueLocation, tr("Cannot assign object type %1 with no default method").arg(QString::fromLatin1(createdSubObject->metaObject()->className())));
1246 return false;
1247 }
1248 qCWarning(lcQmlDefaultMethod) << "Assigning an object to a signal handler is deprecated. "
1249 "Instead, create the object, give it an id, and call the desired slot "
1250 "from the signal handler. The object is:" << createdSubObject;
1251
1252 QMetaMethod signalMethod = _qobject->metaObject()->method(bindingProperty->coreIndex());
1253 if (!QMetaObject::checkConnectArgs(signalMethod, method)) {
1254 recordError(binding->valueLocation,
1255 tr("Cannot connect mismatched signal/slot %1 vs %2")
1256 .arg(QString::fromUtf8(method.methodSignature()),
1257 QString::fromUtf8(signalMethod.methodSignature())));
1258 return false;
1259 }
1260
1261 QQmlPropertyPrivate::connect(_qobject, bindingProperty->coreIndex(), createdSubObject, method.methodIndex());
1262 return true;
1263 }
1264
1265 QQmlPropertyData::WriteFlags propertyWriteFlags = QQmlPropertyData::BypassInterceptor |
1266 QQmlPropertyData::RemoveBindingOnAliasWrite;
1267 int propertyWriteStatus = -1;
1268 void *argv[] = { nullptr, nullptr, &propertyWriteStatus, &propertyWriteFlags };
1269
1270 if (const char *iid = QQmlMetaType::interfaceIId(bindingProperty->propType())) {
1271 void *ptr = createdSubObject->qt_metacast(iid);
1272 if (ptr) {
1273 argv[0] = &ptr;
1274 QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, bindingProperty->coreIndex(), argv);
1275 } else {
1276 recordError(binding->location, tr("Cannot assign object to interface property"));
1277 return false;
1278 }
1279 } else if (bindingProperty->propType() == QMetaType::fromType<QVariant>()) {
1280 if (bindingProperty->isVarProperty()) {
1281 QV4::Scope scope(v4);
1282 QV4::ScopedValue wrappedObject(scope, QV4::QObjectWrapper::wrap(engine->handle(), createdSubObject));
1283 _vmeMetaObject->setVMEProperty(bindingProperty->coreIndex(), wrappedObject);
1284 } else {
1285 QVariant value = QVariant::fromValue(createdSubObject);
1286 argv[0] = &value;
1287 QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, bindingProperty->coreIndex(), argv);
1288 }
1289 } else if (bindingProperty->propType() == QMetaType::fromType<QJSValue>()) {
1290 QV4::Scope scope(v4);
1291 QV4::ScopedValue wrappedObject(scope, QV4::QObjectWrapper::wrap(engine->handle(), createdSubObject));
1292 if (bindingProperty->isVarProperty()) {
1293 _vmeMetaObject->setVMEProperty(bindingProperty->coreIndex(), wrappedObject);
1294 } else {
1295 QJSValue value;
1296 QJSValuePrivate::setValue(&value, wrappedObject);
1297 argv[0] = &value;
1298 QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, bindingProperty->coreIndex(), argv);
1299 }
1300 } else if (bindingProperty->propType().flags().testFlag(QMetaType::IsQmlList)) {
1301 Q_ASSERT(_currentList.object);
1302
1303 QObject *itemToAdd = createdSubObject;
1304
1305 QMetaType listItemType = QQmlMetaType::listValueType(bindingProperty->propType());
1306 if (listItemType.isValid()) {
1307 const char *iid = QQmlMetaType::interfaceIId(listItemType);
1308 if (iid)
1309 itemToAdd = static_cast<QObject *>(createdSubObject->qt_metacast(iid));
1310 }
1311
1312 if (_currentList.append)
1313 _currentList.append(&_currentList, itemToAdd);
1314 else {
1315 recordError(binding->location, tr("Cannot assign object to read only list"));
1316 return false;
1317 }
1318 } else if (bindingProperty->propType().flags().testFlag(QMetaType::PointerToQObject)) {
1319 // pointer compatibility was tested in QQmlPropertyValidator at type compile time
1320 argv[0] = &createdSubObject;
1321 QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, bindingProperty->coreIndex(), argv);
1322 } else {
1323 QVariant target = QQmlValueTypeProvider::createValueType(
1324 QVariant::fromValue(createdSubObject), bindingProperty->propType(), v4);
1325 if (target.isValid())
1326 bindingProperty->writeProperty(_qobject, target.data(), propertyWriteFlags);
1327 else
1328 recordError(binding->location, tr("Cannot construct value type from given object"));
1329 }
1330 return true;
1331 }
1332
1333 if (bindingProperty->isQList()) {
1334 recordError(binding->location, tr("Cannot assign primitives to lists"));
1335 return false;
1336 }
1337
1338 setPropertyValue(bindingProperty, binding);
1339 return true;
1340}
1341
1342void QQmlObjectCreator::setupFunctions()
1343{
1344 QV4::Scope scope(v4);
1345 QV4::ScopedValue function(scope);
1346 QV4::ScopedContext qmlContext(scope, currentQmlContext());
1347
1348 const quint32_le *functionIdx = _compiledObject->functionOffsetTable();
1349 for (quint32 i = 0; i < _compiledObject->nFunctions; ++i, ++functionIdx) {
1350 QV4::Function *runtimeFunction = compilationUnit->runtimeFunctions[*functionIdx];
1351 const QString name = runtimeFunction->name()->toQString();
1352
1353 const QQmlPropertyData *property = _propertyCache->property(name, _qobject, context);
1354 if (!property->isVMEFunction())
1355 continue;
1356
1357 if (runtimeFunction->isGenerator())
1358 function = QV4::GeneratorFunction::create(qmlContext, runtimeFunction);
1359 else
1360 function = QV4::FunctionObject::createScriptFunction(qmlContext, runtimeFunction);
1361 _vmeMetaObject->setVmeMethod(property->coreIndex(), function);
1362 }
1363}
1364
1365void QQmlObjectCreator::recordError(const QV4::CompiledData::Location &location, const QString &description)
1366{
1367 QQmlError error;
1368 error.setUrl(compilationUnit->url());
1369 error.setLine(qmlConvertSourceCoordinate<quint32, int>(location.line()));
1370 error.setColumn(qmlConvertSourceCoordinate<quint32, int>(location.column()));
1371 error.setDescription(description);
1372 errors << error;
1373}
1374
1375void QQmlObjectCreator::registerObjectWithContextById(const QV4::CompiledData::Object *object, QObject *instance) const
1376{
1377 if (object->objectId() >= 0)
1378 context->setIdValue(object->objectId(), instance);
1379}
1380
1381QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isContextObject)
1382{
1383 const QV4::CompiledData::Object *obj = compilationUnit->objectAt(index);
1384 Q_TRACE(QQmlObjectCreator_createInstance_entry, compilationUnit.data(), obj, context->url());
1385 QQmlObjectCreationProfiler profiler(sharedState->profiler.profiler, obj);
1386
1387 const bool isImplicitComponent = index >= compilationUnit->objectCount();
1388 const InitFlags flags = (isContextObject ? InitFlag::IsContextObject : InitFlag::None)
1389 | (index == 0 ? InitFlag::IsDocumentRoot : InitFlag::None)
1390 | (isImplicitComponent ? InitFlag::IsImplicitComponent : InitFlag::None);
1391
1392 if (obj->hasFlag(QV4::CompiledData::Object::IsComponent) || isImplicitComponent) {
1393 Q_TRACE_EXIT(QQmlObjectCreator_createInstance_exit, QStringLiteral("<component>"));
1394 Q_QML_OC_PROFILE(
1395 sharedState->profiler,
1396 profiler.update(
1397 compilationUnit.data(), obj, QStringLiteral("<component>"),
1398 context->url()));
1399 return initializeComponent(
1400 obj, createComponent(engine, compilationUnit.data(), index, parent, context),
1401 flags);
1402 }
1403
1404 const QV4::ResolvedTypeReference *typeRef = resolvedType(obj->inheritedTypeNameIndex);
1405 Q_ASSERT(typeRef);
1406 const QQmlType type = typeRef->type();
1407 Q_ASSERT(type.isValid());
1408
1409 Q_TRACE_EXIT(QQmlObjectCreator_createInstance_exit, type.qmlTypeName());
1410 Q_QML_OC_PROFILE(
1411 sharedState->profiler,
1412 profiler.update(compilationUnit.data(), obj, type.qmlTypeName(), context->url()));
1413
1414 if (type.isCompositeSingleton()) {
1415 recordError(
1416 obj->location,
1417 tr("Composite Singleton Type %1 is not creatable")
1418 .arg(stringAt(obj->inheritedTypeNameIndex)));
1419 return nullptr;
1420 }
1421
1422 if (!type.isComposite() && !type.isInlineComponentType()) {
1423 if (QObject *instance = type.createWithQQmlData())
1424 return initializeNonComposite(index, obj, typeRef, instance, parent, flags);
1425 recordError(
1426 obj->location,
1427 tr("Unable to create object of type %1").arg(
1428 stringAt(obj->inheritedTypeNameIndex)));
1429 return nullptr;
1430 }
1431
1432 QQmlRefPointer<QV4::ExecutableCompilationUnit> executableCu = typeRef->isSelfReference()
1433 ? compilationUnit
1434 : engine->handle()->executableCompilationUnit(typeRef->compilationUnit());
1435 Q_ASSERT(executableCu);
1436
1437 const bool isInlineComponent = type.isInlineComponentType();
1438 const QString inlineComponentName = isInlineComponent ? type.elementName() : QString();
1439 QQmlObjectCreator subCreator(
1440 context, executableCu, inlineComponentName, sharedState.data(),
1441 isContextObject);
1442
1443 if (QObject *instance = isInlineComponent
1444 ? subCreator.create(
1445 executableCu->inlineComponentId(inlineComponentName), nullptr, nullptr,
1446 CreationFlags::InlineComponent)
1447 : subCreator.create()) {
1448 return initializeComposite(index, obj, typeRef, instance, parent, flags);
1449 }
1450
1451 errors += subCreator.errors;
1452 return nullptr;
1453}
1454
1455void QQmlObjectCreator::initializeDData(
1456 const QV4::CompiledData::Object *obj, QObject *instance, QQmlData *ddata, InitFlags flags)
1457{
1458 ddata->lineNumber = obj->location.line();
1459 ddata->columnNumber = obj->location.column();
1460 ddata->setImplicitDestructible();
1461
1462 // inline components are root objects, but their index is != 0, so we need
1463 // an additional check
1464 const bool documentRoot = (flags & InitFlag::IsDocumentRoot)
1465 || ddata->rootObjectInCreation
1466 || obj->hasFlag(QV4::CompiledData::Object::IsInlineComponentRoot);
1467
1468 context->installContext(
1469 ddata, documentRoot ? QQmlContextData::DocumentRoot : QQmlContextData::OrdinaryObject);
1470
1471 // Register the context object in the context early on in order for pending binding
1472 // initialization to find it available.
1473 if ((flags & (InitFlag::IsContextObject | InitFlag::IsImplicitComponent))
1474 == InitFlag::IsContextObject) {
1475 context->setContextObject(instance);
1476 }
1477}
1478
1479void QQmlObjectCreator::initializePropertyCache(
1480 int index, QQmlData *ddata, const QV4::ResolvedTypeReference *typeRef)
1481{
1482 if (!typeRef->isFullyDynamicType()) {
1483 QQmlPropertyCache::ConstPtr cache = propertyCaches->at(index);
1484 Q_ASSERT(!cache.isNull());
1485 ddata->propertyCache = std::move(cache);
1486 }
1487}
1488
1489void QQmlObjectCreator::initializeParent(QObject *instance, QObject *parent)
1490{
1491 if (instance->isWidgetType()) {
1492 if (parent && parent->isWidgetType()) {
1493 QAbstractDeclarativeData::setWidgetParent(instance, parent);
1494 } else {
1495 // No parent! Layouts need to handle this through a default property that
1496 // reparents accordingly. Otherwise the garbage collector will collect.
1497 }
1498 } else if (parent) {
1499 QQml_setParent_noEvent(instance, parent);
1500 }
1501}
1502
1503QObject *QQmlObjectCreator::populateInstanceAndAliasBindings(
1504 int index, QObject *instance, InitFlags flags)
1505{
1506 const auto doPopulate = [&]() {
1507 if (!populateInstance(
1508 index, instance, /*binding target*/instance, /*value type property*/nullptr)) {
1509 // an error occurred, so we can't setup the pending alias bindings
1510 pendingAliasBindings.clear();
1511 return false;
1512 }
1513
1514 if (!flags.testFlag(InitFlag::IsContextObject))
1515 return true;
1516
1517 while (!pendingAliasBindings.empty()) {
1518 for (std::vector<PendingAliasBinding>::iterator it = pendingAliasBindings.begin();
1519 it != pendingAliasBindings.end(); ) {
1520 if ((*it)(sharedState.data()))
1521 it = pendingAliasBindings.erase(it);
1522 else
1523 ++it;
1524 }
1525 }
1526
1527 return true;
1528 };
1529
1530 QObject *scopeObject = instance;
1531 qSwap(_scopeObject, scopeObject);
1532
1533 Q_ASSERT(sharedState->allJavaScriptObjects.canTrack());
1534 sharedState->allJavaScriptObjects.trackObject(v4, instance);
1535
1536 QV4::Scope valueScope(v4);
1537 QV4::QmlContext *qmlContext = static_cast<QV4::QmlContext *>(valueScope.constructUndefined(1));
1538
1539 qSwap(_qmlContext, qmlContext);
1540
1541 const bool ok = doPopulate();
1542
1543 qSwap(_qmlContext, qmlContext);
1544 qSwap(_scopeObject, scopeObject);
1545
1546 return ok ? instance : nullptr;
1547}
1548
1549QObject *QQmlObjectCreator::initializeComponent(
1550 const QV4::CompiledData::Object *obj, QObject *instance, InitFlags flags)
1551{
1552 Q_ASSERT(instance);
1553 Q_ASSERT(obj);
1554
1555 QScopedValueRollback<QQmlObjectCreator*> ocRestore(
1556 QQmlEnginePrivate::get(engine)->activeObjectCreator, this);
1557
1558 // we just created it inside createComponent; so QQmlData::get() without create = true;
1559 initializeDData(obj, instance, QQmlData::get(instance), flags);
1560
1561 if (!flags.testFlag(InitFlag::IsImplicitComponent))
1562 registerObjectWithContextById(obj, instance);
1563 return instance;
1564}
1565
1566QObject *QQmlObjectCreator::initializeComposite(
1567 int index, const QV4::CompiledData::Object *obj, const QV4::ResolvedTypeReference *typeRef,
1568 QObject *instance, QObject *parent, InitFlags flags)
1569{
1570 Q_ASSERT(instance);
1571 Q_ASSERT(typeRef);
1572
1573 QScopedValueRollback<QQmlObjectCreator*> ocRestore(
1574 QQmlEnginePrivate::get(engine)->activeObjectCreator, this);
1575
1576 initializeParent(instance, parent);
1577 QQmlData *ddata = QQmlData::get(instance, /*create*/true);
1578 initializeDData(obj, instance, ddata, flags);
1579
1580 initializePropertyCache(index, ddata, typeRef);
1581
1582 return populateInstanceAndAliasBindings(index, instance, flags);
1583}
1584
1585QObject *QQmlObjectCreator::initializeNonComposite(
1586 int index, const QV4::CompiledData::Object *obj, const QV4::ResolvedTypeReference *typeRef,
1587 QObject *instance, QObject *parent, InitFlags flags)
1588{
1589 Q_ASSERT(instance);
1590 Q_ASSERT(obj);
1591 Q_ASSERT(!obj->hasFlag(QV4::CompiledData::Object::IsComponent));
1592 Q_ASSERT(typeRef);
1593
1594 const QQmlType type = typeRef->type();
1595 Q_ASSERT(type.isValid());
1596 Q_ASSERT(!type.isComposite() && !type.isInlineComponentType());
1597
1598 QScopedValueRollback<QQmlObjectCreator*> ocRestore(QQmlEnginePrivate::get(engine)->activeObjectCreator, this);
1599
1600 if (const int finalizerCast = type.finalizerCast(); finalizerCast != -1) {
1601 const auto hook = reinterpret_cast<QQmlFinalizerHook *>(
1602 reinterpret_cast<char *>(instance) + finalizerCast);
1603 sharedState->finalizeHooks.push_back(hook);
1604 }
1605
1606 QQmlData *ddata = QQmlData::get(instance, /*create*/true);
1607 if (sharedState->rootContext && sharedState->rootContext->isRootObjectInCreation()) {
1608 ddata->rootObjectInCreation = true;
1609 sharedState->rootContext->setRootObjectInCreation(false);
1610 }
1611
1612 const size_t instanceIndex = sharedState->allCreatedObjects.size();
1613 sharedState->allCreatedObjects.push_back(instance);
1614
1615 initializeParent(instance, parent);
1616 initializeDData(obj, instance, ddata, flags);
1617
1618 if (const int parserStatusCast = type.parserStatusCast(); parserStatusCast != -1) {
1619 if (QQmlParserStatus *parserStatus = reinterpret_cast<QQmlParserStatus*>(
1620 reinterpret_cast<char *>(instance) + parserStatusCast)) {
1621 parserStatus->classBegin();
1622 // push() the profiler state here, together with the parserStatus, as we'll pop() them
1623 // together, too.
1624 Q_QML_OC_PROFILE(sharedState->profiler, sharedState->profiler.push(obj));
1625 sharedState->allParserStatusCallbacks.push_back({ instanceIndex, parserStatusCast });
1626 }
1627 }
1628
1629 if (QQmlCustomParser *customParser = type.customParser();
1630 customParser && obj->hasFlag(QV4::CompiledData::Object::HasCustomParserBindings)) {
1631 customParser->engine = QQmlEnginePrivate::get(engine);
1632 customParser->imports = compilationUnit->typeNameCache().data();
1633
1634 QList<const QV4::CompiledData::Binding *> bindings;
1635 const QV4::CompiledData::Object *obj = compilationUnit->objectAt(index);
1636 const QV4::CompiledData::Binding *binding = obj->bindingTable();
1637 for (quint32 i = 0; i < obj->nBindings; ++i, ++binding) {
1638 if (binding->hasFlag(QV4::CompiledData::Binding::IsCustomParserBinding))
1639 bindings << binding;
1640 }
1641 customParser->applyBindings(instance, compilationUnit, bindings);
1642
1643 customParser->engine = nullptr;
1644 customParser->imports = (QQmlTypeNameCache*)nullptr;
1645 }
1646
1647 initializePropertyCache(index, ddata, typeRef);
1648 return populateInstanceAndAliasBindings(index, instance, flags);
1649}
1650
1651/*!
1652 * \internal
1653 * Create a single object at \a objectIndex within an already-existing \a existingContext.
1654 * Unlike create(), this does not allocate a new context — the object is registered as an
1655 * OrdinaryObject in \a existingContext.
1656 */
1657QObject *QQmlObjectCreator::createObjectInContext(
1658 int objectIndex, QObject *parent,
1659 const QQmlRefPointer<QQmlContextData> &existingContext)
1660{
1661 Q_ASSERT(phase == Startup);
1662 phase = CreatingObjects;
1663
1664 context = existingContext;
1665 if (!sharedState->rootContext)
1666 sharedState->rootContext = context;
1667
1668 QV4::Scope scope(v4);
1669 if (topLevelCreator)
1670 sharedState->allJavaScriptObjects = ObjectInCreationGCAnchorList(scope);
1671
1672 QObject *rv = createInstance(objectIndex, parent, /*isContextObject=*/false);
1673 phase = ObjectsCreated;
1674 return rv;
1675}
1676
1677bool QQmlObjectCreator::finalize(QQmlInstantiationInterrupt &interrupt)
1678{
1679 Q_ASSERT(phase == ObjectsCreated || phase == Finalizing);
1680 phase = Finalizing;
1681
1682 QQmlObjectCreatorRecursionWatcher watcher(this);
1683 QScopedValueRollback<QQmlObjectCreator*> ocRestore(QQmlEnginePrivate::get(engine)->activeObjectCreator, this);
1684
1685 /* We install all pending bindings (both plain QML and QProperty), and remove the ones which do not
1686 actually have dependencies.
1687 It is necessary to install the binding so that it runs at least once, which causes it to capture any
1688 dependencies.
1689 We then check for the following conditions:
1690 - Is the binding in an error state?
1691 - Does the binding has any dependencies (from properties)?
1692 - Does it depend on anything in the context, which has not been resolved yet (and thus couldn't be
1693 captured)?
1694 If the answer to all of those questions is "no", it is safe to remove the binding, as there is no
1695 way for it to change its value afterwards from that point on.
1696 */
1697
1698 while (!sharedState->allCreatedBindings.empty()) {
1699 QQmlAbstractBinding::Ptr b = sharedState->allCreatedBindings.back();
1700 sharedState->allCreatedBindings.pop_back();
1701 Q_ASSERT(b);
1702 // skip, if b is not added to an object
1703 if (!b->isAddedToObject())
1704 continue;
1705 QQmlData *data = QQmlData::get(b->targetObject());
1706 Q_ASSERT(data);
1707 data->clearPendingBindingBit(b->targetPropertyIndex().coreIndex());
1708 b->setEnabled(true, QQmlPropertyData::BypassInterceptor |
1709 QQmlPropertyData::DontRemoveBinding);
1710 if (b->kind() == QQmlAbstractBinding::QmlBinding) {
1711 QQmlBinding *binding = static_cast<QQmlBinding*>(b.data());
1712 if (!binding->hasError() && !binding->hasDependencies()
1713 && !binding->hasUnresolvedNames()) {
1714 b->removeFromObject();
1715 }
1716 }
1717
1718 if (watcher.hasRecursed() || interrupt.shouldInterrupt())
1719 return false;
1720 }
1721
1722 while (!sharedState->allQPropertyBindings.isEmpty()) {
1723 auto& [target, index, qmlBinding] = sharedState->allQPropertyBindings.first();
1724
1725 QQmlData *data = QQmlData::get(target);
1726 if (!data || !data->hasBindingBit(index)) {
1727 // The target property has been overwritten since we stashed the binding.
1728 sharedState->allQPropertyBindings.pop_front();
1729 continue;
1730 }
1731
1732 QUntypedBindable bindable;
1733 void *argv[] = { &bindable };
1734 // allow interception
1735 target->metaObject()->metacall(target, QMetaObject::BindableProperty, index, argv);
1736 const bool success = bindable.setBinding(qmlBinding);
1737
1738 const auto bindingPrivateRefCount = QPropertyBindingPrivate::get(qmlBinding)->refCount();
1739
1740 // Only pop_front after setting the binding as the bindings are refcounted.
1741 sharedState->allQPropertyBindings.pop_front();
1742
1743 // If the binding was actually not set, it's deleted now.
1744 if (success && bindingPrivateRefCount > 1) {
1745 if (auto priv = QPropertyBindingPrivate::get(qmlBinding); priv->hasCustomVTable()) {
1746 auto qmlBindingPriv = static_cast<QQmlPropertyBinding *>(priv);
1747 auto jsExpression = qmlBindingPriv->jsExpression();
1748 const bool canRemove = !qmlBinding.error().hasError()
1749 && !qmlBindingPriv->hasDependencies()
1750 && !jsExpression->hasUnresolvedNames();
1751 if (canRemove)
1752 bindable.takeBinding();
1753 }
1754 }
1755
1756 if (watcher.hasRecursed() || interrupt.shouldInterrupt())
1757 return false;
1758 }
1759
1760 if (QQmlVME::componentCompleteEnabled()) { // the qml designer does the component complete later
1761 while (!sharedState->allParserStatusCallbacks.empty()) {
1762 QQmlObjectCompletionProfiler profiler(&sharedState->profiler);
1763 const ParserStatus status = sharedState->allParserStatusCallbacks.back();
1764 sharedState->allParserStatusCallbacks.pop_back();
1765
1766 const QQmlGuard<QObject> &instance = sharedState->allCreatedObjects[status.objectIndex];
1767 if (!instance)
1768 continue;
1769
1770 QQmlParserStatus *parserStatus
1771 = reinterpret_cast<QQmlParserStatus *>(
1772 reinterpret_cast<char *>(instance.data()) + status.parserStatusCast);
1773 parserStatus->componentComplete();
1774
1775 if (watcher.hasRecursed() || interrupt.shouldInterrupt())
1776 return false;
1777 }
1778 }
1779
1780 for (QQmlFinalizerHook *hook: std::as_const(sharedState->finalizeHooks)) {
1781 hook->componentFinalized();
1782 if (watcher.hasRecursed())
1783 return false;
1784 }
1785 sharedState->finalizeHooks.clear();
1786
1787 while (sharedState->componentAttached) {
1788 QQmlComponentAttached *a = sharedState->componentAttached;
1789 a->removeFromList();
1790 QQmlData *d = QQmlData::get(a->parent());
1791 Q_ASSERT(d);
1792 Q_ASSERT(d->context);
1793 d->context->addComponentAttached(a);
1794 if (QQmlVME::componentCompleteEnabled())
1795 emit a->completed();
1796
1797 if (watcher.hasRecursed() || interrupt.shouldInterrupt())
1798 return false;
1799 }
1800
1801 phase = Done;
1802
1803 return true;
1804}
1805
1806void QQmlObjectCreator::clear()
1807{
1808 if (phase == Done || phase == Finalizing || phase == Startup)
1809 return;
1810 Q_ASSERT(phase != Startup);
1811
1812 while (!sharedState->allCreatedObjects.empty()) {
1813 auto object = sharedState->allCreatedObjects.back();
1814 sharedState->allCreatedObjects.pop_back();
1815 if (engine->objectOwnership(object) != QQmlEngine::CppOwnership) {
1816 delete object;
1817 }
1818 }
1819
1820 while (sharedState->componentAttached) {
1821 QQmlComponentAttached *a = sharedState->componentAttached;
1822 a->removeFromList();
1823 }
1824
1825 phase = Done;
1826}
1827
1828void QQmlObjectCreator::registerPostHocRequiredProperties(const QV4::CompiledData::Binding *binding)
1829{
1830 const qsizetype oldRequiredPropertiesCount = sharedState->requiredProperties.size();
1831 QSet<QString> postHocRequired;
1832 for (auto it = _compiledObject->requiredPropertyExtraDataBegin(); it != _compiledObject->requiredPropertyExtraDataEnd(); ++it)
1833 postHocRequired.insert(stringAt(it->nameIndex));
1834 bool hadInheritedRequiredProperties = !postHocRequired.empty();
1835
1836 for (int propertyIndex = 0; propertyIndex != _compiledObject->propertyCount(); ++propertyIndex) {
1837 const QV4::CompiledData::Property* property = _compiledObject->propertiesBegin() + propertyIndex;
1838 const QQmlPropertyData *propertyData = _propertyCache->property(_propertyCache->propertyOffset() + propertyIndex);
1839 // only compute stringAt if there's a chance for the lookup to succeed
1840 auto postHocIt = postHocRequired.isEmpty() ? postHocRequired.end() : postHocRequired.find(stringAt(property->nameIndex()));
1841 if (!property->isRequired() && postHocRequired.end() == postHocIt)
1842 continue;
1843 if (postHocIt != postHocRequired.end())
1844 postHocRequired.erase(postHocIt);
1845 if (isContextObject)
1846 sharedState->hadTopLevelRequiredProperties = true;
1847 sharedState->requiredProperties.insert({_qobject, propertyData},
1848 RequiredPropertyInfo {compilationUnit->stringAt(property->nameIndex()), compilationUnit->finalUrl(), property->location, {}});
1849
1850 }
1851
1852 const auto getPropertyCacheRange = [&]() -> std::pair<int, int> {
1853 // the logic in a nutshell: we work with QML instances here. every
1854 // instance has a QQmlType:
1855 // * if QQmlType is valid && not an inline component, it's a C++ type
1856 // * otherwise, it's a QML-defined type (a.k.a. Composite type), where
1857 // invalid type == "comes from another QML document"
1858 //
1859 // 1. if the type we inherit from comes from C++, we must check *all*
1860 // properties in the property cache so far - since we can have
1861 // required properties defined in C++
1862 // 2. otherwise - the type comes from QML, it's enough to check just
1863 // *own* properties in the property cache, because there's a previous
1864 // type in the hierarchy that has checked the C++ properties (via 1.)
1865 // 3. required attached properties are explicitly not supported. to
1866 // achieve that, go through all its properties
1867 // 4. required group properties: the group itself is covered by 1.
1868 // required sub-properties are not properly handled (QTBUG-96544), so
1869 // just return the old range here for consistency
1870 QV4::ResolvedTypeReference *typeRef = resolvedType(_compiledObject->inheritedTypeNameIndex);
1871 if (!typeRef) { // inside a binding on attached/group property
1872 Q_ASSERT(binding);
1873 if (binding->isAttachedProperty())
1874 return { 0, _propertyCache->propertyCount() }; // 3.
1875 Q_ASSERT(binding->isGroupProperty());
1876 return { 0, _propertyCache->propertyOffset() + 1 }; // 4.
1877 }
1878 Q_ASSERT(!_compiledObject->hasFlag(QV4::CompiledData::Object::IsComponent));
1879 QQmlType type = typeRef->type();
1880 if (type.isComposite() || type.isInlineComponentType())
1881 return { _propertyCache->propertyOffset(), _propertyCache->propertyCount() }; // 2.
1882 return { 0, _propertyCache->propertyCount() }; // 1.
1883 };
1884 const auto [offset, count] = getPropertyCacheRange();
1885 for (int i = offset; i < count; ++i) {
1886 const QQmlPropertyData *propertyData = _propertyCache->maybeUnresolvedProperty(i);
1887 if (!propertyData)
1888 continue;
1889 // TODO: the property might be a group property (in which case we need
1890 // to dive into its sub-properties and check whether there are any
1891 // required elements there) - QTBUG-96544
1892 if (!propertyData->isRequired() && postHocRequired.isEmpty())
1893 continue;
1894 QString name = propertyData->name(_qobject);
1895 const auto postHocIt = postHocRequired.constFind(name);
1896 if (postHocIt == postHocRequired.constEnd()) {
1897 if (!propertyData->isRequired())
1898 continue;
1899 } else {
1900 postHocRequired.erase(postHocIt);
1901 }
1902
1903 if (isContextObject)
1904 sharedState->hadTopLevelRequiredProperties = true;
1905 sharedState->requiredProperties.insert(
1906 {_qobject, propertyData},
1907 RequiredPropertyInfo {
1908 std::move(name), compilationUnit->finalUrl(), _compiledObject->location, {}
1909 });
1910 }
1911
1912 if (binding && binding->isAttachedProperty()
1913 && sharedState->requiredProperties.size() != oldRequiredPropertiesCount) {
1914 recordError(
1915 binding->location,
1916 QLatin1String("Attached property has required properties. This is not supported"));
1917 }
1918
1919 // Note: there's a subtle case with the above logic: if we process a random
1920 // QML-defined leaf type, it could have a required attribute overwrite on an
1921 // *existing* property: `import QtQuick; Text { required text }`. in this
1922 // case, we must add the property to a required list
1923 if (!postHocRequired.isEmpty()) {
1924 // NB: go through [0, offset) range as [offset, count) is already done
1925 for (int i = 0; i < offset; ++i) {
1926 const QQmlPropertyData *propertyData = _propertyCache->maybeUnresolvedProperty(i);
1927 if (!propertyData)
1928 continue;
1929 QString name = propertyData->name(_qobject);
1930 const auto postHocIt = postHocRequired.constFind(name);
1931 if (postHocIt == postHocRequired.constEnd())
1932 continue;
1933 postHocRequired.erase(postHocIt);
1934
1935 if (isContextObject)
1936 sharedState->hadTopLevelRequiredProperties = true;
1937 sharedState->requiredProperties.insert(
1938 {_qobject, propertyData},
1939 RequiredPropertyInfo {
1940 std::move(name), compilationUnit->finalUrl(), _compiledObject->location, {}
1941 });
1942 }
1943 }
1944
1945 if (!postHocRequired.isEmpty() && hadInheritedRequiredProperties)
1946 recordError({}, QLatin1String("Property %1 was marked as required but does not exist").arg(*postHocRequired.begin()));
1947}
1948
1949bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject *bindingTarget,
1950 const QQmlPropertyData *valueTypeProperty,
1951 const QV4::CompiledData::Binding *binding)
1952{
1953 Q_ASSERT(instance);
1954 QQmlData *declarativeData = QQmlData::get(instance, /*create*/true);
1955
1956 qSwap(_qobject, instance);
1957 qSwap(_valueTypeProperty, valueTypeProperty);
1958 qSwap(_compiledObjectIndex, index);
1959 const QV4::CompiledData::Object *obj = compilationUnit->objectAt(_compiledObjectIndex);
1960 qSwap(_compiledObject, obj);
1961 qSwap(_ddata, declarativeData);
1962 qSwap(_bindingTarget, bindingTarget);
1963
1964 QV4::Scope valueScope(v4);
1965 QV4::ScopedValue scopeObjectProtector(valueScope);
1966
1967 QQmlPropertyCache::ConstPtr cache = propertyCaches->at(_compiledObjectIndex);
1968
1969 QQmlVMEMetaObject *vmeMetaObject = nullptr;
1970 if (propertyCaches->needsVMEMetaObject(_compiledObjectIndex)) {
1971 Q_ASSERT(!cache.isNull());
1972 // install on _object
1973 vmeMetaObject = new QQmlVMEMetaObject(v4, _qobject, cache, compilationUnit, _compiledObjectIndex);
1974 _ddata->propertyCache = cache;
1975 scopeObjectProtector = _ddata->jsWrapper.value();
1976 } else {
1977 vmeMetaObject = QQmlVMEMetaObject::get(_qobject);
1978 }
1979
1980 registerObjectWithContextById(_compiledObject, _qobject);
1981
1982 qSwap(_propertyCache, cache);
1983 qSwap(_vmeMetaObject, vmeMetaObject);
1984
1985 // If it's a group property object, don't populate CU and object index.
1986 // It might be populated at the actual instantiation point, or the object might not be
1987 // created by QML at all.
1988 if (!stringAt(_compiledObject->inheritedTypeNameIndex).isEmpty()) {
1989 _ddata->compilationUnit = compilationUnit;
1990 _ddata->cuObjectIndex = int(_compiledObjectIndex);
1991 }
1992
1993 if (_compiledObject->hasFlag(QV4::CompiledData::Object::HasDeferredBindings))
1994 _ddata->deferData(_compiledObjectIndex, compilationUnit, context, m_inlineComponentName);
1995
1996 registerPostHocRequiredProperties(binding);
1997
1998 if (_compiledObject->nFunctions > 0)
1999 setupFunctions();
2000 setupBindings((binding && binding->hasFlag(QV4::CompiledData::Binding::IsDeferredBinding))
2001 ? BindingMode::ApplyAll
2002 : BindingMode::ApplyImmediate);
2003
2004 for (int aliasIndex = 0; aliasIndex != _compiledObject->aliasCount(); ++aliasIndex) {
2005 // Ensure aliasChanged() signals are connected during object creation.
2006 // This is necessary because alias signals may not have been connected
2007 // if the signal handlers are defined and connected in C++ code rather
2008 // than being declared in QML.
2009 _vmeMetaObject->connectAlias(_compiledObject, aliasIndex);
2010 if (!context->isIdValueSet(0)) // TODO: Do we really want 0 here?
2011 continue;
2012 const QQmlPropertyData *aliasProperty =
2013 _propertyCache->property(_vmeMetaObject->aliasOffset() + aliasIndex);
2014 if (!aliasProperty)
2015 continue;
2016 QObject *target = context->idValue(aliasProperty->aliasTargetObjectId());
2017 if (!target)
2018 continue;
2019 QQmlData *targetDData = QQmlData::get(target, /*create*/false);
2020 if (targetDData == nullptr || targetDData->propertyCache.isNull())
2021 continue;
2022
2023 const int targetPropertyIndex = aliasProperty->aliasTarget();
2024 int coreIndex = QQmlPropertyIndex::fromEncoded(targetPropertyIndex).coreIndex();
2025
2026 const QQmlPropertyData *const targetProperty = targetDData->propertyCache->property(coreIndex);
2027 if (!targetProperty)
2028 continue;
2029 auto it = sharedState->requiredProperties.find({target, targetProperty});
2030 if (it != sharedState->requiredProperties.end()) {
2031 const QV4::CompiledData::Alias* alias = _compiledObject->aliasesBegin() + aliasIndex;
2032 it->aliasesToRequired.push_back(
2033 AliasToRequiredInfo {
2034 compilationUnit->stringAt(alias->nameIndex()),
2035 compilationUnit->finalUrl()
2036 });
2037 }
2038 }
2039
2040 qSwap(_vmeMetaObject, vmeMetaObject);
2041 qSwap(_bindingTarget, bindingTarget);
2042 qSwap(_ddata, declarativeData);
2043 qSwap(_compiledObject, obj);
2044 qSwap(_compiledObjectIndex, index);
2045 qSwap(_valueTypeProperty, valueTypeProperty);
2046 qSwap(_qobject, instance);
2047 qSwap(_propertyCache, cache);
2048
2049 return errors.isEmpty();
2050}
2051
2052/*!
2053 \internal
2054*/
2055QQmlComponent *QQmlObjectCreator::createComponent(
2056 QQmlEngine *engine, QV4::ExecutableCompilationUnit *compilationUnit, int index,
2057 QObject *parent, const QQmlRefPointer<QQmlContextData> &context)
2058{
2059 QQmlComponent *component = new QQmlComponent(engine, compilationUnit, index, parent);
2060 QQmlComponentPrivate::get(component)->setCreationContext(context);
2061 QQmlData *ddata = QQmlData::get(component, /*create*/ true);
2062 Q_ASSERT(ddata);
2063 ddata->compilationUnit = compilationUnit;
2064 ddata->cuObjectIndex = index;
2065 return component;
2066}
2067
2068/*!
2069 \internal
2070 Re-populate bindings, functions and child objects on an existing \a instance
2071 whose VME metaobject chain has already been (re-)created externally.
2072
2073 Unlike initializeInstance(), this does not create a new VME — it uses the one
2074 already installed on the object. It sets up the context, registers the object
2075 by id, installs functions, evaluates bindings (which may create child objects),
2076 and connects aliases.
2077
2078 Used by the QML preview/hot-reload system to rebuild an object's contents
2079 after its VME hierarchy has been reconstructed.
2080*/
2081void QQmlObjectCreator::repopulateBindings(
2082 int index, QObject *instance,
2083 const QQmlRefPointer<QQmlContextData> &instanceContext, InitFlags flags)
2084{
2085 phase = QQmlObjectCreator::ObjectsCreated;
2086
2087 // If the object doesn't exist in the CU, there's nothing to do.
2088 if (compilationUnit->objectCount() <= index)
2089 return;
2090
2091 const auto oldContext = std::exchange(context, instanceContext);
2092 const auto contextGuard = qScopeGuard([&]() {
2093 context = oldContext;
2094 });
2095
2096 auto rootContextGuard = qScopeGuard([&]() {
2097 sharedState->rootContext.reset();
2098 });
2099 if (!sharedState->rootContext)
2100 sharedState->rootContext = context;
2101 else
2102 rootContextGuard.dismiss();
2103
2104 QV4::Scope scope(engine->handle());
2105 auto jsObjectsGuard = qScopeGuard([&]() {
2106 sharedState->allJavaScriptObjects = ObjectInCreationGCAnchorList();
2107 });
2108 if (!sharedState->allJavaScriptObjects.canTrack())
2109 sharedState->allJavaScriptObjects = ObjectInCreationGCAnchorList(scope);
2110 else
2111 jsObjectsGuard.dismiss();
2112
2113 QQmlData *ddata = QQmlData::get(instance, /*create=*/true);
2114 Q_ASSERT(ddata);
2115
2116 QQmlVMEMetaObject *vmeMetaObject = QQmlVMEMetaObject::get(instance);
2117
2118 const QV4::CompiledData::Object *obj = compilationUnit->objectAt(index);
2119
2120 // Set up internal state mirroring populateInstanceAndAliasBindings + populateInstance.
2121 qSwap(_qobject, instance);
2122 qSwap(_compiledObjectIndex, index);
2123 qSwap(_compiledObject, obj);
2124 qSwap(_ddata, ddata);
2125 QObject *bindingTarget = _qobject;
2126 qSwap(_bindingTarget, bindingTarget);
2127 QObject *scopeObject = _qobject;
2128 qSwap(_scopeObject, scopeObject);
2129 const QQmlPropertyData *valueTypeProperty = nullptr;
2130 qSwap(_valueTypeProperty, valueTypeProperty);
2131
2132 Q_ASSERT(sharedState->allJavaScriptObjects.canTrack());
2133 sharedState->allJavaScriptObjects.trackObject(v4, _qobject);
2134
2135 QV4::QmlContext *qmlContext = static_cast<QV4::QmlContext *>(scope.constructUndefined(1));
2136 qSwap(_qmlContext, qmlContext);
2137
2138 QV4::ScopedValue scopeObjectProtector(scope);
2139
2140 QQmlPropertyCache::ConstPtr cache = propertyCaches->at(_compiledObjectIndex);
2141 _ddata->propertyCache = cache;
2142 qSwap(_propertyCache, cache);
2143 qSwap(_vmeMetaObject, vmeMetaObject);
2144
2145 if (_compiledObject->objectId() < context->numIdValues())
2146 registerObjectWithContextById(_compiledObject, _qobject);
2147
2148 _ddata->compilationUnit = compilationUnit;
2149 _ddata->cuObjectIndex = int(_compiledObjectIndex);
2150
2151 if (_compiledObject->nFunctions > 0)
2152 setupFunctions();
2153 setupBindings(BindingMode::ApplyImmediate);
2154
2155 if (flags.testFlag(InitFlag::IsContextObject)) {
2156 while (!pendingAliasBindings.empty()) {
2157 for (auto it = pendingAliasBindings.begin(); it != pendingAliasBindings.end();) {
2158 if ((*it)(sharedState.data()))
2159 it = pendingAliasBindings.erase(it);
2160 else
2161 ++it;
2162 }
2163 }
2164 }
2165
2166 // Restore swapped state.
2167 qSwap(_vmeMetaObject, vmeMetaObject);
2168 qSwap(_propertyCache, cache);
2169 qSwap(_qmlContext, qmlContext);
2170 qSwap(_scopeObject, scopeObject);
2171 qSwap(_valueTypeProperty, valueTypeProperty);
2172 qSwap(_bindingTarget, bindingTarget);
2173 qSwap(_ddata, ddata);
2174 qSwap(_compiledObject, obj);
2175 qSwap(_compiledObjectIndex, index);
2176 qSwap(_qobject, instance);
2177}
2178
2184
2185void ObjectInCreationGCAnchorList::trackObject(QV4::ExecutionEngine *engine, QObject *instance)
2186{
2187 QV4::Value *wrapper = allocationScope->construct(1, QV4::QObjectWrapper::wrap(engine, instance));
2188 // we have to handle the case where the gc is already running, but the scope is discarded
2189 // before the collector runs again. In that case, rescanning won't help us. Thus, mark the
2190 // object.
2191 QV4::WriteBarrier::markCustom(engine, [wrapper](QV4::MarkStack *ms) {
2192 wrapper->heapObject()->mark(ms);
2193 });
2194}
QT_BEGIN_NAMESPACE Q_STATIC_LOGGING_CATEGORY(lcSynthesizedIterableAccess, "qt.iterable.synthesized", QtWarningMsg)
static QQmlType qmlTypeForObject(QObject *object)
QQmlObjectCreatorRecursionWatcher(QQmlObjectCreator *creator)