diff options
author | Lars Knoll <lars.knoll@qt.io> | 2018-08-02 15:44:12 +0200 |
---|---|---|
committer | Lars Knoll <lars.knoll@qt.io> | 2018-08-02 20:25:41 +0000 |
commit | 0754f55287f4652382332bce42cd8c7d27846ef1 (patch) | |
tree | 490bbd3c5d66586a1427ba21dde76b2af65230dc /src/qml/jsruntime/qv4qobjectwrapper.cpp | |
parent | 57640959320c87850315eae44c783803d113dc85 (diff) |
Introduce a new mechanism to iterate over object properties
The old advanceIterator schema was extremely ugly and in addition
not flexible enough to support the requirements for Proxy.ownKeys
and some of the methods in Object
Implemented a new scheme through a OwnPropertyKeys method in the
Object VTable that creates and returns an iterator object. Ported
QJSValueIterator and for-in to use the new mechanism.
There's still many places where we use the old ObjectIterator (that
relies on advanceIterator). Those will be ported in subsequent
commits.
Change-Id: I091a9bea9ff6b2b63630cc336814700757a718be
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
Diffstat (limited to 'src/qml/jsruntime/qv4qobjectwrapper.cpp')
-rw-r--r-- | src/qml/jsruntime/qv4qobjectwrapper.cpp | 68 |
1 files changed, 68 insertions, 0 deletions
diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index a17de5d94d..61678acdad 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -814,6 +814,74 @@ void QObjectWrapper::virtualAdvanceIterator(Managed *m, ObjectIterator *it, Valu QV4::Object::virtualAdvanceIterator(m, it, name, index, p, attributes); } +struct QObjectWrapperOwnPropertyKeyIterator : ObjectOwnPropertyKeyIterator +{ + int propertyIndex = 0; + ~QObjectWrapperOwnPropertyKeyIterator() override = default; + PropertyKey next(const Object *o, Property *pd = nullptr, PropertyAttributes *attrs = nullptr) override; + +}; + +PropertyKey QObjectWrapperOwnPropertyKeyIterator::next(const Object *o, Property *pd, PropertyAttributes *attrs) +{ + // Used to block access to QObject::destroyed() and QObject::deleteLater() from QML + static const int destroyedIdx1 = QObject::staticMetaObject.indexOfSignal("destroyed(QObject*)"); + static const int destroyedIdx2 = QObject::staticMetaObject.indexOfSignal("destroyed()"); + static const int deleteLaterIdx = QObject::staticMetaObject.indexOfSlot("deleteLater()"); + + const QObjectWrapper *that = static_cast<const QObjectWrapper*>(o); + + QObject *thatObject = that->d()->object(); + if (thatObject && !QQmlData::wasDeleted(thatObject)) { + const QMetaObject *mo = thatObject->metaObject(); + // These indices don't apply to gadgets, so don't block them. + const bool preventDestruction = mo->superClass() || mo == &QObject::staticMetaObject; + const int propertyCount = mo->propertyCount(); + if (propertyIndex < propertyCount) { + ExecutionEngine *thatEngine = that->engine(); + Scope scope(thatEngine); + const QMetaProperty property = mo->property(propertyIndex); + ScopedString propName(scope, thatEngine->newString(QString::fromUtf8(property.name()))); + ++propertyIndex; + if (attrs) + *attrs= QV4::Attr_Data; + if (pd) { + QQmlPropertyData local; + local.load(property); + pd->value = that->getProperty(thatEngine, thatObject, &local); + } + return propName->toPropertyKey(); + } + const int methodCount = mo->methodCount(); + while (propertyIndex < propertyCount + methodCount) { + Q_ASSERT(propertyIndex >= propertyCount); + int index = propertyIndex - propertyCount; + const QMetaMethod method = mo->method(index); + ++propertyIndex; + if (method.access() == QMetaMethod::Private || (preventDestruction && (index == deleteLaterIdx || index == destroyedIdx1 || index == destroyedIdx2))) + continue; + ExecutionEngine *thatEngine = that->engine(); + Scope scope(thatEngine); + ScopedString methodName(scope, thatEngine->newString(QString::fromUtf8(method.name()))); + if (attrs) + *attrs = QV4::Attr_Data; + if (pd) { + QQmlPropertyData local; + local.load(method); + pd->value = that->getProperty(thatEngine, thatObject, &local); + } + return methodName->toPropertyKey(); + } + } + + return ObjectOwnPropertyKeyIterator::next(o, pd, attrs); +} + +OwnPropertyKeyIterator *QObjectWrapper::virtualOwnPropertyKeys(const Object *) +{ + return new QObjectWrapperOwnPropertyKeyIterator; +} + namespace QV4 { struct QObjectSlotDispatcher : public QtPrivate::QSlotObjectBase |