Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qv4qobjectwrapper.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/qqmlobjectorgadget_p.h>
7#include <private/qqmlengine_p.h>
8#include <private/qqmlvmemetaobject_p.h>
9#include <private/qqmlbinding_p.h>
10#include <private/qjsvalue_p.h>
11#include <private/qqmlexpression_p.h>
12#include <private/qqmlglobal_p.h>
13#include <private/qqmltypewrapper_p.h>
14#include <private/qqmlvaluetypewrapper_p.h>
15#include <private/qqmllistwrapper_p.h>
16#include <private/qqmlbuiltinfunctions_p.h>
17
18#include <private/qv4arraybuffer_p.h>
19#include <private/qv4functionobject_p.h>
20#include <private/qv4runtime_p.h>
21#include <private/qv4variantobject_p.h>
22#include <private/qv4identifiertable_p.h>
23#include <private/qv4lookup_p.h>
24#include <private/qv4qmlcontext_p.h>
25#include <private/qv4sequenceobject_p.h>
26#include <private/qv4objectproto_p.h>
27#include <private/qv4jsonobject_p.h>
28#include <private/qv4regexpobject_p.h>
29#include <private/qv4dateobject_p.h>
30#include <private/qv4scopedvalue_p.h>
31#include <private/qv4jscall_p.h>
32#include <private/qv4mm_p.h>
33#include <private/qqmlscriptstring_p.h>
34#include <private/qv4compileddata_p.h>
35#include <private/qqmlpropertybinding_p.h>
36
37#include <QtQml/qjsvalue.h>
38#include <QtCore/qjsonarray.h>
39#include <QtCore/qjsonobject.h>
40#include <QtCore/qjsonvalue.h>
41#include <QtCore/qvarlengtharray.h>
42#include <QtCore/qtimer.h>
43#include <QtCore/qatomic.h>
44#include <QtCore/qmetaobject.h>
45#if QT_CONFIG(qml_itemmodel)
46#include <QtCore/qabstractitemmodel.h>
47#endif
48#include <QtCore/qloggingcategory.h>
49#include <QtCore/qqueue.h>
50
51#include <vector>
53
54Q_LOGGING_CATEGORY(lcBindingRemoval, "qt.qml.binding.removal", QtWarningMsg)
55Q_LOGGING_CATEGORY(lcObjectConnect, "qt.qml.object.connect", QtWarningMsg)
56Q_LOGGING_CATEGORY(lcOverloadResolution, "qt.qml.overloadresolution", QtWarningMsg)
57Q_LOGGING_CATEGORY(lcMethodBehavior, "qt.qml.method.behavior")
58
59// The code in this file does not violate strict aliasing, but GCC thinks it does
60// so turn off the warnings for us to have a clean build
61QT_WARNING_DISABLE_GCC("-Wstrict-aliasing")
62
63using namespace Qt::StringLiterals;
64
65namespace QV4 {
66
67QPair<QObject *, int> QObjectMethod::extractQtMethod(const FunctionObject *function)
68{
69 ExecutionEngine *v4 = function->engine();
70 if (v4) {
71 Scope scope(v4);
73 if (method)
74 return qMakePair(method->object(), method->methodIndex());
75 }
76
77 return qMakePair((QObject *)nullptr, -1);
78}
79
81{
82 if (value.isObject()) {
83 ExecutionEngine *v4 = value.as<Object>()->engine();
84 Scope scope(v4);
86 if (function)
87 return QObjectMethod::extractQtMethod(function);
88
89 Scoped<QmlSignalHandler> handler(scope, value);
90 if (handler)
91 return qMakePair(handler->object(), handler->signalIndex());
92 }
93
94 return qMakePair((QObject *)nullptr, -1);
95}
96
97static Heap::ReferenceObject::Flags referenceFlags(
100{
101 Heap::ReferenceObject::Flags flags = Heap::ReferenceObject::NoFlag;
102 if (CppStackFrame *stackFrame = v4->currentStackFrame) {
103 if (stackFrame->v4Function->executableCompilationUnit()->valueTypesAreCopied())
104 flags |= Heap::ReferenceObject::EnforcesLocation;
105 }
106
107 if (property.isWritable())
108 flags |= Heap::ReferenceObject::CanWriteBack;
109
110 return flags;
111}
112
114 ExecutionEngine *v4, Heap::Object *wrapper,
115 QObject *object, const QQmlPropertyData &property)
116{
117 Q_ASSERT(!property.isFunction());
118 Scope scope(v4);
119
120 const QMetaType propMetaType = property.propType();
121 if (property.isQObject()) {
122 QObject *rv = nullptr;
123 property.readProperty(object, &rv);
124 if (propMetaType.flags().testFlag(QMetaType::IsConst))
125 return QObjectWrapper::wrapConst(v4, rv);
126 else
127 return QObjectWrapper::wrap(v4, rv);
128 }
129
130 if (property.isQList() && propMetaType.flags().testFlag(QMetaType::IsQmlList))
131 return QmlListWrapper::create(v4, object, property.coreIndex(), propMetaType);
132
133 // TODO: Check all the builtin types here. See getGadgetProperty() in qqmlvaluetypewrapper.cpp
134 switch (property.isEnum() ? propMetaType.underlyingType().id() : propMetaType.id()) {
135 case QMetaType::Int: {
136 int v = 0;
137 property.readProperty(object, &v);
138 return Encode(v);
139 }
140 case QMetaType::Bool: {
141 bool v = false;
142 property.readProperty(object, &v);
143 return Encode(v);
144 }
145 case QMetaType::QString: {
146 QString v;
147 property.readProperty(object, &v);
148 return v4->newString(v)->asReturnedValue();
149 }
150 case QMetaType::UInt: {
151 uint v = 0;
152 property.readProperty(object, &v);
153 return Encode(v);
154 }
155 case QMetaType::Float: {
156 float v = 0;
157 property.readProperty(object, &v);
158 return Encode(v);
159 }
160 case QMetaType::Double: {
161 double v = 0;
162 property.readProperty(object, &v);
163 return Encode(v);
164 }
165 default:
166 break;
167 }
168
169 if (propMetaType == QMetaType::fromType<QJSValue>()) {
170 QJSValue v;
171 property.readProperty(object, &v);
173 }
174
175 if (property.isQVariant()) {
176 // We have to read the property even if it's a lazy-loaded reference object.
177 // Without reading it, we wouldn't know its inner type.
178 QVariant v;
179 property.readProperty(object, &v);
180 return scope.engine->fromVariant(
181 v, wrapper, property.coreIndex(),
182 referenceFlags(scope.engine, property) | Heap::ReferenceObject::IsVariant);
183 }
184
185 if (!propMetaType.isValid()) {
186 QMetaProperty p = object->metaObject()->property(property.coreIndex());
187 qWarning("QMetaProperty::read: Unable to handle unregistered datatype '%s' for property "
188 "'%s::%s'", p.typeName(), object->metaObject()->className(), p.name());
189 return Encode::undefined();
190 }
191
192 // TODO: For historical reasons we don't enforce locations for reference objects here.
193 // Once we do, we can eager load and use the fromVariant() below.
194 // Then the extra checks for value types and sequences can be dropped.
195
196 if (QQmlMetaType::isValueType(propMetaType)) {
197 if (const QMetaObject *valueTypeMetaObject
198 = QQmlMetaType::metaObjectForValueType(propMetaType)) {
199 // Lazy loaded value type reference. Pass nullptr as data.
200 return QQmlValueTypeWrapper::create(
201 v4, nullptr, valueTypeMetaObject, propMetaType, wrapper,
202 property.coreIndex(), referenceFlags(scope.engine, property));
203 }
204 }
205
206 // See if it's a sequence type.
207 // Pass nullptr as data. It's lazy-loaded.
208 const QQmlType qmlType = QQmlMetaType::qmlListType(propMetaType);
209 if (qmlType.isSequentialContainer()) {
211 v4, propMetaType, qmlType.listMetaSequence(), nullptr,
212 wrapper, property.coreIndex(), referenceFlags(scope.engine, property));
213 }
214
215 QVariant v(propMetaType);
216 property.readProperty(object, v.data());
217 return scope.engine->fromVariant(
218 v, wrapper, property.coreIndex(), referenceFlags(scope.engine, property));
219}
220
221void QObjectWrapper::initializeBindings(ExecutionEngine *engine)
222{
223 engine->functionPrototype()->defineDefaultProperty(QStringLiteral("connect"), method_connect);
224 engine->functionPrototype()->defineDefaultProperty(QStringLiteral("disconnect"), method_disconnect);
225}
226
227const QQmlPropertyData *QObjectWrapper::findProperty(
229 Flags flags, QQmlPropertyData *local) const
230{
231 return findProperty(d()->object(), qmlContext, name, flags, local);
232}
233
234const QQmlPropertyData *QObjectWrapper::findProperty(
237{
239
240 QQmlData *ddata = QQmlData::get(o, false);
241 const QQmlPropertyData *result = nullptr;
242 if (ddata && ddata->propertyCache)
243 result = ddata->propertyCache->property(name, o, qmlContext);
244 else
246 return result;
247}
248
249ReturnedValue QObjectWrapper::getProperty(
250 ExecutionEngine *engine, Heap::Object *wrapper, QObject *object,
252{
253 QQmlData::flushPendingBinding(object, property->coreIndex());
254
255 if (property->isFunction() && !property->isVarProperty()) {
256 if (property->isVMEFunction()) {
258 Q_ASSERT(vmemo);
259 return vmemo->vmeMethod(property->coreIndex());
260 } else if (property->isV4Function()) {
261 Scope scope(engine);
262 ScopedContext global(scope, engine->qmlContext());
263 if (!global)
264 global = engine->rootContext();
265 return QObjectMethod::create(
266 global, (flags & AttachMethods) ? wrapper : nullptr, property->coreIndex());
267 } else if (property->isSignalHandler()) {
268 QmlSignalHandler::initProto(engine);
269 return engine->memoryManager->allocate<QmlSignalHandler>(
270 object, property->coreIndex())->asReturnedValue();
271 } else {
272 ExecutionContext *global = engine->rootContext();
273 return QObjectMethod::create(
274 global, (flags & AttachMethods) ? wrapper : nullptr, property->coreIndex());
275 }
276 }
277
278 QQmlEnginePrivate *ep = engine->qmlEngine() ? QQmlEnginePrivate::get(engine->qmlEngine()) : nullptr;
279
280 if (ep && ep->propertyCapture && !property->isConstant())
282 ep->propertyCapture->captureProperty(object, property->coreIndex(), property->notifyIndex());
283
284 if (property->isVarProperty()) {
286 Q_ASSERT(vmemo);
287 return vmemo->vmeProperty(property->coreIndex());
288 } else {
289 return loadProperty(engine, wrapper, object, *property);
290 }
291}
292
294 ExecutionEngine *v4, String *name, Heap::Object *qobj, bool *hasProperty = nullptr)
295{
296 int index = 0;
297 if (name->equals(v4->id_destroy()))
298 index = QObjectMethod::DestroyMethod;
299 else if (name->equals(v4->id_toString()))
300 index = QObjectMethod::ToStringMethod;
301 else
302 return OptionalReturnedValue();
303
304 if (hasProperty)
305 *hasProperty = true;
307 return OptionalReturnedValue(QObjectMethod::create(global, qobj, index));
308}
309
312 QObject *qobj, bool *hasProperty = nullptr)
313{
314 if (!qmlContext || !qmlContext->imports())
315 return OptionalReturnedValue();
316
317 QQmlTypeNameCache::Result r = qmlContext->imports()->query(name);
318
319 if (hasProperty)
320 *hasProperty = true;
321
322 if (!r.isValid())
323 return OptionalReturnedValue();
324
325 if (r.scriptIndex != -1) {
326 return OptionalReturnedValue(Encode::undefined());
327 } else if (r.type.isValid()) {
328 return OptionalReturnedValue(QQmlTypeWrapper::create(v4, qobj,r.type, Heap::QQmlTypeWrapper::ExcludeEnums));
329 } else if (r.importNamespace) {
330 return OptionalReturnedValue(QQmlTypeWrapper::create(
331 v4, qobj, qmlContext->imports(), r.importNamespace,
332 Heap::QQmlTypeWrapper::ExcludeEnums));
333 }
334 Q_UNREACHABLE_RETURN(OptionalReturnedValue());
335}
336
337ReturnedValue QObjectWrapper::getQmlProperty(
339 QObjectWrapper::Flags flags, bool *hasProperty) const
340{
341 // Keep this code in sync with ::virtualResolveLookupGetter
342
343 if (QQmlData::wasDeleted(d()->object())) {
344 if (hasProperty)
345 *hasProperty = false;
346 return Encode::undefined();
347 }
348
349 ExecutionEngine *v4 = engine();
350
351 if (auto methodValue = getDestroyOrToStringMethod(v4, name, d(), hasProperty))
352 return *methodValue;
353
354 QQmlPropertyData local;
355 const QQmlPropertyData *result = findProperty(qmlContext, name, flags, &local);
356
357 if (!result) {
358 // Check for attached properties
359 if ((flags & IncludeImports) && name->startsWithUpper()) {
360 if (auto importProperty = getPropertyFromImports(
361 v4, name, qmlContext, d()->object(), hasProperty))
362 return *importProperty;
363 }
364 return Object::virtualGet(this, name->propertyKey(), this, hasProperty);
365 }
366
367 QQmlData *ddata = QQmlData::get(d()->object(), false);
368
369 if ((flags & CheckRevision) && result->hasRevision()) {
370 if (ddata && ddata->propertyCache && !ddata->propertyCache->isAllowedInRevision(result)) {
371 if (hasProperty)
372 *hasProperty = false;
373 return Encode::undefined();
374 }
375 }
376
377 if (hasProperty)
378 *hasProperty = true;
379
380 return getProperty(v4, d(), d()->object(), result, flags);
381}
382
383ReturnedValue QObjectWrapper::getQmlProperty(
384 ExecutionEngine *engine, const QQmlRefPointer<QQmlContextData> &qmlContext,
385 Heap::Object *wrapper, QObject *object, String *name, QObjectWrapper::Flags flags,
386 bool *hasProperty, const QQmlPropertyData **property)
387{
388 if (QQmlData::wasDeleted(object)) {
389 if (hasProperty)
390 *hasProperty = false;
391 return Encode::null();
392 }
393
394 if (auto methodValue = getDestroyOrToStringMethod(engine, name, wrapper, hasProperty))
395 return *methodValue;
396
397 QQmlData *ddata = QQmlData::get(object, false);
398 QQmlPropertyData local;
399 const QQmlPropertyData *result = findProperty(object, qmlContext, name, flags, &local);
400
401 if (result) {
402 if ((flags & QObjectWrapper::CheckRevision) && result->hasRevision()) {
403 if (ddata && ddata->propertyCache
404 && !ddata->propertyCache->isAllowedInRevision(result)) {
405 if (hasProperty)
406 *hasProperty = false;
407 return Encode::undefined();
408 }
409 }
410
411 if (hasProperty)
412 *hasProperty = true;
413
414 if (property && result != &local)
415 *property = result;
416
417 return getProperty(engine, wrapper, object, result, flags);
418 } else {
419 // Check if this object is already wrapped.
420 if (!ddata || (ddata->jsWrapper.isUndefined() &&
421 (ddata->jsEngineId == 0 || // Nobody owns the QObject
422 !ddata->hasTaintedV4Object))) { // Someone else has used the QObject, but it isn't tainted
423
424 // Not wrapped. Last chance: try query QObjectWrapper's prototype.
425 // If it can't handle this, then there is no point
426 // to wrap the QObject just to look at an empty set of JS props.
427 Object *proto = QObjectWrapper::defaultPrototype(engine);
428 return proto->get(name, hasProperty);
429 }
430 }
431
432 // If we get here, we must already be wrapped (which implies a ddata).
433 // There's no point wrapping again, as there wouldn't be any new props.
434 Q_ASSERT(ddata);
435
436 Scope scope(engine);
437 Scoped<QObjectWrapper> rewrapped(scope, wrap(engine, object));
438 if (!rewrapped) {
439 if (hasProperty)
440 *hasProperty = false;
441 return Encode::null();
442 }
443 return rewrapped->getQmlProperty(qmlContext, name, flags, hasProperty);
444}
445
446
447bool QObjectWrapper::setQmlProperty(
449 String *name, QObjectWrapper::Flags flags, const Value &value)
450{
451 if (QQmlData::wasDeleted(object))
452 return false;
453
454 QQmlPropertyData local;
456 if (!result)
457 return false;
458
459 if ((flags & QObjectWrapper::CheckRevision) && result->hasRevision()) {
460 QQmlData *ddata = QQmlData::get(object);
461 if (ddata && ddata->propertyCache && !ddata->propertyCache->isAllowedInRevision(result))
462 return false;
463 }
464
465 setProperty(engine, object, result, value);
466 return true;
467}
468
469void QObjectWrapper::setProperty(
471 const QQmlPropertyData *property, const Value &value)
472{
473 if (!property->isWritable() && !property->isQList()) {
474 QString error = QLatin1String("Cannot assign to read-only property \"") +
475 property->name(object) + QLatin1Char('\"');
476 engine->throwTypeError(error);
477 return;
478 }
479
480 Scope scope(engine);
481 if (ScopedFunctionObject f(scope, value); f) {
482 if (!f->isBinding()) {
483 const bool isAliasToAllowed = [&]() {
484 if (property->isAlias()) {
485 const QQmlPropertyIndex originalIndex(property->coreIndex(), -1);
486 auto [targetObject, targetIndex] = QQmlPropertyPrivate::findAliasTarget(object, originalIndex);
487 Q_ASSERT(targetObject);
488 const QQmlPropertyCache *targetCache
489 = QQmlData::get(targetObject)->propertyCache.data();
490 Q_ASSERT(targetCache);
491 const QQmlPropertyData *targetProperty
492 = targetCache->property(targetIndex.coreIndex());
493 object = targetObject;
494 property = targetProperty;
495 return targetProperty->isVarProperty() || targetProperty->propType() == QMetaType::fromType<QJSValue>();
496 } else {
497 return false;
498 }
499 }();
500 if (!isAliasToAllowed && !property->isVarProperty()
501 && property->propType() != QMetaType::fromType<QJSValue>()) {
502 // assigning a JS function to a non var or QJSValue property or is not allowed.
503 QString error = QLatin1String("Cannot assign JavaScript function to ");
504 if (!QMetaType(property->propType()).name())
505 error += QLatin1String("[unknown property type]");
506 else
507 error += QLatin1String(QMetaType(property->propType()).name());
508 scope.engine->throwError(error);
509 return;
510 }
511 } else {
512
513 QQmlRefPointer<QQmlContextData> callingQmlContext = scope.engine->callingQmlContext();
514 Scoped<QQmlBindingFunction> bindingFunction(scope, (const Value &)f);
515 ScopedFunctionObject f(scope, bindingFunction->bindingFunction());
516 ScopedContext ctx(scope, f->scope());
517
518 // binding assignment.
519 if (property->isBindable()) {
520 const QQmlPropertyIndex idx(property->coreIndex(), /*not a value type*/-1);
521 auto [targetObject, targetIndex] = QQmlPropertyPrivate::findAliasTarget(object, idx);
523 if (f->isBoundFunction()) {
524 auto boundFunction = static_cast<BoundFunction *>(f.getPointer());
525 binding = QQmlPropertyBinding::createFromBoundFunction(property, boundFunction, object, callingQmlContext,
526 ctx, targetObject, targetIndex);
527 } else {
528 binding = QQmlPropertyBinding::create(property, f->function(), object, callingQmlContext,
529 ctx, targetObject, targetIndex);
530 }
531 QUntypedBindable bindable;
532 void *argv = {&bindable};
533 // indirect metacall in case interceptors are installed
534 targetObject->metaObject()->metacall(targetObject, QMetaObject::BindableProperty, targetIndex.coreIndex(), &argv);
535 bool ok = bindable.setBinding(binding);
536 if (!ok) {
537 auto error = QStringLiteral("Failed to set binding on %1::%2.").
538 arg(QString::fromUtf8(object->metaObject()->className()), property->name(object));
539 scope.engine->throwError(error);
540 }
541 } else {
542 QQmlBinding *newBinding = QQmlBinding::create(property, f->function(), object, callingQmlContext, ctx);
543 newBinding->setSourceLocation(bindingFunction->currentLocation());
544 if (f->isBoundFunction())
545 newBinding->setBoundFunction(static_cast<BoundFunction *>(f.getPointer()));
546 newBinding->setTarget(object, *property, nullptr);
548 }
549 return;
550 }
551 }
552
553 if (Q_UNLIKELY(lcBindingRemoval().isInfoEnabled())) {
554 if (auto binding = QQmlPropertyPrivate::binding(object, QQmlPropertyIndex(property->coreIndex()))) {
555 const auto stackFrame = engine->currentStackFrame;
556 switch (binding->kind()) {
558 const auto qmlBinding = static_cast<const QQmlBinding*>(binding);
559 qCInfo(lcBindingRemoval,
560 "Overwriting binding on %s::%s at %s:%d that was initially bound at %s",
561 object->metaObject()->className(), qPrintable(property->name(object)),
562 qPrintable(stackFrame->source()), stackFrame->lineNumber(),
563 qPrintable(qmlBinding->expressionIdentifier()));
564 break;
565 }
568 qCInfo(lcBindingRemoval,
569 "Overwriting binding on %s::%s at %s:%d",
570 object->metaObject()->className(), qPrintable(property->name(object)),
571 qPrintable(stackFrame->source()), stackFrame->lineNumber());
572 break;
573 }
574 }
575 }
576 }
578
579 if (property->isVarProperty()) {
580 // allow assignment of "special" values (null, undefined, function) to var properties
582 Q_ASSERT(vmemo);
583 vmemo->setVMEProperty(property->coreIndex(), value);
584 return;
585 }
586
587#define PROPERTY_STORE(cpptype, value) \
588 cpptype o = value; \
589 int status = -1; \
590 int flags = 0; \
591 void *argv[] = { &o, 0, &status, &flags }; \
592 QMetaObject::metacall(object, QMetaObject::WriteProperty, property->coreIndex(), argv);
593
594 const QMetaType propType = property->propType();
595 // functions are already handled, except for the QJSValue case
596 Q_ASSERT(!value.as<FunctionObject>() || propType == QMetaType::fromType<QJSValue>());
597
598 if (value.isNull() && property->isQObject()) {
599 PROPERTY_STORE(QObject*, nullptr);
600 } else if (value.isUndefined() && property->isResettable()) {
601 void *a[] = { nullptr };
603 } else if (value.isUndefined() && propType == QMetaType::fromType<QVariant>()) {
605 } else if (value.isUndefined() && propType == QMetaType::fromType<QJsonValue>()) {
607 } else if (propType == QMetaType::fromType<QJSValue>()) {
609 } else if (value.isUndefined() && propType != QMetaType::fromType<QQmlScriptString>()) {
610 QString error = QLatin1String("Cannot assign [undefined] to ");
611 if (!propType.name())
612 error += QLatin1String("[unknown property type]");
613 else
614 error += QLatin1String(propType.name());
615 scope.engine->throwError(error);
616 return;
617 } else if (propType == QMetaType::fromType<int>() && value.isNumber()) {
618 PROPERTY_STORE(int, value.toInt32());
619 } else if (propType == QMetaType::fromType<qreal>() && value.isNumber()) {
620 PROPERTY_STORE(qreal, qreal(value.asDouble()));
621 } else if (propType == QMetaType::fromType<float>() && value.isNumber()) {
622 PROPERTY_STORE(float, float(value.asDouble()));
623 } else if (propType == QMetaType::fromType<double>() && value.isNumber()) {
624 PROPERTY_STORE(double, double(value.asDouble()));
625 } else if (propType == QMetaType::fromType<QString>() && value.isString()) {
626 PROPERTY_STORE(QString, value.toQStringNoThrow());
627 } else if (property->isVarProperty()) {
629 Q_ASSERT(vmemo);
630 vmemo->setVMEProperty(property->coreIndex(), value);
631 } else if (propType == QMetaType::fromType<QQmlScriptString>()
632 && (value.isUndefined() || value.isPrimitive())) {
633 QQmlScriptString ss(value.toQStringNoThrow(), nullptr /* context */, object);
634 if (value.isNumber()) {
635 ss.d->numberValue = value.toNumber();
636 ss.d->isNumberLiteral = true;
637 } else if (value.isString()) {
638 ss.d->script = CompiledData::Binding::escapedString(ss.d->script);
639 ss.d->isStringLiteral = true;
640 }
642 } else {
643 QVariant v;
644 if (property->isQList() && propType.flags().testFlag(QMetaType::IsQmlList))
645 v = ExecutionEngine::toVariant(value, QMetaType::fromType<QList<QObject *> >());
646 else
647 v = ExecutionEngine::toVariant(value, propType);
648
649 QQmlRefPointer<QQmlContextData> callingQmlContext = scope.engine->callingQmlContext();
650 if (!QQmlPropertyPrivate::write(object, *property, v, callingQmlContext)) {
651 const char *valueType = (v.userType() == QMetaType::UnknownType)
652 ? "an unknown type"
653 : QMetaType(v.userType()).name();
654
655 const char *targetTypeName = propType.name();
656 if (!targetTypeName)
657 targetTypeName = "an unregistered type";
658
659 QString error = QLatin1String("Cannot assign ") +
660 QLatin1String(valueType) +
661 QLatin1String(" to ") +
662 QLatin1String(targetTypeName);
663 scope.engine->throwError(error);
664 return;
665 }
666 }
667}
668
669ReturnedValue QObjectWrapper::wrap_slowPath(ExecutionEngine *engine, QObject *object)
670{
672
673 QQmlData *ddata = QQmlData::get(object, true);
674 if (!ddata)
675 return Encode::undefined();
676
677 Scope scope(engine);
678
679 if (ddata->jsWrapper.isUndefined() &&
680 (ddata->jsEngineId == engine->m_engineId || // We own the QObject
681 ddata->jsEngineId == 0 || // No one owns the QObject
682 !ddata->hasTaintedV4Object)) { // Someone else has used the QObject, but it isn't tainted
683
684 ScopedValue rv(scope, create(engine, object));
685 ddata->jsWrapper.set(scope.engine, rv);
686 ddata->jsEngineId = engine->m_engineId;
687 return rv->asReturnedValue();
688
689 } else {
690 // If this object is tainted, we have to check to see if it is in our
691 // tainted object list
692 ScopedObject alternateWrapper(scope, (Object *)nullptr);
693 if (engine->m_multiplyWrappedQObjects && ddata->hasTaintedV4Object)
694 alternateWrapper = engine->m_multiplyWrappedQObjects->value(object);
695
696 // If our tainted handle doesn't exist or has been collected, and there isn't
697 // a handle in the ddata, we can assume ownership of the ddata->jsWrapper
698 if (ddata->jsWrapper.isUndefined() && !alternateWrapper) {
699 ScopedValue result(scope, create(engine, object));
700 ddata->jsWrapper.set(scope.engine, result);
701 ddata->jsEngineId = engine->m_engineId;
702 return result->asReturnedValue();
703 }
704
705 if (!alternateWrapper) {
706 alternateWrapper = create(engine, object);
707 if (!engine->m_multiplyWrappedQObjects)
708 engine->m_multiplyWrappedQObjects = new MultiplyWrappedQObjectMap;
709 engine->m_multiplyWrappedQObjects->insert(object, alternateWrapper->d());
710 ddata->hasTaintedV4Object = true;
711 }
712
713 return alternateWrapper.asReturnedValue();
714 }
715}
716
717ReturnedValue QObjectWrapper::wrapConst_slowPath(ExecutionEngine *engine, QObject *object)
718{
719 const QObject *constObject = object;
720
721 QQmlData *ddata = QQmlData::get(object, true);
722
723 Scope scope(engine);
724 ScopedObject constWrapper(scope);
725 if (engine->m_multiplyWrappedQObjects && ddata->hasConstWrapper)
726 constWrapper = engine->m_multiplyWrappedQObjects->value(constObject);
727
728 if (!constWrapper) {
729 constWrapper = create(engine, object);
730 constWrapper->setInternalClass(constWrapper->internalClass()->cryopreserved());
731 if (!engine->m_multiplyWrappedQObjects)
732 engine->m_multiplyWrappedQObjects = new MultiplyWrappedQObjectMap;
733 engine->m_multiplyWrappedQObjects->insert(constObject, constWrapper->d());
734 ddata->hasConstWrapper = true;
735 }
736
737 return constWrapper.asReturnedValue();
738}
739
740void QObjectWrapper::markWrapper(QObject *object, MarkStack *markStack)
741{
742 if (QQmlData::wasDeleted(object))
743 return;
744
745 QQmlData *ddata = QQmlData::get(object);
746 if (!ddata)
747 return;
748
749 const ExecutionEngine *engine = markStack->engine();
750 if (ddata->jsEngineId == engine->m_engineId)
751 ddata->jsWrapper.markOnce(markStack);
752 else if (engine->m_multiplyWrappedQObjects && ddata->hasTaintedV4Object)
753 engine->m_multiplyWrappedQObjects->mark(object, markStack);
754 if (ddata->hasConstWrapper) {
755 Q_ASSERT(engine->m_multiplyWrappedQObjects);
756 engine->m_multiplyWrappedQObjects->mark(static_cast<const QObject *>(object), markStack);
757 }
758}
759
760void QObjectWrapper::setProperty(ExecutionEngine *engine, int propertyIndex, const Value &value)
761{
762 setProperty(engine, d()->object(), propertyIndex, value);
763}
764
765void QObjectWrapper::setProperty(ExecutionEngine *engine, QObject *object, int propertyIndex, const Value &value)
766{
767 Q_ASSERT(propertyIndex < 0xffff);
768 Q_ASSERT(propertyIndex >= 0);
769
770 if (QQmlData::wasDeleted(object))
771 return;
772 QQmlData *ddata = QQmlData::get(object, /*create*/false);
773 if (!ddata)
774 return;
775
776 Q_ASSERT(ddata->propertyCache);
777 const QQmlPropertyData *property = ddata->propertyCache->property(propertyIndex);
778 Q_ASSERT(property); // We resolved this property earlier, so it better exist!
779 return setProperty(engine, object, property, value);
780}
781
782bool QObjectWrapper::virtualIsEqualTo(Managed *a, Managed *b)
783{
784 Q_ASSERT(a->as<QObjectWrapper>());
785 const QObjectWrapper *aobjectWrapper = static_cast<QObjectWrapper *>(a);
786 if (const QQmlTypeWrapper *qmlTypeWrapper = b->as<QQmlTypeWrapper>())
787 return qmlTypeWrapper->object() == aobjectWrapper->object();
788
789 // We can have a const and a non-const wrapper for the same object.
790 const QObjectWrapper *bobjectWrapper = b->as<QObjectWrapper>();
791 return bobjectWrapper && aobjectWrapper->object() == bobjectWrapper->object();
792}
793
794ReturnedValue QObjectWrapper::create(ExecutionEngine *engine, QObject *object)
795{
797 ReturnedValue result = Encode::null();
798 void *args[] = { &result, &engine };
799 if (cache->callJSFactoryMethod(object, args))
800 return result;
801 }
802 return (engine->memoryManager->allocate<QObjectWrapper>(object))->asReturnedValue();
803}
804
805ReturnedValue QObjectWrapper::virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty)
806{
807 if (!id.isString())
808 return Object::virtualGet(m, id, receiver, hasProperty);
809
810 const QObjectWrapper *that = static_cast<const QObjectWrapper*>(m);
811 Scope scope(that);
812 ScopedString n(scope, id.asStringOrSymbol());
814 return that->getQmlProperty(qmlContext, n, IncludeImports | AttachMethods, hasProperty);
815}
816
817bool QObjectWrapper::virtualPut(Managed *m, PropertyKey id, const Value &value, Value *receiver)
818{
819 if (!id.isString())
820 return Object::virtualPut(m, id, value, receiver);
821
822 Scope scope(m);
823 QObjectWrapper *that = static_cast<QObjectWrapper*>(m);
824 ScopedString name(scope, id.asStringOrSymbol());
825
826 if (that->internalClass()->isFrozen()) {
827 QString error = QLatin1String("Cannot assign to property \"") +
828 name->toQString() + QLatin1String("\" of read-only object");
829 scope.engine->throwError(error);
830 return false;
831 }
832
833 if (scope.hasException() || QQmlData::wasDeleted(that->d()->object()))
834 return false;
835
837 if (!setQmlProperty(scope.engine, qmlContext, that->d()->object(), name, NoFlag, value)) {
838 QQmlData *ddata = QQmlData::get(that->d()->object());
839 // Types created by QML are not extensible at run-time, but for other QObjects we can store them
840 // as regular JavaScript properties, like on JavaScript objects.
841 if (ddata && ddata->context) {
842 QString error = QLatin1String("Cannot assign to non-existent property \"") +
843 name->toQString() + QLatin1Char('\"');
844 scope.engine->throwError(error);
845 return false;
846 } else {
847 return Object::virtualPut(m, id, value, receiver);
848 }
849 }
850
851 return true;
852}
853
854PropertyAttributes QObjectWrapper::virtualGetOwnProperty(const Managed *m, PropertyKey id, Property *p)
855{
856 if (id.isString()) {
857 const QObjectWrapper *that = static_cast<const QObjectWrapper*>(m);
858 const QObject *thatObject = that->d()->object();
859 if (!QQmlData::wasDeleted(thatObject)) {
860 Scope scope(m);
861 ScopedString n(scope, id.asStringOrSymbol());
863 QQmlPropertyData local;
864 if (that->findProperty(qmlContext, n, NoFlag, &local)
865 || n->equals(scope.engine->id_destroy()) || n->equals(scope.engine->id_toString())) {
866 if (p) {
867 // ### probably not the fastest implementation
868 bool hasProperty;
869 p->value = that->getQmlProperty(
870 qmlContext, n, IncludeImports | AttachMethods, &hasProperty);
871 }
872 return Attr_Data;
873 }
874 }
875 }
876
877 return Object::virtualGetOwnProperty(m, id, p);
878}
879
881{
882 int propertyIndex = 0;
884 PropertyKey next(const Object *o, Property *pd = nullptr, PropertyAttributes *attrs = nullptr) override;
885
886private:
887 QSet<QByteArray> m_alreadySeen;
888};
889
890PropertyKey QObjectWrapperOwnPropertyKeyIterator::next(const Object *o, Property *pd, PropertyAttributes *attrs)
891{
892 // Used to block access to QObject::destroyed() and QObject::deleteLater() from QML
893 static const int destroyedIdx1 = QObject::staticMetaObject.indexOfSignal("destroyed(QObject*)");
894 static const int destroyedIdx2 = QObject::staticMetaObject.indexOfSignal("destroyed()");
895 static const int deleteLaterIdx = QObject::staticMetaObject.indexOfSlot("deleteLater()");
896
897 const QObjectWrapper *that = static_cast<const QObjectWrapper*>(o);
898
899 QObject *thatObject = that->d()->object();
900 if (thatObject && !QQmlData::wasDeleted(thatObject)) {
901 const QMetaObject *mo = thatObject->metaObject();
902 // These indices don't apply to gadgets, so don't block them.
903 const bool preventDestruction = mo->superClass() || mo == &QObject::staticMetaObject;
904 const int propertyCount = mo->propertyCount();
905 if (propertyIndex < propertyCount) {
906 ExecutionEngine *thatEngine = that->engine();
907 Scope scope(thatEngine);
908 const QMetaProperty property = mo->property(propertyIndex);
909 ScopedString propName(scope, thatEngine->newString(QString::fromUtf8(property.name())));
910 ++propertyIndex;
911 if (attrs)
913 if (pd) {
914 QQmlPropertyData local;
915 local.load(property);
916 pd->value = that->getProperty(
917 thatEngine, that->d(), thatObject, &local,
918 QObjectWrapper::AttachMethods);
919 }
920 return propName->toPropertyKey();
921 }
922 const int methodCount = mo->methodCount();
923 while (propertyIndex < propertyCount + methodCount) {
924 Q_ASSERT(propertyIndex >= propertyCount);
925 int index = propertyIndex - propertyCount;
926 const QMetaMethod method = mo->method(index);
927 ++propertyIndex;
928 if (method.access() == QMetaMethod::Private || (preventDestruction && (index == deleteLaterIdx || index == destroyedIdx1 || index == destroyedIdx2)))
929 continue;
930 // filter out duplicates due to overloads:
931 if (m_alreadySeen.contains(method.name()))
932 continue;
933 else
934 m_alreadySeen.insert(method.name());
935 ExecutionEngine *thatEngine = that->engine();
936 Scope scope(thatEngine);
937 ScopedString methodName(scope, thatEngine->newString(QString::fromUtf8(method.name())));
938 if (attrs)
939 *attrs = Attr_Data;
940 if (pd) {
941 QQmlPropertyData local;
942 local.load(method);
943 pd->value = that->getProperty(
944 thatEngine, that->d(), thatObject, &local,
945 QObjectWrapper::AttachMethods);
946 }
947 return methodName->toPropertyKey();
948 }
949 }
950
951 return ObjectOwnPropertyKeyIterator::next(o, pd, attrs);
952}
953
954OwnPropertyKeyIterator *QObjectWrapper::virtualOwnPropertyKeys(const Object *m, Value *target)
955{
956 *target = *m;
958}
959
960ReturnedValue QObjectWrapper::virtualResolveLookupGetter(const Object *object, ExecutionEngine *engine, Lookup *lookup)
961{
962 // Keep this code in sync with ::getQmlProperty
963 PropertyKey id = engine->identifierTable->asPropertyKey(engine->currentStackFrame->v4Function->compilationUnit->
964 runtimeStrings[lookup->nameIndex]);
965 if (!id.isString())
966 return Object::virtualResolveLookupGetter(object, engine, lookup);
967 Scope scope(engine);
968
969 const QObjectWrapper *This = static_cast<const QObjectWrapper *>(object);
970 ScopedString name(scope, id.asStringOrSymbol());
972
973 QObject * const qobj = This->d()->object();
974
975 if (QQmlData::wasDeleted(qobj))
976 return Encode::undefined();
977
978 QQmlData *ddata = QQmlData::get(qobj, false);
979 if (auto methodValue = getDestroyOrToStringMethod(engine, name, This->d())) {
980 Scoped<QObjectMethod> method(scope, *methodValue);
982 lookup, ddata ? ddata : QQmlData::get(qobj, true), nullptr, This, method->d());
983 lookup->getter = Lookup::getterQObjectMethod;
984 return method.asReturnedValue();
985 }
986
987 if (!ddata || !ddata->propertyCache) {
988 QQmlPropertyData local;
990 qobj, name, qmlContext, &local);
991 return property
992 ? getProperty(engine, This->d(), qobj, property,
993 lookup->forCall ? NoFlag : AttachMethods)
994 : Encode::undefined();
995 }
996 const QQmlPropertyData *property = ddata->propertyCache->property(name.getPointer(), qobj, qmlContext);
997
998 if (!property) {
999 // Check for attached properties
1000 if (name->startsWithUpper()) {
1001 if (auto importProperty = getPropertyFromImports(engine, name, qmlContext, qobj))
1002 return *importProperty;
1003 }
1004 return Object::virtualResolveLookupGetter(object, engine, lookup);
1005 }
1006
1007 if (property->isFunction()
1008 && !property->isVarProperty()
1009 && !property->isVMEFunction() // Handled by QObjectLookup
1010 && !property->isSignalHandler()) { // TODO: Optimize SignalHandler, too
1011 setupQObjectMethodLookup(lookup, ddata, property, This, nullptr);
1012 lookup->getter = Lookup::getterQObjectMethod;
1013 return lookup->getter(lookup, engine, *object);
1014 }
1015
1016 setupQObjectLookup(lookup, ddata, property, This);
1017 lookup->getter = Lookup::getterQObject;
1018 return lookup->getter(lookup, engine, *object);
1019}
1020
1021ReturnedValue QObjectWrapper::lookupAttached(
1022 Lookup *l, ExecutionEngine *engine, const Value &object)
1023{
1024 return Lookup::getterGeneric(l, engine, object);
1025}
1026
1027bool QObjectWrapper::virtualResolveLookupSetter(Object *object, ExecutionEngine *engine, Lookup *lookup,
1028 const Value &value)
1029{
1030 return Object::virtualResolveLookupSetter(object, engine, lookup, value);
1031}
1032
1033int QObjectWrapper::virtualMetacall(Object *object, QMetaObject::Call call, int index, void **a)
1034{
1035 QObjectWrapper *wrapper = object->as<QObjectWrapper>();
1037
1038 if (QObject *qObject = wrapper->object())
1039 return QMetaObject::metacall(qObject, call, index, a);
1040
1041 return 0;
1042}
1043
1044QString QObjectWrapper::objectToString(
1046{
1047 if (!metaObject)
1048 return QLatin1String("null");
1049
1050 if (!object)
1051 return QString::fromUtf8(metaObject->className()) + QLatin1String("(0x0)");
1052
1053 const int id = metaObject->indexOfMethod("toString()");
1054 if (id >= 0) {
1055 const QMetaMethod method = metaObject->method(id);
1056 const QMetaType returnType = method.returnMetaType();
1057 QVariant result(returnType);
1058 method.invoke(object, QGenericReturnArgument(returnType.name(), result.data()));
1059 if (result.metaType() == QMetaType::fromType<QString>())
1060 return result.toString();
1061 QV4::Scope scope(engine);
1063 return value->toQString();
1064 }
1065
1067 result += QString::fromUtf8(metaObject->className()) +
1068 QLatin1String("(0x") + QString::number(quintptr(object), 16);
1069 QString objectName = object->objectName();
1070 if (!objectName.isEmpty())
1071 result += QLatin1String(", \"") + objectName + QLatin1Char('\"');
1072 result += QLatin1Char(')');
1073 return result;
1074}
1075
1077{
1081
1083 : QtPrivate::QSlotObjectBase(&impl)
1084 {}
1085
1086 static void impl(int which, QSlotObjectBase *this_, QObject *receiver, void **metaArgs, bool *ret)
1087 {
1088 Q_UNUSED(receiver);
1089 switch (which) {
1090 case Destroy: {
1091 delete static_cast<QObjectSlotDispatcher*>(this_);
1092 }
1093 break;
1094 case Call: {
1095 QObjectSlotDispatcher *This = static_cast<QObjectSlotDispatcher*>(this_);
1096 ExecutionEngine *v4 = This->function.engine();
1097 // Might be that we're still connected to a signal that's emitted long
1098 // after the engine died. We don't track connections in a global list, so
1099 // we need this safeguard.
1100 if (!v4)
1101 break;
1102
1105
1106 int argCount = storage.size();
1107
1108 Scope scope(v4);
1109 ScopedFunctionObject f(scope, This->function.value());
1110
1111 JSCallArguments jsCallData(scope, argCount);
1112 *jsCallData.thisObject = This->thisObject.isUndefined() ? v4->globalObject->asReturnedValue() : This->thisObject.value();
1113 for (int ii = 0; ii < argCount; ++ii) {
1114 QMetaType type = storage[ii];
1115 if (type == QMetaType::fromType<QVariant>()) {
1116 jsCallData.args[ii] = v4->fromVariant(*((QVariant *)metaArgs[ii + 1]));
1117 } else {
1118 jsCallData.args[ii] = v4->fromVariant(QVariant(type, metaArgs[ii + 1]));
1119 }
1120 }
1121
1122 f->call(jsCallData);
1123 if (scope.hasException()) {
1125 if (error.description().isEmpty()) {
1126 ScopedString name(scope, f->name());
1127 error.setDescription(QStringLiteral("Unknown exception occurred during evaluation of connected function: %1").arg(name->toQString()));
1128 }
1129 if (QQmlEngine *qmlEngine = v4->qmlEngine()) {
1131 } else {
1132 QMessageLogger(error.url().toString().toLatin1().constData(),
1133 error.line(), nullptr).warning().noquote()
1134 << error.toString();
1135 }
1136 }
1137 }
1138 break;
1139 case Compare: {
1141 if (connection->function.isUndefined()) {
1142 *ret = false;
1143 return;
1144 }
1145
1146 // This is tricky. Normally the metaArgs[0] pointer is a pointer to the _function_
1147 // for the new-style QObject::connect. Here we use the engine pointer as sentinel
1148 // to distinguish those type of QSlotObjectBase connections from our QML connections.
1149 ExecutionEngine *v4 = reinterpret_cast<ExecutionEngine*>(metaArgs[0]);
1150 if (v4 != connection->function.engine()) {
1151 *ret = false;
1152 return;
1153 }
1154
1155 Scope scope(v4);
1156 ScopedValue function(scope, *reinterpret_cast<Value*>(metaArgs[1]));
1157 ScopedValue thisObject(scope, *reinterpret_cast<Value*>(metaArgs[2]));
1158 QObject *receiverToDisconnect = reinterpret_cast<QObject*>(metaArgs[3]);
1159 int slotIndexToDisconnect = *reinterpret_cast<int*>(metaArgs[4]);
1160
1161 if (slotIndexToDisconnect != -1) {
1162 // This is a QObject function wrapper
1163 if (connection->thisObject.isUndefined() == thisObject->isUndefined() &&
1164 (connection->thisObject.isUndefined() || RuntimeHelpers::strictEqual(*connection->thisObject.valueRef(), thisObject))) {
1165
1166 ScopedFunctionObject f(scope, connection->function.value());
1167 QPair<QObject *, int> connectedFunctionData = QObjectMethod::extractQtMethod(f);
1168 if (connectedFunctionData.first == receiverToDisconnect &&
1169 connectedFunctionData.second == slotIndexToDisconnect) {
1170 *ret = true;
1171 return;
1172 }
1173 }
1174 } else {
1175 // This is a normal JS function
1176 if (RuntimeHelpers::strictEqual(*connection->function.valueRef(), function) &&
1177 connection->thisObject.isUndefined() == thisObject->isUndefined() &&
1178 (connection->thisObject.isUndefined() || RuntimeHelpers::strictEqual(*connection->thisObject.valueRef(), thisObject))) {
1179 *ret = true;
1180 return;
1181 }
1182 }
1183
1184 *ret = false;
1185 }
1186 break;
1187 case NumOperations:
1188 break;
1189 }
1190 };
1191};
1192
1193ReturnedValue QObjectWrapper::method_connect(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
1194{
1195 Scope scope(b);
1196
1197 if (argc == 0)
1198 THROW_GENERIC_ERROR("Function.prototype.connect: no arguments given");
1199
1200 QPair<QObject *, int> signalInfo = extractQtSignal(*thisObject);
1201 QObject *signalObject = signalInfo.first;
1202 int signalIndex = signalInfo.second; // in method range, not signal range!
1203
1204 if (signalIndex < 0)
1205 THROW_GENERIC_ERROR("Function.prototype.connect: this object is not a signal");
1206
1207 if (!signalObject)
1208 THROW_GENERIC_ERROR("Function.prototype.connect: cannot connect to deleted QObject");
1209
1210 auto signalMetaMethod = signalObject->metaObject()->method(signalIndex);
1211 if (signalMetaMethod.methodType() != QMetaMethod::Signal)
1212 THROW_GENERIC_ERROR("Function.prototype.connect: this object is not a signal");
1213
1214 ScopedFunctionObject f(scope);
1215 ScopedValue object (scope, Encode::undefined());
1216
1217 if (argc == 1) {
1218 f = argv[0];
1219 } else if (argc >= 2) {
1220 object = argv[0];
1221 f = argv[1];
1222 }
1223
1224 if (!f)
1225 THROW_GENERIC_ERROR("Function.prototype.connect: target is not a function");
1226
1227 if (!object->isUndefined() && !object->isObject())
1228 THROW_GENERIC_ERROR("Function.prototype.connect: target this is not an object");
1229
1231 slot->signal = signalMetaMethod;
1232
1233 slot->thisObject.set(scope.engine, object);
1234 slot->function.set(scope.engine, f);
1235
1236 if (QQmlData *ddata = QQmlData::get(signalObject)) {
1237 if (const QQmlPropertyCache *propertyCache = ddata->propertyCache.data()) {
1238 QQmlPropertyPrivate::flushSignal(signalObject, propertyCache->methodIndexToSignalIndex(signalIndex));
1239 }
1240 }
1241
1242 QPair<QObject *, int> functionData = QObjectMethod::extractQtMethod(f); // align with disconnect
1243 if (QObject *receiver = functionData.first) {
1244 QObjectPrivate::connect(signalObject, signalIndex, receiver, slot, Qt::AutoConnection);
1245 } else {
1246 qCInfo(lcObjectConnect,
1247 "Could not find receiver of the connection, using sender as receiver. Disconnect "
1248 "explicitly (or delete the sender) to make sure the connection is removed.");
1249 QObjectPrivate::connect(signalObject, signalIndex, signalObject, slot, Qt::AutoConnection);
1250 }
1251
1253}
1254
1255ReturnedValue QObjectWrapper::method_disconnect(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
1256{
1257 Scope scope(b);
1258
1259 if (argc == 0)
1260 THROW_GENERIC_ERROR("Function.prototype.disconnect: no arguments given");
1261
1262 QPair<QObject *, int> signalInfo = extractQtSignal(*thisObject);
1263 QObject *signalObject = signalInfo.first;
1264 int signalIndex = signalInfo.second;
1265
1266 if (signalIndex == -1)
1267 THROW_GENERIC_ERROR("Function.prototype.disconnect: this object is not a signal");
1268
1269 if (!signalObject)
1270 THROW_GENERIC_ERROR("Function.prototype.disconnect: cannot disconnect from deleted QObject");
1271
1272 if (signalIndex < 0 || signalObject->metaObject()->method(signalIndex).methodType() != QMetaMethod::Signal)
1273 THROW_GENERIC_ERROR("Function.prototype.disconnect: this object is not a signal");
1274
1275 ScopedFunctionObject functionValue(scope);
1276 ScopedValue functionThisValue(scope, Encode::undefined());
1277
1278 if (argc == 1) {
1279 functionValue = argv[0];
1280 } else if (argc >= 2) {
1281 functionThisValue = argv[0];
1282 functionValue = argv[1];
1283 }
1284
1285 if (!functionValue)
1286 THROW_GENERIC_ERROR("Function.prototype.disconnect: target is not a function");
1287
1288 if (!functionThisValue->isUndefined() && !functionThisValue->isObject())
1289 THROW_GENERIC_ERROR("Function.prototype.disconnect: target this is not an object");
1290
1291 QPair<QObject *, int> functionData = QObjectMethod::extractQtMethod(functionValue);
1292
1293 void *a[] = {
1294 scope.engine,
1295 functionValue.ptr,
1296 functionThisValue.ptr,
1297 functionData.first,
1298 &functionData.second
1299 };
1300
1301 if (QObject *receiver = functionData.first) {
1302 QObjectPrivate::disconnect(signalObject, signalIndex, receiver,
1303 reinterpret_cast<void **>(&a));
1304 } else {
1305 QObjectPrivate::disconnect(signalObject, signalIndex, signalObject,
1306 reinterpret_cast<void **>(&a));
1307 }
1308
1310}
1311
1313{
1315 queue.append(parent->children());
1316
1317 while (!queue.isEmpty()) {
1318 QObject *child = queue.dequeue();
1319 if (!child)
1320 continue;
1321 QObjectWrapper::markWrapper(child, markStack);
1322 queue.append(child->children());
1323 }
1324}
1325
1326void Heap::QObjectWrapper::markObjects(Heap::Base *that, MarkStack *markStack)
1327{
1328 QObjectWrapper *This = static_cast<QObjectWrapper *>(that);
1329
1330 if (QObject *o = This->object()) {
1332 if (vme)
1333 vme->mark(markStack);
1334
1335 // Children usually don't need to be marked, the gc keeps them alive.
1336 // But in the rare case of a "floating" QObject without a parent that
1337 // _gets_ marked (we've been called here!) then we also need to
1338 // propagate the marking down to the children recursively.
1339 if (!o->parent())
1340 markChildQObjectsRecursively(o, markStack);
1341 }
1342
1343 Object::markObjects(that, markStack);
1344}
1345
1346void QObjectWrapper::destroyObject(bool lastCall)
1347{
1349 Q_ASSERT(h->internalClass);
1350
1351 if (QObject *o = h->object()) {
1352 QQmlData *ddata = QQmlData::get(o, false);
1353 if (ddata) {
1354 if (!o->parent() && !ddata->indestructible) {
1355 if (ddata && ddata->ownContext) {
1356 Q_ASSERT(ddata->ownContext.data() == ddata->context);
1357 ddata->ownContext->emitDestruction();
1358 ddata->ownContext.reset();
1359 ddata->context = nullptr;
1360 }
1361 // This object is notionally destroyed now
1362 ddata->isQueuedForDeletion = true;
1363 ddata->disconnectNotifiers();
1364 if (lastCall)
1365 delete o;
1366 else
1367 o->deleteLater();
1368 } else {
1369 // If the object is C++-owned, we still have to release the weak reference we have
1370 // to it.
1371 ddata->jsWrapper.clear();
1372 if (lastCall && ddata->propertyCache)
1373 ddata->propertyCache.reset();
1374 }
1375 }
1376 }
1377
1378 h->destroy();
1379}
1380
1381
1383
1384namespace {
1385
1386template<typename A, typename B, typename C, typename D, typename E, typename F, typename G>
1387class MaxSizeOf7 {
1388 template<typename Z, typename X>
1389 struct SMax {
1390 char dummy[sizeof(Z) > sizeof(X) ? sizeof(Z) : sizeof(X)];
1391 };
1392public:
1393 static const size_t Size = sizeof(SMax<A, SMax<B, SMax<C, SMax<D, SMax<E, SMax<F, G> > > > > >);
1394};
1395
1396struct CallArgument {
1397 Q_DISABLE_COPY_MOVE(CallArgument);
1398
1399 CallArgument() = default;
1400 ~CallArgument() { cleanup(); }
1401
1402 inline void *dataPtr();
1403
1404 inline void initAsType(QMetaType type);
1405 inline bool fromValue(QMetaType type, ExecutionEngine *, const Value &);
1406 inline ReturnedValue toValue(ExecutionEngine *);
1407
1408private:
1409 // QVariantWrappedType denotes that we're storing a QVariant, but we mean
1410 // the type inside the QVariant, not QVariant itself.
1411 enum { QVariantWrappedType = -1 };
1412
1413 inline void cleanup();
1414
1415 template <class T, class M>
1416 bool fromContainerValue(const Value &object, M CallArgument::*member);
1417
1418 union {
1419 float floatValue;
1420 double doubleValue;
1421 quint32 intValue;
1422 bool boolValue;
1423 QObject *qobjectPtr;
1424 std::vector<int> *stdVectorIntPtr;
1425 std::vector<qreal> *stdVectorRealPtr;
1426 std::vector<bool> *stdVectorBoolPtr;
1427 std::vector<QString> *stdVectorQStringPtr;
1428 std::vector<QUrl> *stdVectorQUrlPtr;
1429#if QT_CONFIG(qml_itemmodel)
1430 std::vector<QModelIndex> *stdVectorQModelIndexPtr;
1431#endif
1432
1433 char allocData[MaxSizeOf7<QVariant,
1434 QString,
1436 QJSValue,
1437 QJsonArray,
1440 qint64 q_for_alignment;
1441 };
1442
1443 // Pointers to allocData
1444 union {
1445 QString *qstringPtr;
1446 QByteArray *qbyteArrayPtr;
1447 QVariant *qvariantPtr;
1448 QList<QObject *> *qlistPtr;
1449 QJSValue *qjsValuePtr;
1450 QJsonArray *jsonArrayPtr;
1451 QJsonObject *jsonObjectPtr;
1452 QJsonValue *jsonValuePtr;
1453 };
1454
1456};
1457}
1458
1459static ReturnedValue CallMethod(const QQmlObjectOrGadget &object, int index, QMetaType returnType, int argCount,
1460 const QMetaType *argTypes, ExecutionEngine *engine, CallData *callArgs,
1462{
1463 if (argCount > 0) {
1464 // Convert all arguments.
1466 args[0].initAsType(returnType);
1467 for (int ii = 0; ii < argCount; ++ii) {
1468 if (!args[ii + 1].fromValue(argTypes[ii], engine,
1469 callArgs->args[ii].asValue<Value>())) {
1470 qWarning() << QString::fromLatin1("Could not convert argument %1 at").arg(ii);
1471 const StackTrace stack = engine->stackTrace();
1472 for (const StackFrame &frame : stack) {
1473 qWarning() << "\t" << frame.function + QLatin1Char('@') + frame.source
1474 + (frame.line > 0
1475 ? (QLatin1Char(':') + QString::number(frame.line))
1476 : QString());
1477
1478 }
1479
1480 const bool is_signal =
1481 object.metaObject()->method(index).methodType() == QMetaMethod::Signal;
1482 if (is_signal) {
1483 qWarning() << "Passing incompatible arguments to signals is not supported.";
1484 } else {
1485 return engine->throwTypeError(
1486 QLatin1String("Passing incompatible arguments to C++ functions from "
1487 "JavaScript is not allowed."));
1488 }
1489 }
1490 }
1492 for (int ii = 0; ii < args.size(); ++ii)
1493 argData[ii] = args[ii].dataPtr();
1494
1495 object.metacall(callType, index, argData.data());
1496
1497 return args[0].toValue(engine);
1498
1499 } else if (returnType != QMetaType::fromType<void>()) {
1500
1501 CallArgument arg;
1502 arg.initAsType(returnType);
1503
1504 void *args[] = { arg.dataPtr() };
1505
1506 object.metacall(callType, index, args);
1507
1508 return arg.toValue(engine);
1509
1510 } else {
1511
1512 void *args[] = { nullptr };
1513 object.metacall(callType, index, args);
1514 return Encode::undefined();
1515
1516 }
1517}
1518
1519template<typename Retrieve>
1520int MatchVariant(QMetaType conversionMetaType, Retrieve &&retrieve) {
1521 if (conversionMetaType == QMetaType::fromType<QVariant>())
1522 return 0;
1523
1524 const QMetaType type = retrieve();
1525 if (type == conversionMetaType)
1526 return 0;
1527
1528 if (const QMetaObject *conversionMetaObject = conversionMetaType.metaObject()) {
1529 if (const QMetaObject *mo = type.metaObject(); mo && mo->inherits(conversionMetaObject))
1530 return 1;
1531 }
1532
1533 if (QMetaType::canConvert(type, conversionMetaType))
1534 return 5;
1535
1536 return 10;
1537};
1538
1539/*
1540 Returns the match score for converting \a actual to be of type \a conversionType. A
1541 zero score means "perfect match" whereas a higher score is worse.
1542
1543 The conversion table is copied out of the \l QScript::callQtMethod() function.
1544*/
1545static int MatchScore(const Value &actual, QMetaType conversionMetaType)
1546{
1547 const int conversionType = conversionMetaType.id();
1548 if (actual.isNumber()) {
1549 switch (conversionType) {
1550 case QMetaType::Double:
1551 return 0;
1552 case QMetaType::Float:
1553 return 1;
1554 case QMetaType::LongLong:
1555 case QMetaType::ULongLong:
1556 return 2;
1557 case QMetaType::Long:
1558 case QMetaType::ULong:
1559 return 3;
1560 case QMetaType::Int:
1561 case QMetaType::UInt:
1562 return 4;
1563 case QMetaType::Short:
1564 case QMetaType::UShort:
1565 return 5;
1566 break;
1567 case QMetaType::Char:
1568 case QMetaType::UChar:
1569 return 6;
1570 case QMetaType::QJsonValue:
1571 return 5;
1572 default:
1573 return 10;
1574 }
1575 } else if (actual.isString()) {
1576 switch (conversionType) {
1577 case QMetaType::QString:
1578 return 0;
1579 case QMetaType::QJsonValue:
1580 return 5;
1581 case QMetaType::QUrl:
1582 return 6; // we like to convert strings to URLs in QML
1583 default:
1584 return 10;
1585 }
1586 } else if (actual.isBoolean()) {
1587 switch (conversionType) {
1588 case QMetaType::Bool:
1589 return 0;
1590 case QMetaType::QJsonValue:
1591 return 5;
1592 default:
1593 return 10;
1594 }
1595 } else if (actual.as<DateObject>()) {
1596 switch (conversionType) {
1597 case QMetaType::QDateTime:
1598 return 0;
1599 case QMetaType::QDate:
1600 return 1;
1601 case QMetaType::QTime:
1602 return 2;
1603 default:
1604 return 10;
1605 }
1606 } else if (actual.as<RegExpObject>()) {
1607 switch (conversionType) {
1608#if QT_CONFIG(regularexpression)
1609 case QMetaType::QRegularExpression:
1610 return 0;
1611#endif
1612 default:
1613 return 10;
1614 }
1615 } else if (actual.as<ArrayBuffer>()) {
1616 switch (conversionType) {
1617 case QMetaType::QByteArray:
1618 return 0;
1619 default:
1620 return 10;
1621 }
1622 } else if (actual.as<ArrayObject>()) {
1623 switch (conversionType) {
1624 case QMetaType::QJsonArray:
1625 return 3;
1626 case QMetaType::QStringList:
1627 case QMetaType::QVariantList:
1628 return 5;
1629 case QMetaType::QVector4D:
1630 case QMetaType::QMatrix4x4:
1631 return 6;
1632 case QMetaType::QVector3D:
1633 return 7;
1634 default:
1635 return 10;
1636 }
1637 } else if (actual.isNull()) {
1638 switch (conversionType) {
1639 case QMetaType::Nullptr:
1640 case QMetaType::VoidStar:
1641 case QMetaType::QObjectStar:
1642 case QMetaType::QJsonValue:
1643 return 0;
1644 default: {
1645 if (conversionMetaType.flags().testFlag(QMetaType::IsPointer))
1646 return 0;
1647 else
1648 return 10;
1649 }
1650 }
1651 } else if (const Object *obj = actual.as<Object>()) {
1652 if (const VariantObject *variantObject = obj->as<VariantObject>()) {
1653 return MatchVariant(conversionMetaType, [variantObject]() {
1654 return variantObject->d()->data().metaType();
1655 });
1656 }
1657
1658 if (const QObjectWrapper *wrapper = obj->as<QObjectWrapper>()) {
1659 switch (conversionType) {
1660 case QMetaType::QObjectStar:
1661 return 0;
1662 default:
1663 if (conversionMetaType.flags() & QMetaType::PointerToQObject) {
1664 QObject *wrapped = wrapper->object();
1665 if (!wrapped)
1666 return 0;
1667 if (qmlobject_can_cpp_cast(wrapped, conversionMetaType.metaObject()))
1668 return 0;
1669 }
1670 }
1671 return 10;
1672 }
1673
1674 if (const QQmlTypeWrapper *wrapper = obj->as<QQmlTypeWrapper>()) {
1675 const QQmlType type = wrapper->d()->type();
1676 if (type.isSingleton()) {
1677 const QMetaType metaType = type.typeId();
1678 if (metaType == conversionMetaType)
1679 return 0;
1680
1681 if (conversionMetaType.flags() & QMetaType::PointerToQObject
1682 && metaType.flags() & QMetaType::PointerToQObject
1683 && type.metaObject()->inherits(conversionMetaType.metaObject())) {
1684 return 0;
1685 }
1686 } else if (QObject *object = wrapper->object()) {
1687 if (conversionMetaType.flags() & QMetaType::PointerToQObject
1688 && qmlobject_can_cpp_cast(object, conversionMetaType.metaObject())) {
1689 return 0;
1690 }
1691 }
1692
1693 return 10;
1694 }
1695
1696 if (const Sequence *sequence = obj->as<Sequence>()) {
1697 if (SequencePrototype::metaTypeForSequence(sequence) == conversionMetaType)
1698 return 1;
1699 else
1700 return 10;
1701 }
1702
1704 return MatchVariant(conversionMetaType, [wrapper]() {
1705 return wrapper->d()->isVariant()
1706 ? wrapper->toVariant().metaType()
1707 : wrapper->type();
1708 });
1709 }
1710
1711 if (conversionType == QMetaType::QJsonObject)
1712 return 5;
1713 if (conversionType == qMetaTypeId<QJSValue>())
1714 return 0;
1715 if (conversionType == QMetaType::QVariantMap)
1716 return 5;
1717 }
1718
1719 return 10;
1720}
1721
1722static int numDefinedArguments(CallData *callArgs)
1723{
1724 int numDefinedArguments = callArgs->argc();
1725 while (numDefinedArguments > 0
1726 && callArgs->args[numDefinedArguments - 1].type() == StaticValue::Undefined_Type) {
1728 }
1729 return numDefinedArguments;
1730}
1731
1733 ExecutionEngine *engine, CallData *callArgs,
1735{
1736 QByteArray unknownTypeError;
1737
1738 QMetaType returnType = object.methodReturnType(data, &unknownTypeError);
1739
1740 if (!returnType.isValid()) {
1741 return engine->throwError(QLatin1String("Unknown method return type: ")
1742 + QLatin1String(unknownTypeError));
1743 }
1744
1745 auto handleTooManyArguments = [&](int expectedArguments) {
1746 const QMetaObject *metaObject = object.metaObject();
1747 const int indexOfClassInfo = metaObject->indexOfClassInfo("QML.StrictArguments");
1748 if (indexOfClassInfo != -1
1749 && QString::fromUtf8(metaObject->classInfo(indexOfClassInfo).value())
1750 == QStringLiteral("true")) {
1751 engine->throwError(QStringLiteral("Too many arguments"));
1752 return false;
1753 }
1754
1755 const auto stackTrace = engine->stackTrace();
1756 if (stackTrace.isEmpty()) {
1757 qWarning().nospace().noquote()
1758 << "When matching arguments for "
1759 << object.className() << "::" << data.name(object.metaObject()) << "():";
1760 } else {
1761 const StackFrame frame = engine->stackTrace().first();
1762 qWarning().noquote() << frame.function + QLatin1Char('@') + frame.source
1763 + (frame.line > 0 ? (QLatin1Char(':') + QString::number(frame.line))
1764 : QString());
1765 }
1766
1767 qWarning().noquote() << QStringLiteral("Too many arguments, ignoring %1")
1768 .arg(callArgs->argc() - expectedArguments);
1769 return true;
1770 };
1771
1772 const int definedArgumentCount = numDefinedArguments(callArgs);
1773
1774 if (data.hasArguments()) {
1775
1777
1778 bool ok = false;
1779 if (data.isConstructor())
1780 ok = object.constructorParameterTypes(data.coreIndex(), &storage, &unknownTypeError);
1781 else
1782 ok = object.methodParameterTypes(data.coreIndex(), &storage, &unknownTypeError);
1783
1784 if (!ok) {
1785 return engine->throwError(QLatin1String("Unknown method parameter type: ")
1786 + QLatin1String(unknownTypeError));
1787 }
1788
1789 if (storage.size() > callArgs->argc()) {
1790 QString error = QLatin1String("Insufficient arguments");
1791 return engine->throwError(error);
1792 }
1793
1794 if (storage.size() < definedArgumentCount) {
1795 if (!handleTooManyArguments(storage.size()))
1796 return Encode::undefined();
1797
1798 }
1799
1800 return CallMethod(object, data.coreIndex(), returnType, storage.size(), storage.constData(), engine, callArgs, callType);
1801
1802 } else {
1803 if (definedArgumentCount > 0 && !handleTooManyArguments(0))
1804 return Encode::undefined();
1805
1806 return CallMethod(object, data.coreIndex(), returnType, 0, nullptr, engine, callArgs, callType);
1807 }
1808}
1809
1810/*
1811Resolve the overloaded method to call. The algorithm works conceptually like this:
1812 1. Resolve the set of overloads it is *possible* to call.
1813 Impossible overloads include those that have too many parameters or have parameters
1814 of unknown type.
1815 2. Filter the set of overloads to only contain those with the closest number of
1816 parameters.
1817 For example, if we are called with 3 parameters and there are 2 overloads that
1818 take 2 parameters and one that takes 3, eliminate the 2 parameter overloads.
1819 3. Find the best remaining overload based on its match score.
1820 If two or more overloads have the same match score, return the last one. The match
1821 score is constructed by adding the matchScore() result for each of the parameters.
1822*/
1824 const QQmlObjectOrGadget &object, const QQmlPropertyData *methods, int methodCount,
1825 ExecutionEngine *engine, CallData *callArgs)
1826{
1827 const int argumentCount = callArgs->argc();
1828 const int definedArgumentCount = numDefinedArguments(callArgs);
1829
1830 const QQmlPropertyData *best = nullptr;
1831 int bestParameterScore = INT_MAX;
1832 int bestMaxMatchScore = INT_MAX;
1833 int bestSumMatchScore = INT_MAX;
1834
1835 Scope scope(engine);
1836 ScopedValue v(scope);
1837
1838 for (int i = 0; i < methodCount; ++i) {
1839 const QQmlPropertyData *attempt = methods + i;
1840
1841 if (lcOverloadResolution().isDebugEnabled()) {
1842 const QQmlPropertyData &candidate = methods[i];
1843 const QMetaMethod m = candidate.isConstructor()
1844 ? object.metaObject()->constructor(candidate.coreIndex())
1845 : object.metaObject()->method(candidate.coreIndex());
1846 qCDebug(lcOverloadResolution) << "::: considering signature" << m.methodSignature();
1847 }
1848
1849 // QQmlV4Function overrides anything that doesn't provide the exact number of arguments
1850 int methodParameterScore = 1;
1851 // QQmlV4Function overrides the "no idea" option, which is 10
1852 int maxMethodMatchScore = 9;
1853 // QQmlV4Function cannot provide a best sum of match scores as we don't match the arguments
1854 int sumMethodMatchScore = bestSumMatchScore;
1855
1856 if (!attempt->isV4Function()) {
1858 int methodArgumentCount = 0;
1859 if (attempt->hasArguments()) {
1860 if (attempt->isConstructor()) {
1861 if (!object.constructorParameterTypes(attempt->coreIndex(), &storage, nullptr)) {
1862 qCDebug(lcOverloadResolution, "rejected, could not get ctor argument types");
1863 continue;
1864 }
1865 } else {
1866 if (!object.methodParameterTypes(attempt->coreIndex(), &storage, nullptr)) {
1867 qCDebug(lcOverloadResolution, "rejected, could not get ctor argument types");
1868 continue;
1869 }
1870 }
1871 methodArgumentCount = storage.size();
1872 }
1873
1874 if (methodArgumentCount > argumentCount) {
1875 qCDebug(lcOverloadResolution, "rejected, insufficient arguments");
1876 continue; // We don't have sufficient arguments to call this method
1877 }
1878
1879 methodParameterScore = (definedArgumentCount == methodArgumentCount)
1880 ? 0
1881 : (definedArgumentCount - methodArgumentCount + 1);
1882 if (methodParameterScore > bestParameterScore) {
1883 qCDebug(lcOverloadResolution) << "rejected, score too bad. own" << methodParameterScore << "vs best:" << bestParameterScore;
1884 continue; // We already have a better option
1885 }
1886
1887 maxMethodMatchScore = 0;
1888 sumMethodMatchScore = 0;
1889 for (int ii = 0; ii < methodArgumentCount; ++ii) {
1890 const int score = MatchScore((v = Value::fromStaticValue(callArgs->args[ii])),
1891 storage[ii]);
1892 maxMethodMatchScore = qMax(maxMethodMatchScore, score);
1893 sumMethodMatchScore += score;
1894 }
1895 }
1896
1897 if (bestParameterScore > methodParameterScore || bestMaxMatchScore > maxMethodMatchScore
1898 || (bestParameterScore == methodParameterScore
1899 && bestMaxMatchScore == maxMethodMatchScore
1900 && bestSumMatchScore > sumMethodMatchScore)) {
1901 best = attempt;
1902 bestParameterScore = methodParameterScore;
1903 bestMaxMatchScore = maxMethodMatchScore;
1904 bestSumMatchScore = sumMethodMatchScore;
1905 qCDebug(lcOverloadResolution) << "updated best" << "bestParameterScore" << bestParameterScore << "\n"
1906 << "bestMaxMatchScore" << bestMaxMatchScore << "\n"
1907 << "bestSumMatchScore" << bestSumMatchScore << "\n";
1908 } else {
1909 qCDebug(lcOverloadResolution) << "did not update best\n"
1910 << "bestParameterScore" << bestParameterScore << "\t"
1911 << "methodParameterScore" << methodParameterScore << "\n"
1912 << "bestMaxMatchScore" << bestMaxMatchScore << "\t"
1913 << "maxMethodMatchScore" << maxMethodMatchScore << "\n"
1914 << "bestSumMatchScore" << bestSumMatchScore << "\t"
1915 << "sumMethodMatchScore" << sumMethodMatchScore << "\n";
1916 }
1917
1918 if (bestParameterScore == 0 && bestMaxMatchScore == 0) {
1919 qCDebug(lcOverloadResolution, "perfect match");
1920 break; // We can't get better than that
1921 }
1922
1923 };
1924
1925 if (best && best->isValid()) {
1926 return best;
1927 } else {
1928 QString error = QLatin1String("Unable to determine callable overload. Candidates are:");
1929 for (int i = 0; i < methodCount; ++i) {
1930 for (int i = 0; i < methodCount; ++i) {
1931 const QQmlPropertyData &candidate = methods[i];
1932 const QMetaMethod m = candidate.isConstructor()
1933 ? object.metaObject()->constructor(candidate.coreIndex())
1934 : object.metaObject()->method(candidate.coreIndex());
1935 error += u"\n " + QString::fromUtf8(m.methodSignature());
1936 }
1937 }
1938
1940 return nullptr;
1941 }
1942}
1943
1944
1945
1946void CallArgument::cleanup()
1947{
1948 switch (type) {
1949 case QMetaType::QString:
1950 qstringPtr->~QString();
1951 break;
1952 case QMetaType::QByteArray:
1953 qbyteArrayPtr->~QByteArray();
1954 break;
1956 case QVariantWrappedType:
1957 qvariantPtr->~QVariant();
1958 break;
1959 case QMetaType::QJsonArray:
1960 jsonArrayPtr->~QJsonArray();
1961 break;
1962 case QMetaType::QJsonObject:
1963 jsonObjectPtr->~QJsonObject();
1964 break;
1965 case QMetaType::QJsonValue:
1966 jsonValuePtr->~QJsonValue();
1967 break;
1968 default:
1969 if (type == qMetaTypeId<QJSValue>()) {
1970 qjsValuePtr->~QJSValue();
1971 break;
1972 }
1973
1974 if (type == qMetaTypeId<QList<QObject *> >()) {
1975 qlistPtr->~QList<QObject *>();
1976 break;
1977 }
1978
1979 // The sequence types need no cleanup because we don't own them.
1980
1981 break;
1982 }
1983}
1984
1985void *CallArgument::dataPtr()
1986{
1987 switch (type) {
1989 return nullptr;
1990 case QVariantWrappedType:
1991 return qvariantPtr->data();
1992 default:
1993 if (type == qMetaTypeId<std::vector<int>>())
1994 return stdVectorIntPtr;
1995 if (type == qMetaTypeId<std::vector<qreal>>())
1996 return stdVectorRealPtr;
1997 if (type == qMetaTypeId<std::vector<bool>>())
1998 return stdVectorBoolPtr;
1999 if (type == qMetaTypeId<std::vector<QString>>())
2000 return stdVectorQStringPtr;
2001 if (type == qMetaTypeId<std::vector<QUrl>>())
2002 return stdVectorQUrlPtr;
2003#if QT_CONFIG(qml_itemmodel)
2004 if (type == qMetaTypeId<std::vector<QModelIndex>>())
2005 return stdVectorQModelIndexPtr;
2006#endif
2007 break;
2008 }
2009
2010 return (void *)&allocData;
2011}
2012
2013void CallArgument::initAsType(QMetaType metaType)
2014{
2016 cleanup();
2017
2018 type = metaType.id();
2019 switch (type) {
2020 case QMetaType::Void:
2022 break;
2024 case QMetaType::Int:
2025 case QMetaType::UInt:
2026 case QMetaType::Bool:
2027 case QMetaType::Double:
2028 case QMetaType::Float:
2029 break;
2030 case QMetaType::QObjectStar:
2031 qobjectPtr = nullptr;
2032 break;
2033 case QMetaType::QString:
2034 qstringPtr = new (&allocData) QString();
2035 break;
2037 qvariantPtr = new (&allocData) QVariant();
2038 break;
2039 case QMetaType::QJsonArray:
2040 jsonArrayPtr = new (&allocData) QJsonArray();
2041 break;
2042 case QMetaType::QJsonObject:
2043 jsonObjectPtr = new (&allocData) QJsonObject();
2044 break;
2045 case QMetaType::QJsonValue:
2046 jsonValuePtr = new (&allocData) QJsonValue();
2047 break;
2048 default: {
2049 if (metaType == QMetaType::fromType<QJSValue>()) {
2050 qjsValuePtr = new (&allocData) QJSValue();
2051 break;
2052 }
2053
2054 if (metaType == QMetaType::fromType<QList<QObject *>>()) {
2055 qlistPtr = new (&allocData) QList<QObject *>();
2056 break;
2057 }
2058
2059 type = QVariantWrappedType;
2060 qvariantPtr = new (&allocData) QVariant(metaType, (void *)nullptr);
2061 break;
2062 }
2063 }
2064}
2065
2066template <class T, class M>
2067bool CallArgument::fromContainerValue(const Value &value, M CallArgument::*member)
2068{
2069 if (const Sequence *sequence = value.as<Sequence>()) {
2070 if (T* ptr = static_cast<T *>(SequencePrototype::getRawContainerPtr(
2071 sequence, QMetaType(type)))) {
2072 (this->*member) = ptr;
2073 return true;
2074 }
2075 }
2076 (this->*member) = nullptr;
2077 return false;
2078}
2079
2080bool CallArgument::fromValue(QMetaType metaType, ExecutionEngine *engine, const Value &value)
2081{
2083 cleanup();
2084
2085 type = metaType.id();
2086
2087 switch (type) {
2088 case QMetaType::Int:
2089 intValue = quint32(value.toInt32());
2090 return true;
2091 case QMetaType::UInt:
2092 intValue = quint32(value.toUInt32());
2093 return true;
2094 case QMetaType::Bool:
2095 boolValue = value.toBoolean();
2096 return true;
2097 case QMetaType::Double:
2098 doubleValue = double(value.toNumber());
2099 return true;
2100 case QMetaType::Float:
2101 floatValue = float(value.toNumber());
2102 return true;
2103 case QMetaType::QString:
2104 if (value.isNullOrUndefined())
2105 qstringPtr = new (&allocData) QString();
2106 else
2107 qstringPtr = new (&allocData) QString(value.toQStringNoThrow());
2108 return true;
2109 case QMetaType::QObjectStar:
2110 if (const QObjectWrapper *qobjectWrapper = value.as<QObjectWrapper>()) {
2111 qobjectPtr = qobjectWrapper->object();
2112 return true;
2113 }
2114
2115 if (const QQmlTypeWrapper *qmlTypeWrapper = value.as<QQmlTypeWrapper>()) {
2116 if (qmlTypeWrapper->isSingleton()) {
2117 // Convert via QVariant below.
2118 // TODO: Can't we just do qobjectPtr = qmlTypeWrapper->object() instead?
2119 break;
2120 } else if (QObject *obj = qmlTypeWrapper->object()) {
2121 // attached object case
2122 qobjectPtr = obj;
2123 return true;
2124 }
2125
2126 // If this is a plain type wrapper without an instance,
2127 // then we got a namespace, and that's a type error
2129 return false;
2130 }
2131
2132 qobjectPtr = nullptr;
2133 return value.isNullOrUndefined(); // null and undefined are nullptr
2135 qvariantPtr = new (&allocData) QVariant(ExecutionEngine::toVariant(value, QMetaType {}));
2136 return true;
2137 case QMetaType::QJsonArray: {
2138 Scope scope(engine);
2139 ScopedArrayObject a(scope, value);
2140 jsonArrayPtr = new (&allocData) QJsonArray(JsonObject::toJsonArray(a));
2141 return true;
2142 }
2143 case QMetaType::QJsonObject: {
2144 Scope scope(engine);
2145 ScopedObject o(scope, value);
2146 jsonObjectPtr = new (&allocData) QJsonObject(JsonObject::toJsonObject(o));
2147 return true;
2148 }
2149 case QMetaType::QJsonValue:
2150 jsonValuePtr = new (&allocData) QJsonValue(JsonObject::toJsonValue(value));
2151 return true;
2152 case QMetaType::Void:
2154 // TODO: This only doesn't leak because a default constructed QVariant doesn't allocate.
2155 *qvariantPtr = QVariant();
2156 return true;
2157 default:
2158 if (type == qMetaTypeId<QJSValue>()) {
2159 qjsValuePtr = new (&allocData) QJSValue;
2160 QJSValuePrivate::setValue(qjsValuePtr, value.asReturnedValue());
2161 return true;
2162 }
2163
2164 if (type == qMetaTypeId<QList<QObject*> >()) {
2165 qlistPtr = new (&allocData) QList<QObject *>();
2166 Scope scope(engine);
2168 if (array) {
2169 Scoped<QObjectWrapper> qobjectWrapper(scope);
2170
2171 uint length = array->getLength();
2172 for (uint ii = 0; ii < length; ++ii) {
2173 QObject *o = nullptr;
2174 qobjectWrapper = array->get(ii);
2175 if (!!qobjectWrapper)
2176 o = qobjectWrapper->object();
2177 qlistPtr->append(o);
2178 }
2179 return true;
2180 }
2181
2182 if (const QObjectWrapper *qobjectWrapper = value.as<QObjectWrapper>()) {
2183 qlistPtr->append(qobjectWrapper->object());
2184 return true;
2185 }
2186
2187 if (const QmlListWrapper *listWrapper = value.as<QmlListWrapper>()) {
2188 *qlistPtr = listWrapper->d()->property()->toList<QList<QObject *>>();
2189 return true;
2190 }
2191
2192 qlistPtr->append(nullptr);
2193 return value.isNullOrUndefined();
2194 }
2195
2197 // You can assign null or undefined to any pointer. The result is a nullptr.
2198 if (value.isNullOrUndefined()) {
2199 qvariantPtr = new (&allocData) QVariant(metaType, nullptr);
2200 return true;
2201 }
2202 break;
2203 }
2204
2205 if (type == qMetaTypeId<std::vector<int>>()) {
2206 if (fromContainerValue<std::vector<int>>(value, &CallArgument::stdVectorIntPtr))
2207 return true;
2208 } else if (type == qMetaTypeId<std::vector<qreal>>()) {
2209 if (fromContainerValue<std::vector<qreal>>(value, &CallArgument::stdVectorRealPtr))
2210 return true;
2211 } else if (type == qMetaTypeId<std::vector<bool>>()) {
2212 if (fromContainerValue<std::vector<bool>>(value, &CallArgument::stdVectorBoolPtr))
2213 return true;
2214 } else if (type == qMetaTypeId<std::vector<QString>>()) {
2215 if (fromContainerValue<std::vector<QString>>(value, &CallArgument::stdVectorQStringPtr))
2216 return true;
2217 } else if (type == qMetaTypeId<std::vector<QUrl>>()) {
2218 if (fromContainerValue<std::vector<QUrl>>(value, &CallArgument::stdVectorQUrlPtr))
2219 return true;
2220#if QT_CONFIG(qml_itemmodel)
2221 } else if (type == qMetaTypeId<std::vector<QModelIndex>>()) {
2222 if (fromContainerValue<std::vector<QModelIndex>>(
2223 value, &CallArgument::stdVectorQModelIndexPtr)) {
2224 return true;
2225 }
2226#endif
2227 }
2228 break;
2229 }
2230
2231 // Convert via QVariant through the QML engine.
2232 qvariantPtr = new (&allocData) QVariant(metaType);
2233 type = QVariantWrappedType;
2234
2235 if (ExecutionEngine::metaTypeFromJS(value, metaType, qvariantPtr->data()))
2236 return true;
2237
2238 const QVariant v = ExecutionEngine::toVariant(value, metaType);
2239 return QMetaType::convert(v.metaType(), v.constData(), metaType, qvariantPtr->data());
2240}
2241
2242ReturnedValue CallArgument::toValue(ExecutionEngine *engine)
2243{
2244 switch (type) {
2245 case QMetaType::Int:
2246 return Encode(int(intValue));
2247 case QMetaType::UInt:
2248 return Encode((uint)intValue);
2249 case QMetaType::Bool:
2250 return Encode(boolValue);
2251 case QMetaType::Double:
2252 return Encode(doubleValue);
2253 case QMetaType::Float:
2254 return Encode(floatValue);
2255 case QMetaType::QString:
2256 return Encode(engine->newString(*qstringPtr));
2257 case QMetaType::QByteArray:
2258 return Encode(engine->newArrayBuffer(*qbyteArrayPtr));
2259 case QMetaType::QObjectStar:
2260 if (qobjectPtr)
2261 QQmlData::get(qobjectPtr, true)->setImplicitDestructible();
2262 return QObjectWrapper::wrap(engine, qobjectPtr);
2263 case QMetaType::QJsonArray:
2264 return JsonObject::fromJsonArray(engine, *jsonArrayPtr);
2265 case QMetaType::QJsonObject:
2266 return JsonObject::fromJsonObject(engine, *jsonObjectPtr);
2267 case QMetaType::QJsonValue:
2268 return JsonObject::fromJsonValue(engine, *jsonValuePtr);
2270 case QVariantWrappedType: {
2271 Scope scope(engine);
2272 ScopedValue rv(scope, scope.engine->fromVariant(*qvariantPtr));
2273 Scoped<QObjectWrapper> qobjectWrapper(scope, rv);
2274 if (!!qobjectWrapper) {
2275 if (QObject *object = qobjectWrapper->object())
2276 QQmlData::get(object, true)->setImplicitDestructible();
2277 }
2278 return rv->asReturnedValue();
2279 }
2280 default:
2281 break;
2282 }
2283
2284 if (type == qMetaTypeId<QJSValue>()) {
2285 // The QJSValue can be passed around via dataPtr()
2287 return QJSValuePrivate::asReturnedValue(qjsValuePtr);
2288 }
2289
2290 if (type == qMetaTypeId<QList<QObject *> >()) {
2291 // XXX Can this be made more by using Array as a prototype and implementing
2292 // directly against QList<QObject*>?
2293 QList<QObject *> &list = *qlistPtr;
2294 Scope scope(engine);
2295 ScopedArrayObject array(scope, engine->newArrayObject());
2296 array->arrayReserve(list.size());
2297 ScopedValue v(scope);
2298 for (int ii = 0; ii < list.size(); ++ii)
2299 array->arrayPut(ii, (v = QObjectWrapper::wrap(engine, list.at(ii))));
2300 array->setArrayLengthUnchecked(list.size());
2301 return array.asReturnedValue();
2302 }
2303
2304 return Encode::undefined();
2305}
2306
2307ReturnedValue QObjectMethod::create(ExecutionContext *scope, Heap::Object *wrapper, int index)
2308{
2309 Scope valueScope(scope);
2311 valueScope,
2312 valueScope.engine->memoryManager->allocate<QObjectMethod>(scope, wrapper, index));
2313 return method.asReturnedValue();
2314}
2315
2316ReturnedValue QObjectMethod::create(ExecutionContext *scope, Heap::QQmlValueTypeWrapper *valueType, int index)
2317{
2318 Scope valueScope(scope);
2320 valueScope,
2321 valueScope.engine->memoryManager->allocate<QObjectMethod>(scope, valueType, index));
2322 return method.asReturnedValue();
2323}
2324
2325ReturnedValue QObjectMethod::create(
2326 ExecutionEngine *engine, Heap::QObjectMethod *cloneFrom,
2327 Heap::Object *wrapper, Heap::Object *object)
2328{
2329 Scope valueScope(engine);
2330
2331 Scoped<QQmlValueTypeWrapper> valueTypeWrapper(valueScope);
2332 if (cloneFrom->wrapper) {
2333 Scoped<QQmlValueTypeWrapper> ref(valueScope, cloneFrom->wrapper);
2334 if (ref) {
2335 valueTypeWrapper = QQmlValueTypeWrapper::create(engine, ref->d(), wrapper);
2336 } else {
2337 // We cannot re-attach a plain QQmlValueTypeWrapper because don't we know what
2338 // value we should operate on. Without knowledge of the property the value
2339 // was read from, we cannot load the value from the given object.
2340 return Encode::undefined();
2341 }
2342 }
2343
2344 Scoped<ExecutionContext> context(valueScope, cloneFrom->scope.get());
2346 valueScope,
2347 engine->memoryManager->allocate<QV4::QObjectMethod>(
2348 context, valueTypeWrapper ? valueTypeWrapper->d() : object, cloneFrom->index));
2349
2350 method->d()->methodCount = cloneFrom->methodCount;
2351
2352 Q_ASSERT(method->d()->methods == nullptr);
2353 switch (cloneFrom->methodCount) {
2354 case 0:
2355 Q_ASSERT(cloneFrom->methods == nullptr);
2356 break;
2357 case 1:
2358 Q_ASSERT(cloneFrom->methods
2359 == reinterpret_cast<QQmlPropertyData *>(&cloneFrom->_singleMethod));
2360 method->d()->methods = reinterpret_cast<QQmlPropertyData *>(&method->d()->_singleMethod);
2361 *method->d()->methods = *cloneFrom->methods;
2362 break;
2363 default:
2364 Q_ASSERT(cloneFrom->methods != nullptr);
2365 method->d()->methods = new QQmlPropertyData[cloneFrom->methodCount];
2366 memcpy(method->d()->methods, cloneFrom->methods,
2367 cloneFrom->methodCount * sizeof(QQmlPropertyData));
2368 break;
2369 }
2370
2371 return method.asReturnedValue();
2372}
2373
2374void Heap::QObjectMethod::init(QV4::ExecutionContext *scope, Object *object, int methodIndex)
2375{
2376 Heap::FunctionObject::init(scope);
2377 wrapper.set(internalClass->engine, object);
2378 index = methodIndex;
2379}
2380
2381const QMetaObject *Heap::QObjectMethod::metaObject() const
2382{
2383 Scope scope(internalClass->engine);
2384
2385 if (Scoped<QV4::QObjectWrapper> objectWrapper(scope, wrapper); objectWrapper)
2386 return objectWrapper->metaObject();
2387 if (Scoped<QV4::QQmlTypeWrapper> typeWrapper(scope, wrapper); typeWrapper)
2388 return typeWrapper->metaObject();
2389 if (Scoped<QV4::QQmlValueTypeWrapper> valueWrapper(scope, wrapper); valueWrapper)
2390 return valueWrapper->metaObject();
2391
2392 return nullptr;
2393}
2394
2395QObject *Heap::QObjectMethod::object() const
2396{
2397 Scope scope(internalClass->engine);
2398
2399 if (Scoped<QV4::QObjectWrapper> objectWrapper(scope, wrapper); objectWrapper)
2400 return objectWrapper->object();
2401 if (Scoped<QV4::QQmlTypeWrapper> typeWrapper(scope, wrapper); typeWrapper)
2402 return typeWrapper->object();
2403 return nullptr;
2404}
2405
2406bool Heap::QObjectMethod::isDetached() const
2407{
2408 if (!wrapper)
2409 return true;
2410
2411 QV4::Scope scope(internalClass->engine);
2412 if (Scoped<QV4::QQmlValueTypeWrapper> valueWrapper(scope, wrapper); valueWrapper)
2413 return valueWrapper->d()->object() == nullptr;
2414
2415 return false;
2416}
2417
2418bool Heap::QObjectMethod::isAttachedTo(QObject *o) const
2419{
2420 QV4::Scope scope(internalClass->engine);
2421 if (Scoped<QV4::QObjectWrapper> objectWrapper(scope, wrapper); objectWrapper)
2422 return objectWrapper->object() == o;
2423 if (Scoped<QV4::QQmlTypeWrapper> typeWrapper(scope, wrapper); typeWrapper)
2424 return typeWrapper->object() == o;
2425
2426 if (Scoped<QV4::QQmlValueTypeWrapper> valueWrapper(scope, wrapper); valueWrapper) {
2427 QV4::Scope scope(wrapper->internalClass->engine);
2428 if (QV4::Scoped<QV4::QObjectWrapper> qobject(scope, valueWrapper->d()->object()); qobject)
2429 return qobject->object() == o;
2430 if (QV4::Scoped<QV4::QQmlTypeWrapper> type(scope, valueWrapper->d()->object()); type)
2431 return type->object() == o;
2432
2433 // Attached to some nested value type or sequence object
2434 return false;
2435 }
2436
2437 return false;
2438}
2439
2440Heap::QObjectMethod::ThisObjectMode Heap::QObjectMethod::checkThisObject(
2441 const QMetaObject *thisMeta) const
2442{
2443 // Check that the metaobject matches.
2444
2445 if (!thisMeta) {
2446 // You can only get a detached method via a lookup, and then you have a thisObject.
2448 return Included;
2449 }
2450
2451 const auto check = [&](const QMetaObject *included) {
2452 const auto stackFrame = internalClass->engine->currentStackFrame;
2453 if (stackFrame && !stackFrame->v4Function->executableCompilationUnit()
2454 ->nativeMethodsAcceptThisObjects()) {
2455 qCWarning(lcMethodBehavior,
2456 "%s:%d: Calling C++ methods with 'this' objects different from the one "
2457 "they were retrieved from is broken, due to historical reasons. The "
2458 "original object is used as 'this' object. You can allow the given "
2459 "'this' object to be used by setting "
2460 "'pragma NativeMethodBehavior: AcceptThisObject'",
2461 qPrintable(stackFrame->source()), stackFrame->lineNumber());
2462 return Included;
2463 }
2464
2465 // destroy() and toString() can be called on all QObjects, but not on gadgets.
2466 if (index < 0)
2467 return thisMeta->inherits(&QObject::staticMetaObject) ? Explicit : Invalid;
2468
2469 // Find the base type the method belongs to.
2470 int methodOffset = included->methodOffset();
2471 while (true) {
2472 if (included == thisMeta)
2473 return Explicit;
2474
2475 if (methodOffset <= index)
2476 return thisMeta->inherits(included) ? Explicit : Invalid;
2477
2478 included = included->superClass();
2479 Q_ASSERT(included);
2480 methodOffset -= QMetaObjectPrivate::get(included)->methodCount;
2481 };
2482
2483 Q_UNREACHABLE_RETURN(Invalid);
2484 };
2485
2486 if (const QMetaObject *meta = metaObject())
2487 return check(meta);
2488
2489 // If the QObjectMethod is detached, we can only have gotten here via a lookup.
2490 // The lookup checks that the QQmlPropertyCache matches.
2491 return Explicit;
2492}
2493
2494QString Heap::QObjectMethod::name() const
2495{
2497 return QStringLiteral("destroy");
2499 return QStringLiteral("toString");
2500
2501 const QMetaObject *mo = metaObject();
2502 if (!mo)
2503 return QString();
2504
2505 int methodOffset = mo->methodOffset();
2506 while (methodOffset > index) {
2507 mo = mo->superClass();
2508 methodOffset -= QMetaObjectPrivate::get(mo)->methodCount;
2509 }
2510
2511 return "%1::%2"_L1.arg(QLatin1StringView{mo->className()},
2512 QLatin1StringView{mo->method(index).name()});
2513}
2514
2515void Heap::QObjectMethod::ensureMethodsCache(const QMetaObject *thisMeta)
2516{
2517 if (methods) {
2518 Q_ASSERT(methodCount > 0);
2519 return;
2520 }
2521
2522 const QMetaObject *mo = metaObject();
2523
2524 if (!mo)
2525 mo = thisMeta;
2526
2527 Q_ASSERT(mo);
2528
2529 int methodOffset = mo->methodOffset();
2530 while (methodOffset > index) {
2531 mo = mo->superClass();
2532 methodOffset -= QMetaObjectPrivate::get(mo)->methodCount;
2533 }
2535 QQmlPropertyData dummy;
2536 QMetaMethod method = mo->method(index);
2537 dummy.load(method);
2538 resolvedMethods.append(dummy);
2539 // Look for overloaded methods
2540 QByteArray methodName = method.name();
2541 for (int ii = index - 1; ii >= methodOffset; --ii) {
2542 if (methodName == mo->method(ii).name()) {
2543 method = mo->method(ii);
2544 dummy.load(method);
2545 resolvedMethods.append(dummy);
2546 }
2547 }
2548 if (resolvedMethods.size() > 1) {
2549 methods = new QQmlPropertyData[resolvedMethods.size()];
2550 memcpy(methods, resolvedMethods.data(), resolvedMethods.size()*sizeof(QQmlPropertyData));
2551 methodCount = resolvedMethods.size();
2552 } else {
2553 methods = reinterpret_cast<QQmlPropertyData *>(&_singleMethod);
2554 *methods = resolvedMethods.at(0);
2555 methodCount = 1;
2556 }
2557
2558 Q_ASSERT(methodCount > 0);
2559}
2560
2561ReturnedValue QObjectMethod::method_toString(ExecutionEngine *engine, QObject *o) const
2562{
2563 return engine->newString(
2564 QObjectWrapper::objectToString(
2565 engine, o ? o->metaObject() : d()->metaObject(), o))->asReturnedValue();
2566}
2567
2568ReturnedValue QObjectMethod::method_destroy(
2569 ExecutionEngine *engine, QObject *o, const Value *args, int argc) const
2570{
2571 if (!o)
2572 return Encode::undefined();
2573
2575 return engine->throwError(QStringLiteral("Invalid attempt to destroy() an indestructible object"));
2576
2577 int delay = 0;
2578 if (argc > 0)
2579 delay = args[0].toUInt32();
2580
2581 if (delay > 0)
2582 QTimer::singleShot(delay, o, SLOT(deleteLater()));
2583 else
2584 o->deleteLater();
2585
2586 return Encode::undefined();
2587}
2588
2589ReturnedValue QObjectMethod::virtualCall(const FunctionObject *m, const Value *thisObject, const Value *argv, int argc)
2590{
2591 const QObjectMethod *This = static_cast<const QObjectMethod*>(m);
2592 return This->callInternal(thisObject, argv, argc);
2593}
2594
2595ReturnedValue QObjectMethod::callInternal(const Value *thisObject, const Value *argv, int argc) const
2596{
2597 ExecutionEngine *v4 = engine();
2598
2599 const QMetaObject *thisMeta = nullptr;
2600
2601 QObject *o = nullptr;
2602 Heap::QQmlValueTypeWrapper *valueWrapper = nullptr;
2603 if (const QObjectWrapper *w = thisObject->as<QObjectWrapper>()) {
2604 thisMeta = w->metaObject();
2605 o = w->object();
2606 } else if (const QQmlTypeWrapper *w = thisObject->as<QQmlTypeWrapper>()) {
2607 thisMeta = w->metaObject();
2608 o = w->object();
2609 } else if (const QQmlValueTypeWrapper *w = thisObject->as<QQmlValueTypeWrapper>()) {
2610 thisMeta = w->metaObject();
2611 valueWrapper = w->d();
2612 }
2613
2614 Heap::QObjectMethod::ThisObjectMode mode = Heap::QObjectMethod::Invalid;
2615 if (o && o == d()->object()) {
2616 mode = Heap::QObjectMethod::Explicit;
2617 // Nothing to do; objects are the same. This should be common
2618 } else if (valueWrapper && valueWrapper == d()->wrapper) {
2619 mode = Heap::QObjectMethod::Explicit;
2620 // Nothing to do; gadgets are the same. This should be somewhat common
2621 } else {
2622 mode = d()->checkThisObject(thisMeta);
2623 if (mode == Heap::QObjectMethod::Invalid) {
2624 v4->throwError(QLatin1String("Cannot call method %1 on %2").arg(
2625 d()->name(), thisObject->toQStringNoThrow()));
2626 return Encode::undefined();
2627 }
2628 }
2629
2630 QQmlObjectOrGadget object = [&](){
2631 if (mode == Heap::QObjectMethod::Included) {
2632 QV4::Scope scope(v4);
2633 if (QV4::Scoped<QV4::QObjectWrapper> qobject(scope, d()->wrapper); qobject)
2634 return QQmlObjectOrGadget(qobject->object());
2636 return QQmlObjectOrGadget(type->object());
2638 valueWrapper = value->d();
2639 return QQmlObjectOrGadget(valueWrapper->metaObject(), valueWrapper->gadgetPtr());
2640 }
2641 Q_UNREACHABLE();
2642 } else {
2643 if (o)
2644 return QQmlObjectOrGadget(o);
2645
2646 Q_ASSERT(valueWrapper);
2647 if (!valueWrapper->enforcesLocation())
2649 return QQmlObjectOrGadget(thisMeta, valueWrapper->gadgetPtr());
2650 }
2651 }();
2652
2653 if (object.isNull())
2654 return Encode::undefined();
2655
2656 if (d()->index == DestroyMethod)
2657 return method_destroy(v4, object.qObject(), argv, argc);
2658 else if (d()->index == ToStringMethod)
2659 return method_toString(v4, object.qObject());
2660
2661 d()->ensureMethodsCache(thisMeta);
2662
2663 Scope scope(v4);
2664 JSCallData cData(thisObject, argv, argc);
2665 CallData *callData = cData.callData(scope);
2666
2667 const QQmlPropertyData *method = d()->methods;
2668
2669 // If we call the method, we have to write back any value type references afterwards.
2670 // The method might change the value.
2671 const auto doCall = [&](const auto &call) {
2672 if (!method->isConstant()) {
2673 if (valueWrapper && valueWrapper->isReference()) {
2674 ScopedValue rv(scope, call());
2675 valueWrapper->writeBack();
2676 return rv->asReturnedValue();
2677 }
2678 }
2679
2680 return call();
2681 };
2682
2683 if (d()->methodCount != 1) {
2684 Q_ASSERT(d()->methodCount > 0);
2685 method = ResolveOverloaded(object, d()->methods, d()->methodCount, v4, callData);
2686 if (method == nullptr)
2687 return Encode::undefined();
2688 }
2689
2690 if (method->isV4Function()) {
2691 return doCall([&]() {
2692 ScopedValue rv(scope, Value::undefinedValue());
2693 QQmlV4Function func(callData, rv, v4);
2694 QQmlV4Function *funcptr = &func;
2695
2696 void *args[] = { nullptr, &funcptr };
2697 object.metacall(QMetaObject::InvokeMetaMethod, method->coreIndex(), args);
2698
2699 return rv->asReturnedValue();
2700 });
2701 }
2702
2703 return doCall([&]() { return CallPrecise(object, *method, v4, callData); });
2704}
2705
2707
2708
2709void Heap::QMetaObjectWrapper::init(const QMetaObject *metaObject)
2710{
2711 FunctionObject::init();
2712 this->metaObject = metaObject;
2713 constructors = nullptr;
2714 constructorCount = 0;
2715}
2716
2717void Heap::QMetaObjectWrapper::destroy()
2718{
2719 delete[] constructors;
2720}
2721
2722void Heap::QMetaObjectWrapper::ensureConstructorsCache() {
2723
2724 const int count = metaObject->constructorCount();
2725 if (constructorCount != count) {
2726 delete[] constructors;
2727 constructorCount = count;
2728 if (count == 0) {
2729 constructors = nullptr;
2730 return;
2731 }
2733
2734 for (int i = 0; i < count; ++i) {
2735 QMetaMethod method = metaObject->constructor(i);
2737 d.load(method);
2738 d.setCoreIndex(i);
2739 }
2740 }
2741}
2742
2743
2744ReturnedValue QMetaObjectWrapper::create(ExecutionEngine *engine, const QMetaObject* metaObject) {
2745
2746 Scope scope(engine);
2748 mo->init(engine);
2749 return mo->asReturnedValue();
2750}
2751
2752void QMetaObjectWrapper::init(ExecutionEngine *) {
2753 const QMetaObject & mo = *d()->metaObject;
2754
2755 for (int i = 0; i < mo.enumeratorCount(); i++) {
2756 QMetaEnum Enum = mo.enumerator(i);
2757 for (int k = 0; k < Enum.keyCount(); k++) {
2758 const char* key = Enum.key(k);
2759 const int value = Enum.value(k);
2760 defineReadonlyProperty(QLatin1String(key), Value::fromInt32(value));
2761 }
2762 }
2763}
2764
2765ReturnedValue QMetaObjectWrapper::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *)
2766{
2767 const QMetaObjectWrapper *This = static_cast<const QMetaObjectWrapper*>(f);
2768 return This->constructInternal(argv, argc);
2769}
2770
2771ReturnedValue QMetaObjectWrapper::constructInternal(const Value *argv, int argc) const
2772{
2773
2774 d()->ensureConstructorsCache();
2775
2776 ExecutionEngine *v4 = engine();
2777 const QMetaObject* mo = d()->metaObject;
2778 if (d()->constructorCount == 0) {
2779 return v4->throwTypeError(QLatin1String(mo->className())
2780 + QLatin1String(" has no invokable constructor"));
2781 }
2782
2783 Scope scope(v4);
2784 Scoped<QObjectWrapper> object(scope);
2785 JSCallData cData(nullptr, argv, argc);
2786 CallData *callData = cData.callData(scope);
2787
2788 const QQmlObjectOrGadget objectOrGadget(mo);
2789
2790 if (d()->constructorCount == 1) {
2791 object = CallPrecise(objectOrGadget, d()->constructors[0], v4, callData, QMetaObject::CreateInstance);
2792 } else if (const QQmlPropertyData *ctor = ResolveOverloaded(
2793 objectOrGadget, d()->constructors, d()->constructorCount, v4, callData)) {
2794 object = CallPrecise(objectOrGadget, *ctor, v4, callData, QMetaObject::CreateInstance);
2795 }
2796 if (object) {
2797 Scoped<QMetaObjectWrapper> metaObject(scope, this);
2798 object->defineDefaultProperty(v4->id_constructor(), metaObject);
2799 object->setPrototypeOf(const_cast<QMetaObjectWrapper*>(this));
2800 }
2801 return object.asReturnedValue();
2802
2803}
2804
2805bool QMetaObjectWrapper::virtualIsEqualTo(Managed *a, Managed *b)
2806{
2807 const QMetaObjectWrapper *aMetaObject = a->as<QMetaObjectWrapper>();
2808 Q_ASSERT(aMetaObject);
2809 const QMetaObjectWrapper *bMetaObject = b->as<QMetaObjectWrapper>();
2810 return bMetaObject && aMetaObject->metaObject() == bMetaObject->metaObject();
2811}
2812
2814
2815
2816void Heap::QmlSignalHandler::init(QObject *object, int signalIndex)
2817{
2818 Object::init();
2819 this->signalIndex = signalIndex;
2820 setObject(object);
2821}
2822
2824
2825void QmlSignalHandler::initProto(ExecutionEngine *engine)
2826{
2827 if (engine->signalHandlerPrototype()->d_unchecked())
2828 return;
2829
2830 Scope scope(engine);
2831 ScopedObject o(scope, engine->newObject());
2832 ScopedString connect(scope, engine->newIdentifier(QStringLiteral("connect")));
2833 ScopedString disconnect(scope, engine->newIdentifier(QStringLiteral("disconnect")));
2834 o->put(connect, ScopedValue(scope, engine->functionPrototype()->get(connect)));
2835 o->put(disconnect, ScopedValue(scope, engine->functionPrototype()->get(disconnect)));
2836
2837 engine->jsObjects[ExecutionEngine::SignalHandlerProto] = o->d();
2838}
2839
2840
2841MultiplyWrappedQObjectMap::Iterator MultiplyWrappedQObjectMap::erase(
2843{
2844 const QObjectBiPointer key = it.key();
2845 const QObject *obj = key.isT1() ? key.asT1() : key.asT2();
2846 disconnect(obj, &QObject::destroyed, this, &MultiplyWrappedQObjectMap::removeDestroyedObject);
2848}
2849
2850void MultiplyWrappedQObjectMap::removeDestroyedObject(QObject *object)
2851{
2853 QHash<QObjectBiPointer, WeakValue>::remove(static_cast<const QObject *>(object));
2854}
2855
2856} // namespace QV4
2857
2859
2860#include "moc_qv4qobjectwrapper_p.cpp"
static JNINativeMethod methods[]
Definition main.cpp:8
\inmodule QtCore
Definition qbytearray.h:57
\inmodule QtCore
\inmodule QtCore
Definition qhash.h:1093
bool remove(const Key &key)
Removes the item that has the key from the hash.
Definition qhash.h:956
iterator erase(const_iterator it)
Definition qhash.h:1223
void throwError(const QString &message)
Throws a run-time error (exception) with the given message.
QJSValue newObject()
Creates a JavaScript object of class Object.
T fromVariant(const QVariant &value)
Returns the given value converted to the template type {T}.
Definition qjsengine.h:115
static QJSValue fromReturnedValue(QV4::ReturnedValue d)
Definition qjsvalue_p.h:189
static QV4::ReturnedValue asReturnedValue(const QJSValue *jsval)
Definition qjsvalue_p.h:249
static QV4::ReturnedValue convertToReturnedValue(QV4::ExecutionEngine *e, const QJSValue &jsval)
Definition qjsvalue_p.h:298
static void setValue(QJSValue *jsval, const QV4::Value &v)
Definition qjsvalue_p.h:282
static void manageStringOnV4Heap(QV4::ExecutionEngine *e, QJSValue *jsval)
Definition qjsvalue_p.h:288
The QJSValue class acts as a container for Qt/JavaScript data types.
Definition qjsvalue.h:31
\inmodule QtCore\reentrant
Definition qjsonarray.h:18
\inmodule QtCore\reentrant
Definition qjsonobject.h:20
\inmodule QtCore\reentrant
Definition qjsonvalue.h:24
Definition qlist.h:74
qsizetype size() const noexcept
Definition qlist.h:386
const_reference at(qsizetype i) const noexcept
Definition qlist.h:429
void append(parameter_type t)
Definition qlist.h:441
\inmodule QtCore
Definition qlogging.h:68
void void Q_DECL_COLD_FUNCTION void warning(const char *msg,...) const Q_ATTRIBUTE_FORMAT_PRINTF(2
Logs a warning message specified with format msg.
Definition qlogging.cpp:648
\inmodule QtCore
int value(int index) const
Returns the value with the given index; or returns -1 if there is no such value.
const char * key(int index) const
Returns the key with the given index, or \nullptr if no such key exists.
int keyCount() const
Returns the number of keys.
\inmodule QtCore
Definition qmetaobject.h:18
\inmodule QtCore
\inmodule QtCore
Definition qmetatype.h:320
static constexpr QMetaType fromType()
Definition qmetatype.h:2612
static bool canConvert(QMetaType fromType, QMetaType toType)
Returns true if QMetaType::convert can convert from fromType to toType.
constexpr TypeFlags flags() const
Definition qmetatype.h:2628
QMetaType underlyingType() const
bool isValid() const
int id(int=0) const
Definition qmetatype.h:454
@ PointerToQObject
Definition qmetatype.h:385
@ PointerToGadget
Definition qmetatype.h:392
constexpr const QMetaObject * metaObject() const
Definition qmetatype.h:2633
constexpr const char * name() const
Definition qmetatype.h:2650
static bool convert(QMetaType fromType, const void *from, QMetaType toType, void *to)
Converts the object at from from fromType to the preallocated space at to typed toType.
friend class QVariant
Definition qmetatype.h:775
static QMetaObject::Connection connect(const typename QtPrivate::FunctionPointer< Func1 >::Object *sender, Func1 signal, const typename QtPrivate::FunctionPointer< Func2 >::Object *receiverPrivate, Func2 slot, Qt::ConnectionType type=Qt::AutoConnection)
Definition qobject_p.h:298
static bool disconnect(const typename QtPrivate::FunctionPointer< Func1 >::Object *sender, Func1 signal, const typename QtPrivate::FunctionPointer< Func2 >::Object *receiverPrivate, Func2 slot)
Definition qobject_p.h:327
\inmodule QtCore
Definition qobject.h:90
void destroyed(QObject *=nullptr)
This signal is emitted immediately before the object obj is destroyed, after any instances of QPointe...
void setTarget(const QQmlProperty &)
void setBoundFunction(QV4::BoundFunction *boundFunction)
void setSourceLocation(const QQmlSourceLocation &location)
static QQmlBinding * create(const QQmlPropertyData *, const QQmlScriptString &, QObject *, QQmlContext *)
quint32 hasConstWrapper
Definition qqmldata_p.h:109
static void flushPendingBinding(QObject *object, int coreIndex)
Definition qqmldata_p.h:393
QV4::WeakValue jsWrapper
Definition qqmldata_p.h:193
static QQmlPropertyCache::ConstPtr ensurePropertyCache(QObject *object)
Definition qqmldata_p.h:252
QQmlPropertyCache::ConstPtr propertyCache
Definition qqmldata_p.h:195
quint32 hasTaintedV4Object
Definition qqmldata_p.h:98
static bool keepAliveDuringGarbageCollection(const QObject *object)
Definition qqmldata_p.h:233
QQmlRefPointer< QQmlContextData > ownContext
Definition qqmldata_p.h:150
void disconnectNotifiers()
QQmlContextData * context
Definition qqmldata_p.h:147
static bool wasDeleted(const QObject *)
Definition qqmldata_p.h:312
static QQmlData * get(QObjectPrivate *priv, bool create)
Definition qqmldata_p.h:199
void setImplicitDestructible()
Definition qqmldata_p.h:81
quint32 isQueuedForDeletion
Definition qqmldata_p.h:99
quint32 jsEngineId
Definition qqmldata_p.h:171
quint32 indestructible
Definition qqmldata_p.h:92
QQmlPropertyCapture * propertyCapture
void warning(const QQmlError &)
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
virtual bool mustCaptureBindableProperty() const
bool methodParameterTypes(int index, ArgTypeStorage *argStorage, QByteArray *unknownTypeError) const
static QQmlType qmlListType(QMetaType metaType)
static const QMetaObject * metaObjectForValueType(QMetaType type)
static bool isValueType(QMetaType type)
static QUntypedPropertyBinding createFromBoundFunction(const QQmlPropertyData *pd, QV4::BoundFunction *function, QObject *obj, const QQmlRefPointer< QQmlContextData > &ctxt, QV4::ExecutionContext *scope, QObject *target, QQmlPropertyIndex targetIndex)
static QUntypedPropertyBinding create(const QQmlPropertyData *pd, QV4::Function *function, QObject *obj, const QQmlRefPointer< QQmlContextData > &ctxt, QV4::ExecutionContext *scope, QObject *target, QQmlPropertyIndex targetIndex)
const QQmlPropertyData * property(const K &key, QObject *object, const QQmlRefPointer< QQmlContextData > &context) const
QQmlJavaScriptExpression * expression
void captureProperty(QQmlNotifier *)
bool isConstructor() const
bool isVarProperty() const
bool hasArguments() const
QMetaType propType() const
bool isV4Function() const
void load(const QMetaProperty &)
static void setBinding(QQmlAbstractBinding *binding, BindingFlags flags=None, QQmlPropertyData::WriteFlags writeFlags=QQmlPropertyData::DontRemoveBinding)
static void findAliasTarget(QObject *, QQmlPropertyIndex, QObject **, QQmlPropertyIndex *)
static void removeBinding(const QQmlProperty &that)
static bool write(QObject *, const QQmlPropertyData &, const QVariant &, const QQmlRefPointer< QQmlContextData > &, QQmlPropertyData::WriteFlags flags={})
static void flushSignal(const QObject *sender, int signal_index)
static QQmlAbstractBinding * binding(QObject *, QQmlPropertyIndex index)
T * data() const
void reset(T *t=nullptr)
The QQmlScriptString class encapsulates a script and its context.
bool isSequentialContainer() const
Definition qqmltype.cpp:638
QMetaSequence listMetaSequence() const
Definition qqmltype.cpp:653
QV4::ReturnedValue vmeMethod(int index) const
void mark(QV4::MarkStack *markStack)
QV4::ReturnedValue vmeProperty(int index) const
static QQmlVMEMetaObject * get(QObject *o)
void setVMEProperty(int index, const QV4::Value &v)
\inmodule QtCore
Definition qqueue.h:14
Definition qset.h:18
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5710
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5857
QString arg(qlonglong a, int fieldwidth=0, int base=10, QChar fillChar=u' ') const
Definition qstring.cpp:8606
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:1083
static QString number(int, int base=10)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:7822
bool singleShot
whether the timer is a single-shot timer
Definition qtimer.h:22
\inmodule QtCore
Definition qproperty.h:677
bool setBinding(const QUntypedPropertyBinding &binding)
Sets the underlying property's binding to binding.
Definition qproperty.h:766
ObjectType::Data * allocate(Args &&... args)
Definition qv4mm_p.h:199
ExecutionEngine * engine() const
ReturnedValue value() const
void set(ExecutionEngine *engine, const Value &value)
bool isUndefined() const
void markOnce(MarkStack *markStack)
void set(ExecutionEngine *engine, const Value &value)
constexpr size_type size() const noexcept
const T & at(qsizetype idx) const
void append(const T &t)
T * data() noexcept
\inmodule QtCore
Definition qvariant.h:64
EGLContext ctx
object setProperty("down", true)
QCache< int, Employee > cache
[0]
QSet< QString >::iterator it
auto signalIndex
auto mo
[7]
short next
Definition keywords.cpp:445
Combined button and popup list for selecting options.
\qmltype Particle \inqmlmodule QtQuick.Particles
static int MatchScore(const Value &actual, QMetaType conversionMetaType)
static ReturnedValue CallPrecise(const QQmlObjectOrGadget &object, const QQmlPropertyData &data, ExecutionEngine *engine, CallData *callArgs, QMetaObject::Call callType=QMetaObject::InvokeMetaMethod)
static const QQmlPropertyData * ResolveOverloaded(const QQmlObjectOrGadget &object, const QQmlPropertyData *methods, int methodCount, ExecutionEngine *engine, CallData *callArgs)
static QPair< QObject *, int > extractQtSignal(const Value &value)
static ReturnedValue CallMethod(const QQmlObjectOrGadget &object, int index, QMetaType returnType, int argCount, const QMetaType *argTypes, ExecutionEngine *engine, CallData *callArgs, QMetaObject::Call callType=QMetaObject::InvokeMetaMethod)
quint64 ReturnedValue
static ReturnedValue loadProperty(ExecutionEngine *v4, Heap::Object *wrapper, QObject *object, const QQmlPropertyData &property)
static void markChildQObjectsRecursively(QObject *parent, MarkStack *markStack)
void setupQObjectLookup(Lookup *lookup, const QQmlData *ddata, const QQmlPropertyData *propertyData)
Scoped< Object > ScopedObject
void setupQObjectMethodLookup(Lookup *lookup, const QQmlData *ddata, const QQmlPropertyData *propertyData, const Object *self, Heap::QObjectMethod *method)
Scoped< ArrayObject > ScopedArrayObject
int MatchVariant(QMetaType conversionMetaType, Retrieve &&retrieve)
@ Attr_Data
static OptionalReturnedValue getDestroyOrToStringMethod(ExecutionEngine *v4, String *name, Heap::Object *qobj, bool *hasProperty=nullptr)
static Heap::ReferenceObject::Flags referenceFlags(ExecutionEngine *v4, const QQmlPropertyData &property)
static OptionalReturnedValue getPropertyFromImports(ExecutionEngine *v4, String *name, const QQmlRefPointer< QQmlContextData > &qmlContext, QObject *qobj, bool *hasProperty=nullptr)
static int numDefinedArguments(CallData *callArgs)
\macro QT_NAMESPACE
@ AutoConnection
QString boolValue(bool v)
Definition language.cpp:456
static void * context
#define Q_UNLIKELY(x)
#define QT_WARNING_DISABLE_GCC(text)
std::pair< T1, T2 > QPair
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction function
DBusConnection const char DBusError * error
DBusConnection * connection
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
static QString methodName(const QDBusIntrospection::Method &method)
static struct AttrInfo attrs[]
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
Flags
#define Size(name)
@ QtWarningMsg
Definition qlogging.h:31
#define qWarning
Definition qlogging.h:162
#define Q_LOGGING_CATEGORY(name,...)
#define qCInfo(category,...)
#define qCWarning(category,...)
#define qCDebug(category,...)
return ret
static ControlElement< T > * ptr(QWidget *widget)
@ Invalid
constexpr int qMetaTypeId()
Definition qmetatype.h:1384
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
#define SLOT(a)
Definition qobjectdefs.h:51
GLboolean GLboolean GLboolean b
GLsizei const GLfloat * v
[13]
GLenum mode
const GLfloat * m
GLuint64 key
GLfloat GLfloat GLfloat w
[0]
GLboolean GLboolean GLboolean GLboolean a
[7]
GLuint index
[2]
GLboolean r
[2]
GLenum GLuint GLenum GLsizei length
GLenum GLenum GLsizei count
GLuint object
[3]
GLfloat GLfloat f
GLenum type
GLenum target
GLbitfield flags
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLint ref
GLuint name
GLfloat n
GLfloat GLfloat GLfloat GLfloat h
GLhandleARB obj
[2]
GLenum func
Definition qopenglext.h:663
GLenum array
GLuint64EXT * result
[6]
GLfloat GLfloat p
[1]
constexpr decltype(auto) qMakePair(T1 &&value1, T2 &&value2) noexcept(noexcept(std::make_pair(std::forward< T1 >(value1), std::forward< T2 >(value2))))
Definition qpair.h:19
QQmlEngine * qmlEngine(const QObject *obj)
Definition qqml.cpp:76
QQmlContext * qmlContext(const QObject *obj)
Definition qqml.cpp:71
bool qmlobject_can_cpp_cast(QObject *object, const QMetaObject *mo)
#define X(name)
static QCborArray constructors(const QCborMap *classDef, QLatin1StringView key, QTypeRevision maxMajorVersion)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define M(_x, _y)
SSL_CTX int(*) void arg)
static QT_BEGIN_NAMESPACE QAsn1Element wrap(quint8 type, const QAsn1Element &child)
#define qPrintable(string)
Definition qstring.h:1391
QLatin1StringView QLatin1String
Definition qstringfwd.h:31
#define QStringLiteral(str)
#define Q_UNUSED(x)
unsigned int quint32
Definition qtypes.h:45
size_t quintptr
Definition qtypes.h:72
unsigned int uint
Definition qtypes.h:29
long long qint64
Definition qtypes.h:55
double qreal
Definition qtypes.h:92
#define PROPERTY_STORE(cpptype, value)
#define RETURN_UNDEFINED()
#define THROW_GENERIC_ERROR(str)
#define DEFINE_OBJECT_VTABLE(classname)
const char property[13]
Definition qwizard.cpp:101
QList< int > list
[14]
QStorageInfo storage
[1]
connect(quitButton, &QPushButton::clicked, &app, &QCoreApplication::quit, Qt::QueuedConnection)
obj metaObject() -> className()
myObject disconnect()
[26]
QQueue< int > queue
[0]
QLayoutItem * child
[0]
QFrame frame
[0]
view create()
QJSValueList args
QJSValue global
QJSEngine engine
[0]
\inmodule QtCore \reentrant
Definition qchar.h:17
static const QMetaObjectPrivate * get(const QMetaObject *metaobject)
\inmodule QtCore
static int metacall(QObject *, Call, int, void **)
struct QMetaObject::Data d
bool inherits(const QMetaObject *metaObject) const noexcept
Returns true if the class described by this QMetaObject inherits the type described by metaObject; ot...
StaticValue args[1]
int argc() const
MemoryManager * memoryManager
CppStackFrame * currentStackFrame
ExecutionContext * rootContext() const
QQmlRefPointer< QQmlContextData > callingQmlContext() const
Heap::String * newString(const QString &s=QString())
QQmlError catchExceptionAsQmlError()
String * id_constructor() const
ReturnedValue throwError(const Value &value)
QV4::ReturnedValue fromVariant(const QVariant &)
String * id_destroy() const
String * id_toString() const
QQmlEngine * qmlEngine() const
ReturnedValue throwTypeError()
ReturnedValue asReturnedValue() const
Definition qv4value_p.h:339
CallData * callData(const Scope &scope, const FunctionObject *f=nullptr) const
Definition qv4jscall_p.h:89
ReturnedValue(* getter)(Lookup *l, ExecutionEngine *engine, const Value &object)
Definition qv4lookup_p.h:36
Heap::InternalClass * internalClass() const
ExecutionEngine * engine() const
ExecutionEngine * engine() const
const QMetaObject * metaObject() const
ReturnedValue callInternal(const Value *thisObject, const Value *argv, int argc) const
static void impl(int which, QSlotObjectBase *this_, QObject *receiver, void **metaArgs, bool *ret)
~QObjectWrapperOwnPropertyKeyIterator() override=default
static const QQmlPropertyData * findProperty(QObject *o, const QQmlRefPointer< QQmlContextData > &qmlContext, String *name, Flags flags, QQmlPropertyData *local)
ReturnedValue getQmlProperty(const QQmlRefPointer< QQmlContextData > &qmlContext, String *name, Flags flags, bool *hasProperty=nullptr) const
static ReturnedValue getProperty(ExecutionEngine *engine, Heap::Object *wrapper, QObject *object, const QQmlPropertyData *property, Flags flags)
QObject * object() const
static bool readReference(HeapObject *ref)
bool hasException() const
ExecutionEngine * engine
static ReturnedValue newSequence(QV4::ExecutionEngine *engine, QMetaType type, QMetaSequence metaSequence, const void *data, Heap::Object *object, int propertyIndex, Heap::ReferenceObject::Flags flags)
static void * getRawContainerPtr(const Sequence *object, QMetaType typeHint)
bool isNumber() const
const Value & asValue() const
constexpr ReturnedValue asReturnedValue() const
bool isBoolean() const
bool isUndefined() const
bool isString() const
Definition qv4value_p.h:284
const T * as() const
Definition qv4value_p.h:132
QString toQStringNoThrow() const
Definition qv4value.cpp:122
bool isObject() const
Definition qv4value_p.h:302
void wrapper()
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent
virtual HRESULT STDMETHODCALLTYPE Compare(__RPC__in_opt ITextRangeProvider *range, __RPC__out BOOL *pRetVal)=0