1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtQml module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qqmltypewrapper_p.h"
41
42#include <private/qqmlengine_p.h>
43#include <private/qqmlcontext_p.h>
44#include <private/qqmlmetaobject_p.h>
45#include <private/qqmltypedata_p.h>
46
47#include <private/qjsvalue_p.h>
48#include <private/qv4functionobject_p.h>
49#include <private/qv4objectproto_p.h>
50#include <private/qv4qobjectwrapper_p.h>
51#include <private/qv4identifiertable_p.h>
52#include <private/qv4lookup_p.h>
53
54QT_BEGIN_NAMESPACE
55
56using namespace QV4;
57
58DEFINE_OBJECT_VTABLE(QQmlTypeWrapper);
59DEFINE_OBJECT_VTABLE(QQmlScopedEnumWrapper);
60
61void Heap::QQmlTypeWrapper::init()
62{
63 Object::init();
64 mode = IncludeEnums;
65 object.init();
66}
67
68void Heap::QQmlTypeWrapper::destroy()
69{
70 QQmlType::derefHandle(priv: typePrivate);
71 typePrivate = nullptr;
72 if (typeNamespace)
73 typeNamespace->release();
74 object.destroy();
75 Object::destroy();
76}
77
78QQmlType Heap::QQmlTypeWrapper::type() const
79{
80 return QQmlType(typePrivate);
81}
82
83bool QQmlTypeWrapper::isSingleton() const
84{
85 return d()->type().isSingleton();
86}
87
88QObject* QQmlTypeWrapper::singletonObject() const
89{
90 if (!isSingleton())
91 return nullptr;
92
93 QQmlEnginePrivate *e = QQmlEnginePrivate::get(e: engine()->qmlEngine());
94 return e->singletonInstance<QObject*>(type: d()->type());
95}
96
97QVariant QQmlTypeWrapper::toVariant() const
98{
99 if (!isSingleton())
100 return QVariant::fromValue<QObject *>(value: d()->object);
101
102 QQmlEnginePrivate *e = QQmlEnginePrivate::get(e: engine()->qmlEngine());
103 const QQmlType type = d()->type();
104 if (type.isQJSValueSingleton())
105 return QVariant::fromValue<QJSValue>(value: e->singletonInstance<QJSValue>(type));
106
107 return QVariant::fromValue<QObject*>(value: e->singletonInstance<QObject*>(type));
108}
109
110
111// Returns a type wrapper for type t on o. This allows access of enums, and attached properties.
112ReturnedValue QQmlTypeWrapper::create(QV4::ExecutionEngine *engine, QObject *o, const QQmlType &t,
113 Heap::QQmlTypeWrapper::TypeNameMode mode)
114{
115 Q_ASSERT(t.isValid());
116 Scope scope(engine);
117
118 Scoped<QQmlTypeWrapper> w(scope, engine->memoryManager->allocate<QQmlTypeWrapper>());
119 w->d()->mode = mode; w->d()->object = o;
120 w->d()->typePrivate = t.priv();
121 QQmlType::refHandle(priv: w->d()->typePrivate);
122 return w.asReturnedValue();
123}
124
125// Returns a type wrapper for importNamespace (of t) on o. This allows nested resolution of a type in a
126// namespace.
127ReturnedValue QQmlTypeWrapper::create(QV4::ExecutionEngine *engine, QObject *o, const QQmlRefPointer<QQmlTypeNameCache> &t, const QQmlImportRef *importNamespace,
128 Heap::QQmlTypeWrapper::TypeNameMode mode)
129{
130 Q_ASSERT(t);
131 Q_ASSERT(importNamespace);
132 Scope scope(engine);
133
134 Scoped<QQmlTypeWrapper> w(scope, engine->memoryManager->allocate<QQmlTypeWrapper>());
135 w->d()->mode = mode; w->d()->object = o; w->d()->typeNamespace = t.data(); w->d()->importNamespace = importNamespace;
136 t->addref();
137 return w.asReturnedValue();
138}
139
140static int enumForSingleton(QV4::ExecutionEngine *v4, String *name, QObject *qobjectSingleton,
141 const QQmlType &type, bool *ok)
142{
143 Q_ASSERT(ok != nullptr);
144 int value = type.enumValue(engine: QQmlEnginePrivate::get(e: v4->qmlEngine()), name, ok);
145 if (*ok)
146 return value;
147
148 // ### Optimize
149 QByteArray enumName = name->toQString().toUtf8();
150 const QMetaObject *metaObject = qobjectSingleton->metaObject();
151 for (int ii = metaObject->enumeratorCount() - 1; ii >= 0; --ii) {
152 QMetaEnum e = metaObject->enumerator(index: ii);
153 value = e.keyToValue(key: enumName.constData(), ok);
154 if (*ok)
155 return value;
156 }
157 *ok = false;
158 return -1;
159}
160
161static ReturnedValue throwLowercaseEnumError(QV4::ExecutionEngine *v4, String *name, const QQmlType &type)
162{
163 const QString message =
164 QStringLiteral("Cannot access enum value '%1' of '%2', enum values need to start with an uppercase letter.")
165 .arg(a: name->toQString()).arg(a: QLatin1String(type.typeName()));
166 return v4->throwTypeError(message);
167}
168
169ReturnedValue QQmlTypeWrapper::virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty)
170{
171 // Keep this code in sync with ::virtualResolveLookupGetter
172 Q_ASSERT(m->as<QQmlTypeWrapper>());
173
174 if (!id.isString())
175 return Object::virtualGet(m, id, receiver, hasProperty);
176
177 QV4::ExecutionEngine *v4 = static_cast<const QQmlTypeWrapper *>(m)->engine();
178 QV4::Scope scope(v4);
179 ScopedString name(scope, id.asStringOrSymbol());
180
181 Scoped<QQmlTypeWrapper> w(scope, static_cast<const QQmlTypeWrapper *>(m));
182
183 if (hasProperty)
184 *hasProperty = true;
185
186 QQmlContextData *context = v4->callingQmlContext();
187
188 QObject *object = w->d()->object;
189 QQmlType type = w->d()->type();
190
191 if (type.isValid()) {
192
193 // singleton types are handled differently to other types.
194 if (type.isSingleton()) {
195 QQmlEnginePrivate *e = QQmlEnginePrivate::get(e: v4->qmlEngine());
196 QJSValue scriptSingleton;
197 if (type.isQObjectSingleton() || type.isCompositeSingleton()) {
198 if (QObject *qobjectSingleton = e->singletonInstance<QObject*>(type)) {
199 // check for enum value
200 const bool includeEnums = w->d()->mode == Heap::QQmlTypeWrapper::IncludeEnums;
201 if (includeEnums && name->startsWithUpper()) {
202 bool ok = false;
203 int value = enumForSingleton(v4, name, qobjectSingleton, type, ok: &ok);
204 if (ok)
205 return QV4::Value::fromInt32(i: value).asReturnedValue();
206
207 value = type.scopedEnumIndex(engine: QQmlEnginePrivate::get(e: v4->qmlEngine()), name, ok: &ok);
208 if (ok) {
209 Scoped<QQmlScopedEnumWrapper> enumWrapper(scope, v4->memoryManager->allocate<QQmlScopedEnumWrapper>());
210 enumWrapper->d()->typePrivate = type.priv();
211 QQmlType::refHandle(priv: enumWrapper->d()->typePrivate);
212 enumWrapper->d()->scopeEnumIndex = value;
213 return enumWrapper.asReturnedValue();
214 }
215 }
216
217 // check for property.
218 bool ok;
219 const ReturnedValue result = QV4::QObjectWrapper::getQmlProperty(engine: v4, qmlContext: context, object: qobjectSingleton, name, revisionMode: QV4::QObjectWrapper::IgnoreRevision, hasProperty: &ok);
220 if (hasProperty)
221 *hasProperty = ok;
222
223 // Warn when attempting to access a lowercased enum value, singleton case
224 if (!ok && includeEnums && !name->startsWithUpper()) {
225 enumForSingleton(v4, name, qobjectSingleton, type, ok: &ok);
226 if (ok)
227 return throwLowercaseEnumError(v4, name, type);
228 }
229
230 return result;
231 }
232 } else if (type.isQJSValueSingleton()) {
233 QJSValue scriptSingleton = e->singletonInstance<QJSValue>(type);
234 if (!scriptSingleton.isUndefined()) {
235 // NOTE: if used in a binding, changes will not trigger re-evaluation since non-NOTIFYable.
236 QV4::ScopedObject o(scope, QJSValuePrivate::convertedToValue(e: v4, jsval: scriptSingleton));
237 if (!!o)
238 return o->get(name);
239 }
240 }
241
242 // Fall through to base implementation
243
244 } else {
245
246 if (name->startsWithUpper()) {
247 bool ok = false;
248 int value = type.enumValue(engine: QQmlEnginePrivate::get(e: v4->qmlEngine()), name, ok: &ok);
249 if (ok)
250 return QV4::Value::fromInt32(i: value).asReturnedValue();
251
252 value = type.scopedEnumIndex(engine: QQmlEnginePrivate::get(e: v4->qmlEngine()), name, ok: &ok);
253 if (ok) {
254 Scoped<QQmlScopedEnumWrapper> enumWrapper(scope, v4->memoryManager->allocate<QQmlScopedEnumWrapper>());
255 enumWrapper->d()->typePrivate = type.priv();
256 QQmlType::refHandle(priv: enumWrapper->d()->typePrivate);
257 enumWrapper->d()->scopeEnumIndex = value;
258 return enumWrapper.asReturnedValue();
259 }
260
261 // Fall through to base implementation
262
263 } else if (w->d()->object) {
264 QObject *ao = qmlAttachedPropertiesObject(
265 object,
266 func: type.attachedPropertiesFunction(engine: QQmlEnginePrivate::get(e: v4->qmlEngine())));
267 if (ao)
268 return QV4::QObjectWrapper::getQmlProperty(engine: v4, qmlContext: context, object: ao, name, revisionMode: QV4::QObjectWrapper::IgnoreRevision, hasProperty);
269
270 // Fall through to base implementation
271 }
272
273 // Fall through to base implementation
274 }
275
276 // Fall through to base implementation
277
278 } else if (w->d()->typeNamespace) {
279 Q_ASSERT(w->d()->importNamespace);
280 QQmlTypeNameCache::Result r = w->d()->typeNamespace->query(name, importNamespace: w->d()->importNamespace);
281
282 if (r.isValid()) {
283 if (r.type.isValid()) {
284 return create(engine: scope.engine, o: object, t: r.type, mode: w->d()->mode);
285 } else if (r.scriptIndex != -1) {
286 QV4::ScopedObject scripts(scope, context->importedScripts.valueRef());
287 return scripts->get(idx: r.scriptIndex);
288 } else if (r.importNamespace) {
289 return create(engine: scope.engine, o: object, t: context->imports, importNamespace: r.importNamespace);
290 }
291
292 return QV4::Encode::undefined();
293
294 }
295
296 // Fall through to base implementation
297
298 } else {
299 Q_ASSERT(!"Unreachable");
300 }
301
302 bool ok = false;
303 const ReturnedValue result = Object::virtualGet(m, id, receiver, hasProperty: &ok);
304 if (hasProperty)
305 *hasProperty = ok;
306
307 // Warn when attempting to access a lowercased enum value, non-singleton case
308 if (!ok && type.isValid() && !type.isSingleton() && !name->startsWithUpper()) {
309 bool enumOk = false;
310 type.enumValue(engine: QQmlEnginePrivate::get(e: v4->qmlEngine()), name, ok: &enumOk);
311 if (enumOk)
312 return throwLowercaseEnumError(v4, name, type);
313 }
314
315 return result;
316}
317
318
319bool QQmlTypeWrapper::virtualPut(Managed *m, PropertyKey id, const Value &value, Value *receiver)
320{
321 if (!id.isString())
322 return Object::virtualPut(m, id, value, receiver);
323
324
325 Q_ASSERT(m->as<QQmlTypeWrapper>());
326 QQmlTypeWrapper *w = static_cast<QQmlTypeWrapper *>(m);
327 QV4::Scope scope(w);
328 if (scope.engine->hasException)
329 return false;
330
331 ScopedString name(scope, id.asStringOrSymbol());
332 QQmlContextData *context = scope.engine->callingQmlContext();
333
334 QQmlType type = w->d()->type();
335 if (type.isValid() && !type.isSingleton() && w->d()->object) {
336 QObject *object = w->d()->object;
337 QQmlEngine *e = scope.engine->qmlEngine();
338 QObject *ao = qmlAttachedPropertiesObject(
339 object, func: type.attachedPropertiesFunction(engine: QQmlEnginePrivate::get(e)));
340 if (ao)
341 return QV4::QObjectWrapper::setQmlProperty(engine: scope.engine, qmlContext: context, object: ao, name, revisionMode: QV4::QObjectWrapper::IgnoreRevision, value);
342 return false;
343 } else if (type.isSingleton()) {
344 QQmlEnginePrivate *e = QQmlEnginePrivate::get(e: scope.engine->qmlEngine());
345 if (type.isQObjectSingleton() || type.isCompositeSingleton()) {
346 if (QObject *qobjectSingleton = e->singletonInstance<QObject*>(type))
347 return QV4::QObjectWrapper::setQmlProperty(engine: scope.engine, qmlContext: context, object: qobjectSingleton, name, revisionMode: QV4::QObjectWrapper::IgnoreRevision, value);
348
349 } else {
350 QJSValue scriptSingleton = e->singletonInstance<QJSValue>(type);
351 if (!scriptSingleton.isUndefined()) {
352 QV4::ScopedObject apiprivate(scope, QJSValuePrivate::convertedToValue(e: scope.engine, jsval: scriptSingleton));
353 if (!apiprivate) {
354 QString error = QLatin1String("Cannot assign to read-only property \"") + name->toQString() + QLatin1Char('\"');
355 scope.engine->throwError(message: error);
356 return false;
357 } else {
358 return apiprivate->put(name, v: value);
359 }
360 }
361 }
362 }
363
364 return false;
365}
366
367PropertyAttributes QQmlTypeWrapper::virtualGetOwnProperty(const Managed *m, PropertyKey id, Property *p)
368{
369 if (id.isString()) {
370 Scope scope(m);
371 ScopedString n(scope, id.asStringOrSymbol());
372 // ### Implement more efficiently.
373 bool hasProperty = false;
374 static_cast<const Object *>(m)->get(name: n, hasProperty: &hasProperty);
375 return hasProperty ? Attr_Data : Attr_Invalid;
376 }
377
378 return QV4::Object::virtualGetOwnProperty(m, id, p);
379}
380
381bool QQmlTypeWrapper::virtualIsEqualTo(Managed *a, Managed *b)
382{
383 Q_ASSERT(a->as<QV4::QQmlTypeWrapper>());
384 QV4::QQmlTypeWrapper *qmlTypeWrapperA = static_cast<QV4::QQmlTypeWrapper *>(a);
385 if (QV4::QQmlTypeWrapper *qmlTypeWrapperB = b->as<QV4::QQmlTypeWrapper>())
386 return qmlTypeWrapperA->toVariant() == qmlTypeWrapperB->toVariant();
387 else if (QV4::QObjectWrapper *qobjectWrapper = b->as<QV4::QObjectWrapper>())
388 return qmlTypeWrapperA->toVariant().value<QObject*>() == qobjectWrapper->object();
389
390 return false;
391}
392
393ReturnedValue QQmlTypeWrapper::virtualInstanceOf(const Object *typeObject, const Value &var)
394{
395 Q_ASSERT(typeObject->as<QV4::QQmlTypeWrapper>());
396 const QV4::QQmlTypeWrapper *typeWrapper = static_cast<const QV4::QQmlTypeWrapper *>(typeObject);
397 QV4::ExecutionEngine *engine = typeObject->internalClass()->engine;
398 QQmlEnginePrivate *qenginepriv = QQmlEnginePrivate::get(e: engine->qmlEngine());
399
400 // can only compare a QObject* against a QML type
401 const QObjectWrapper *wrapper = var.as<QObjectWrapper>();
402 if (!wrapper)
403 return QV4::Encode(false);
404
405 // in case the wrapper outlived the QObject*
406 const QObject *wrapperObject = wrapper->object();
407 if (!wrapperObject)
408 return engine->throwTypeError();
409
410 const int myTypeId = typeWrapper->d()->type().typeId();
411 QQmlMetaObject myQmlType;
412 if (myTypeId == 0) {
413 // we're a composite type; a composite type cannot be equal to a
414 // non-composite object instance (Rectangle{} is never an instance of
415 // CustomRectangle)
416 QQmlData *theirDData = QQmlData::get(object: wrapperObject, /*create=*/false);
417 Q_ASSERT(theirDData); // must exist, otherwise how do we have a QObjectWrapper for it?!
418 if (!theirDData->compilationUnit)
419 return Encode(false);
420
421 QQmlRefPointer<QQmlTypeData> td = qenginepriv->typeLoader.getType(unNormalizedUrl: typeWrapper->d()->type().sourceUrl());
422 ExecutableCompilationUnit *cu = td->compilationUnit();
423 myQmlType = qenginepriv->metaObjectForType(cu->metaTypeId);
424 } else {
425 myQmlType = qenginepriv->metaObjectForType(myTypeId);
426 }
427
428 const QMetaObject *theirType = wrapperObject->metaObject();
429
430 return QV4::Encode(QQmlMetaObject::canConvert(from: theirType, to: myQmlType));
431}
432
433ReturnedValue QQmlTypeWrapper::virtualResolveLookupGetter(const Object *object, ExecutionEngine *engine, Lookup *lookup)
434{
435 // Keep this code in sync with ::virtualGet
436 PropertyKey id = engine->identifierTable->asPropertyKey(str: engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[lookup->nameIndex]);
437 if (!id.isString())
438 return Object::virtualResolveLookupGetter(object, engine, lookup);
439 Scope scope(engine);
440
441 const QQmlTypeWrapper *This = static_cast<const QQmlTypeWrapper *>(object);
442 ScopedString name(scope, id.asStringOrSymbol());
443 QQmlContextData *qmlContext = engine->callingQmlContext();
444
445 Scoped<QQmlTypeWrapper> w(scope, static_cast<const QQmlTypeWrapper *>(This));
446 QQmlType type = w->d()->type();
447
448 if (type.isValid()) {
449
450 if (type.isSingleton()) {
451 QQmlEnginePrivate *e = QQmlEnginePrivate::get(e: engine->qmlEngine());
452 if (type.isQObjectSingleton() || type.isCompositeSingleton()) {
453 if (QObject *qobjectSingleton = e->singletonInstance<QObject*>(type)) {
454 const bool includeEnums = w->d()->mode == Heap::QQmlTypeWrapper::IncludeEnums;
455 if (!includeEnums || !name->startsWithUpper()) {
456 QQmlData *ddata = QQmlData::get(object: qobjectSingleton, create: false);
457 if (ddata && ddata->propertyCache) {
458 QQmlPropertyData *property = ddata->propertyCache->property(key: name.getPointer(), object: qobjectSingleton, context: qmlContext);
459 if (property) {
460 ScopedValue val(scope, Value::fromReturnedValue(val: QV4::QObjectWrapper::wrap(engine, object: qobjectSingleton)));
461 setupQObjectLookup(lookup, ddata, propertyData: property,
462 self: val->objectValue(), qmlType: This);
463 lookup->getter = QQmlTypeWrapper::lookupSingletonProperty;
464 return lookup->getter(lookup, engine, *object);
465 }
466 // Fall through to base implementation
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
477 if (name->startsWithUpper()) {
478 bool ok = false;
479 int value = type.enumValue(engine: QQmlEnginePrivate::get(e: engine->qmlEngine()), name, ok: &ok);
480 if (ok) {
481 lookup->qmlEnumValueLookup.ic = This->internalClass();
482 lookup->qmlEnumValueLookup.encodedEnumValue
483 = QV4::Value::fromInt32(i: value).asReturnedValue();
484 lookup->getter = QQmlTypeWrapper::lookupEnumValue;
485 return lookup->getter(lookup, engine, *object);
486 }
487
488 value = type.scopedEnumIndex(engine: QQmlEnginePrivate::get(e: engine->qmlEngine()), name, ok: &ok);
489 if (ok) {
490 Scoped<QQmlScopedEnumWrapper> enumWrapper(
491 scope, engine->memoryManager->allocate<QQmlScopedEnumWrapper>());
492 enumWrapper->d()->typePrivate = type.priv();
493 QQmlType::refHandle(priv: enumWrapper->d()->typePrivate);
494 enumWrapper->d()->scopeEnumIndex = value;
495
496 lookup->qmlScopedEnumWrapperLookup.ic = This->internalClass();
497 lookup->qmlScopedEnumWrapperLookup.qmlScopedEnumWrapper
498 = static_cast<Heap::Object*>(enumWrapper->heapObject());
499 lookup->getter = QQmlTypeWrapper::lookupScopedEnum;
500 return enumWrapper.asReturnedValue();
501 }
502 // Fall through to base implementation
503 }
504 // Fall through to base implementation
505 }
506 return QV4::Object::virtualResolveLookupGetter(object, engine, lookup);
507}
508
509bool QQmlTypeWrapper::virtualResolveLookupSetter(Object *object, ExecutionEngine *engine, Lookup *lookup, const Value &value)
510{
511 return Object::virtualResolveLookupSetter(object, engine, lookup, value);
512}
513
514ReturnedValue QQmlTypeWrapper::lookupSingletonProperty(Lookup *l, ExecutionEngine *engine, const Value &object)
515{
516 const auto revertLookup = [l, engine, &object]() {
517 l->qobjectLookup.propertyCache->release();
518 l->qobjectLookup.propertyCache = nullptr;
519 l->getter = Lookup::getterGeneric;
520 return Lookup::getterGeneric(l, engine, object);
521 };
522
523 // we can safely cast to a QV4::Object here. If object is something else,
524 // the internal class won't match
525 Heap::Object *o = static_cast<Heap::Object *>(object.heapObject());
526 if (!o || o->internalClass != l->qobjectLookup.qmlTypeIc)
527 return revertLookup();
528
529 Heap::QQmlTypeWrapper *This = static_cast<Heap::QQmlTypeWrapper *>(o);
530
531 QQmlType type = This->type();
532 if (!type.isValid())
533 return revertLookup();
534
535 if (!type.isQObjectSingleton() && !type.isCompositeSingleton())
536 return revertLookup();
537
538 QQmlEnginePrivate *e = QQmlEnginePrivate::get(e: engine->qmlEngine());
539 QObject *qobjectSingleton = e->singletonInstance<QObject *>(type);
540 Q_ASSERT(qobjectSingleton);
541
542 Scope scope(engine);
543 ScopedValue obj(scope, QV4::QObjectWrapper::wrap(engine, object: qobjectSingleton));
544 return QObjectWrapper::lookupGetterImpl(lookup: l, engine, object: obj, /*useOriginalProperty*/ true, revertLookup);
545}
546
547ReturnedValue QQmlTypeWrapper::lookupEnumValue(Lookup *l, ExecutionEngine *engine, const Value &base)
548{
549 auto *o = static_cast<Heap::Object *>(base.heapObject());
550 if (!o || o->internalClass != l->qmlEnumValueLookup.ic) {
551 l->getter = Lookup::getterGeneric;
552 return Lookup::getterGeneric(l, engine, object: base);
553 }
554
555 return l->qmlEnumValueLookup.encodedEnumValue;
556}
557
558ReturnedValue QQmlTypeWrapper::lookupScopedEnum(Lookup *l, ExecutionEngine *engine, const Value &base)
559{
560 Scope scope(engine);
561 Scoped<QQmlScopedEnumWrapper> enumWrapper(scope, static_cast<Heap::QQmlScopedEnumWrapper *>(
562 l->qmlScopedEnumWrapperLookup.qmlScopedEnumWrapper));
563
564 auto *o = static_cast<Heap::Object *>(base.heapObject());
565 if (!o || o->internalClass != l->qmlScopedEnumWrapperLookup.ic) {
566 QQmlType::derefHandle(priv: enumWrapper->d()->typePrivate);
567 l->qmlScopedEnumWrapperLookup.qmlScopedEnumWrapper = nullptr;
568 l->getter = Lookup::getterGeneric;
569 return Lookup::getterGeneric(l, engine, object: base);
570 }
571
572 return enumWrapper.asReturnedValue();
573}
574
575void Heap::QQmlScopedEnumWrapper::destroy()
576{
577 QQmlType::derefHandle(priv: typePrivate);
578 typePrivate = nullptr;
579 Object::destroy();
580}
581
582QQmlType Heap::QQmlScopedEnumWrapper::type() const
583{
584 return QQmlType(typePrivate);
585}
586
587ReturnedValue QQmlScopedEnumWrapper::virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty)
588{
589 Q_ASSERT(m->as<QQmlScopedEnumWrapper>());
590 if (!id.isString())
591 return Object::virtualGet(m, id, receiver, hasProperty);
592
593 const QQmlScopedEnumWrapper *resource = static_cast<const QQmlScopedEnumWrapper *>(m);
594 QV4::ExecutionEngine *v4 = resource->engine();
595 QV4::Scope scope(v4);
596 ScopedString name(scope, id.asStringOrSymbol());
597
598 QQmlType type = resource->d()->type();
599 int index = resource->d()->scopeEnumIndex;
600
601 bool ok = false;
602 int value = type.scopedEnumValue(engine: QQmlEnginePrivate::get(e: v4->qmlEngine()), index, name, ok: &ok);
603 if (hasProperty)
604 *hasProperty = ok;
605 if (ok)
606 return QV4::Value::fromInt32(i: value).asReturnedValue();
607
608 return Encode::undefined();
609}
610
611QT_END_NAMESPACE
612

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