diff options
-rw-r--r-- | src/qml/qml/qqmlpropertycache.cpp | 167 | ||||
-rw-r--r-- | src/qml/qml/qqmlpropertycache_p.h | 2 | ||||
-rw-r--r-- | tests/auto/qml/qqmlpropertycache/tst_qqmlpropertycache.cpp | 161 |
3 files changed, 293 insertions, 37 deletions
diff --git a/src/qml/qml/qqmlpropertycache.cpp b/src/qml/qml/qqmlpropertycache.cpp index 502557fa9f..01be38ada1 100644 --- a/src/qml/qml/qqmlpropertycache.cpp +++ b/src/qml/qml/qqmlpropertycache.cpp @@ -1246,6 +1246,173 @@ void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder) } } +namespace { +template <typename StringVisitor, typename TypeInfoVisitor> +int visitMethods(const QMetaObject &mo, int methodOffset, int methodCount, + StringVisitor visitString, TypeInfoVisitor visitTypeInfo) +{ + const int intsPerMethod = 5; + + int fieldsForParameterData = 0; + + bool hasRevisionedMethods = false; + + for (int i = 0; i < methodCount; ++i) { + const int handle = methodOffset + i * intsPerMethod; + + const uint flags = mo.d.data[handle + 4]; + if (flags & MethodRevisioned) + hasRevisionedMethods = true; + + visitString(mo.d.data[handle + 0]); // name + visitString(mo.d.data[handle + 3]); // tag + + const int argc = mo.d.data[handle + 1]; + const int paramIndex = mo.d.data[handle + 2]; + + fieldsForParameterData += argc * 2; // type and name + fieldsForParameterData += 1; // + return type + + // return type + args + for (int i = 0; i < 1 + argc; ++i) { + // type name (maybe) + visitTypeInfo(mo.d.data[paramIndex + i]); + + // parameter name + if (i > 0) + visitString(mo.d.data[paramIndex + argc + i]); + } + } + + int fieldsForRevisions = 0; + if (hasRevisionedMethods) + fieldsForRevisions = methodCount; + + return methodCount * intsPerMethod + fieldsForRevisions + fieldsForParameterData; +} + +template <typename StringVisitor, typename TypeInfoVisitor> +int visitProperties(const QMetaObject &mo, StringVisitor visitString, TypeInfoVisitor visitTypeInfo) +{ + const QMetaObjectPrivate *const priv = reinterpret_cast<const QMetaObjectPrivate*>(mo.d.data); + const int intsPerProperty = 3; + + bool hasRevisionedProperties = false; + bool hasNotifySignals = false; + + for (int i = 0; i < priv->propertyCount; ++i) { + const int handle = priv->propertyData + i * intsPerProperty; + + const auto flags = mo.d.data[handle + 2]; + if (flags & Revisioned) { + hasRevisionedProperties = true; + } + if (flags & Notify) + hasNotifySignals = true; + + visitString(mo.d.data[handle]); // name + visitTypeInfo(mo.d.data[handle + 1]); + } + + int fieldsForPropertyRevisions = 0; + if (hasRevisionedProperties) + fieldsForPropertyRevisions = priv->propertyCount; + + int fieldsForNotifySignals = 0; + if (hasNotifySignals) + fieldsForNotifySignals = priv->propertyCount; + + return priv->propertyCount * intsPerProperty + fieldsForPropertyRevisions + + fieldsForNotifySignals; +} + +template <typename StringVisitor> +int visitClassInfo(const QMetaObject &mo, StringVisitor visitString) +{ + const QMetaObjectPrivate *const priv = reinterpret_cast<const QMetaObjectPrivate*>(mo.d.data); + const int intsPerClassInfo = 2; + + for (int i = 0; i < priv->classInfoCount; ++i) { + const int handle = priv->classInfoData + i * intsPerClassInfo; + + visitString(mo.d.data[handle]); // key + visitString(mo.d.data[handle + 1]); // value + } + + return priv->classInfoCount * intsPerClassInfo; +} + +template <typename StringVisitor> +int visitEnumerations(const QMetaObject &mo, StringVisitor visitString) +{ + const QMetaObjectPrivate *const priv = reinterpret_cast<const QMetaObjectPrivate*>(mo.d.data); + const int intsPerEnumerator = 4; + + int fieldCount = priv->enumeratorCount * intsPerEnumerator; + + for (int i = 0; i < priv->enumeratorCount; ++i) { + const uint *enumeratorData = mo.d.data + priv->enumeratorData + i * intsPerEnumerator; + + const uint keyCount = enumeratorData[2]; + fieldCount += keyCount * 2; + + visitString(enumeratorData[0]); // name + + const uint keyOffset = enumeratorData[3]; + + for (uint j = 0; j < keyCount; ++j) { + visitString(mo.d.data[keyOffset + 2 * j]); + } + } + + return fieldCount; +} + +template <typename StringVisitor> +int countMetaObjectFields(const QMetaObject &mo, StringVisitor stringVisitor) +{ + const QMetaObjectPrivate *const priv = reinterpret_cast<const QMetaObjectPrivate*>(mo.d.data); + + const auto typeInfoVisitor = [&stringVisitor](uint typeInfo) { + if (typeInfo & IsUnresolvedType) + stringVisitor(typeInfo & TypeNameIndexMask); + }; + + int fieldCount = MetaObjectPrivateFieldCount; + + fieldCount += visitMethods(mo, priv->methodData, priv->methodCount, stringVisitor, + typeInfoVisitor); + fieldCount += visitMethods(mo, priv->constructorData, priv->constructorCount, stringVisitor, + typeInfoVisitor); + + fieldCount += visitProperties(mo, stringVisitor, typeInfoVisitor); + fieldCount += visitClassInfo(mo, stringVisitor); + fieldCount += visitEnumerations(mo, stringVisitor); + + return fieldCount; +} + +} // anonymous namespace + +bool QQmlPropertyCache::determineMetaObjectSizes(const QMetaObject &mo, int *fieldCount, + int *stringCount) +{ + const QMetaObjectPrivate *priv = reinterpret_cast<const QMetaObjectPrivate*>(mo.d.data); + if (priv->revision != 7) { + return false; + } + + uint highestStringIndex = 0; + const auto stringIndexVisitor = [&highestStringIndex](uint index) { + highestStringIndex = qMax(highestStringIndex, index); + }; + + *fieldCount = countMetaObjectFields(mo, stringIndexVisitor); + *stringCount = highestStringIndex + 1; + + return true; +} + /*! \internal \a index MUST be in the signal index range (see QObjectPrivate::signalIndex()). This is different from QMetaMethod::methodIndex(). diff --git a/src/qml/qml/qqmlpropertycache_p.h b/src/qml/qml/qqmlpropertycache_p.h index ad6db9756f..fd29cc8e6a 100644 --- a/src/qml/qml/qqmlpropertycache_p.h +++ b/src/qml/qml/qqmlpropertycache_p.h @@ -366,6 +366,8 @@ public: void toMetaObjectBuilder(QMetaObjectBuilder &); + static bool determineMetaObjectSizes(const QMetaObject &mo, int *fieldCount, int *stringCount); + protected: virtual void destroy(); virtual void clear(); diff --git a/tests/auto/qml/qqmlpropertycache/tst_qqmlpropertycache.cpp b/tests/auto/qml/qqmlpropertycache/tst_qqmlpropertycache.cpp index 5f15afff85..acc68befb5 100644 --- a/tests/auto/qml/qqmlpropertycache/tst_qqmlpropertycache.cpp +++ b/tests/auto/qml/qqmlpropertycache/tst_qqmlpropertycache.cpp @@ -30,6 +30,7 @@ #include <private/qqmlpropertycache_p.h> #include <QtQml/qqmlengine.h> #include <private/qv8engine_p.h> +#include <private/qmetaobjectbuilder_p.h> #include "../../shared/util.h" class tst_qqmlpropertycache : public QObject @@ -45,6 +46,8 @@ private slots: void methodsDerived(); void signalHandlers(); void signalHandlersDerived(); + void metaObjectSize_data(); + void metaObjectSize(); private: QQmlEngine engine; @@ -105,16 +108,16 @@ void tst_qqmlpropertycache::properties() QQmlRefPointer<QQmlPropertyCache> cache(new QQmlPropertyCache(v4, metaObject)); QQmlPropertyData *data; - QVERIFY(data = cacheProperty(cache, "propertyA")); + QVERIFY((data = cacheProperty(cache, "propertyA"))); QCOMPARE(data->coreIndex, metaObject->indexOfProperty("propertyA")); - QVERIFY(data = cacheProperty(cache, "propertyB")); + QVERIFY((data = cacheProperty(cache, "propertyB"))); QCOMPARE(data->coreIndex, metaObject->indexOfProperty("propertyB")); - QVERIFY(data = cacheProperty(cache, "propertyC")); + QVERIFY((data = cacheProperty(cache, "propertyC"))); QCOMPARE(data->coreIndex, metaObject->indexOfProperty("propertyC")); - QVERIFY(data = cacheProperty(cache, "propertyD")); + QVERIFY((data = cacheProperty(cache, "propertyD"))); QCOMPARE(data->coreIndex, metaObject->indexOfProperty("propertyD")); } @@ -129,16 +132,16 @@ void tst_qqmlpropertycache::propertiesDerived() QQmlRefPointer<QQmlPropertyCache> cache(parentCache->copyAndAppend(object.metaObject())); QQmlPropertyData *data; - QVERIFY(data = cacheProperty(cache, "propertyA")); + QVERIFY((data = cacheProperty(cache, "propertyA"))); QCOMPARE(data->coreIndex, metaObject->indexOfProperty("propertyA")); - QVERIFY(data = cacheProperty(cache, "propertyB")); + QVERIFY((data = cacheProperty(cache, "propertyB"))); QCOMPARE(data->coreIndex, metaObject->indexOfProperty("propertyB")); - QVERIFY(data = cacheProperty(cache, "propertyC")); + QVERIFY((data = cacheProperty(cache, "propertyC"))); QCOMPARE(data->coreIndex, metaObject->indexOfProperty("propertyC")); - QVERIFY(data = cacheProperty(cache, "propertyD")); + QVERIFY((data = cacheProperty(cache, "propertyD"))); QCOMPARE(data->coreIndex, metaObject->indexOfProperty("propertyD")); } @@ -152,28 +155,28 @@ void tst_qqmlpropertycache::methods() QQmlRefPointer<QQmlPropertyCache> cache(new QQmlPropertyCache(v4, metaObject)); QQmlPropertyData *data; - QVERIFY(data = cacheProperty(cache, "slotA")); + QVERIFY((data = cacheProperty(cache, "slotA"))); QCOMPARE(data->coreIndex, metaObject->indexOfMethod("slotA()")); - QVERIFY(data = cacheProperty(cache, "slotB")); + QVERIFY((data = cacheProperty(cache, "slotB"))); QCOMPARE(data->coreIndex, metaObject->indexOfMethod("slotB()")); - QVERIFY(data = cacheProperty(cache, "signalA")); + QVERIFY((data = cacheProperty(cache, "signalA"))); QCOMPARE(data->coreIndex, metaObject->indexOfMethod("signalA()")); - QVERIFY(data = cacheProperty(cache, "signalB")); + QVERIFY((data = cacheProperty(cache, "signalB"))); QCOMPARE(data->coreIndex, metaObject->indexOfMethod("signalB()")); - QVERIFY(data = cacheProperty(cache, "propertyAChanged")); + QVERIFY((data = cacheProperty(cache, "propertyAChanged"))); QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyAChanged()")); - QVERIFY(data = cacheProperty(cache, "propertyBChanged")); + QVERIFY((data = cacheProperty(cache, "propertyBChanged"))); QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyBChanged()")); - QVERIFY(data = cacheProperty(cache, "propertyCChanged")); + QVERIFY((data = cacheProperty(cache, "propertyCChanged"))); QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyCChanged()")); - QVERIFY(data = cacheProperty(cache, "propertyDChanged")); + QVERIFY((data = cacheProperty(cache, "propertyDChanged"))); QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyDChanged()")); } @@ -188,28 +191,28 @@ void tst_qqmlpropertycache::methodsDerived() QQmlRefPointer<QQmlPropertyCache> cache(parentCache->copyAndAppend(object.metaObject())); QQmlPropertyData *data; - QVERIFY(data = cacheProperty(cache, "slotA")); + QVERIFY((data = cacheProperty(cache, "slotA"))); QCOMPARE(data->coreIndex, metaObject->indexOfMethod("slotA()")); - QVERIFY(data = cacheProperty(cache, "slotB")); + QVERIFY((data = cacheProperty(cache, "slotB"))); QCOMPARE(data->coreIndex, metaObject->indexOfMethod("slotB()")); - QVERIFY(data = cacheProperty(cache, "signalA")); + QVERIFY((data = cacheProperty(cache, "signalA"))); QCOMPARE(data->coreIndex, metaObject->indexOfMethod("signalA()")); - QVERIFY(data = cacheProperty(cache, "signalB")); + QVERIFY((data = cacheProperty(cache, "signalB"))); QCOMPARE(data->coreIndex, metaObject->indexOfMethod("signalB()")); - QVERIFY(data = cacheProperty(cache, "propertyAChanged")); + QVERIFY((data = cacheProperty(cache, "propertyAChanged"))); QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyAChanged()")); - QVERIFY(data = cacheProperty(cache, "propertyBChanged")); + QVERIFY((data = cacheProperty(cache, "propertyBChanged"))); QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyBChanged()")); - QVERIFY(data = cacheProperty(cache, "propertyCChanged")); + QVERIFY((data = cacheProperty(cache, "propertyCChanged"))); QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyCChanged()")); - QVERIFY(data = cacheProperty(cache, "propertyDChanged")); + QVERIFY((data = cacheProperty(cache, "propertyDChanged"))); QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyDChanged()")); } @@ -223,22 +226,22 @@ void tst_qqmlpropertycache::signalHandlers() QQmlRefPointer<QQmlPropertyCache> cache(new QQmlPropertyCache(v4, metaObject)); QQmlPropertyData *data; - QVERIFY(data = cacheProperty(cache, "onSignalA")); + QVERIFY((data = cacheProperty(cache, "onSignalA"))); QCOMPARE(data->coreIndex, metaObject->indexOfMethod("signalA()")); - QVERIFY(data = cacheProperty(cache, "onSignalB")); + QVERIFY((data = cacheProperty(cache, "onSignalB"))); QCOMPARE(data->coreIndex, metaObject->indexOfMethod("signalB()")); - QVERIFY(data = cacheProperty(cache, "onPropertyAChanged")); + QVERIFY((data = cacheProperty(cache, "onPropertyAChanged"))); QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyAChanged()")); - QVERIFY(data = cacheProperty(cache, "onPropertyBChanged")); + QVERIFY((data = cacheProperty(cache, "onPropertyBChanged"))); QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyBChanged()")); - QVERIFY(data = cacheProperty(cache, "onPropertyCChanged")); + QVERIFY((data = cacheProperty(cache, "onPropertyCChanged"))); QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyCChanged()")); - QVERIFY(data = cacheProperty(cache, "onPropertyDChanged")); + QVERIFY((data = cacheProperty(cache, "onPropertyDChanged"))); QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyDChanged()")); } @@ -253,25 +256,109 @@ void tst_qqmlpropertycache::signalHandlersDerived() QQmlRefPointer<QQmlPropertyCache> cache(parentCache->copyAndAppend(object.metaObject())); QQmlPropertyData *data; - QVERIFY(data = cacheProperty(cache, "onSignalA")); + QVERIFY((data = cacheProperty(cache, "onSignalA"))); QCOMPARE(data->coreIndex, metaObject->indexOfMethod("signalA()")); - QVERIFY(data = cacheProperty(cache, "onSignalB")); + QVERIFY((data = cacheProperty(cache, "onSignalB"))); QCOMPARE(data->coreIndex, metaObject->indexOfMethod("signalB()")); - QVERIFY(data = cacheProperty(cache, "onPropertyAChanged")); + QVERIFY((data = cacheProperty(cache, "onPropertyAChanged"))); QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyAChanged()")); - QVERIFY(data = cacheProperty(cache, "onPropertyBChanged")); + QVERIFY((data = cacheProperty(cache, "onPropertyBChanged"))); QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyBChanged()")); - QVERIFY(data = cacheProperty(cache, "onPropertyCChanged")); + QVERIFY((data = cacheProperty(cache, "onPropertyCChanged"))); QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyCChanged()")); - QVERIFY(data = cacheProperty(cache, "onPropertyDChanged")); + QVERIFY((data = cacheProperty(cache, "onPropertyDChanged"))); QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyDChanged()")); } -QTEST_MAIN(tst_qqmlpropertycache) +class TestClass : public QObject +{ + Q_OBJECT + Q_PROPERTY(int prop READ prop WRITE setProp NOTIFY propChanged) + int m_prop; + +public: + enum MyEnum { + First, Second + }; + Q_ENUM(MyEnum) + + Q_CLASSINFO("Foo", "Bar") + + TestClass() {} + + int prop() const + { + return m_prop; + } + +public slots: + void setProp(int prop) + { + if (m_prop == prop) + return; + + m_prop = prop; + emit propChanged(prop); + } +signals: + void propChanged(int prop); +}; + +class TestClassWithParameters : public QObject +{ + Q_OBJECT + +public: + Q_INVOKABLE void slotWithArguments(int firstArg) { + Q_UNUSED(firstArg); + } +}; + +class TestClassWithClassInfo : public QObject +{ + Q_OBJECT + Q_CLASSINFO("Key", "Value") +}; #include "tst_qqmlpropertycache.moc" + +#define ARRAY_SIZE(arr) \ + int(sizeof(arr) / sizeof(arr[0])) + +#define TEST_CLASS(Class) \ + QTest::newRow(#Class) << &Class::staticMetaObject << ARRAY_SIZE(qt_meta_data_##Class) << ARRAY_SIZE(qt_meta_stringdata_##Class.data) + +Q_DECLARE_METATYPE(const QMetaObject*); + +void tst_qqmlpropertycache::metaObjectSize_data() +{ + QTest::addColumn<const QMetaObject*>("metaObject"); + QTest::addColumn<int>("expectedFieldCount"); + QTest::addColumn<int>("expectedStringCount"); + + TEST_CLASS(TestClass); + TEST_CLASS(TestClassWithParameters); + TEST_CLASS(TestClassWithClassInfo); +} + +void tst_qqmlpropertycache::metaObjectSize() +{ + QFETCH(const QMetaObject *, metaObject); + QFETCH(int, expectedFieldCount); + QFETCH(int, expectedStringCount); + + int size = 0; + int stringDataSize = 0; + bool valid = QQmlPropertyCache::determineMetaObjectSizes(*metaObject, &size, &stringDataSize); + QVERIFY(valid); + + QCOMPARE(size, expectedFieldCount - 1); // Remove trailing zero field until fixed in moc. + QCOMPARE(stringDataSize, expectedStringCount); +} + +QTEST_MAIN(tst_qqmlpropertycache) |