1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the tools applications of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qqmlobjectcreator_p.h"
41
42#include <private/qqmlengine_p.h>
43#include <private/qqmlvmemetaobject_p.h>
44#include <private/qv4function_p.h>
45#include <private/qv4functionobject_p.h>
46#include <private/qv4qobjectwrapper_p.h>
47#include <private/qqmlbinding_p.h>
48#include <private/qqmlstringconverters_p.h>
49#include <private/qqmlboundsignal_p.h>
50#include <private/qqmlcomponentattached_p.h>
51#include <private/qqmlcomponent_p.h>
52#include <private/qqmlcustomparser_p.h>
53#include <private/qqmlscriptstring_p.h>
54#include <private/qqmlpropertyvalueinterceptor_p.h>
55#include <private/qqmlvaluetypeproxybinding_p.h>
56#include <private/qqmldebugconnector_p.h>
57#include <private/qqmldebugserviceinterfaces_p.h>
58#include <private/qqmlscriptdata_p.h>
59#include <private/qjsvalue_p.h>
60#include <private/qv4generatorobject_p.h>
61
62#include <qtqml_tracepoints_p.h>
63
64QT_USE_NAMESPACE
65
66namespace {
67struct ActiveOCRestorer
68{
69 ActiveOCRestorer(QQmlObjectCreator *creator, QQmlEnginePrivate *ep)
70 : ep(ep), oldCreator(ep->activeObjectCreator) { ep->activeObjectCreator = creator; }
71 ~ActiveOCRestorer() { ep->activeObjectCreator = oldCreator; }
72
73 QQmlEnginePrivate *ep;
74 QQmlObjectCreator *oldCreator;
75};
76}
77
78QQmlObjectCreator::QQmlObjectCreator(QQmlContextData *parentContext, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, QQmlContextData *creationContext,
79 QQmlIncubatorPrivate *incubator)
80 : phase(Startup)
81 , compilationUnit(compilationUnit)
82 , propertyCaches(&compilationUnit->propertyCaches)
83 , sharedState(new QQmlObjectCreatorSharedState)
84 , topLevelCreator(true)
85 , incubator(incubator)
86{
87 init(parentContext);
88
89 sharedState->componentAttached = nullptr;
90 sharedState->allCreatedBindings.allocate(compilationUnit->totalBindingsCount);
91 sharedState->allParserStatusCallbacks.allocate(compilationUnit->totalParserStatusCount);
92 sharedState->allCreatedObjects.allocate(compilationUnit->totalObjectCount);
93 sharedState->allJavaScriptObjects = nullptr;
94 sharedState->creationContext = creationContext;
95 sharedState->rootContext = nullptr;
96
97 if (auto profiler = QQmlEnginePrivate::get(engine)->profiler) {
98 Q_QML_PROFILE_IF_ENABLED(QQmlProfilerDefinitions::ProfileCreating, profiler,
99 sharedState->profiler.init(profiler, compilationUnit->totalParserStatusCount));
100 } else {
101 Q_UNUSED(profiler);
102 }
103}
104
105QQmlObjectCreator::QQmlObjectCreator(QQmlContextData *parentContext, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, QQmlObjectCreatorSharedState *inheritedSharedState)
106 : phase(Startup)
107 , compilationUnit(compilationUnit)
108 , propertyCaches(&compilationUnit->propertyCaches)
109 , sharedState(inheritedSharedState)
110 , topLevelCreator(false)
111 , incubator(nullptr)
112{
113 init(parentContext);
114}
115
116void QQmlObjectCreator::init(QQmlContextData *providedParentContext)
117{
118 parentContext = providedParentContext;
119 engine = parentContext->engine;
120 v4 = engine->handle();
121
122 if (compilationUnit && !compilationUnit->engine)
123 compilationUnit->linkToEngine(v4);
124
125 qmlUnit = compilationUnit->unitData();
126 context = nullptr;
127 _qobject = nullptr;
128 _scopeObject = nullptr;
129 _bindingTarget = nullptr;
130 _valueTypeProperty = nullptr;
131 _compiledObject = nullptr;
132 _compiledObjectIndex = -1;
133 _ddata = nullptr;
134 _propertyCache = nullptr;
135 _vmeMetaObject = nullptr;
136 _qmlContext = nullptr;
137}
138
139QQmlObjectCreator::~QQmlObjectCreator()
140{
141 if (topLevelCreator) {
142 {
143 QQmlObjectCreatorRecursionWatcher watcher(this);
144 }
145 for (int i = 0; i < sharedState->allParserStatusCallbacks.count(); ++i) {
146 QQmlParserStatus *ps = sharedState->allParserStatusCallbacks.at(i);
147 if (ps)
148 ps->d = nullptr;
149 }
150 while (sharedState->componentAttached) {
151 QQmlComponentAttached *a = sharedState->componentAttached;
152 a->rem();
153 }
154 }
155}
156
157QObject *QQmlObjectCreator::create(int subComponentIndex, QObject *parent, QQmlInstantiationInterrupt *interrupt)
158{
159 if (phase == CreatingObjectsPhase2) {
160 phase = ObjectsCreated;
161 return context->contextObject;
162 }
163 Q_ASSERT(phase == Startup);
164 phase = CreatingObjects;
165
166 int objectToCreate;
167
168 if (subComponentIndex == -1) {
169 objectToCreate = /*root object*/0;
170 } else {
171 const QV4::CompiledData::Object *compObj = compilationUnit->objectAt(subComponentIndex);
172 objectToCreate = compObj->bindingTable()->value.objectIndex;
173 }
174
175 context = new QQmlContextData;
176 context->isInternal = true;
177 context->imports = compilationUnit->typeNameCache;
178 context->initFromTypeCompilationUnit(compilationUnit, subComponentIndex);
179 context->setParent(parentContext);
180
181 if (!sharedState->rootContext) {
182 sharedState->rootContext = context;
183 sharedState->rootContext->incubator = incubator;
184 sharedState->rootContext->isRootObjectInCreation = true;
185 }
186
187 QV4::Scope scope(v4);
188
189 Q_ASSERT(sharedState->allJavaScriptObjects || topLevelCreator);
190 if (topLevelCreator)
191 sharedState->allJavaScriptObjects = scope.alloc(compilationUnit->totalObjectCount);
192
193 if (subComponentIndex == -1 && compilationUnit->dependentScripts.count()) {
194 QV4::ScopedObject scripts(scope, v4->newArrayObject(compilationUnit->dependentScripts.count()));
195 context->importedScripts.set(v4, scripts);
196 QV4::ScopedValue v(scope);
197 for (int i = 0; i < compilationUnit->dependentScripts.count(); ++i) {
198 QQmlRefPointer<QQmlScriptData> s = compilationUnit->dependentScripts.at(i);
199 scripts->put(i, (v = s->scriptValueForContext(context)));
200 }
201 } else if (sharedState->creationContext) {
202 context->importedScripts = sharedState->creationContext->importedScripts;
203 }
204
205 QObject *instance = createInstance(objectToCreate, parent, /*isContextObject*/true);
206 if (instance) {
207 QQmlData *ddata = QQmlData::get(instance);
208 Q_ASSERT(ddata);
209 ddata->compilationUnit = compilationUnit;
210 }
211
212 if (topLevelCreator)
213 sharedState->allJavaScriptObjects = nullptr;
214
215 phase = CreatingObjectsPhase2;
216
217 if (interrupt && interrupt->shouldInterrupt())
218 return nullptr;
219
220 phase = ObjectsCreated;
221
222 if (instance) {
223 if (QQmlEngineDebugService *service
224 = QQmlDebugConnector::service<QQmlEngineDebugService>()) {
225 if (!parentContext->isInternal)
226 parentContext->asQQmlContextPrivate()->instances.append(instance);
227 service->objectCreated(engine, instance);
228 } else if (!parentContext->isInternal && QQmlDebugConnector::service<QV4DebugService>()) {
229 parentContext->asQQmlContextPrivate()->instances.append(instance);
230 }
231 }
232
233 return instance;
234}
235
236// ### unify or keep in sync with populateDeferredBinding()
237bool QQmlObjectCreator::populateDeferredProperties(QObject *instance, QQmlData::DeferredData *deferredData)
238{
239 QQmlData *declarativeData = QQmlData::get(instance);
240 context = deferredData->context;
241 sharedState->rootContext = context;
242
243 QObject *bindingTarget = instance;
244
245 QQmlRefPointer<QQmlPropertyCache> cache = declarativeData->propertyCache;
246 QQmlVMEMetaObject *vmeMetaObject = QQmlVMEMetaObject::get(instance);
247
248 QObject *scopeObject = instance;
249 qSwap(_scopeObject, scopeObject);
250
251 QV4::Scope valueScope(v4);
252
253 Q_ASSERT(topLevelCreator);
254 Q_ASSERT(!sharedState->allJavaScriptObjects);
255 sharedState->allJavaScriptObjects = valueScope.alloc(compilationUnit->totalObjectCount);
256
257 QV4::QmlContext *qmlContext = static_cast<QV4::QmlContext *>(valueScope.alloc());
258
259 qSwap(_qmlContext, qmlContext);
260
261 qSwap(_propertyCache, cache);
262 qSwap(_qobject, instance);
263
264 int objectIndex = deferredData->deferredIdx;
265 qSwap(_compiledObjectIndex, objectIndex);
266
267 const QV4::CompiledData::Object *obj = compilationUnit->objectAt(_compiledObjectIndex);
268 qSwap(_compiledObject, obj);
269
270 qSwap(_ddata, declarativeData);
271 qSwap(_bindingTarget, bindingTarget);
272 qSwap(_vmeMetaObject, vmeMetaObject);
273
274 setupBindings(/*applyDeferredBindings=*/true);
275
276 qSwap(_vmeMetaObject, vmeMetaObject);
277 qSwap(_bindingTarget, bindingTarget);
278 qSwap(_ddata, declarativeData);
279 qSwap(_compiledObject, obj);
280 qSwap(_compiledObjectIndex, objectIndex);
281 qSwap(_qobject, instance);
282 qSwap(_propertyCache, cache);
283
284 qSwap(_qmlContext, qmlContext);
285 qSwap(_scopeObject, scopeObject);
286
287 deferredData->bindings.clear();
288 phase = ObjectsCreated;
289
290 return errors.isEmpty();
291}
292
293// ### unify or keep in sync with populateDeferredProperties()
294bool QQmlObjectCreator::populateDeferredBinding(const QQmlProperty &qmlProperty, QQmlData::DeferredData *deferredData, const QV4::CompiledData::Binding *binding)
295{
296 Q_ASSERT(binding->flags & QV4::CompiledData::Binding::IsDeferredBinding);
297
298 QObject *instance = qmlProperty.object();
299 QQmlData *declarativeData = QQmlData::get(instance);
300 context = deferredData->context;
301 sharedState->rootContext = context;
302
303 QObject *bindingTarget = instance;
304
305 QQmlRefPointer<QQmlPropertyCache> cache = declarativeData->propertyCache;
306 QQmlVMEMetaObject *vmeMetaObject = QQmlVMEMetaObject::get(instance);
307
308 QObject *scopeObject = instance;
309 qSwap(_scopeObject, scopeObject);
310
311 QV4::Scope valueScope(v4);
312
313 Q_ASSERT(topLevelCreator);
314 if (!sharedState->allJavaScriptObjects)
315 sharedState->allJavaScriptObjects = valueScope.alloc(compilationUnit->totalObjectCount);
316
317 QV4::QmlContext *qmlContext = static_cast<QV4::QmlContext *>(valueScope.alloc());
318
319 qSwap(_qmlContext, qmlContext);
320
321 qSwap(_propertyCache, cache);
322 qSwap(_qobject, instance);
323
324 int objectIndex = deferredData->deferredIdx;
325 qSwap(_compiledObjectIndex, objectIndex);
326
327 const QV4::CompiledData::Object *obj = compilationUnit->objectAt(_compiledObjectIndex);
328 qSwap(_compiledObject, obj);
329
330 qSwap(_ddata, declarativeData);
331 qSwap(_bindingTarget, bindingTarget);
332 qSwap(_vmeMetaObject, vmeMetaObject);
333
334 QQmlListProperty<void> savedList;
335 qSwap(_currentList, savedList);
336
337 const QQmlPropertyData &property = QQmlPropertyPrivate::get(qmlProperty)->core;
338
339 if (property.isQList()) {
340 void *argv[1] = { (void*)&_currentList };
341 QMetaObject::metacall(_qobject, QMetaObject::ReadProperty, property.coreIndex(), argv);
342 } else if (_currentList.object) {
343 _currentList = QQmlListProperty<void>();
344 }
345
346 setPropertyBinding(&property, binding);
347
348 qSwap(_currentList, savedList);
349
350 qSwap(_vmeMetaObject, vmeMetaObject);
351 qSwap(_bindingTarget, bindingTarget);
352 qSwap(_ddata, declarativeData);
353 qSwap(_compiledObject, obj);
354 qSwap(_compiledObjectIndex, objectIndex);
355 qSwap(_qobject, instance);
356 qSwap(_propertyCache, cache);
357
358 qSwap(_qmlContext, qmlContext);
359 qSwap(_scopeObject, scopeObject);
360
361 phase = ObjectsCreated;
362
363 return errors.isEmpty();
364}
365
366void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const QV4::CompiledData::Binding *binding)
367{
368 QQmlPropertyData::WriteFlags propertyWriteFlags = QQmlPropertyData::BypassInterceptor | QQmlPropertyData::RemoveBindingOnAliasWrite;
369 QV4::Scope scope(v4);
370
371 int propertyType = property->propType();
372
373 if (property->isEnum()) {
374 if (binding->flags & QV4::CompiledData::Binding::IsResolvedEnum) {
375 propertyType = QMetaType::Int;
376 } else {
377 // ### This should be resolved earlier at compile time and the binding value should be changed accordingly.
378 QVariant value = compilationUnit->bindingValueAsString(binding);
379 bool ok = QQmlPropertyPrivate::write(_qobject, *property, value, context);
380 Q_ASSERT(ok);
381 Q_UNUSED(ok);
382 return;
383 }
384 }
385
386 auto assertOrNull = [&](bool ok)
387 {
388 Q_ASSERT(ok || binding->type == QV4::CompiledData::Binding::Type_Null);
389 Q_UNUSED(ok);
390 };
391
392 auto assertType = [&](QV4::CompiledData::Binding::ValueType type)
393 {
394 Q_ASSERT(binding->type == type || binding->type == QV4::CompiledData::Binding::Type_Null);
395 Q_UNUSED(type);
396 };
397
398 if (property->isQObject()) {
399 if (binding->type == QV4::CompiledData::Binding::Type_Null) {
400 QObject *value = nullptr;
401 const bool ok = property->writeProperty(_qobject, &value, propertyWriteFlags);
402 Q_ASSERT(ok);
403 Q_UNUSED(ok);
404 return;
405 }
406 }
407
408 switch (propertyType) {
409 case QMetaType::QVariant: {
410 if (binding->type == QV4::CompiledData::Binding::Type_Number) {
411 double n = compilationUnit->bindingValueAsNumber(binding);
412 if (double(int(n)) == n) {
413 if (property->isVarProperty()) {
414 _vmeMetaObject->setVMEProperty(property->coreIndex(), QV4::Value::fromInt32(int(n)));
415 } else {
416 int i = int(n);
417 QVariant value(i);
418 property->writeProperty(_qobject, &value, propertyWriteFlags);
419 }
420 } else {
421 if (property->isVarProperty()) {
422 _vmeMetaObject->setVMEProperty(property->coreIndex(), QV4::Value::fromDouble(n));
423 } else {
424 QVariant value(n);
425 property->writeProperty(_qobject, &value, propertyWriteFlags);
426 }
427 }
428 } else if (binding->type == QV4::CompiledData::Binding::Type_Boolean) {
429 if (property->isVarProperty()) {
430 _vmeMetaObject->setVMEProperty(property->coreIndex(), QV4::Value::fromBoolean(binding->valueAsBoolean()));
431 } else {
432 QVariant value(binding->valueAsBoolean());
433 property->writeProperty(_qobject, &value, propertyWriteFlags);
434 }
435 } else if (binding->type == QV4::CompiledData::Binding::Type_Null) {
436 if (property->isVarProperty()) {
437 _vmeMetaObject->setVMEProperty(property->coreIndex(), QV4::Value::nullValue());
438 } else {
439 QVariant nullValue = QVariant::fromValue(nullptr);
440 property->writeProperty(_qobject, &nullValue, propertyWriteFlags);
441 }
442 } else {
443 QString stringValue = compilationUnit->bindingValueAsString(binding);
444 if (property->isVarProperty()) {
445 QV4::ScopedString s(scope, v4->newString(stringValue));
446 _vmeMetaObject->setVMEProperty(property->coreIndex(), s);
447 } else {
448 QVariant value = QQmlStringConverters::variantFromString(stringValue);
449 property->writeProperty(_qobject, &value, propertyWriteFlags);
450 }
451 }
452 }
453 break;
454 case QVariant::String: {
455 assertOrNull(binding->evaluatesToString());
456 QString value = compilationUnit->bindingValueAsString(binding);
457 property->writeProperty(_qobject, &value, propertyWriteFlags);
458 }
459 break;
460 case QVariant::StringList: {
461 assertOrNull(binding->evaluatesToString());
462 QStringList value(compilationUnit->bindingValueAsString(binding));
463 property->writeProperty(_qobject, &value, propertyWriteFlags);
464 }
465 break;
466 case QVariant::ByteArray: {
467 assertType(QV4::CompiledData::Binding::Type_String);
468 QByteArray value(compilationUnit->bindingValueAsString(binding).toUtf8());
469 property->writeProperty(_qobject, &value, propertyWriteFlags);
470 }
471 break;
472 case QVariant::Url: {
473 assertType(QV4::CompiledData::Binding::Type_String);
474 QString string = compilationUnit->bindingValueAsString(binding);
475 // Encoded dir-separators defeat QUrl processing - decode them first
476 string.replace(QLatin1String("%2f"), QLatin1String("/"), Qt::CaseInsensitive);
477 QUrl value = string.isEmpty() ? QUrl() : compilationUnit->finalUrl().resolved(QUrl(string));
478 // Apply URL interceptor
479 if (engine->urlInterceptor())
480 value = engine->urlInterceptor()->intercept(value, QQmlAbstractUrlInterceptor::UrlString);
481 property->writeProperty(_qobject, &value, propertyWriteFlags);
482 }
483 break;
484 case QVariant::UInt: {
485 assertType(QV4::CompiledData::Binding::Type_Number);
486 double d = compilationUnit->bindingValueAsNumber(binding);
487 uint value = uint(d);
488 property->writeProperty(_qobject, &value, propertyWriteFlags);
489 break;
490 }
491 break;
492 case QVariant::Int: {
493 assertType(QV4::CompiledData::Binding::Type_Number);
494 double d = compilationUnit->bindingValueAsNumber(binding);
495 int value = int(d);
496 property->writeProperty(_qobject, &value, propertyWriteFlags);
497 break;
498 }
499 break;
500 case QMetaType::Float: {
501 assertType(QV4::CompiledData::Binding::Type_Number);
502 float value = float(compilationUnit->bindingValueAsNumber(binding));
503 property->writeProperty(_qobject, &value, propertyWriteFlags);
504 }
505 break;
506 case QVariant::Double: {
507 assertType(QV4::CompiledData::Binding::Type_Number);
508 double value = compilationUnit->bindingValueAsNumber(binding);
509 property->writeProperty(_qobject, &value, propertyWriteFlags);
510 }
511 break;
512 case QVariant::Color: {
513 bool ok = false;
514 uint colorValue = QQmlStringConverters::rgbaFromString(compilationUnit->bindingValueAsString(binding), &ok);
515 assertOrNull(ok);
516 struct { void *data[4]; } buffer;
517 if (QQml_valueTypeProvider()->storeValueType(property->propType(), &colorValue, &buffer, sizeof(buffer))) {
518 property->writeProperty(_qobject, &buffer, propertyWriteFlags);
519 }
520 }
521 break;
522#if QT_CONFIG(datestring)
523 case QVariant::Date: {
524 bool ok = false;
525 QDate value = QQmlStringConverters::dateFromString(compilationUnit->bindingValueAsString(binding), &ok);
526 assertOrNull(ok);
527 property->writeProperty(_qobject, &value, propertyWriteFlags);
528 }
529 break;
530 case QVariant::Time: {
531 bool ok = false;
532 QTime value = QQmlStringConverters::timeFromString(compilationUnit->bindingValueAsString(binding), &ok);
533 assertOrNull(ok);
534 property->writeProperty(_qobject, &value, propertyWriteFlags);
535 }
536 break;
537 case QVariant::DateTime: {
538 bool ok = false;
539 QDateTime value = QQmlStringConverters::dateTimeFromString(compilationUnit->bindingValueAsString(binding), &ok);
540 // ### VME compatibility :(
541 {
542 const qint64 date = value.date().toJulianDay();
543 const int msecsSinceStartOfDay = value.time().msecsSinceStartOfDay();
544 value = QDateTime(QDate::fromJulianDay(date), QTime::fromMSecsSinceStartOfDay(msecsSinceStartOfDay));
545 }
546 assertOrNull(ok);
547 property->writeProperty(_qobject, &value, propertyWriteFlags);
548 }
549 break;
550#endif // datestring
551 case QVariant::Point: {
552 bool ok = false;
553 QPoint value = QQmlStringConverters::pointFFromString(compilationUnit->bindingValueAsString(binding), &ok).toPoint();
554 assertOrNull(ok);
555 property->writeProperty(_qobject, &value, propertyWriteFlags);
556 }
557 break;
558 case QVariant::PointF: {
559 bool ok = false;
560 QPointF value = QQmlStringConverters::pointFFromString(compilationUnit->bindingValueAsString(binding), &ok);
561 assertOrNull(ok);
562 property->writeProperty(_qobject, &value, propertyWriteFlags);
563 }
564 break;
565 case QVariant::Size: {
566 bool ok = false;
567 QSize value = QQmlStringConverters::sizeFFromString(compilationUnit->bindingValueAsString(binding), &ok).toSize();
568 assertOrNull(ok);
569 property->writeProperty(_qobject, &value, propertyWriteFlags);
570 }
571 break;
572 case QVariant::SizeF: {
573 bool ok = false;
574 QSizeF value = QQmlStringConverters::sizeFFromString(compilationUnit->bindingValueAsString(binding), &ok);
575 assertOrNull(ok);
576 property->writeProperty(_qobject, &value, propertyWriteFlags);
577 }
578 break;
579 case QVariant::Rect: {
580 bool ok = false;
581 QRect value = QQmlStringConverters::rectFFromString(compilationUnit->bindingValueAsString(binding), &ok).toRect();
582 assertOrNull(ok);
583 property->writeProperty(_qobject, &value, propertyWriteFlags);
584 }
585 break;
586 case QVariant::RectF: {
587 bool ok = false;
588 QRectF value = QQmlStringConverters::rectFFromString(compilationUnit->bindingValueAsString(binding), &ok);
589 assertOrNull(ok);
590 property->writeProperty(_qobject, &value, propertyWriteFlags);
591 }
592 break;
593 case QVariant::Bool: {
594 assertType(QV4::CompiledData::Binding::Type_Boolean);
595 bool value = binding->valueAsBoolean();
596 property->writeProperty(_qobject, &value, propertyWriteFlags);
597 }
598 break;
599 case QVariant::Vector2D: {
600 struct {
601 float xp;
602 float yp;
603 } vec;
604 bool ok = QQmlStringConverters::createFromString(QMetaType::QVector2D, compilationUnit->bindingValueAsString(binding), &vec, sizeof(vec));
605 assertOrNull(ok);
606 Q_UNUSED(ok);
607 property->writeProperty(_qobject, &vec, propertyWriteFlags);
608 }
609 break;
610 case QVariant::Vector3D: {
611 struct {
612 float xp;
613 float yp;
614 float zy;
615 } vec;
616 bool ok = QQmlStringConverters::createFromString(QMetaType::QVector3D, compilationUnit->bindingValueAsString(binding), &vec, sizeof(vec));
617 assertOrNull(ok);
618 Q_UNUSED(ok);
619 property->writeProperty(_qobject, &vec, propertyWriteFlags);
620 }
621 break;
622 case QVariant::Vector4D: {
623 struct {
624 float xp;
625 float yp;
626 float zy;
627 float wp;
628 } vec;
629 bool ok = QQmlStringConverters::createFromString(QMetaType::QVector4D, compilationUnit->bindingValueAsString(binding), &vec, sizeof(vec));
630 assertOrNull(ok);
631 Q_UNUSED(ok);
632 property->writeProperty(_qobject, &vec, propertyWriteFlags);
633 }
634 break;
635 case QVariant::Quaternion: {
636 struct {
637 float wp;
638 float xp;
639 float yp;
640 float zp;
641 } vec;
642 bool ok = QQmlStringConverters::createFromString(QMetaType::QQuaternion, compilationUnit->bindingValueAsString(binding), &vec, sizeof(vec));
643 assertOrNull(ok);
644 Q_UNUSED(ok);
645 property->writeProperty(_qobject, &vec, propertyWriteFlags);
646 }
647 break;
648 case QVariant::RegExp:
649 assertOrNull(!"not possible");
650 break;
651 default: {
652 // generate single literal value assignment to a list property if required
653 if (property->propType() == qMetaTypeId<QList<qreal> >()) {
654 assertType(QV4::CompiledData::Binding::Type_Number);
655 QList<qreal> value;
656 value.append(compilationUnit->bindingValueAsNumber(binding));
657 property->writeProperty(_qobject, &value, propertyWriteFlags);
658 break;
659 } else if (property->propType() == qMetaTypeId<QList<int> >()) {
660 assertType(QV4::CompiledData::Binding::Type_Number);
661 double n = compilationUnit->bindingValueAsNumber(binding);
662 QList<int> value;
663 value.append(int(n));
664 property->writeProperty(_qobject, &value, propertyWriteFlags);
665 break;
666 } else if (property->propType() == qMetaTypeId<QList<bool> >()) {
667 assertType(QV4::CompiledData::Binding::Type_Boolean);
668 QList<bool> value;
669 value.append(binding->valueAsBoolean());
670 property->writeProperty(_qobject, &value, propertyWriteFlags);
671 break;
672 } else if (property->propType() == qMetaTypeId<QList<QUrl> >()) {
673 assertType(QV4::CompiledData::Binding::Type_String);
674 QString urlString = compilationUnit->bindingValueAsString(binding);
675 QUrl u = urlString.isEmpty() ? QUrl()
676 : compilationUnit->finalUrl().resolved(QUrl(urlString));
677 QList<QUrl> value;
678 value.append(u);
679 property->writeProperty(_qobject, &value, propertyWriteFlags);
680 break;
681 } else if (property->propType() == qMetaTypeId<QList<QString> >()) {
682 assertOrNull(binding->evaluatesToString());
683 QList<QString> value;
684 value.append(compilationUnit->bindingValueAsString(binding));
685 property->writeProperty(_qobject, &value, propertyWriteFlags);
686 break;
687 } else if (property->propType() == qMetaTypeId<QJSValue>()) {
688 QJSValue value;
689 if (binding->type == QV4::CompiledData::Binding::Type_Boolean) {
690 value = QJSValue(binding->valueAsBoolean());
691 } else if (binding->type == QV4::CompiledData::Binding::Type_Number) {
692 double n = compilationUnit->bindingValueAsNumber(binding);
693 if (double(int(n)) == n) {
694 value = QJSValue(int(n));
695 } else
696 value = QJSValue(n);
697 } else if (binding->type == QV4::CompiledData::Binding::Type_Null) {
698 value = QJSValue::NullValue;
699 } else {
700 value = QJSValue(compilationUnit->bindingValueAsString(binding));
701 }
702 property->writeProperty(_qobject, &value, propertyWriteFlags);
703 break;
704 }
705
706 // otherwise, try a custom type assignment
707 QString stringValue = compilationUnit->bindingValueAsString(binding);
708 QQmlMetaType::StringConverter converter = QQmlMetaType::customStringConverter(property->propType());
709 Q_ASSERT(converter);
710 QVariant value = (*converter)(stringValue);
711
712 QMetaProperty metaProperty = _qobject->metaObject()->property(property->coreIndex());
713 if (value.isNull() || ((int)metaProperty.type() != property->propType() && metaProperty.userType() != property->propType())) {
714 recordError(binding->location, tr("Cannot assign value %1 to property %2").arg(stringValue).arg(QString::fromUtf8(metaProperty.name())));
715 break;
716 }
717
718 property->writeProperty(_qobject, value.data(), propertyWriteFlags);
719 }
720 break;
721 }
722}
723
724static QQmlType qmlTypeForObject(QObject *object)
725{
726 QQmlType type;
727 const QMetaObject *mo = object->metaObject();
728 while (mo && !type.isValid()) {
729 type = QQmlMetaType::qmlType(mo);
730 mo = mo->superClass();
731 }
732 return type;
733}
734
735void QQmlObjectCreator::setupBindings(bool applyDeferredBindings)
736{
737 QQmlListProperty<void> savedList;
738 qSwap(_currentList, savedList);
739
740 const QV4::BindingPropertyData &propertyData = compilationUnit->bindingPropertyDataPerObject.at(_compiledObjectIndex);
741
742 if (_compiledObject->idNameIndex) {
743 const QQmlPropertyData *idProperty = propertyData.last();
744 Q_ASSERT(!idProperty || !idProperty->isValid() || idProperty->name(_qobject) == QLatin1String("id"));
745 if (idProperty && idProperty->isValid() && idProperty->isWritable() && idProperty->propType() == QMetaType::QString) {
746 QV4::CompiledData::Binding idBinding;
747 idBinding.propertyNameIndex = 0; // Not used
748 idBinding.flags = 0;
749 idBinding.type = QV4::CompiledData::Binding::Type_String;
750 idBinding.stringIndex = _compiledObject->idNameIndex;
751 idBinding.location = _compiledObject->location; // ###
752 setPropertyValue(idProperty, &idBinding);
753 }
754 }
755
756 // ### this is best done through type-compile-time binding skip lists.
757 if (_valueTypeProperty) {
758 QQmlAbstractBinding *binding = QQmlPropertyPrivate::binding(_bindingTarget, QQmlPropertyIndex(_valueTypeProperty->coreIndex()));
759
760 if (binding && !binding->isValueTypeProxy()) {
761 QQmlPropertyPrivate::removeBinding(_bindingTarget, QQmlPropertyIndex(_valueTypeProperty->coreIndex()));
762 } else if (binding) {
763 QQmlValueTypeProxyBinding *proxy = static_cast<QQmlValueTypeProxyBinding *>(binding);
764
765 if (qmlTypeForObject(_bindingTarget).isValid()) {
766 quint32 bindingSkipList = 0;
767
768 QQmlPropertyData *defaultProperty = _compiledObject->indexOfDefaultPropertyOrAlias != -1 ? _propertyCache->parent()->defaultProperty() : _propertyCache->defaultProperty();
769
770 const QV4::CompiledData::Binding *binding = _compiledObject->bindingTable();
771 for (quint32 i = 0; i < _compiledObject->nBindings; ++i, ++binding) {
772 QQmlPropertyData *property = binding->propertyNameIndex != 0 ? _propertyCache->property(stringAt(binding->propertyNameIndex), _qobject, context) : defaultProperty;
773 if (property)
774 bindingSkipList |= (1 << property->coreIndex());
775 }
776
777 proxy->removeBindings(bindingSkipList);
778 }
779 }
780 }
781
782 int currentListPropertyIndex = -1;
783
784 const QV4::CompiledData::Binding *binding = _compiledObject->bindingTable();
785 for (quint32 i = 0; i < _compiledObject->nBindings; ++i, ++binding) {
786 if (binding->flags & QV4::CompiledData::Binding::IsCustomParserBinding)
787 continue;
788
789 if (binding->flags & QV4::CompiledData::Binding::IsDeferredBinding) {
790 if (!applyDeferredBindings)
791 continue;
792 } else {
793 if (applyDeferredBindings)
794 continue;
795 }
796
797 const QQmlPropertyData *property = propertyData.at(i);
798
799 if (property && property->isQList()) {
800 if (property->coreIndex() != currentListPropertyIndex) {
801 void *argv[1] = { (void*)&_currentList };
802 QMetaObject::metacall(_qobject, QMetaObject::ReadProperty, property->coreIndex(), argv);
803 currentListPropertyIndex = property->coreIndex();
804 }
805 } else if (_currentList.object) {
806 _currentList = QQmlListProperty<void>();
807 currentListPropertyIndex = -1;
808 }
809
810 if (!setPropertyBinding(property, binding))
811 return;
812 }
813
814 qSwap(_currentList, savedList);
815}
816
817bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProperty, const QV4::CompiledData::Binding *binding)
818{
819 if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) {
820 Q_ASSERT(stringAt(compilationUnit->objectAt(binding->value.objectIndex)->inheritedTypeNameIndex).isEmpty());
821 QV4::ResolvedTypeReference *tr = resolvedType(binding->propertyNameIndex);
822 Q_ASSERT(tr);
823 QQmlType attachedType = tr->type;
824 if (!attachedType.isValid()) {
825 QQmlTypeNameCache::Result res = context->imports->query(stringAt(binding->propertyNameIndex));
826 if (res.isValid())
827 attachedType = res.type;
828 else
829 return false;
830 }
831 QObject *qmlObject = qmlAttachedPropertiesObject(
832 _qobject, attachedType.attachedPropertiesFunction(QQmlEnginePrivate::get(engine)));
833 if (!populateInstance(binding->value.objectIndex, qmlObject, qmlObject, /*value type property*/nullptr))
834 return false;
835 return true;
836 }
837
838 // ### resolve this at compile time
839 if (bindingProperty && bindingProperty->propType() == qMetaTypeId<QQmlScriptString>()) {
840 QQmlScriptString ss(compilationUnit->bindingValueAsScriptString(binding),
841 context->asQQmlContext(), _scopeObject);
842 ss.d.data()->bindingId = binding->type == QV4::CompiledData::Binding::Type_Script ? binding->value.compiledScriptIndex : (quint32)QQmlBinding::Invalid;
843 ss.d.data()->lineNumber = binding->location.line;
844 ss.d.data()->columnNumber = binding->location.column;
845 ss.d.data()->isStringLiteral = binding->type == QV4::CompiledData::Binding::Type_String;
846 ss.d.data()->isNumberLiteral = binding->type == QV4::CompiledData::Binding::Type_Number;
847 ss.d.data()->numberValue = compilationUnit->bindingValueAsNumber(binding);
848
849 QQmlPropertyData::WriteFlags propertyWriteFlags = QQmlPropertyData::BypassInterceptor |
850 QQmlPropertyData::RemoveBindingOnAliasWrite;
851 int propertyWriteStatus = -1;
852 void *argv[] = { &ss, nullptr, &propertyWriteStatus, &propertyWriteFlags };
853 QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, bindingProperty->coreIndex(), argv);
854 return true;
855 }
856
857 QObject *createdSubObject = nullptr;
858 if (binding->type == QV4::CompiledData::Binding::Type_Object) {
859 createdSubObject = createInstance(binding->value.objectIndex, _bindingTarget);
860 if (!createdSubObject)
861 return false;
862 }
863
864 if (!bindingProperty) // ### error
865 return true;
866
867 if (binding->type == QV4::CompiledData::Binding::Type_GroupProperty) {
868 const QV4::CompiledData::Object *obj = compilationUnit->objectAt(binding->value.objectIndex);
869 if (stringAt(obj->inheritedTypeNameIndex).isEmpty()) {
870
871 QObject *groupObject = nullptr;
872 QQmlValueType *valueType = nullptr;
873 const QQmlPropertyData *valueTypeProperty = nullptr;
874 QObject *bindingTarget = _bindingTarget;
875
876 if (QQmlValueTypeFactory::isValueType(bindingProperty->propType())) {
877 valueType = QQmlValueTypeFactory::valueType(bindingProperty->propType());
878 if (!valueType) {
879 recordError(binding->location, tr("Cannot set properties on %1 as it is null").arg(stringAt(binding->propertyNameIndex)));
880 return false;
881 }
882
883 valueType->read(_qobject, bindingProperty->coreIndex());
884
885 groupObject = valueType;
886 valueTypeProperty = bindingProperty;
887 } else {
888 void *argv[1] = { &groupObject };
889 QMetaObject::metacall(_qobject, QMetaObject::ReadProperty, bindingProperty->coreIndex(), argv);
890 if (!groupObject) {
891 recordError(binding->location, tr("Cannot set properties on %1 as it is null").arg(stringAt(binding->propertyNameIndex)));
892 return false;
893 }
894
895 bindingTarget = groupObject;
896 }
897
898 if (!populateInstance(binding->value.objectIndex, groupObject, bindingTarget, valueTypeProperty))
899 return false;
900
901 if (valueType)
902 valueType->write(_qobject, bindingProperty->coreIndex(), QQmlPropertyData::BypassInterceptor);
903
904 return true;
905 }
906 }
907
908 if (_ddata->hasBindingBit(bindingProperty->coreIndex()) && !(binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression)
909 && !(binding->flags & QV4::CompiledData::Binding::IsOnAssignment)
910 && !_valueTypeProperty)
911 QQmlPropertyPrivate::removeBinding(_bindingTarget, QQmlPropertyIndex(bindingProperty->coreIndex()));
912
913 if (binding->type == QV4::CompiledData::Binding::Type_Script || binding->isTranslationBinding()) {
914 if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression) {
915 QV4::Function *runtimeFunction = compilationUnit->runtimeFunctions[binding->value.compiledScriptIndex];
916 int signalIndex = _propertyCache->methodIndexToSignalIndex(bindingProperty->coreIndex());
917 QQmlBoundSignal *bs = new QQmlBoundSignal(_bindingTarget, signalIndex, _scopeObject, engine);
918 QQmlBoundSignalExpression *expr = new QQmlBoundSignalExpression(_bindingTarget, signalIndex,
919 context, _scopeObject, runtimeFunction, currentQmlContext());
920
921 bs->takeExpression(expr);
922 } else {
923 // When writing bindings to grouped properties implemented as value types,
924 // such as point.x: { someExpression; }, then the binding is installed on
925 // the point property (_qobjectForBindings) and after evaluating the expression,
926 // the result is written to a value type virtual property, that contains the sub-index
927 // of the "x" property.
928 QQmlBinding::Ptr qmlBinding;
929 const QQmlPropertyData *targetProperty = bindingProperty;
930 const QQmlPropertyData *subprop = nullptr;
931 if (_valueTypeProperty) {
932 targetProperty = _valueTypeProperty;
933 subprop = bindingProperty;
934 }
935 if (binding->isTranslationBinding()) {
936 qmlBinding = QQmlBinding::createTranslationBinding(compilationUnit, binding, _scopeObject, context);
937 } else {
938 QV4::Function *runtimeFunction = compilationUnit->runtimeFunctions[binding->value.compiledScriptIndex];
939 qmlBinding = QQmlBinding::create(targetProperty, runtimeFunction, _scopeObject, context, currentQmlContext());
940 }
941
942 auto bindingTarget = _bindingTarget;
943 auto valueTypeProperty = _valueTypeProperty;
944 auto assignBinding = [qmlBinding, bindingTarget, targetProperty, subprop, bindingProperty, valueTypeProperty](QQmlObjectCreatorSharedState *sharedState) mutable -> bool {
945 if (!qmlBinding->setTarget(bindingTarget, *targetProperty, subprop) && targetProperty->isAlias())
946 return false;
947
948 sharedState->allCreatedBindings.push(qmlBinding);
949
950 if (bindingProperty->isAlias()) {
951 QQmlPropertyPrivate::setBinding(qmlBinding.data(), QQmlPropertyPrivate::DontEnable);
952 } else {
953 qmlBinding->addToObject();
954
955 if (!valueTypeProperty) {
956 QQmlData *targetDeclarativeData = QQmlData::get(bindingTarget);
957 Q_ASSERT(targetDeclarativeData);
958 targetDeclarativeData->setPendingBindingBit(bindingTarget, bindingProperty->coreIndex());
959 }
960 }
961
962 return true;
963 };
964 if (!assignBinding(sharedState.data()))
965 pendingAliasBindings.push_back(assignBinding);
966 }
967 return true;
968 }
969
970 if (binding->type == QV4::CompiledData::Binding::Type_Object) {
971 if (binding->flags & QV4::CompiledData::Binding::IsOnAssignment) {
972 // ### determine value source and interceptor casts ahead of time.
973 QQmlType type = qmlTypeForObject(createdSubObject);
974 Q_ASSERT(type.isValid());
975
976 int valueSourceCast = type.propertyValueSourceCast();
977 if (valueSourceCast != -1) {
978 QQmlPropertyValueSource *vs = reinterpret_cast<QQmlPropertyValueSource *>(reinterpret_cast<char *>(createdSubObject) + valueSourceCast);
979 QObject *target = createdSubObject->parent();
980 QQmlProperty prop;
981 if (_valueTypeProperty)
982 prop = QQmlPropertyPrivate::restore(target, *_valueTypeProperty, bindingProperty, context);
983 else
984 prop = QQmlPropertyPrivate::restore(target, *bindingProperty, nullptr, context);
985 vs->setTarget(prop);
986 return true;
987 }
988 int valueInterceptorCast = type.propertyValueInterceptorCast();
989 if (valueInterceptorCast != -1) {
990 QQmlPropertyValueInterceptor *vi = reinterpret_cast<QQmlPropertyValueInterceptor *>(reinterpret_cast<char *>(createdSubObject) + valueInterceptorCast);
991 QObject *target = createdSubObject->parent();
992
993 QQmlPropertyIndex propertyIndex;
994 if (bindingProperty->isAlias()) {
995 QQmlPropertyIndex originalIndex(bindingProperty->coreIndex(), _valueTypeProperty ? _valueTypeProperty->coreIndex() : -1);
996 QQmlPropertyIndex propIndex;
997 QQmlPropertyPrivate::findAliasTarget(target, originalIndex, &target, &propIndex);
998 QQmlData *data = QQmlData::get(target);
999 if (!data || !data->propertyCache) {
1000 qWarning() << "can't resolve property alias for 'on' assignment";
1001 return false;
1002 }
1003
1004 // we can't have aliasses on subproperties of value types, so:
1005 QQmlPropertyData targetPropertyData = *data->propertyCache->property(propIndex.coreIndex());
1006 auto prop = QQmlPropertyPrivate::restore(target, targetPropertyData, nullptr, context);
1007 vi->setTarget(prop);
1008 propertyIndex = QQmlPropertyPrivate::propertyIndex(prop);
1009 } else {
1010 QQmlProperty prop;
1011 if (_valueTypeProperty)
1012 prop = QQmlPropertyPrivate::restore(target, *_valueTypeProperty, bindingProperty, context);
1013 else
1014 prop = QQmlPropertyPrivate::restore(target, *bindingProperty, nullptr, context);
1015 vi->setTarget(prop);
1016 propertyIndex = QQmlPropertyPrivate::propertyIndex(prop);
1017 }
1018
1019 QQmlInterceptorMetaObject *mo = QQmlInterceptorMetaObject::get(target);
1020 if (!mo)
1021 mo = new QQmlInterceptorMetaObject(target, QQmlData::get(target)->propertyCache);
1022 mo->registerInterceptor(propertyIndex, vi);
1023 return true;
1024 }
1025 return false;
1026 }
1027
1028 // Assigning object to signal property?
1029 if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject) {
1030 if (!bindingProperty->isFunction()) {
1031 recordError(binding->valueLocation, tr("Cannot assign an object to signal property %1").arg(bindingProperty->name(_qobject)));
1032 return false;
1033 }
1034 QMetaMethod method = QQmlMetaType::defaultMethod(createdSubObject);
1035 if (!method.isValid()) {
1036 recordError(binding->valueLocation, tr("Cannot assign object type %1 with no default method").arg(QString::fromLatin1(createdSubObject->metaObject()->className())));
1037 return false;
1038 }
1039
1040 QMetaMethod signalMethod = _qobject->metaObject()->method(bindingProperty->coreIndex());
1041 if (!QMetaObject::checkConnectArgs(signalMethod, method)) {
1042 recordError(binding->valueLocation,
1043 tr("Cannot connect mismatched signal/slot %1 %vs. %2")
1044 .arg(QString::fromUtf8(method.methodSignature()))
1045 .arg(QString::fromUtf8(signalMethod.methodSignature())));
1046 return false;
1047 }
1048
1049 QQmlPropertyPrivate::connect(_qobject, bindingProperty->coreIndex(), createdSubObject, method.methodIndex());
1050 return true;
1051 }
1052
1053 QQmlPropertyData::WriteFlags propertyWriteFlags = QQmlPropertyData::BypassInterceptor |
1054 QQmlPropertyData::RemoveBindingOnAliasWrite;
1055 int propertyWriteStatus = -1;
1056 void *argv[] = { nullptr, nullptr, &propertyWriteStatus, &propertyWriteFlags };
1057
1058 if (const char *iid = QQmlMetaType::interfaceIId(bindingProperty->propType())) {
1059 void *ptr = createdSubObject->qt_metacast(iid);
1060 if (ptr) {
1061 argv[0] = &ptr;
1062 QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, bindingProperty->coreIndex(), argv);
1063 } else {
1064 recordError(binding->location, tr("Cannot assign object to interface property"));
1065 return false;
1066 }
1067 } else if (bindingProperty->propType() == QMetaType::QVariant) {
1068 if (bindingProperty->isVarProperty()) {
1069 QV4::Scope scope(v4);
1070 QV4::ScopedValue wrappedObject(scope, QV4::QObjectWrapper::wrap(engine->handle(), createdSubObject));
1071 _vmeMetaObject->setVMEProperty(bindingProperty->coreIndex(), wrappedObject);
1072 } else {
1073 QVariant value = QVariant::fromValue(createdSubObject);
1074 argv[0] = &value;
1075 QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, bindingProperty->coreIndex(), argv);
1076 }
1077 } else if (bindingProperty->propType() == qMetaTypeId<QJSValue>()) {
1078 QV4::Scope scope(v4);
1079 QV4::ScopedValue wrappedObject(scope, QV4::QObjectWrapper::wrap(engine->handle(), createdSubObject));
1080 if (bindingProperty->isVarProperty()) {
1081 _vmeMetaObject->setVMEProperty(bindingProperty->coreIndex(), wrappedObject);
1082 } else {
1083 QJSValue value;
1084 QJSValuePrivate::setValue(&value, v4, wrappedObject);
1085 argv[0] = &value;
1086 QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, bindingProperty->coreIndex(), argv);
1087 }
1088 } else if (bindingProperty->isQList()) {
1089 Q_ASSERT(_currentList.object);
1090
1091 void *itemToAdd = createdSubObject;
1092
1093 const char *iid = nullptr;
1094 int listItemType = QQmlEnginePrivate::get(engine)->listType(bindingProperty->propType());
1095 if (listItemType != -1)
1096 iid = QQmlMetaType::interfaceIId(listItemType);
1097 if (iid)
1098 itemToAdd = createdSubObject->qt_metacast(iid);
1099
1100 if (_currentList.append)
1101 _currentList.append(&_currentList, itemToAdd);
1102 else {
1103 recordError(binding->location, tr("Cannot assign object to read only list"));
1104 return false;
1105 }
1106
1107 } else {
1108 // pointer compatibility was tested in QQmlPropertyValidator at type compile time
1109 argv[0] = &createdSubObject;
1110 QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, bindingProperty->coreIndex(), argv);
1111 }
1112 return true;
1113 }
1114
1115 if (bindingProperty->isQList()) {
1116 recordError(binding->location, tr("Cannot assign primitives to lists"));
1117 return false;
1118 }
1119
1120 setPropertyValue(bindingProperty, binding);
1121 return true;
1122}
1123
1124void QQmlObjectCreator::setupFunctions()
1125{
1126 QV4::Scope scope(v4);
1127 QV4::ScopedValue function(scope);
1128 QV4::ScopedContext qmlContext(scope, currentQmlContext());
1129
1130 const quint32_le *functionIdx = _compiledObject->functionOffsetTable();
1131 for (quint32 i = 0; i < _compiledObject->nFunctions; ++i, ++functionIdx) {
1132 QV4::Function *runtimeFunction = compilationUnit->runtimeFunctions[*functionIdx];
1133 const QString name = runtimeFunction->name()->toQString();
1134
1135 QQmlPropertyData *property = _propertyCache->property(name, _qobject, context);
1136 if (!property->isVMEFunction())
1137 continue;
1138
1139 if (runtimeFunction->isGenerator())
1140 function = QV4::GeneratorFunction::create(qmlContext, runtimeFunction);
1141 else
1142 function = QV4::FunctionObject::createScriptFunction(qmlContext, runtimeFunction);
1143 _vmeMetaObject->setVmeMethod(property->coreIndex(), function);
1144 }
1145}
1146
1147void QQmlObjectCreator::recordError(const QV4::CompiledData::Location &location, const QString &description)
1148{
1149 QQmlError error;
1150 error.setUrl(compilationUnit->url());
1151 error.setLine(location.line);
1152 error.setColumn(location.column);
1153 error.setDescription(description);
1154 errors << error;
1155}
1156
1157void QQmlObjectCreator::registerObjectWithContextById(const QV4::CompiledData::Object *object, QObject *instance) const
1158{
1159 if (object->id >= 0)
1160 context->setIdProperty(object->id, instance);
1161}
1162
1163void QQmlObjectCreator::createQmlContext()
1164{
1165 _qmlContext->setM(QV4::QmlContext::create(v4->rootContext(), context, _scopeObject));
1166}
1167
1168QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isContextObject)
1169{
1170 const QV4::CompiledData::Object *obj = compilationUnit->objectAt(index);
1171 QQmlObjectCreationProfiler profiler(sharedState->profiler.profiler, obj);
1172 Q_TRACE(QQmlObjectCreator_createInstance_entry, compilationUnit.data(), obj, context->url());
1173 QString typeName;
1174 Q_TRACE_EXIT(QQmlObjectCreator_createInstance_exit, typeName);
1175
1176 ActiveOCRestorer ocRestorer(this, QQmlEnginePrivate::get(engine));
1177
1178 bool isComponent = false;
1179 QObject *instance = nullptr;
1180 QQmlData *ddata = nullptr;
1181 QQmlCustomParser *customParser = nullptr;
1182 QQmlParserStatus *parserStatus = nullptr;
1183 bool installPropertyCache = true;
1184
1185 if (obj->flags & QV4::CompiledData::Object::IsComponent) {
1186 isComponent = true;
1187 QQmlComponent *component = new QQmlComponent(engine, compilationUnit.data(), index, parent);
1188 typeName = QStringLiteral("<component>");
1189 QQmlComponentPrivate::get(component)->creationContext = context;
1190 instance = component;
1191 ddata = QQmlData::get(instance, /*create*/true);
1192 } else {
1193 QV4::ResolvedTypeReference *typeRef = resolvedType(obj->inheritedTypeNameIndex);
1194 Q_ASSERT(typeRef);
1195 installPropertyCache = !typeRef->isFullyDynamicType;
1196 QQmlType type = typeRef->type;
1197 if (type.isValid()) {
1198 typeName = type.qmlTypeName();
1199
1200 void *ddataMemory = nullptr;
1201 type.create(&instance, &ddataMemory, sizeof(QQmlData));
1202 if (!instance) {
1203 recordError(obj->location, tr("Unable to create object of type %1").arg(stringAt(obj->inheritedTypeNameIndex)));
1204 return nullptr;
1205 }
1206
1207 {
1208 QQmlData *ddata = new (ddataMemory) QQmlData;
1209 ddata->ownMemory = false;
1210 QObjectPrivate* p = QObjectPrivate::get(instance);
1211 Q_ASSERT(!p->isDeletingChildren);
1212 p->declarativeData = ddata;
1213 }
1214
1215 const int parserStatusCast = type.parserStatusCast();
1216 if (parserStatusCast != -1)
1217 parserStatus = reinterpret_cast<QQmlParserStatus*>(reinterpret_cast<char *>(instance) + parserStatusCast);
1218
1219 customParser = type.customParser();
1220
1221 if (sharedState->rootContext && sharedState->rootContext->isRootObjectInCreation) {
1222 QQmlData *ddata = QQmlData::get(instance, /*create*/true);
1223 ddata->rootObjectInCreation = true;
1224 sharedState->rootContext->isRootObjectInCreation = false;
1225 }
1226
1227 sharedState->allCreatedObjects.push(instance);
1228 } else {
1229 Q_ASSERT(typeRef->compilationUnit);
1230 typeName = typeRef->compilationUnit->fileName();
1231 if (typeRef->compilationUnit->unitData()->isSingleton())
1232 {
1233 recordError(obj->location, tr("Composite Singleton Type %1 is not creatable").arg(stringAt(obj->inheritedTypeNameIndex)));
1234 return nullptr;
1235 }
1236
1237 QQmlObjectCreator subCreator(context, typeRef->compilationUnit, sharedState.data());
1238 instance = subCreator.create();
1239 if (!instance) {
1240 errors += subCreator.errors;
1241 return nullptr;
1242 }
1243 }
1244 if (instance->isWidgetType()) {
1245 if (parent && parent->isWidgetType()) {
1246 QAbstractDeclarativeData::setWidgetParent(instance, parent);
1247 } else {
1248 // No parent! Layouts need to handle this through a default property that
1249 // reparents accordingly. Otherwise the garbage collector will collect.
1250 }
1251 } else if (parent) {
1252 QQml_setParent_noEvent(instance, parent);
1253 }
1254
1255 ddata = QQmlData::get(instance, /*create*/true);
1256 }
1257
1258 Q_QML_OC_PROFILE(sharedState->profiler, profiler.update(
1259 compilationUnit.data(), obj, typeName, context->url()));
1260 Q_UNUSED(typeName); // only relevant for tracing
1261
1262 ddata->lineNumber = obj->location.line;
1263 ddata->columnNumber = obj->location.column;
1264
1265 ddata->setImplicitDestructible();
1266 if (static_cast<quint32>(index) == /*root object*/0 || ddata->rootObjectInCreation) {
1267 if (ddata->context) {
1268 Q_ASSERT(ddata->context != context);
1269 Q_ASSERT(ddata->outerContext);
1270 Q_ASSERT(ddata->outerContext != context);
1271 QQmlContextData *c = ddata->context;
1272 while (c->linkedContext) c = c->linkedContext;
1273 c->linkedContext = context;
1274 } else {
1275 ddata->context = context;
1276 }
1277 ddata->ownContext = ddata->context;
1278 } else if (!ddata->context) {
1279 ddata->context = context;
1280 }
1281
1282 context->addObject(ddata);
1283
1284 if (parserStatus) {
1285 parserStatus->classBegin();
1286 // push() the profiler state here, together with the parserStatus, as we'll pop() them
1287 // together, too.
1288 Q_QML_OC_PROFILE(sharedState->profiler, sharedState->profiler.push(obj));
1289 sharedState->allParserStatusCallbacks.push(parserStatus);
1290 parserStatus->d = &sharedState->allParserStatusCallbacks.top();
1291 }
1292
1293 // Register the context object in the context early on in order for pending binding
1294 // initialization to find it available.
1295 if (isContextObject)
1296 context->contextObject = instance;
1297
1298 if (customParser && obj->flags & QV4::CompiledData::Object::HasCustomParserBindings) {
1299 customParser->engine = QQmlEnginePrivate::get(engine);
1300 customParser->imports = compilationUnit->typeNameCache.data();
1301
1302 QList<const QV4::CompiledData::Binding *> bindings;
1303 const QV4::CompiledData::Object *obj = compilationUnit->objectAt(index);
1304 const QV4::CompiledData::Binding *binding = obj->bindingTable();
1305 for (quint32 i = 0; i < obj->nBindings; ++i, ++binding) {
1306 if (binding->flags & QV4::CompiledData::Binding::IsCustomParserBinding) {
1307 bindings << binding;
1308 }
1309 }
1310 customParser->applyBindings(instance, compilationUnit.data(), bindings);
1311
1312 customParser->engine = nullptr;
1313 customParser->imports = (QQmlTypeNameCache*)nullptr;
1314 }
1315
1316 if (isComponent) {
1317 registerObjectWithContextById(obj, instance);
1318 return instance;
1319 }
1320
1321 QQmlRefPointer<QQmlPropertyCache> cache = propertyCaches->at(index);
1322 Q_ASSERT(!cache.isNull());
1323 if (installPropertyCache) {
1324 if (ddata->propertyCache)
1325 ddata->propertyCache->release();;
1326 ddata->propertyCache = cache.data();
1327 ddata->propertyCache->addref();
1328 }
1329
1330 QObject *scopeObject = instance;
1331 qSwap(_scopeObject, scopeObject);
1332
1333 Q_ASSERT(sharedState->allJavaScriptObjects);
1334 *sharedState->allJavaScriptObjects = QV4::QObjectWrapper::wrap(v4, instance);
1335 ++sharedState->allJavaScriptObjects;
1336
1337 QV4::Scope valueScope(v4);
1338 QV4::QmlContext *qmlContext = static_cast<QV4::QmlContext *>(valueScope.alloc());
1339
1340 qSwap(_qmlContext, qmlContext);
1341
1342 bool ok = populateInstance(index, instance, /*binding target*/instance, /*value type property*/nullptr);
1343 if (ok) {
1344 if (isContextObject && !pendingAliasBindings.empty()) {
1345 bool processedAtLeastOneBinding = false;
1346 do {
1347 processedAtLeastOneBinding = false;
1348 for (std::vector<PendingAliasBinding>::iterator it = pendingAliasBindings.begin();
1349 it != pendingAliasBindings.end(); ) {
1350 if ((*it)(sharedState.data())) {
1351 it = pendingAliasBindings.erase(it);
1352 processedAtLeastOneBinding = true;
1353 } else {
1354 ++it;
1355 }
1356 }
1357 } while (processedAtLeastOneBinding && pendingAliasBindings.empty());
1358 Q_ASSERT(pendingAliasBindings.empty());
1359 }
1360 } else {
1361 // an error occurred, so we can't setup the pending alias bindings
1362 pendingAliasBindings.clear();
1363 }
1364
1365 qSwap(_qmlContext, qmlContext);
1366 qSwap(_scopeObject, scopeObject);
1367
1368 return ok ? instance : nullptr;
1369}
1370
1371QQmlContextData *QQmlObjectCreator::finalize(QQmlInstantiationInterrupt &interrupt)
1372{
1373 Q_ASSERT(phase == ObjectsCreated || phase == Finalizing);
1374 phase = Finalizing;
1375
1376 QQmlObjectCreatorRecursionWatcher watcher(this);
1377 ActiveOCRestorer ocRestorer(this, QQmlEnginePrivate::get(engine));
1378
1379 while (!sharedState->allCreatedBindings.isEmpty()) {
1380 QQmlAbstractBinding::Ptr b = sharedState->allCreatedBindings.pop();
1381 Q_ASSERT(b);
1382 // skip, if b is not added to an object
1383 if (!b->isAddedToObject())
1384 continue;
1385 QQmlData *data = QQmlData::get(b->targetObject());
1386 Q_ASSERT(data);
1387 data->clearPendingBindingBit(b->targetPropertyIndex().coreIndex());
1388 b->setEnabled(true, QQmlPropertyData::BypassInterceptor |
1389 QQmlPropertyData::DontRemoveBinding);
1390 if (!b->isValueTypeProxy()) {
1391 QQmlBinding *binding = static_cast<QQmlBinding*>(b.data());
1392 if (!binding->hasError() && !binding->hasDependencies()
1393 && binding->context() && !binding->context()->unresolvedNames)
1394 b->removeFromObject();
1395 }
1396
1397 if (watcher.hasRecursed() || interrupt.shouldInterrupt())
1398 return nullptr;
1399 }
1400
1401 if (QQmlVME::componentCompleteEnabled()) { // the qml designer does the component complete later
1402 while (!sharedState->allParserStatusCallbacks.isEmpty()) {
1403 QQmlObjectCompletionProfiler profiler(&sharedState->profiler);
1404 QQmlParserStatus *status = sharedState->allParserStatusCallbacks.pop();
1405
1406 if (status && status->d) {
1407 status->d = nullptr;
1408 status->componentComplete();
1409 }
1410
1411 if (watcher.hasRecursed() || interrupt.shouldInterrupt())
1412 return nullptr;
1413 }
1414 }
1415
1416 for (int ii = 0; ii < sharedState->finalizeCallbacks.count(); ++ii) {
1417 QQmlEnginePrivate::FinalizeCallback callback = sharedState->finalizeCallbacks.at(ii);
1418 QObject *obj = callback.first;
1419 if (obj) {
1420 void *args[] = { nullptr };
1421 QMetaObject::metacall(obj, QMetaObject::InvokeMetaMethod, callback.second, args);
1422 }
1423 if (watcher.hasRecursed())
1424 return nullptr;
1425 }
1426 sharedState->finalizeCallbacks.clear();
1427
1428 while (sharedState->componentAttached) {
1429 QQmlComponentAttached *a = sharedState->componentAttached;
1430 a->rem();
1431 QQmlData *d = QQmlData::get(a->parent());
1432 Q_ASSERT(d);
1433 Q_ASSERT(d->context);
1434 a->add(&d->context->componentAttached);
1435 if (QQmlVME::componentCompleteEnabled())
1436 emit a->completed();
1437
1438 if (watcher.hasRecursed() || interrupt.shouldInterrupt())
1439 return nullptr;
1440 }
1441
1442 phase = Done;
1443
1444 return sharedState->rootContext;
1445}
1446
1447void QQmlObjectCreator::clear()
1448{
1449 if (phase == Done || phase == Finalizing || phase == Startup)
1450 return;
1451 Q_ASSERT(phase != Startup);
1452
1453 while (!sharedState->allCreatedObjects.isEmpty()) {
1454 auto object = sharedState->allCreatedObjects.pop();
1455 if (engine->objectOwnership(object) != QQmlEngine::CppOwnership) {
1456 delete object;
1457 }
1458 }
1459
1460 while (sharedState->componentAttached) {
1461 QQmlComponentAttached *a = sharedState->componentAttached;
1462 a->rem();
1463 }
1464
1465 phase = Done;
1466}
1467
1468bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject *bindingTarget, const QQmlPropertyData *valueTypeProperty)
1469{
1470 QQmlData *declarativeData = QQmlData::get(instance, /*create*/true);
1471
1472 qSwap(_qobject, instance);
1473 qSwap(_valueTypeProperty, valueTypeProperty);
1474 qSwap(_compiledObjectIndex, index);
1475 const QV4::CompiledData::Object *obj = compilationUnit->objectAt(_compiledObjectIndex);
1476 qSwap(_compiledObject, obj);
1477 qSwap(_ddata, declarativeData);
1478 qSwap(_bindingTarget, bindingTarget);
1479
1480 QV4::Scope valueScope(v4);
1481 QV4::ScopedValue scopeObjectProtector(valueScope);
1482
1483 QQmlRefPointer<QQmlPropertyCache> cache = propertyCaches->at(_compiledObjectIndex);
1484
1485 QQmlVMEMetaObject *vmeMetaObject = nullptr;
1486 if (propertyCaches->needsVMEMetaObject(_compiledObjectIndex)) {
1487 Q_ASSERT(!cache.isNull());
1488 // install on _object
1489 vmeMetaObject = new QQmlVMEMetaObject(v4, _qobject, cache, compilationUnit, _compiledObjectIndex);
1490 if (_ddata->propertyCache)
1491 _ddata->propertyCache->release();
1492 _ddata->propertyCache = cache.data();
1493 _ddata->propertyCache->addref();
1494 scopeObjectProtector = _ddata->jsWrapper.value();
1495 } else {
1496 vmeMetaObject = QQmlVMEMetaObject::get(_qobject);
1497 }
1498
1499 registerObjectWithContextById(_compiledObject, _qobject);
1500
1501 qSwap(_propertyCache, cache);
1502 qSwap(_vmeMetaObject, vmeMetaObject);
1503
1504 if (_compiledObject->flags & QV4::CompiledData::Object::HasDeferredBindings)
1505 _ddata->deferData(_compiledObjectIndex, compilationUnit, context);
1506
1507 if (_compiledObject->nFunctions > 0)
1508 setupFunctions();
1509 setupBindings();
1510
1511 qSwap(_vmeMetaObject, vmeMetaObject);
1512 qSwap(_bindingTarget, bindingTarget);
1513 qSwap(_ddata, declarativeData);
1514 qSwap(_compiledObject, obj);
1515 qSwap(_compiledObjectIndex, index);
1516 qSwap(_valueTypeProperty, valueTypeProperty);
1517 qSwap(_qobject, instance);
1518 qSwap(_propertyCache, cache);
1519
1520 return errors.isEmpty();
1521}
1522
1523
1524
1525
1526QQmlObjectCreatorRecursionWatcher::QQmlObjectCreatorRecursionWatcher(QQmlObjectCreator *creator)
1527 : sharedState(creator->sharedState)
1528 , watcher(creator->sharedState.data())
1529{
1530}
1531