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 
54 QT_BEGIN_NAMESPACE
55 
56 using namespace QV4;
57 
58 DEFINE_OBJECT_VTABLE(QQmlTypeWrapper);
59 DEFINE_OBJECT_VTABLE(QQmlScopedEnumWrapper);
60 
init()61 void Heap::QQmlTypeWrapper::init()
62 {
63     Object::init();
64     mode = IncludeEnums;
65     object.init();
66 }
67 
destroy()68 void Heap::QQmlTypeWrapper::destroy()
69 {
70     QQmlType::derefHandle(typePrivate);
71     typePrivate = nullptr;
72     if (typeNamespace)
73         typeNamespace->release();
74     object.destroy();
75     Object::destroy();
76 }
77 
type() const78 QQmlType Heap::QQmlTypeWrapper::type() const
79 {
80     return QQmlType(typePrivate);
81 }
82 
isSingleton() const83 bool QQmlTypeWrapper::isSingleton() const
84 {
85     return d()->type().isSingleton();
86 }
87 
singletonObject() const88 QObject* QQmlTypeWrapper::singletonObject() const
89 {
90     if (!isSingleton())
91         return nullptr;
92 
93     QQmlEnginePrivate *e = QQmlEnginePrivate::get(engine()->qmlEngine());
94     return e->singletonInstance<QObject*>(d()->type());
95 }
96 
toVariant() const97 QVariant QQmlTypeWrapper::toVariant() const
98 {
99     if (!isSingleton())
100         return QVariant::fromValue<QObject *>(d()->object);
101 
102     QQmlEnginePrivate *e = QQmlEnginePrivate::get(engine()->qmlEngine());
103     const QQmlType type = d()->type();
104     if (type.isQJSValueSingleton())
105         return QVariant::fromValue<QJSValue>(e->singletonInstance<QJSValue>(type));
106 
107     return QVariant::fromValue<QObject*>(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.
create(QV4::ExecutionEngine * engine,QObject * o,const QQmlType & t,Heap::QQmlTypeWrapper::TypeNameMode mode)112 ReturnedValue 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(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.
create(QV4::ExecutionEngine * engine,QObject * o,const QQmlRefPointer<QQmlTypeNameCache> & t,const QQmlImportRef * importNamespace,Heap::QQmlTypeWrapper::TypeNameMode mode)127 ReturnedValue 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 
enumForSingleton(QV4::ExecutionEngine * v4,String * name,QObject * qobjectSingleton,const QQmlType & type,bool * ok)140 static 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(QQmlEnginePrivate::get(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(ii);
153         value = e.keyToValue(enumName.constData(), ok);
154         if (*ok)
155             return value;
156     }
157     *ok = false;
158     return -1;
159 }
160 
throwLowercaseEnumError(QV4::ExecutionEngine * v4,String * name,const QQmlType & type)161 static 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(name->toQString()).arg(QLatin1String(type.typeName()));
166     return v4->throwTypeError(message);
167 }
168 
virtualGet(const Managed * m,PropertyKey id,const Value * receiver,bool * hasProperty)169 ReturnedValue 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(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);
204                         if (ok)
205                             return QV4::Value::fromInt32(value).asReturnedValue();
206 
207                         value = type.scopedEnumIndex(QQmlEnginePrivate::get(v4->qmlEngine()), name, &ok);
208                         if (ok) {
209                             Scoped<QQmlScopedEnumWrapper> enumWrapper(scope, v4->memoryManager->allocate<QQmlScopedEnumWrapper>());
210                             enumWrapper->d()->typePrivate = type.priv();
211                             QQmlType::refHandle(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(v4, context, qobjectSingleton, name, QV4::QObjectWrapper::IgnoreRevision, &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);
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(v4, 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(QQmlEnginePrivate::get(v4->qmlEngine()), name, &ok);
249                 if (ok)
250                     return QV4::Value::fromInt32(value).asReturnedValue();
251 
252                 value = type.scopedEnumIndex(QQmlEnginePrivate::get(v4->qmlEngine()), name, &ok);
253                 if (ok) {
254                     Scoped<QQmlScopedEnumWrapper> enumWrapper(scope, v4->memoryManager->allocate<QQmlScopedEnumWrapper>());
255                     enumWrapper->d()->typePrivate = type.priv();
256                     QQmlType::refHandle(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                         type.attachedPropertiesFunction(QQmlEnginePrivate::get(v4->qmlEngine())));
267                 if (ao)
268                     return QV4::QObjectWrapper::getQmlProperty(v4, context, ao, name, 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, w->d()->importNamespace);
281 
282         if (r.isValid()) {
283             if (r.type.isValid()) {
284                 return create(scope.engine, object, r.type, w->d()->mode);
285             } else if (r.scriptIndex != -1) {
286                 QV4::ScopedObject scripts(scope, context->importedScripts.valueRef());
287                 return scripts->get(r.scriptIndex);
288             } else if (r.importNamespace) {
289                 return create(scope.engine, object, context->imports, 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, &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(QQmlEnginePrivate::get(v4->qmlEngine()), name, &enumOk);
311         if (enumOk)
312             return throwLowercaseEnumError(v4, name, type);
313     }
314 
315     return result;
316 }
317 
318 
virtualPut(Managed * m,PropertyKey id,const Value & value,Value * receiver)319 bool 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, type.attachedPropertiesFunction(QQmlEnginePrivate::get(e)));
340         if (ao)
341             return QV4::QObjectWrapper::setQmlProperty(scope.engine, context, ao, name, QV4::QObjectWrapper::IgnoreRevision, value);
342         return false;
343     } else if (type.isSingleton()) {
344         QQmlEnginePrivate *e = QQmlEnginePrivate::get(scope.engine->qmlEngine());
345         if (type.isQObjectSingleton() || type.isCompositeSingleton()) {
346             if (QObject *qobjectSingleton = e->singletonInstance<QObject*>(type))
347                 return QV4::QObjectWrapper::setQmlProperty(scope.engine, context, qobjectSingleton, name, 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(scope.engine, scriptSingleton));
353                 if (!apiprivate) {
354                     QString error = QLatin1String("Cannot assign to read-only property \"") + name->toQString() + QLatin1Char('\"');
355                     scope.engine->throwError(error);
356                     return false;
357                 } else {
358                     return apiprivate->put(name, value);
359                 }
360             }
361         }
362     }
363 
364     return false;
365 }
366 
virtualGetOwnProperty(const Managed * m,PropertyKey id,Property * p)367 PropertyAttributes 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(n, &hasProperty);
375         return hasProperty ? Attr_Data : Attr_Invalid;
376     }
377 
378     return QV4::Object::virtualGetOwnProperty(m, id, p);
379 }
380 
virtualIsEqualTo(Managed * a,Managed * b)381 bool 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 
virtualInstanceOf(const Object * typeObject,const Value & var)393 ReturnedValue 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(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(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(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(theirType, myQmlType));
431 }
432 
virtualResolveLookupGetter(const Object * object,ExecutionEngine * engine,Lookup * lookup)433 ReturnedValue QQmlTypeWrapper::virtualResolveLookupGetter(const Object *object, ExecutionEngine *engine, Lookup *lookup)
434 {
435     // Keep this code in sync with ::virtualGet
436     PropertyKey id = engine->identifierTable->asPropertyKey(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(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(qobjectSingleton, false);
457                         if (ddata && ddata->propertyCache) {
458                             QQmlPropertyData *property = ddata->propertyCache->property(name.getPointer(), qobjectSingleton, qmlContext);
459                             if (property) {
460                                 ScopedValue val(scope, Value::fromReturnedValue(QV4::QObjectWrapper::wrap(engine, qobjectSingleton)));
461                                 lookup->qobjectLookup.qmlTypeIc = This->internalClass();
462                                 lookup->qobjectLookup.ic = val->objectValue()->internalClass();
463                                 lookup->qobjectLookup.propertyCache = ddata->propertyCache;
464                                 lookup->qobjectLookup.propertyCache->addref();
465                                 lookup->qobjectLookup.propertyData = property;
466                                 lookup->getter = QQmlTypeWrapper::lookupSingletonProperty;
467                                 return lookup->getter(lookup, engine, *object);
468                             }
469                             // Fall through to base implementation
470                         }
471                         // Fall through to base implementation
472                     }
473                     // Fall through to base implementation
474                 }
475                 // Fall through to base implementation
476             }
477             // Fall through to base implementation
478         }
479 
480         if (name->startsWithUpper()) {
481             bool ok = false;
482             int value = type.enumValue(QQmlEnginePrivate::get(engine->qmlEngine()), name, &ok);
483             if (ok) {
484                 lookup->qmlEnumValueLookup.ic = This->internalClass();
485                 lookup->qmlEnumValueLookup.encodedEnumValue
486                         = QV4::Value::fromInt32(value).asReturnedValue();
487                 lookup->getter = QQmlTypeWrapper::lookupEnumValue;
488                 return lookup->getter(lookup, engine, *object);
489             }
490 
491             value = type.scopedEnumIndex(QQmlEnginePrivate::get(engine->qmlEngine()), name, &ok);
492             if (ok) {
493                 Scoped<QQmlScopedEnumWrapper> enumWrapper(
494                             scope, engine->memoryManager->allocate<QQmlScopedEnumWrapper>());
495                 enumWrapper->d()->typePrivate = type.priv();
496                 QQmlType::refHandle(enumWrapper->d()->typePrivate);
497                 enumWrapper->d()->scopeEnumIndex = value;
498 
499                 lookup->qmlScopedEnumWrapperLookup.ic = This->internalClass();
500                 lookup->qmlScopedEnumWrapperLookup.qmlScopedEnumWrapper
501                         = static_cast<Heap::Object*>(enumWrapper->heapObject());
502                 lookup->getter = QQmlTypeWrapper::lookupScopedEnum;
503                 return enumWrapper.asReturnedValue();
504             }
505             // Fall through to base implementation
506         }
507         // Fall through to base implementation
508     }
509     return QV4::Object::virtualResolveLookupGetter(object, engine, lookup);
510 }
511 
virtualResolveLookupSetter(Object * object,ExecutionEngine * engine,Lookup * lookup,const Value & value)512 bool QQmlTypeWrapper::virtualResolveLookupSetter(Object *object, ExecutionEngine *engine, Lookup *lookup, const Value &value)
513 {
514     return Object::virtualResolveLookupSetter(object, engine, lookup, value);
515 }
516 
lookupSingletonProperty(Lookup * l,ExecutionEngine * engine,const Value & object)517 ReturnedValue QQmlTypeWrapper::lookupSingletonProperty(Lookup *l, ExecutionEngine *engine, const Value &object)
518 {
519     const auto revertLookup = [l, engine, &object]() {
520         l->qobjectLookup.propertyCache->release();
521         l->qobjectLookup.propertyCache = nullptr;
522         l->getter = Lookup::getterGeneric;
523         return Lookup::getterGeneric(l, engine, object);
524     };
525 
526     // we can safely cast to a QV4::Object here. If object is something else,
527     // the internal class won't match
528     Heap::Object *o = static_cast<Heap::Object *>(object.heapObject());
529     if (!o || o->internalClass != l->qobjectLookup.qmlTypeIc)
530         return revertLookup();
531 
532     Heap::QQmlTypeWrapper *This = static_cast<Heap::QQmlTypeWrapper *>(o);
533 
534     QQmlType type = This->type();
535     if (!type.isValid())
536         return revertLookup();
537 
538     if (!type.isQObjectSingleton() && !type.isCompositeSingleton())
539         return revertLookup();
540 
541     QQmlEnginePrivate *e = QQmlEnginePrivate::get(engine->qmlEngine());
542     QObject *qobjectSingleton = e->singletonInstance<QObject *>(type);
543     Q_ASSERT(qobjectSingleton);
544 
545     Scope scope(engine);
546     ScopedValue obj(scope, QV4::QObjectWrapper::wrap(engine, qobjectSingleton));
547     return QObjectWrapper::lookupGetterImpl(l, engine, obj, /*useOriginalProperty*/ true, revertLookup);
548 }
549 
lookupEnumValue(Lookup * l,ExecutionEngine * engine,const Value & base)550 ReturnedValue QQmlTypeWrapper::lookupEnumValue(Lookup *l, ExecutionEngine *engine, const Value &base)
551 {
552     auto *o = static_cast<Heap::Object *>(base.heapObject());
553     if (!o || o->internalClass != l->qmlEnumValueLookup.ic) {
554         l->getter = Lookup::getterGeneric;
555         return Lookup::getterGeneric(l, engine, base);
556     }
557 
558     return l->qmlEnumValueLookup.encodedEnumValue;
559 }
560 
lookupScopedEnum(Lookup * l,ExecutionEngine * engine,const Value & base)561 ReturnedValue QQmlTypeWrapper::lookupScopedEnum(Lookup *l, ExecutionEngine *engine, const Value &base)
562 {
563     Scope scope(engine);
564     Scoped<QQmlScopedEnumWrapper> enumWrapper(scope, static_cast<Heap::QQmlScopedEnumWrapper *>(
565                 l->qmlScopedEnumWrapperLookup.qmlScopedEnumWrapper));
566 
567     auto *o = static_cast<Heap::Object *>(base.heapObject());
568     if (!o || o->internalClass != l->qmlScopedEnumWrapperLookup.ic) {
569         QQmlType::derefHandle(enumWrapper->d()->typePrivate);
570         l->qmlScopedEnumWrapperLookup.qmlScopedEnumWrapper = nullptr;
571         l->getter = Lookup::getterGeneric;
572         return Lookup::getterGeneric(l, engine, base);
573     }
574 
575     return enumWrapper.asReturnedValue();
576 }
577 
destroy()578 void Heap::QQmlScopedEnumWrapper::destroy()
579 {
580     QQmlType::derefHandle(typePrivate);
581     typePrivate = nullptr;
582     Object::destroy();
583 }
584 
type() const585 QQmlType Heap::QQmlScopedEnumWrapper::type() const
586 {
587     return QQmlType(typePrivate);
588 }
589 
virtualGet(const Managed * m,PropertyKey id,const Value * receiver,bool * hasProperty)590 ReturnedValue QQmlScopedEnumWrapper::virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty)
591 {
592     Q_ASSERT(m->as<QQmlScopedEnumWrapper>());
593     if (!id.isString())
594         return Object::virtualGet(m, id, receiver, hasProperty);
595 
596     const QQmlScopedEnumWrapper *resource = static_cast<const QQmlScopedEnumWrapper *>(m);
597     QV4::ExecutionEngine *v4 = resource->engine();
598     QV4::Scope scope(v4);
599     ScopedString name(scope, id.asStringOrSymbol());
600 
601     QQmlType type = resource->d()->type();
602     int index = resource->d()->scopeEnumIndex;
603 
604     bool ok = false;
605     int value = type.scopedEnumValue(QQmlEnginePrivate::get(v4->qmlEngine()), index, name, &ok);
606     if (hasProperty)
607         *hasProperty = ok;
608     if (ok)
609         return QV4::Value::fromInt32(value).asReturnedValue();
610 
611     return Encode::undefined();
612 }
613 
614 QT_END_NAMESPACE
615