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()) {
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.isInlineComponent();
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());
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->isQmlBinding()) {
1746 const auto qmlBindingBase = static_cast<const QQmlPropertyBindingBase *>(priv);
1747 if (qmlBindingBase->bindingKind()
1748 == QQmlPropertyBindingBase::BindingKind::JavaScript) {
1749 const auto qmlBindingPriv =
1750 static_cast<const QQmlPropertyBinding *>(qmlBindingBase);
1751 const auto jsExpression = qmlBindingPriv->jsExpression();
1752 const bool canRemove = !qmlBinding.error().hasError()
1753 && !qmlBindingPriv->hasDependencies()
1754 && !jsExpression->hasUnresolvedNames();
1755 if (canRemove)
1756 bindable.takeBinding();
1757 }
1758 }
1759 }
1760
1761 if (watcher.hasRecursed() || interrupt.shouldInterrupt())
1762 return false;
1763 }
1764
1765 if (QQmlVME::componentCompleteEnabled()) { // the qml designer does the component complete later
1766 while (!sharedState->allParserStatusCallbacks.empty()) {
1767 QQmlObjectCompletionProfiler profiler(&sharedState->profiler);
1768 const ParserStatus status = sharedState->allParserStatusCallbacks.back();
1769 sharedState->allParserStatusCallbacks.pop_back();
1770
1771 const QQmlGuard<QObject> &instance = sharedState->allCreatedObjects[status.objectIndex];
1772 if (!instance)
1773 continue;
1774
1775 QQmlParserStatus *parserStatus
1776 = reinterpret_cast<QQmlParserStatus *>(
1777 reinterpret_cast<char *>(instance.data()) + status.parserStatusCast);
1778 parserStatus->componentComplete();
1779
1780 if (watcher.hasRecursed() || interrupt.shouldInterrupt())
1781 return false;
1782 }
1783 }
1784
1785 for (QQmlFinalizerHook *hook: std::as_const(sharedState->finalizeHooks)) {
1786 hook->componentFinalized();
1787 if (watcher.hasRecursed())
1788 return false;
1789 }
1790 sharedState->finalizeHooks.clear();
1791
1792 while (sharedState->componentAttached) {
1793 QQmlComponentAttached *a = sharedState->componentAttached;
1794 a->removeFromList();
1795 QQmlData *d = QQmlData::get(a->parent());
1796 Q_ASSERT(d);
1797 Q_ASSERT(d->context);
1798 d->context->addComponentAttached(a);
1799 if (QQmlVME::componentCompleteEnabled())
1800 emit a->completed();
1801
1802 if (watcher.hasRecursed() || interrupt.shouldInterrupt())
1803 return false;
1804 }
1805
1806 phase = Done;
1807
1808 return true;
1809}
1810
1811void QQmlObjectCreator::clear()
1812{
1813 if (phase == Done || phase == Finalizing || phase == Startup)
1814 return;
1815 Q_ASSERT(phase != Startup);
1816
1817 while (!sharedState->allCreatedObjects.empty()) {
1818 auto object = sharedState->allCreatedObjects.back();
1819 sharedState->allCreatedObjects.pop_back();
1820 if (engine->objectOwnership(object) != QQmlEngine::CppOwnership) {
1821 delete object;
1822 }
1823 }
1824
1825 while (sharedState->componentAttached) {
1826 QQmlComponentAttached *a = sharedState->componentAttached;
1827 a->removeFromList();
1828 }
1829
1830 phase = Done;
1831}
1832
1833void QQmlObjectCreator::registerPostHocRequiredProperties(const QV4::CompiledData::Binding *binding)
1834{
1835 const qsizetype oldRequiredPropertiesCount = sharedState->requiredProperties.size();
1836 QSet<QString> postHocRequired;
1837 for (auto it = _compiledObject->requiredPropertyExtraDataBegin(); it != _compiledObject->requiredPropertyExtraDataEnd(); ++it)
1838 postHocRequired.insert(stringAt(it->nameIndex));
1839 bool hadInheritedRequiredProperties = !postHocRequired.empty();
1840
1841 for (int propertyIndex = 0; propertyIndex != _compiledObject->propertyCount(); ++propertyIndex) {
1842 const QV4::CompiledData::Property* property = _compiledObject->propertiesBegin() + propertyIndex;
1843 const QQmlPropertyData *propertyData = _propertyCache->property(_propertyCache->propertyOffset() + propertyIndex);
1844 // only compute stringAt if there's a chance for the lookup to succeed
1845 auto postHocIt = postHocRequired.isEmpty() ? postHocRequired.end() : postHocRequired.find(stringAt(property->nameIndex()));
1846 if (!property->isRequired() && postHocRequired.end() == postHocIt)
1847 continue;
1848 if (postHocIt != postHocRequired.end())
1849 postHocRequired.erase(postHocIt);
1850 if (isContextObject)
1851 sharedState->hadTopLevelRequiredProperties = true;
1852 sharedState->requiredProperties.insert({_qobject, propertyData},
1853 RequiredPropertyInfo {compilationUnit->stringAt(property->nameIndex()), compilationUnit->finalUrl(), property->location, {}});
1854
1855 }
1856
1857 const auto getPropertyCacheRange = [&]() -> std::pair<int, int> {
1858 // the logic in a nutshell: we work with QML instances here. every
1859 // instance has a QQmlType:
1860 // * if QQmlType is valid && not an inline component, it's a C++ type
1861 // * otherwise, it's a QML-defined type (a.k.a. Composite type), where
1862 // invalid type == "comes from another QML document"
1863 //
1864 // 1. if the type we inherit from comes from C++, we must check *all*
1865 // properties in the property cache so far - since we can have
1866 // required properties defined in C++
1867 // 2. otherwise - the type comes from QML, it's enough to check just
1868 // *own* properties in the property cache, because there's a previous
1869 // type in the hierarchy that has checked the C++ properties (via 1.)
1870 // 3. required attached properties are explicitly not supported. to
1871 // achieve that, go through all its properties
1872 // 4. required group properties: the group itself is covered by 1.
1873 // required sub-properties are not properly handled (QTBUG-96544), so
1874 // just return the old range here for consistency
1875 QV4::ResolvedTypeReference *typeRef = resolvedType(_compiledObject->inheritedTypeNameIndex);
1876 if (!typeRef) { // inside a binding on attached/group property
1877 Q_ASSERT(binding);
1878 if (binding->isAttachedProperty())
1879 return { 0, _propertyCache->propertyCount() }; // 3.
1880 Q_ASSERT(binding->isGroupProperty());
1881 return { 0, _propertyCache->propertyOffset() + 1 }; // 4.
1882 }
1883 Q_ASSERT(!_compiledObject->hasFlag(QV4::CompiledData::Object::IsComponent));
1884 QQmlType type = typeRef->type();
1885 if (type.isComposite())
1886 return { _propertyCache->propertyOffset(), _propertyCache->propertyCount() }; // 2.
1887 return { 0, _propertyCache->propertyCount() }; // 1.
1888 };
1889 const auto [offset, count] = getPropertyCacheRange();
1890 for (int i = offset; i < count; ++i) {
1891 const QQmlPropertyData *propertyData = _propertyCache->maybeUnresolvedProperty(i);
1892 if (!propertyData)
1893 continue;
1894 // TODO: the property might be a group property (in which case we need
1895 // to dive into its sub-properties and check whether there are any
1896 // required elements there) - QTBUG-96544
1897 if (!propertyData->isRequired() && postHocRequired.isEmpty())
1898 continue;
1899 QString name = propertyData->name(_qobject);
1900 const auto postHocIt = postHocRequired.constFind(name);
1901 if (postHocIt == postHocRequired.constEnd()) {
1902 if (!propertyData->isRequired())
1903 continue;
1904 } else {
1905 postHocRequired.erase(postHocIt);
1906 }
1907
1908 if (isContextObject)
1909 sharedState->hadTopLevelRequiredProperties = true;
1910 sharedState->requiredProperties.insert(
1911 {_qobject, propertyData},
1912 RequiredPropertyInfo {
1913 std::move(name), compilationUnit->finalUrl(), _compiledObject->location, {}
1914 });
1915 }
1916
1917 if (binding && binding->isAttachedProperty()
1918 && sharedState->requiredProperties.size() != oldRequiredPropertiesCount) {
1919 recordError(
1920 binding->location,
1921 QLatin1String("Attached property has required properties. This is not supported"));
1922 }
1923
1924 // Note: there's a subtle case with the above logic: if we process a random
1925 // QML-defined leaf type, it could have a required attribute overwrite on an
1926 // *existing* property: `import QtQuick; Text { required text }`. in this
1927 // case, we must add the property to a required list
1928 if (!postHocRequired.isEmpty()) {
1929 // NB: go through [0, offset) range as [offset, count) is already done
1930 for (int i = 0; i < offset; ++i) {
1931 const QQmlPropertyData *propertyData = _propertyCache->maybeUnresolvedProperty(i);
1932 if (!propertyData)
1933 continue;
1934 QString name = propertyData->name(_qobject);
1935 const auto postHocIt = postHocRequired.constFind(name);
1936 if (postHocIt == postHocRequired.constEnd())
1937 continue;
1938 postHocRequired.erase(postHocIt);
1939
1940 if (isContextObject)
1941 sharedState->hadTopLevelRequiredProperties = true;
1942 sharedState->requiredProperties.insert(
1943 {_qobject, propertyData},
1944 RequiredPropertyInfo {
1945 std::move(name), compilationUnit->finalUrl(), _compiledObject->location, {}
1946 });
1947 }
1948 }
1949
1950 if (!postHocRequired.isEmpty() && hadInheritedRequiredProperties)
1951 recordError({}, QLatin1String("Property %1 was marked as required but does not exist").arg(*postHocRequired.begin()));
1952}
1953
1954bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject *bindingTarget,
1955 const QQmlPropertyData *valueTypeProperty,
1956 const QV4::CompiledData::Binding *binding)
1957{
1958 Q_ASSERT(instance);
1959 QQmlData *declarativeData = QQmlData::get(instance, /*create*/true);
1960
1961 qSwap(_qobject, instance);
1962 qSwap(_valueTypeProperty, valueTypeProperty);
1963 qSwap(_compiledObjectIndex, index);
1964 const QV4::CompiledData::Object *obj = compilationUnit->objectAt(_compiledObjectIndex);
1965 qSwap(_compiledObject, obj);
1966 qSwap(_ddata, declarativeData);
1967 qSwap(_bindingTarget, bindingTarget);
1968
1969 QV4::Scope valueScope(v4);
1970 QV4::ScopedValue scopeObjectProtector(valueScope);
1971
1972 QQmlPropertyCache::ConstPtr cache = propertyCaches->at(_compiledObjectIndex);
1973
1974 QQmlVMEMetaObject *vmeMetaObject = nullptr;
1975 if (propertyCaches->needsVMEMetaObject(_compiledObjectIndex)) {
1976 Q_ASSERT(!cache.isNull());
1977 // install on _object
1978 vmeMetaObject = new QQmlVMEMetaObject(v4, _qobject, cache, compilationUnit, _compiledObjectIndex);
1979 _ddata->propertyCache = cache;
1980 scopeObjectProtector = _ddata->jsWrapper.value();
1981 } else {
1982 vmeMetaObject = QQmlVMEMetaObject::get(_qobject);
1983 }
1984
1985 registerObjectWithContextById(_compiledObject, _qobject);
1986
1987 qSwap(_propertyCache, cache);
1988 qSwap(_vmeMetaObject, vmeMetaObject);
1989
1990 // If it's a group property object, don't populate CU and object index.
1991 // It might be populated at the actual instantiation point, or the object might not be
1992 // created by QML at all.
1993 if (!stringAt(_compiledObject->inheritedTypeNameIndex).isEmpty()) {
1994 _ddata->compilationUnit = compilationUnit;
1995 _ddata->cuObjectIndex = int(_compiledObjectIndex);
1996 }
1997
1998 if (_compiledObject->hasFlag(QV4::CompiledData::Object::HasDeferredBindings))
1999 _ddata->deferData(_compiledObjectIndex, compilationUnit, context, m_inlineComponentName);
2000
2001 registerPostHocRequiredProperties(binding);
2002
2003 if (_compiledObject->nFunctions > 0)
2004 setupFunctions();
2005 setupBindings((binding && binding->hasFlag(QV4::CompiledData::Binding::IsDeferredBinding))
2006 ? BindingMode::ApplyAll
2007 : BindingMode::ApplyImmediate);
2008
2009 for (int aliasIndex = 0; aliasIndex != _compiledObject->aliasCount(); ++aliasIndex) {
2010 // Ensure aliasChanged() signals are connected during object creation.
2011 // This is necessary because alias signals may not have been connected
2012 // if the signal handlers are defined and connected in C++ code rather
2013 // than being declared in QML.
2014 _vmeMetaObject->connectAlias(_compiledObject, aliasIndex);
2015 if (!context->isIdValueSet(0)) // TODO: Do we really want 0 here?
2016 continue;
2017 const QQmlPropertyData *aliasProperty =
2018 _propertyCache->property(_vmeMetaObject->aliasOffset() + aliasIndex);
2019 if (!aliasProperty)
2020 continue;
2021 QObject *target = context->idValue(aliasProperty->aliasTargetObjectId());
2022 if (!target)
2023 continue;
2024 QQmlData *targetDData = QQmlData::get(target, /*create*/false);
2025 if (targetDData == nullptr || targetDData->propertyCache.isNull())
2026 continue;
2027
2028 const int targetPropertyIndex = aliasProperty->aliasTarget();
2029 int coreIndex = QQmlPropertyIndex::fromEncoded(targetPropertyIndex).coreIndex();
2030
2031 const QQmlPropertyData *const targetProperty = targetDData->propertyCache->property(coreIndex);
2032 if (!targetProperty)
2033 continue;
2034 auto it = sharedState->requiredProperties.find({target, targetProperty});
2035 if (it != sharedState->requiredProperties.end()) {
2036 const QV4::CompiledData::Alias* alias = _compiledObject->aliasesBegin() + aliasIndex;
2037 it->aliasesToRequired.push_back(
2038 AliasToRequiredInfo {
2039 compilationUnit->stringAt(alias->nameIndex()),
2040 compilationUnit->finalUrl()
2041 });
2042 }
2043 }
2044
2045 qSwap(_vmeMetaObject, vmeMetaObject);
2046 qSwap(_bindingTarget, bindingTarget);
2047 qSwap(_ddata, declarativeData);
2048 qSwap(_compiledObject, obj);
2049 qSwap(_compiledObjectIndex, index);
2050 qSwap(_valueTypeProperty, valueTypeProperty);
2051 qSwap(_qobject, instance);
2052 qSwap(_propertyCache, cache);
2053
2054 return errors.isEmpty();
2055}
2056
2057/*!
2058 \internal
2059*/
2060QQmlComponent *QQmlObjectCreator::createComponent(
2061 QQmlEngine *engine, QV4::ExecutableCompilationUnit *compilationUnit, int index,
2062 QObject *parent, const QQmlRefPointer<QQmlContextData> &context)
2063{
2064 QQmlComponent *component = new QQmlComponent(engine, compilationUnit, index, parent);
2065 QQmlComponentPrivate::get(component)->setCreationContext(context);
2066 QQmlData *ddata = QQmlData::get(component, /*create*/ true);
2067 Q_ASSERT(ddata);
2068 ddata->compilationUnit = compilationUnit;
2069 ddata->cuObjectIndex = index;
2070 return component;
2071}
2072
2073/*!
2074 \internal
2075 Re-populate bindings, functions and child objects on an existing \a instance
2076 whose VME metaobject chain has already been (re-)created externally.
2077
2078 Unlike initializeInstance(), this does not create a new VME — it uses the one
2079 already installed on the object. It sets up the context, registers the object
2080 by id, installs functions, evaluates bindings (which may create child objects),
2081 and connects aliases.
2082
2083 Used by the QML preview/hot-reload system to rebuild an object's contents
2084 after its VME hierarchy has been reconstructed.
2085*/
2086void QQmlObjectCreator::repopulateBindings(
2087 int index, QObject *instance,
2088 const QQmlRefPointer<QQmlContextData> &instanceContext, InitFlags flags)
2089{
2090 phase = QQmlObjectCreator::ObjectsCreated;
2091
2092 // If the object doesn't exist in the CU, there's nothing to do.
2093 if (compilationUnit->objectCount() <= index)
2094 return;
2095
2096 const auto oldContext = std::exchange(context, instanceContext);
2097 const auto contextGuard = qScopeGuard([&]() {
2098 context = oldContext;
2099 });
2100
2101 auto rootContextGuard = qScopeGuard([&]() {
2102 sharedState->rootContext.reset();
2103 });
2104 if (!sharedState->rootContext)
2105 sharedState->rootContext = context;
2106 else
2107 rootContextGuard.dismiss();
2108
2109 QV4::Scope scope(engine->handle());
2110 auto jsObjectsGuard = qScopeGuard([&]() {
2111 sharedState->allJavaScriptObjects = ObjectInCreationGCAnchorList();
2112 });
2113 if (!sharedState->allJavaScriptObjects.canTrack())
2114 sharedState->allJavaScriptObjects = ObjectInCreationGCAnchorList(scope);
2115 else
2116 jsObjectsGuard.dismiss();
2117
2118 QQmlData *ddata = QQmlData::get(instance, /*create=*/true);
2119 Q_ASSERT(ddata);
2120
2121 QQmlVMEMetaObject *vmeMetaObject = QQmlVMEMetaObject::get(instance);
2122
2123 const QV4::CompiledData::Object *obj = compilationUnit->objectAt(index);
2124
2125 // Set up internal state mirroring populateInstanceAndAliasBindings + populateInstance.
2126 qSwap(_qobject, instance);
2127 qSwap(_compiledObjectIndex, index);
2128 qSwap(_compiledObject, obj);
2129 qSwap(_ddata, ddata);
2130 QObject *bindingTarget = _qobject;
2131 qSwap(_bindingTarget, bindingTarget);
2132 QObject *scopeObject = _qobject;
2133 qSwap(_scopeObject, scopeObject);
2134 const QQmlPropertyData *valueTypeProperty = nullptr;
2135 qSwap(_valueTypeProperty, valueTypeProperty);
2136
2137 Q_ASSERT(sharedState->allJavaScriptObjects.canTrack());
2138 sharedState->allJavaScriptObjects.trackObject(v4, _qobject);
2139
2140 QV4::QmlContext *qmlContext = static_cast<QV4::QmlContext *>(scope.constructUndefined(1));
2141 qSwap(_qmlContext, qmlContext);
2142
2143 QV4::ScopedValue scopeObjectProtector(scope);
2144
2145 QQmlPropertyCache::ConstPtr cache = propertyCaches->at(_compiledObjectIndex);
2146 _ddata->propertyCache = cache;
2147 qSwap(_propertyCache, cache);
2148 qSwap(_vmeMetaObject, vmeMetaObject);
2149
2150 if (_compiledObject->objectId() < context->numIdValues())
2151 registerObjectWithContextById(_compiledObject, _qobject);
2152
2153 _ddata->compilationUnit = compilationUnit;
2154 _ddata->cuObjectIndex = int(_compiledObjectIndex);
2155
2156 if (_compiledObject->nFunctions > 0)
2157 setupFunctions();
2158 setupBindings(BindingMode::ApplyImmediate);
2159
2160 if (flags.testFlag(InitFlag::IsContextObject)) {
2161 while (!pendingAliasBindings.empty()) {
2162 for (auto it = pendingAliasBindings.begin(); it != pendingAliasBindings.end();) {
2163 if ((*it)(sharedState.data()))
2164 it = pendingAliasBindings.erase(it);
2165 else
2166 ++it;
2167 }
2168 }
2169 }
2170
2171 // Restore swapped state.
2172 qSwap(_vmeMetaObject, vmeMetaObject);
2173 qSwap(_propertyCache, cache);
2174 qSwap(_qmlContext, qmlContext);
2175 qSwap(_scopeObject, scopeObject);
2176 qSwap(_valueTypeProperty, valueTypeProperty);
2177 qSwap(_bindingTarget, bindingTarget);
2178 qSwap(_ddata, ddata);
2179 qSwap(_compiledObject, obj);
2180 qSwap(_compiledObjectIndex, index);
2181 qSwap(_qobject, instance);
2182}
2183
2189
2190void ObjectInCreationGCAnchorList::trackObject(QV4::ExecutionEngine *engine, QObject *instance)
2191{
2192 QV4::Value *wrapper = allocationScope->construct(1, QV4::QObjectWrapper::wrap(engine, instance));
2193 // we have to handle the case where the gc is already running, but the scope is discarded
2194 // before the collector runs again. In that case, rescanning won't help us. Thus, mark the
2195 // object.
2196 QV4::WriteBarrier::markCustom(engine, [wrapper](QV4::MarkStack *ms) {
2197 wrapper->heapObject()->mark(ms);
2198 });
2199}
QT_BEGIN_NAMESPACE Q_STATIC_LOGGING_CATEGORY(lcSynthesizedIterableAccess, "qt.iterable.synthesized", QtWarningMsg)
static QQmlType qmlTypeForObject(QObject *object)
QQmlObjectCreatorRecursionWatcher(QQmlObjectCreator *creator)