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