diff options
author | Simon Hausmann <simon.hausmann@digia.com> | 2013-08-08 12:52:56 +0200 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2013-08-08 15:35:18 +0200 |
commit | 0c179baade8f4a57c0f9fe7b48367412e8a41f2a (patch) | |
tree | 30c775eda2fcba23827bdfc7f5d4c042813b8a2e /src | |
parent | 5046e8898803ab3e83f4dae1260345fdba207a32 (diff) |
Fix hasOwnProperty on various types wrapped in QML
* Change semantics of Object::query to not walk the prototype chain but let the
caller do that where needed (__hasProperty__)
* Re-implement query in various places
* Implement method_hasOwnProperty to fall back to query() if getOwnProperty failed
* Fix missing prototype initialization in some qml wrappers, as well as missing base
class calls to ::get()
Change-Id: Ic2a702fd5ff3be2ff3c8317a8a24f99940a9594f
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/qml/jsruntime/qv4object.cpp | 55 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4object_p.h | 4 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4objectproto.cpp | 2 | ||||
-rw-r--r-- | src/qml/qml/qqmllistwrapper.cpp | 4 | ||||
-rw-r--r-- | src/qml/qml/qqmltypewrapper.cpp | 15 | ||||
-rw-r--r-- | src/qml/qml/qqmltypewrapper_p.h | 1 | ||||
-rw-r--r-- | src/qml/qml/qqmlvaluetypewrapper.cpp | 19 | ||||
-rw-r--r-- | src/qml/qml/qqmlvaluetypewrapper_p.h | 1 |
8 files changed, 74 insertions, 27 deletions
diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp index edfb535e7a..ad18edd857 100644 --- a/src/qml/jsruntime/qv4object.cpp +++ b/src/qml/jsruntime/qv4object.cpp @@ -411,7 +411,30 @@ bool Object::__hasProperty__(String *name) const { if (__getPropertyDescriptor__(name)) return true; - return !query(name).isEmpty(); + + const Object *o = this; + while (o) { + if (!o->query(name).isEmpty()) + return true; + o = o->prototype; + } + + return false; +} + +bool Object::__hasProperty__(uint index) const +{ + if (__getPropertyDescriptor__(index)) + return true; + + const Object *o = this; + while (o) { + if (!o->queryIndexed(index).isEmpty()) + return true; + o = o->prototype; + } + + return false; } Value Object::get(Managed *m, String *name, bool *hasProperty) @@ -441,32 +464,26 @@ PropertyAttributes Object::query(const Managed *m, String *name) return queryIndexed(m, idx); const Object *o = static_cast<const Object *>(m); - while (o) { - uint idx = o->internalClass->find(name); - if (idx < UINT_MAX) - return o->internalClass->propertyData[idx]; + idx = o->internalClass->find(name); + if (idx < UINT_MAX) + return o->internalClass->propertyData[idx]; - o = o->prototype; - } return Attr_Invalid; } PropertyAttributes Object::queryIndexed(const Managed *m, uint index) { const Object *o = static_cast<const Object *>(m); - while (o) { - uint pidx = o->propertyIndexFromArrayIndex(index); - if (pidx < UINT_MAX) { - if (o->arrayAttributes) - return o->arrayAttributes[pidx]; + uint pidx = o->propertyIndexFromArrayIndex(index); + if (pidx < UINT_MAX) { + if (o->arrayAttributes) + return o->arrayAttributes[pidx]; + return Attr_Data; + } + if (o->isStringObject()) { + Property *p = static_cast<const StringObject *>(o)->getIndex(index); + if (p) return Attr_Data; - } - if (o->isStringObject()) { - Property *p = static_cast<const StringObject *>(o)->getIndex(index); - if (p) - return Attr_Data; - } - o = o->prototype; } return Attr_Invalid; } diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h index a9f947b629..ffcca133b7 100644 --- a/src/qml/jsruntime/qv4object_p.h +++ b/src/qml/jsruntime/qv4object_p.h @@ -131,9 +131,7 @@ struct Q_QML_EXPORT Object: Managed { Property *__getPropertyDescriptor__(uint index, PropertyAttributes *attrs = 0) const; bool __hasProperty__(String *name) const; - bool __hasProperty__(uint index) const { - return __getPropertyDescriptor__(index); - } + bool __hasProperty__(uint index) const; bool __defineOwnProperty__(ExecutionContext *ctx, Property *current, String *member, const Property &p, PropertyAttributes attrs); bool __defineOwnProperty__(ExecutionContext *ctx, String *name, const Property &p, PropertyAttributes attrs); diff --git a/src/qml/jsruntime/qv4objectproto.cpp b/src/qml/jsruntime/qv4objectproto.cpp index 462c9ca81e..fd4afa3a32 100644 --- a/src/qml/jsruntime/qv4objectproto.cpp +++ b/src/qml/jsruntime/qv4objectproto.cpp @@ -399,6 +399,8 @@ Value ObjectPrototype::method_hasOwnProperty(SimpleCallContext *ctx) String *P = ctx->argument(0).toString(ctx); Object *O = ctx->thisObject.toObject(ctx); bool r = O->__getOwnProperty__(P) != 0; + if (!r) + r = !O->query(P).isEmpty(); return Value::fromBoolean(r); } diff --git a/src/qml/qml/qqmllistwrapper.cpp b/src/qml/qml/qqmllistwrapper.cpp index e396f700af..7afbe3fd29 100644 --- a/src/qml/qml/qqmllistwrapper.cpp +++ b/src/qml/qml/qqmllistwrapper.cpp @@ -42,6 +42,7 @@ #include "qqmllistwrapper_p.h" #include <private/qv8engine_p.h> #include <private/qqmllist_p.h> +#include <private/qv4objectproto_p.h> #include <private/qv4functionobject_p.h> @@ -56,6 +57,7 @@ QmlListWrapper::QmlListWrapper(QV8Engine *engine) v8(engine) { vtbl = &static_vtbl; + prototype = QV8Engine::getV4(engine)->objectPrototype; } QmlListWrapper::~QmlListWrapper() @@ -113,7 +115,7 @@ Value QmlListWrapper::get(Managed *m, String *name, bool *hasProperty) if (idx != UINT_MAX) return getIndexed(m, idx, hasProperty); - return Value::undefinedValue(); + return Object::get(m, name, hasProperty); } Value QmlListWrapper::getIndexed(Managed *m, uint index, bool *hasProperty) diff --git a/src/qml/qml/qqmltypewrapper.cpp b/src/qml/qml/qqmltypewrapper.cpp index f4e9d9b406..20c403c95c 100644 --- a/src/qml/qml/qqmltypewrapper.cpp +++ b/src/qml/qml/qqmltypewrapper.cpp @@ -157,7 +157,7 @@ Value QmlTypeWrapper::get(Managed *m, String *name, bool *hasProperty) } // check for property. - return QV4::QObjectWrapper::getQmlProperty(v4->current, context, qobjectSingleton, name, QV4::QObjectWrapper::IgnoreRevision); + return QV4::QObjectWrapper::getQmlProperty(v4->current, context, qobjectSingleton, name, QV4::QObjectWrapper::IgnoreRevision, hasProperty); } else if (!siinfo->scriptApi(e).isUndefined()) { QV4::ExecutionEngine *engine = QV8Engine::getV4(v8engine); // NOTE: if used in a binding, changes will not trigger re-evaluation since non-NOTIFYable. @@ -181,7 +181,7 @@ Value QmlTypeWrapper::get(Managed *m, String *name, bool *hasProperty) } else if (w->object) { QObject *ao = qmlAttachedPropertiesObjectById(type->attachedPropertiesId(), object); if (ao) - return QV4::QObjectWrapper::getQmlProperty(v4->current, context, ao, name, QV4::QObjectWrapper::IgnoreRevision); + return QV4::QObjectWrapper::getQmlProperty(v4->current, context, ao, name, QV4::QObjectWrapper::IgnoreRevision, hasProperty); // Fall through to base implementation } @@ -193,8 +193,7 @@ Value QmlTypeWrapper::get(Managed *m, String *name, bool *hasProperty) } else if (w->typeNamespace) { Q_ASSERT(w->importNamespace); - QQmlTypeNameCache::Result r = w->typeNamespace->query(name, - w->importNamespace); + QQmlTypeNameCache::Result r = w->typeNamespace->query(name, w->importNamespace); if (r.isValid()) { QQmlContextData *context = v8engine->callingContext(); @@ -260,6 +259,14 @@ void QmlTypeWrapper::put(Managed *m, String *name, const Value &value) } } +PropertyAttributes QmlTypeWrapper::query(const Managed *m, String *name) +{ + // ### Implement more efficiently. + bool hasProperty = false; + const_cast<Managed*>(m)->get(name, &hasProperty); + return hasProperty ? Attr_Data : Attr_Invalid; +} + void QmlTypeWrapper::destroy(Managed *that) { static_cast<QmlTypeWrapper *>(that)->~QmlTypeWrapper(); diff --git a/src/qml/qml/qqmltypewrapper_p.h b/src/qml/qml/qqmltypewrapper_p.h index ae70367dc4..944621b1d6 100644 --- a/src/qml/qml/qqmltypewrapper_p.h +++ b/src/qml/qml/qqmltypewrapper_p.h @@ -84,6 +84,7 @@ public: static Value get(Managed *m, String *name, bool *hasProperty); static void put(Managed *m, String *name, const Value &value); + static PropertyAttributes query(const Managed *, String *name); static void destroy(Managed *that); private: diff --git a/src/qml/qml/qqmlvaluetypewrapper.cpp b/src/qml/qml/qqmlvaluetypewrapper.cpp index 05412e99a7..64baf8b1ce 100644 --- a/src/qml/qml/qqmlvaluetypewrapper.cpp +++ b/src/qml/qml/qqmlvaluetypewrapper.cpp @@ -201,6 +201,25 @@ bool QmlValueTypeWrapper::isEqualTo(Managed *m, Managed *other) return false; } +PropertyAttributes QmlValueTypeWrapper::query(const Managed *m, String *name) +{ + const QmlValueTypeWrapper *r = m->as<const QmlValueTypeWrapper>(); + QV4::ExecutionEngine *v4 = m->engine(); + if (!r) + v4->current->throwTypeError(); + + QQmlPropertyData local; + QQmlPropertyData *result = 0; + { + QQmlData *ddata = QQmlData::get(r->type, false); + if (ddata && ddata->propertyCache) + result = ddata->propertyCache->property(name, 0, 0); + else + result = QQmlPropertyCache::property(r->v8->engine(), r->type, name, 0, local); + } + return result ? Attr_Data : Attr_Invalid; +} + bool QmlValueTypeWrapper::isEqual(const QVariant& value) { if (objectType == QmlValueTypeWrapper::Reference) { diff --git a/src/qml/qml/qqmlvaluetypewrapper_p.h b/src/qml/qml/qqmlvaluetypewrapper_p.h index 18dca0a4c9..f5088a5954 100644 --- a/src/qml/qml/qqmlvaluetypewrapper_p.h +++ b/src/qml/qml/qqmlvaluetypewrapper_p.h @@ -87,6 +87,7 @@ public: static void put(Managed *m, String *name, const Value &value); static void destroy(Managed *that); static bool isEqualTo(Managed *m, Managed *other); + static PropertyAttributes query(const Managed *, String *name); static QV4::Value method_toString(SimpleCallContext *ctx); |