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