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