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