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