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