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
4#include "qqmltypewrapper_p.h"
5
6#include <private/qqmlengine_p.h>
7#include <private/qqmlcontext_p.h>
8#include <private/qqmlmetaobject_p.h>
9#include <private/qqmltypedata_p.h>
10#include <private/qqmlvaluetypewrapper_p.h>
11
12#include <private/qjsvalue_p.h>
13#include <private/qv4functionobject_p.h>
14#include <private/qv4objectproto_p.h>
15#include <private/qv4qobjectwrapper_p.h>
16#include <private/qv4identifiertable_p.h>
17#include <private/qv4lookup_p.h>
18
19QT_BEGIN_NAMESPACE
20
21using namespace QV4;
22
23DEFINE_OBJECT_VTABLE(QQmlTypeWrapper);
24DEFINE_OBJECT_VTABLE(QQmlScopedEnumWrapper);
25
26void Heap::QQmlTypeWrapper::init()
27{
28 Object::init();
29 mode = IncludeEnums;
30 object.init();
31}
32
33void Heap::QQmlTypeWrapper::destroy()
34{
35 QQmlType::derefHandle(priv: typePrivate);
36 typePrivate = nullptr;
37 if (typeNamespace)
38 typeNamespace->release();
39 object.destroy();
40 Object::destroy();
41}
42
43QQmlType Heap::QQmlTypeWrapper::type() const
44{
45 return QQmlType(typePrivate);
46}
47
48bool QQmlTypeWrapper::isSingleton() const
49{
50 return d()->type().isSingleton();
51}
52
53const QMetaObject *QQmlTypeWrapper::metaObject() const
54{
55 const QQmlType type = d()->type();
56 if (!type.isValid())
57 return nullptr;
58
59 if (type.isSingleton())
60 return type.metaObject();
61
62 return type.attachedPropertiesType(engine: QQmlEnginePrivate::get(e: engine()->qmlEngine()));
63}
64
65QObject *QQmlTypeWrapper::object() const
66{
67 const QQmlType type = d()->type();
68 if (!type.isValid())
69 return nullptr;
70
71 QQmlEnginePrivate *qmlEngine = QQmlEnginePrivate::get(e: engine()->qmlEngine());
72 if (type.isSingleton())
73 return qmlEngine->singletonInstance<QObject *>(type);
74
75 return qmlAttachedPropertiesObject(
76 d()->object,
77 func: type.attachedPropertiesFunction(engine: qmlEngine));
78}
79
80QObject* QQmlTypeWrapper::singletonObject() const
81{
82 if (!isSingleton())
83 return nullptr;
84
85 QQmlEnginePrivate *e = QQmlEnginePrivate::get(e: engine()->qmlEngine());
86 return e->singletonInstance<QObject*>(type: d()->type());
87}
88
89QVariant QQmlTypeWrapper::toVariant() const
90{
91 QQmlEnginePrivate *e = QQmlEnginePrivate::get(e: engine()->qmlEngine());
92 const QQmlType type = d()->type();
93
94 if (!isSingleton()) {
95 return QVariant::fromValue(value: qmlAttachedPropertiesObject(
96 d()->object, func: type.attachedPropertiesFunction(engine: e)));
97 }
98
99 if (type.isQJSValueSingleton())
100 return QVariant::fromValue<QJSValue>(value: e->singletonInstance<QJSValue>(type));
101
102 return QVariant::fromValue<QObject*>(value: e->singletonInstance<QObject*>(type));
103}
104
105
106// Returns a type wrapper for type t on o. This allows access of enums, and attached properties.
107ReturnedValue QQmlTypeWrapper::create(QV4::ExecutionEngine *engine, QObject *o, const QQmlType &t,
108 Heap::QQmlTypeWrapper::TypeNameMode mode)
109{
110 Q_ASSERT(t.isValid());
111 Scope scope(engine);
112
113 Scoped<QQmlTypeWrapper> w(scope, engine->memoryManager->allocate<QQmlTypeWrapper>());
114 w->d()->mode = mode; w->d()->object = o;
115 w->d()->typePrivate = t.priv();
116 QQmlType::refHandle(priv: w->d()->typePrivate);
117 return w.asReturnedValue();
118}
119
120// Returns a type wrapper for importNamespace (of t) on o. This allows nested resolution of a type in a
121// namespace.
122ReturnedValue QQmlTypeWrapper::create(QV4::ExecutionEngine *engine, QObject *o, const QQmlRefPointer<QQmlTypeNameCache> &t, const QQmlImportRef *importNamespace,
123 Heap::QQmlTypeWrapper::TypeNameMode mode)
124{
125 Q_ASSERT(t);
126 Q_ASSERT(importNamespace);
127 Scope scope(engine);
128
129 Scoped<QQmlTypeWrapper> w(scope, engine->memoryManager->allocate<QQmlTypeWrapper>());
130 w->d()->mode = mode; w->d()->object = o; w->d()->typeNamespace = t.data(); w->d()->importNamespace = importNamespace;
131 t->addref();
132 return w.asReturnedValue();
133}
134
135static int enumForSingleton(QV4::ExecutionEngine *v4, String *name, QObject *qobjectSingleton,
136 const QQmlType &type, bool *ok)
137{
138 Q_ASSERT(ok != nullptr);
139 int value = type.enumValue(engine: QQmlEnginePrivate::get(e: v4->qmlEngine()), name, ok);
140 if (*ok)
141 return value;
142
143 // ### Optimize
144 QByteArray enumName = name->toQString().toUtf8();
145 const QMetaObject *metaObject = qobjectSingleton->metaObject();
146 for (int ii = metaObject->enumeratorCount() - 1; ii >= 0; --ii) {
147 QMetaEnum e = metaObject->enumerator(index: ii);
148 value = e.keyToValue(key: enumName.constData(), ok);
149 if (*ok)
150 return value;
151 }
152 *ok = false;
153 return -1;
154}
155
156ReturnedValue QQmlTypeWrapper::virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty)
157{
158 // Keep this code in sync with ::virtualResolveLookupGetter
159 Q_ASSERT(m->as<QQmlTypeWrapper>());
160
161 if (!id.isString())
162 return Object::virtualGet(m, id, receiver, hasProperty);
163
164 QV4::ExecutionEngine *v4 = static_cast<const QQmlTypeWrapper *>(m)->engine();
165 QV4::Scope scope(v4);
166 ScopedString name(scope, id.asStringOrSymbol());
167
168 Scoped<QQmlTypeWrapper> w(scope, static_cast<const QQmlTypeWrapper *>(m));
169
170 if (hasProperty)
171 *hasProperty = true;
172
173 QQmlRefPointer<QQmlContextData> context = v4->callingQmlContext();
174
175 QObject *object = w->d()->object;
176 QQmlType type = w->d()->type();
177
178 if (type.isValid()) {
179
180 // singleton types are handled differently to other types.
181 if (type.isSingleton()) {
182 QQmlEnginePrivate *e = QQmlEnginePrivate::get(e: v4->qmlEngine());
183 QJSValue scriptSingleton;
184 if (type.isQObjectSingleton() || type.isCompositeSingleton()) {
185 if (QObject *qobjectSingleton = e->singletonInstance<QObject*>(type)) {
186 // check for enum value
187 const bool includeEnums = w->d()->mode == Heap::QQmlTypeWrapper::IncludeEnums;
188 if (includeEnums && name->startsWithUpper()) {
189 bool ok = false;
190 int value = enumForSingleton(v4, name, qobjectSingleton, type, ok: &ok);
191 if (ok)
192 return QV4::Value::fromInt32(i: value).asReturnedValue();
193
194 value = type.scopedEnumIndex(engine: QQmlEnginePrivate::get(e: v4->qmlEngine()), name, ok: &ok);
195 if (ok) {
196 Scoped<QQmlScopedEnumWrapper> enumWrapper(scope, v4->memoryManager->allocate<QQmlScopedEnumWrapper>());
197 enumWrapper->d()->typePrivate = type.priv();
198 QQmlType::refHandle(priv: enumWrapper->d()->typePrivate);
199 enumWrapper->d()->scopeEnumIndex = value;
200 return enumWrapper.asReturnedValue();
201 }
202 }
203
204 // check for property.
205 bool ok;
206 const ReturnedValue result = QV4::QObjectWrapper::getQmlProperty(
207 engine: v4, qmlContext: context, wrapper: w->d(), object: qobjectSingleton, name,
208 flags: QV4::QObjectWrapper::AttachMethods, hasProperty: &ok);
209 if (hasProperty)
210 *hasProperty = ok;
211
212 return result;
213 }
214 } else if (type.isQJSValueSingleton()) {
215 QJSValue scriptSingleton = e->singletonInstance<QJSValue>(type);
216 if (!scriptSingleton.isUndefined()) {
217 // NOTE: if used in a binding, changes will not trigger re-evaluation since non-NOTIFYable.
218 QV4::ScopedObject o(scope, QJSValuePrivate::asReturnedValue(jsval: &scriptSingleton));
219 if (!!o)
220 return o->get(name);
221 }
222 }
223
224 // Fall through to base implementation
225
226 } else {
227
228 if (name->startsWithUpper()) {
229 bool ok = false;
230 int value = type.enumValue(engine: QQmlEnginePrivate::get(e: v4->qmlEngine()), name, ok: &ok);
231 if (ok)
232 return QV4::Value::fromInt32(i: value).asReturnedValue();
233
234 value = type.scopedEnumIndex(engine: QQmlEnginePrivate::get(e: v4->qmlEngine()), name, ok: &ok);
235 if (ok) {
236 Scoped<QQmlScopedEnumWrapper> enumWrapper(scope, v4->memoryManager->allocate<QQmlScopedEnumWrapper>());
237 enumWrapper->d()->typePrivate = type.priv();
238 QQmlType::refHandle(priv: enumWrapper->d()->typePrivate);
239 enumWrapper->d()->scopeEnumIndex = value;
240 return enumWrapper.asReturnedValue();
241 }
242
243 // Fall through to base implementation
244
245 } else if (w->d()->object) {
246 QObject *ao = qmlAttachedPropertiesObject(
247 object,
248 func: type.attachedPropertiesFunction(engine: QQmlEnginePrivate::get(e: v4->qmlEngine())));
249 if (ao)
250 return QV4::QObjectWrapper::getQmlProperty(
251 engine: v4, qmlContext: context, wrapper: w->d(), object: ao, name, flags: QV4::QObjectWrapper::AttachMethods,
252 hasProperty);
253
254 // Fall through to base implementation
255 }
256
257 // Fall through to base implementation
258 }
259
260 // Fall through to base implementation
261
262 } else if (w->d()->typeNamespace) {
263 Q_ASSERT(w->d()->importNamespace);
264 QQmlTypeNameCache::Result r = w->d()->typeNamespace->query(key: name, importNamespace: w->d()->importNamespace);
265
266 if (r.isValid()) {
267 if (r.type.isValid()) {
268 return create(engine: scope.engine, o: object, t: r.type, mode: w->d()->mode);
269 } else if (r.scriptIndex != -1) {
270 QV4::ScopedObject scripts(scope, context->importedScripts().valueRef());
271 return scripts->get(idx: r.scriptIndex);
272 } else if (r.importNamespace) {
273 return create(engine: scope.engine, o: object, t: context->imports(), importNamespace: r.importNamespace);
274 }
275
276 return QV4::Encode::undefined();
277
278 }
279
280 // Fall through to base implementation
281
282 } else {
283 Q_ASSERT(!"Unreachable");
284 }
285
286 bool ok = false;
287 const ReturnedValue result = Object::virtualGet(m, id, receiver, hasProperty: &ok);
288 if (hasProperty)
289 *hasProperty = ok;
290
291 return result;
292}
293
294
295bool QQmlTypeWrapper::virtualPut(Managed *m, PropertyKey id, const Value &value, Value *receiver)
296{
297 if (!id.isString())
298 return Object::virtualPut(m, id, value, receiver);
299
300
301 Q_ASSERT(m->as<QQmlTypeWrapper>());
302 QQmlTypeWrapper *w = static_cast<QQmlTypeWrapper *>(m);
303 QV4::Scope scope(w);
304 if (scope.hasException())
305 return false;
306
307 ScopedString name(scope, id.asStringOrSymbol());
308 QQmlRefPointer<QQmlContextData> context = scope.engine->callingQmlContext();
309
310 QQmlType type = w->d()->type();
311 if (type.isValid() && !type.isSingleton() && w->d()->object) {
312 QObject *object = w->d()->object;
313 QQmlEngine *e = scope.engine->qmlEngine();
314 QObject *ao = qmlAttachedPropertiesObject(
315 object, func: type.attachedPropertiesFunction(engine: QQmlEnginePrivate::get(e)));
316 if (ao)
317 return QV4::QObjectWrapper::setQmlProperty(
318 engine: scope.engine, qmlContext: context, object: ao, name, flags: QV4::QObjectWrapper::NoFlag, value);
319 return false;
320 } else if (type.isSingleton()) {
321 QQmlEnginePrivate *e = QQmlEnginePrivate::get(e: scope.engine->qmlEngine());
322 if (type.isQObjectSingleton() || type.isCompositeSingleton()) {
323 if (QObject *qobjectSingleton = e->singletonInstance<QObject*>(type))
324 return QV4::QObjectWrapper::setQmlProperty(
325 engine: scope.engine, qmlContext: context, object: qobjectSingleton, name,
326 flags: QV4::QObjectWrapper::NoFlag, value);
327
328 } else {
329 QJSValue scriptSingleton = e->singletonInstance<QJSValue>(type);
330 if (!scriptSingleton.isUndefined()) {
331 QV4::ScopedObject apiprivate(scope, QJSValuePrivate::asReturnedValue(jsval: &scriptSingleton));
332 if (!apiprivate) {
333 QString error = QLatin1String("Cannot assign to read-only property \"") + name->toQString() + QLatin1Char('\"');
334 scope.engine->throwError(message: error);
335 return false;
336 } else {
337 return apiprivate->put(name, v: value);
338 }
339 }
340 }
341 }
342
343 return false;
344}
345
346PropertyAttributes QQmlTypeWrapper::virtualGetOwnProperty(const Managed *m, PropertyKey id, Property *p)
347{
348 if (id.isString()) {
349 Scope scope(m);
350 ScopedString n(scope, id.asStringOrSymbol());
351 // ### Implement more efficiently.
352 bool hasProperty = false;
353 static_cast<const Object *>(m)->get(name: n, hasProperty: &hasProperty);
354 return hasProperty ? Attr_Data : Attr_Invalid;
355 }
356
357 return QV4::Object::virtualGetOwnProperty(m, id, p);
358}
359
360bool QQmlTypeWrapper::virtualIsEqualTo(Managed *a, Managed *b)
361{
362 Q_ASSERT(a->as<QV4::QQmlTypeWrapper>());
363 QV4::QQmlTypeWrapper *qmlTypeWrapperA = static_cast<QV4::QQmlTypeWrapper *>(a);
364 if (QV4::QQmlTypeWrapper *qmlTypeWrapperB = b->as<QV4::QQmlTypeWrapper>())
365 return qmlTypeWrapperA->toVariant() == qmlTypeWrapperB->toVariant();
366 else if (QV4::QObjectWrapper *qobjectWrapper = b->as<QV4::QObjectWrapper>())
367 return qmlTypeWrapperA->toVariant().value<QObject*>() == qobjectWrapper->object();
368
369 return false;
370}
371
372static ReturnedValue instanceOfQObject(const QV4::QQmlTypeWrapper *typeWrapper, const QObjectWrapper *objectWrapper)
373{
374 QV4::ExecutionEngine *engine = typeWrapper->internalClass()->engine;
375 // in case the wrapper outlived the QObject*
376 const QObject *wrapperObject = objectWrapper->object();
377 if (!wrapperObject)
378 return engine->throwTypeError();
379
380 const QMetaType myTypeId = typeWrapper->d()->type().typeId();
381 QQmlMetaObject myQmlType;
382 if (!myTypeId.isValid()) {
383 // we're a composite type; a composite type cannot be equal to a
384 // non-composite object instance (Rectangle{} is never an instance of
385 // CustomRectangle)
386 QQmlData *theirDData = QQmlData::get(object: wrapperObject);
387 Q_ASSERT(theirDData); // must exist, otherwise how do we have a QObjectWrapper for it?!
388 if (!theirDData->compilationUnit)
389 return Encode(false);
390
391 QQmlEnginePrivate *qenginepriv = QQmlEnginePrivate::get(e: engine->qmlEngine());
392 QQmlRefPointer<QQmlTypeData> td = qenginepriv->typeLoader.getType(unNormalizedUrl: typeWrapper->d()->type().sourceUrl());
393 if (ExecutableCompilationUnit *cu = td->compilationUnit())
394 myQmlType = QQmlMetaType::metaObjectForType(metaType: cu->typeIds.id);
395 else
396 return Encode(false); // It seems myQmlType has some errors, so we could not compile it.
397 } else {
398 myQmlType = QQmlMetaType::metaObjectForType(metaType: myTypeId);
399 }
400
401 const QMetaObject *theirType = wrapperObject->metaObject();
402
403 return QV4::Encode(QQmlMetaObject::canConvert(from: theirType, to: myQmlType));
404}
405
406ReturnedValue QQmlTypeWrapper::virtualInstanceOf(const Object *typeObject, const Value &var)
407{
408 Q_ASSERT(typeObject->as<QV4::QQmlTypeWrapper>());
409 const QV4::QQmlTypeWrapper *typeWrapper = static_cast<const QV4::QQmlTypeWrapper *>(typeObject);
410
411 if (const QObjectWrapper *objectWrapper = var.as<QObjectWrapper>())
412 return instanceOfQObject(typeWrapper, objectWrapper);
413
414 if (const QMetaObject *valueTypeMetaObject
415 = QQmlMetaType::metaObjectForValueType(qmlType: typeWrapper->d()->type())) {
416 if (const QQmlValueTypeWrapper *valueWrapper = var.as<QQmlValueTypeWrapper>()) {
417 return QV4::Encode(QQmlMetaObject::canConvert(from: valueWrapper->metaObject(),
418 to: valueTypeMetaObject));
419 }
420
421 // We want "foo as valuetype" to return undefined if it doesn't match.
422 return Encode::undefined();
423 }
424
425 // If the target type is an object type we want null.
426 return Encode(false);
427}
428
429ReturnedValue QQmlTypeWrapper::virtualResolveLookupGetter(const Object *object, ExecutionEngine *engine, Lookup *lookup)
430{
431 // Keep this code in sync with ::virtualGet
432 PropertyKey id = engine->identifierTable->asPropertyKey(str: engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[lookup->nameIndex]);
433 if (!id.isString())
434 return Object::virtualResolveLookupGetter(object, engine, lookup);
435 Scope scope(engine);
436
437 const QQmlTypeWrapper *This = static_cast<const QQmlTypeWrapper *>(object);
438 ScopedString name(scope, id.asStringOrSymbol());
439 QQmlRefPointer<QQmlContextData> qmlContext = engine->callingQmlContext();
440
441 Scoped<QQmlTypeWrapper> w(scope, static_cast<const QQmlTypeWrapper *>(This));
442 QQmlType type = w->d()->type();
443
444 if (type.isValid()) {
445
446 if (type.isSingleton()) {
447 QQmlEnginePrivate *e = QQmlEnginePrivate::get(e: engine->qmlEngine());
448 if (type.isQObjectSingleton() || type.isCompositeSingleton()) {
449 if (QObject *qobjectSingleton = e->singletonInstance<QObject*>(type)) {
450 const bool includeEnums = w->d()->mode == Heap::QQmlTypeWrapper::IncludeEnums;
451 if (!includeEnums || !name->startsWithUpper()) {
452 QQmlData *ddata = QQmlData::get(object: qobjectSingleton, create: false);
453 if (ddata && ddata->propertyCache) {
454 const QQmlPropertyData *property = ddata->propertyCache->property(key: name.getPointer(), object: qobjectSingleton, context: qmlContext);
455 if (property) {
456 ScopedValue val(scope, Value::fromReturnedValue(val: QV4::QObjectWrapper::wrap(engine, object: qobjectSingleton)));
457 if (qualifiesForMethodLookup(propertyData: property)) {
458 setupQObjectMethodLookup(
459 lookup, ddata, propertyData: property, self: val->objectValue(), method: nullptr);
460 lookup->getter = QQmlTypeWrapper::lookupSingletonMethod;
461 } else {
462 setupQObjectLookup(
463 lookup, ddata, propertyData: property, self: val->objectValue(), qmlType: This);
464 lookup->getter = QQmlTypeWrapper::lookupSingletonProperty;
465 }
466 return lookup->getter(lookup, engine, *object);
467 }
468 // Fall through to base implementation
469 }
470 // Fall through to base implementation
471 }
472 // Fall through to base implementation
473 }
474 // Fall through to base implementation
475 }
476 // Fall through to base implementation
477 }
478
479 if (name->startsWithUpper()) {
480 bool ok = false;
481 int value = type.enumValue(engine: QQmlEnginePrivate::get(e: engine->qmlEngine()), name, ok: &ok);
482 if (ok) {
483 lookup->qmlEnumValueLookup.ic = This->internalClass();
484 lookup->qmlEnumValueLookup.encodedEnumValue
485 = QV4::Value::fromInt32(i: value).asReturnedValue();
486 lookup->getter = QQmlTypeWrapper::lookupEnumValue;
487 return lookup->getter(lookup, engine, *object);
488 }
489
490 value = type.scopedEnumIndex(engine: QQmlEnginePrivate::get(e: engine->qmlEngine()), name, ok: &ok);
491 if (ok) {
492 Scoped<QQmlScopedEnumWrapper> enumWrapper(
493 scope, engine->memoryManager->allocate<QQmlScopedEnumWrapper>());
494 enumWrapper->d()->typePrivate = type.priv();
495 QQmlType::refHandle(priv: enumWrapper->d()->typePrivate);
496 enumWrapper->d()->scopeEnumIndex = value;
497
498 lookup->qmlScopedEnumWrapperLookup.ic = This->internalClass();
499 lookup->qmlScopedEnumWrapperLookup.qmlScopedEnumWrapper
500 = static_cast<Heap::Object*>(enumWrapper->heapObject());
501 lookup->getter = QQmlTypeWrapper::lookupScopedEnum;
502 return enumWrapper.asReturnedValue();
503 }
504 // Fall through to base implementation
505 }
506 // Fall through to base implementation
507 }
508 return QV4::Object::virtualResolveLookupGetter(object, engine, lookup);
509}
510
511bool QQmlTypeWrapper::virtualResolveLookupSetter(Object *object, ExecutionEngine *engine, Lookup *lookup, const Value &value)
512{
513 return Object::virtualResolveLookupSetter(object, engine, lookup, value);
514}
515
516OwnPropertyKeyIterator *QQmlTypeWrapper::virtualOwnPropertyKeys(const Object *m, Value *target)
517{
518 QV4::Scope scope(m->engine());
519 QV4::Scoped<QQmlTypeWrapper> typeWrapper(scope, m);
520 Q_ASSERT(typeWrapper);
521 if (QObject *object = typeWrapper->object()) {
522 QV4::Scoped<QV4::QObjectWrapper> objectWrapper(scope, QV4::QObjectWrapper::wrap(engine: typeWrapper->engine(), object));
523 return QV4::QObjectWrapper::virtualOwnPropertyKeys(m: objectWrapper, target);
524 }
525
526 return Object::virtualOwnPropertyKeys(m, target);
527}
528
529int QQmlTypeWrapper::virtualMetacall(Object *object, QMetaObject::Call call, int index, void **a)
530{
531 QQmlTypeWrapper *wrapper = object->as<QQmlTypeWrapper>();
532 Q_ASSERT(wrapper);
533
534 if (QObject *qObject = wrapper->object())
535 return QMetaObject::metacall(qObject, call, index, a);
536
537 return 0;
538}
539
540ReturnedValue QQmlTypeWrapper::lookupSingletonProperty(Lookup *l, ExecutionEngine *engine, const Value &object)
541{
542 const auto revertLookup = [l, engine, &object]() {
543 l->qobjectLookup.propertyCache->release();
544 l->qobjectLookup.propertyCache = nullptr;
545 l->getter = Lookup::getterGeneric;
546 return Lookup::getterGeneric(l, engine, object);
547 };
548
549 // we can safely cast to a QV4::Object here. If object is something else,
550 // the internal class won't match
551 Heap::Object *o = static_cast<Heap::Object *>(object.heapObject());
552
553 // The qmlTypeIc check is not strictly necessary.
554 // If we have different ways to get to the same QObject type
555 // we can use the same lookup to get its properties, no matter
556 // how we've found the object. Most of the few times this check
557 // fails, we will, of course have different object types. So
558 // this check provides an early exit for the error case.
559 //
560 // So, if we ever need more bits in qobjectLookup, qmlTypeIc is the
561 // member to be replaced.
562 if (!o || o->internalClass != l->qobjectLookup.qmlTypeIc)
563 return revertLookup();
564
565 Heap::QQmlTypeWrapper *This = static_cast<Heap::QQmlTypeWrapper *>(o);
566
567 QQmlType type = This->type();
568 if (!type.isValid())
569 return revertLookup();
570
571 if (!type.isQObjectSingleton() && !type.isCompositeSingleton())
572 return revertLookup();
573
574 QQmlEnginePrivate *e = QQmlEnginePrivate::get(e: engine->qmlEngine());
575 QObject *qobjectSingleton = e->singletonInstance<QObject *>(type);
576 Q_ASSERT(qobjectSingleton);
577
578 Scope scope(engine);
579 ScopedValue obj(scope, QV4::QObjectWrapper::wrap(engine, object: qobjectSingleton));
580 const QObjectWrapper::Flags flags = l->forCall
581 ? QObjectWrapper::AllowOverride
582 : (QObjectWrapper::AttachMethods | QObjectWrapper::AllowOverride);
583 return QObjectWrapper::lookupPropertyGetterImpl(lookup: l, engine, object: obj, flags, revertLookup);
584}
585
586ReturnedValue QQmlTypeWrapper::lookupSingletonMethod(Lookup *l, ExecutionEngine *engine, const Value &object)
587{
588 const auto revertLookup = [l, engine, &object]() {
589 l->qobjectMethodLookup.propertyCache->release();
590 l->qobjectMethodLookup.propertyCache = nullptr;
591 l->getter = Lookup::getterGeneric;
592 return Lookup::getterGeneric(l, engine, object);
593 };
594
595 // We cannot safely cast here as we don't explicitly check the IC. Therefore as().
596 const QQmlTypeWrapper *This = object.as<QQmlTypeWrapper>();
597 if (!This)
598 return revertLookup();
599
600 QQmlType type = This->d()->type();
601 if (!type.isValid())
602 return revertLookup();
603
604 if (!type.isQObjectSingleton() && !type.isCompositeSingleton())
605 return revertLookup();
606
607 QQmlEnginePrivate *e = QQmlEnginePrivate::get(e: engine->qmlEngine());
608 QObject *qobjectSingleton = e->singletonInstance<QObject *>(type);
609 Q_ASSERT(qobjectSingleton);
610
611 Scope scope(engine);
612 ScopedValue obj(scope, QV4::QObjectWrapper::wrap(engine, object: qobjectSingleton));
613 return QObjectWrapper::lookupMethodGetterImpl(
614 lookup: l, engine, object: obj, flags: l->forCall ? QObjectWrapper::NoFlag : QObjectWrapper::AttachMethods,
615 revertLookup);
616}
617
618ReturnedValue QQmlTypeWrapper::lookupEnumValue(Lookup *l, ExecutionEngine *engine, const Value &base)
619{
620 auto *o = static_cast<Heap::Object *>(base.heapObject());
621 if (!o || o->internalClass != l->qmlEnumValueLookup.ic) {
622 l->getter = Lookup::getterGeneric;
623 return Lookup::getterGeneric(l, engine, object: base);
624 }
625
626 return l->qmlEnumValueLookup.encodedEnumValue;
627}
628
629ReturnedValue QQmlTypeWrapper::lookupScopedEnum(Lookup *l, ExecutionEngine *engine, const Value &base)
630{
631 Scope scope(engine);
632 Scoped<QQmlScopedEnumWrapper> enumWrapper(scope, static_cast<Heap::QQmlScopedEnumWrapper *>(
633 l->qmlScopedEnumWrapperLookup.qmlScopedEnumWrapper));
634
635 auto *o = static_cast<Heap::Object *>(base.heapObject());
636 if (!o || o->internalClass != l->qmlScopedEnumWrapperLookup.ic) {
637 QQmlType::derefHandle(priv: enumWrapper->d()->typePrivate);
638 l->qmlScopedEnumWrapperLookup.qmlScopedEnumWrapper = nullptr;
639 l->getter = Lookup::getterGeneric;
640 return Lookup::getterGeneric(l, engine, object: base);
641 }
642
643 return enumWrapper.asReturnedValue();
644}
645
646void Heap::QQmlScopedEnumWrapper::destroy()
647{
648 QQmlType::derefHandle(priv: typePrivate);
649 typePrivate = nullptr;
650 Object::destroy();
651}
652
653QQmlType Heap::QQmlScopedEnumWrapper::type() const
654{
655 return QQmlType(typePrivate);
656}
657
658ReturnedValue QQmlScopedEnumWrapper::virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty)
659{
660 Q_ASSERT(m->as<QQmlScopedEnumWrapper>());
661 if (!id.isString())
662 return Object::virtualGet(m, id, receiver, hasProperty);
663
664 const QQmlScopedEnumWrapper *resource = static_cast<const QQmlScopedEnumWrapper *>(m);
665 QV4::ExecutionEngine *v4 = resource->engine();
666 QV4::Scope scope(v4);
667 ScopedString name(scope, id.asStringOrSymbol());
668
669 QQmlType type = resource->d()->type();
670 int index = resource->d()->scopeEnumIndex;
671
672 bool ok = false;
673 int value = type.scopedEnumValue(engine: QQmlEnginePrivate::get(e: v4->qmlEngine()), index, name, ok: &ok);
674 if (hasProperty)
675 *hasProperty = ok;
676 if (ok)
677 return QV4::Value::fromInt32(i: value).asReturnedValue();
678
679 return Encode::undefined();
680}
681
682QT_END_NAMESPACE
683

source code of qtdeclarative/src/qml/qml/qqmltypewrapper.cpp