diff options
-rw-r--r-- | src/qml/jsruntime/qv4engine.cpp | 5 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4qobjectwrapper.cpp | 2 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4variantobject.cpp | 3 | ||||
-rw-r--r-- | src/qml/qml/qqmlboundsignal.cpp | 2 | ||||
-rw-r--r-- | src/qml/qml/qqmlmetaobject.cpp | 4 | ||||
-rw-r--r-- | src/qml/qml/qqmlproperty.cpp | 9 | ||||
-rw-r--r-- | src/qml/qml/qqmlvaluetypewrapper.cpp | 2 | ||||
-rw-r--r-- | tests/auto/qml/qqmllanguage/testtypes.cpp | 4 | ||||
-rw-r--r-- | tests/auto/qml/qqmllanguage/testtypes.h | 146 | ||||
-rw-r--r-- | tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp | 50 |
10 files changed, 211 insertions, 16 deletions
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index 41c7a90906..809892dacf 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -1850,7 +1850,7 @@ QV4::ReturnedValue ExecutionEngine::fromData( } } - } else { + } else if (!(metaType.flags() & QMetaType::IsEnumeration)) { QV4::Scope scope(this); if (metaType == QMetaType::fromType<QQmlListReference>()) { typedef QQmlListReferencePrivate QDLRP; @@ -1936,9 +1936,8 @@ QV4::ReturnedValue ExecutionEngine::fromData( // + QObjectList // + QList<int> - // Enumeration types can just be treated as integers for now if (metaType.flags() & QMetaType::IsEnumeration) - return QV4::Encode(*reinterpret_cast<const int *>(ptr)); + return fromData(metaType.underlyingType(), ptr, container, property, flags); return QV4::Encode(newVariantObject(metaType, ptr)); } diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index e2ebda7d0e..865f2af699 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -131,7 +131,7 @@ static ReturnedValue loadProperty( return QmlListWrapper::create(v4, object, property.coreIndex(), propMetaType); // TODO: Check all the builtin types here. See getGadgetProperty() in qqmlvaluetypewrapper.cpp - switch (property.isEnum() ? QMetaType::Int : propMetaType.id()) { + switch (property.isEnum() ? propMetaType.underlyingType().id() : propMetaType.id()) { case QMetaType::Int: { int v = 0; property.readProperty(object, &v); diff --git a/src/qml/jsruntime/qv4variantobject.cpp b/src/qml/jsruntime/qv4variantobject.cpp index ccea9cac2a..62e21a120c 100644 --- a/src/qml/jsruntime/qv4variantobject.cpp +++ b/src/qml/jsruntime/qv4variantobject.cpp @@ -131,7 +131,8 @@ ReturnedValue VariantPrototype::method_valueOf(const FunctionObject *b, const Va return Encode(v.toBool()); default: if (QMetaType(v.metaType()).flags() & QMetaType::IsEnumeration) - return Encode(v.toInt()); + if (v.metaType().sizeOf() <= qsizetype(sizeof(int))) + return Encode(v.toInt()); if (v.canConvert<double>()) return Encode(v.toDouble()); if (v.canConvert<int>()) diff --git a/src/qml/qml/qqmlboundsignal.cpp b/src/qml/qml/qqmlboundsignal.cpp index da81244f18..55e21abae2 100644 --- a/src/qml/qml/qqmlboundsignal.cpp +++ b/src/qml/qml/qqmlboundsignal.cpp @@ -183,7 +183,7 @@ void QQmlBoundSignalExpression::evaluate(void **a) if (!type.isValid()) argCount = 0; else if (type.flags().testFlag(QMetaType::IsEnumeration)) - storage.append(QMetaType::fromType<int>()); + storage.append(type.underlyingType()); else storage.append(type); } diff --git a/src/qml/qml/qqmlmetaobject.cpp b/src/qml/qml/qqmlmetaobject.cpp index d5f1fb3b96..82903f80b2 100644 --- a/src/qml/qml/qqmlmetaobject.cpp +++ b/src/qml/qml/qqmlmetaobject.cpp @@ -48,7 +48,7 @@ QMetaType QQmlMetaObject::methodReturnType(const QQmlPropertyData &data, QByteAr type = _m->method(data.coreIndex()).returnMetaType(); } if (type.flags().testFlag(QMetaType::IsEnumeration)) - type = QMetaType::fromType<int>(); + type = type.underlyingType(); if (type.isValid()) return type; else if (unknownTypeError) @@ -83,7 +83,7 @@ bool QQmlMetaObject::methodParameterTypes(const QMetaMethod &m, ArgTypeStorage * QMetaType type = m.parameterMetaType(ii); // we treat enumerations as int if (type.flags().testFlag(QMetaType::IsEnumeration)) - type = QMetaType::fromType<int>(); + type = type.underlyingType(); if (!type.isValid()) { if (unknownTypeError) *unknownTypeError = m.parameterTypeName(ii); diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp index 3c039ba55d..c1f327cd5a 100644 --- a/src/qml/qml/qqmlproperty.cpp +++ b/src/qml/qml/qqmlproperty.cpp @@ -1225,14 +1225,9 @@ bool QQmlPropertyPrivate::writeEnumProperty(const QMetaProperty &prop, int idx, v = QVariant(menum.keyToValue(value.toByteArray(), &ok)); if (!ok) return false; - } else if (v.userType() != QMetaType::Int && v.userType() != QMetaType::UInt) { - int enumMetaTypeId = QMetaType::fromName( - QByteArray(menum.scope() + QByteArray("::") + menum.name())).id(); - if ((enumMetaTypeId == QMetaType::UnknownType) || (v.userType() != enumMetaTypeId) || !v.constData()) - return false; - v = QVariant(*reinterpret_cast<const int *>(v.constData())); } - v.convert(QMetaType(QMetaType::Int)); + if (!v.convert(prop.metaType())) // ### TODO: underlyingType might be faster? + return false; } // the status variable is changed by qt_metacall to indicate what it did diff --git a/src/qml/qml/qqmlvaluetypewrapper.cpp b/src/qml/qml/qqmlvaluetypewrapper.cpp index be44f1e8c2..b20e1c79b7 100644 --- a/src/qml/qml/qqmlvaluetypewrapper.cpp +++ b/src/qml/qml/qqmlvaluetypewrapper.cpp @@ -368,7 +368,7 @@ static ReturnedValue getGadgetProperty(ExecutionEngine *engine, QMetaObject::ReadProperty, &metaObject, &index); const int metaTypeId = isEnum - ? QMetaType::Int + ? metaType.underlyingType().id() : (metaType.flags() & QMetaType::PointerToQObject) ? QMetaType::QObjectStar : metaType.id(); diff --git a/tests/auto/qml/qqmllanguage/testtypes.cpp b/tests/auto/qml/qqmllanguage/testtypes.cpp index e775eb165c..e65cbee54b 100644 --- a/tests/auto/qml/qqmllanguage/testtypes.cpp +++ b/tests/auto/qml/qqmllanguage/testtypes.cpp @@ -149,6 +149,10 @@ void registerTypes() qmlRegisterTypesAndRevisions<BaseValueType>("ValueTypes", 1); qmlRegisterTypesAndRevisions<DerivedValueType>("ValueTypes", 1); qmlRegisterTypesAndRevisions<GetterObject>("Test", 1); + + qmlRegisterNamespaceAndRevisions(&TypedEnums::staticMetaObject, "TypedEnums", 1); + qmlRegisterTypesAndRevisions<ObjectWithEnums>("TypedEnums", 1); + qmlRegisterTypesAndRevisions<GadgetWithEnums>("TypedEnums", 1); } QVariant myCustomVariantTypeConverter(const QString &data) diff --git a/tests/auto/qml/qqmllanguage/testtypes.h b/tests/auto/qml/qqmllanguage/testtypes.h index 977c274f6c..5f68deefaf 100644 --- a/tests/auto/qml/qqmllanguage/testtypes.h +++ b/tests/auto/qml/qqmllanguage/testtypes.h @@ -2420,5 +2420,151 @@ public: Q_INVOKABLE quint64 getQTrue() const { return 1; } }; +namespace TypedEnums { +Q_NAMESPACE +QML_ELEMENT + +enum E8S : qint8 { + E8SA = std::numeric_limits<qint8>::min(), + E8SB = -5, + E8SC = -1, + E8SD = 0, + E8SE = 1, + E8SF = 5, + E8SG = std::numeric_limits<qint8>::max(), +}; +Q_ENUM_NS(E8S); + +enum E8U : quint8 { + E8UA = 0, + E8UB = 1, + E8UC = 5, + E8UD = 1 << 7, + E8UE = std::numeric_limits<quint8>::max(), +}; +Q_ENUM_NS(E8U); + +enum E16S : qint16 { + E16SA = std::numeric_limits<qint16>::min(), + E16SB = -5, + E16SC = -1, + E16SD = 0, + E16SE = 1, + E16SF = 5, + E16SG = std::numeric_limits<qint16>::max(), +}; +Q_ENUM_NS(E16S); + +enum E16U : quint16 { + E16UA = 0, + E16UB = 1, + E16UC = 5, + E16UD = 1 << 15, + E16UE = std::numeric_limits<quint16>::max(), +}; +Q_ENUM_NS(E16U); + +enum E32S : qint32 { + E32SA = std::numeric_limits<qint32>::min(), + E32SB = -5, + E32SC = -1, + E32SD = 0, + E32SE = 1, + E32SF = 5, + E32SG = std::numeric_limits<qint32>::max(), +}; +Q_ENUM_NS(E32S); + +enum E32U : quint32 { + E32UA = 0, + E32UB = 1, + E32UC = 5, + E32UD = 1u << 31, + E32UE = std::numeric_limits<quint32>::max(), +}; +Q_ENUM_NS(E32U); + +enum E64S : qint64 { + E64SA = std::numeric_limits<qint64>::min(), + E64SB = -5, + E64SC = -1, + E64SD = 0, + E64SE = 1, + E64SF = 5, + E64SG = std::numeric_limits<qint64>::max(), +}; +Q_ENUM_NS(E64S); + +enum E64U : quint64 { + E64UA = 0, + E64UB = 1, + E64UC = 5, + E64UD = 1ull << 63, + E64UE = std::numeric_limits<quint64>::max(), +}; +Q_ENUM_NS(E64U); +} + +class GadgetWithEnums +{ + Q_GADGET + QML_VALUE_TYPE(gadgetWithEnums) + Q_PROPERTY(TypedEnums::E8S e8s MEMBER m_e8s); + Q_PROPERTY(TypedEnums::E8U e8u MEMBER m_e8u); + Q_PROPERTY(TypedEnums::E16S e16s MEMBER m_e16s); + Q_PROPERTY(TypedEnums::E16U e16u MEMBER m_e16u); + Q_PROPERTY(TypedEnums::E32S e32s MEMBER m_e32s); + Q_PROPERTY(TypedEnums::E32U e32u MEMBER m_e32u); + Q_PROPERTY(TypedEnums::E64S e64s MEMBER m_e64s); + Q_PROPERTY(TypedEnums::E64U e64u MEMBER m_e64u); +public: + TypedEnums::E8S m_e8s = {}; + TypedEnums::E8U m_e8u = {}; + TypedEnums::E16S m_e16s = {}; + TypedEnums::E16U m_e16u = {}; + TypedEnums::E32S m_e32s = {}; + TypedEnums::E32U m_e32u = {}; + TypedEnums::E64S m_e64s = {}; + TypedEnums::E64U m_e64u = {}; +private: + friend bool operator==(const GadgetWithEnums &a, const GadgetWithEnums &b) + { + return a.m_e8s == b.m_e8s && a.m_e8u == b.m_e8u && a.m_e16s == b.m_e16s + && a.m_e16u == b.m_e16u && a.m_e32s == b.m_e32s && a.m_e32u == b.m_e32u + && a.m_e64s == b.m_e64s && a.m_e64u == b.m_e64u; + } + friend bool operator!=(const GadgetWithEnums &a, const GadgetWithEnums &b) + { + return !(a == b); + } +}; + +class ObjectWithEnums : public QObject +{ + Q_OBJECT + QML_ELEMENT + Q_PROPERTY(TypedEnums::E8S e8s MEMBER m_e8s NOTIFY changed); + Q_PROPERTY(TypedEnums::E8U e8u MEMBER m_e8u NOTIFY changed); + Q_PROPERTY(TypedEnums::E16S e16s MEMBER m_e16s NOTIFY changed); + Q_PROPERTY(TypedEnums::E16U e16u MEMBER m_e16u NOTIFY changed); + Q_PROPERTY(TypedEnums::E32S e32s MEMBER m_e32s NOTIFY changed); + Q_PROPERTY(TypedEnums::E32U e32u MEMBER m_e32u NOTIFY changed); + Q_PROPERTY(TypedEnums::E64S e64s MEMBER m_e64s NOTIFY changed); + Q_PROPERTY(TypedEnums::E64U e64u MEMBER m_e64u NOTIFY changed); + Q_PROPERTY(GadgetWithEnums g MEMBER m_g NOTIFY changed); +public: + ObjectWithEnums(QObject *parent = nullptr) : QObject(parent) {} + TypedEnums::E8S m_e8s = {}; + TypedEnums::E8U m_e8u = {}; + TypedEnums::E16S m_e16s = {}; + TypedEnums::E16U m_e16u = {}; + TypedEnums::E32S m_e32s = {}; + TypedEnums::E32U m_e32u = {}; + TypedEnums::E64S m_e64s = {}; + TypedEnums::E64U m_e64u = {}; + GadgetWithEnums m_g; +Q_SIGNALS: + void changed(); +}; #endif // TESTTYPES_H diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp index ce7e0a1b1c..89f5258819 100644 --- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp +++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp @@ -410,6 +410,9 @@ private slots: void longConversion(); + void typedEnums_data(); + void typedEnums(); + private: QQmlEngine engine; QStringList defaultImportPathList; @@ -7924,6 +7927,53 @@ void tst_qqmllanguage::asValueType() QCOMPARE(point.y(), 20.0); } +void tst_qqmllanguage::typedEnums_data() +{ + QTest::addColumn<QString>("property"); + QTest::addColumn<double>("value"); + const QMetaObject *mo = &TypedEnums::staticMetaObject; + for (int i = 0, end = mo->enumeratorCount(); i != end; ++i) { + const QMetaEnum e = mo->enumerator(i); + for (int k = 0, end = e.keyCount(); k != end; ++k) { + QTest::addRow("%s::%s", e.name(), e.key(k)) + << QString::fromLatin1(e.name()).toLower() + << double(e.value(k)); + } + } +} +void tst_qqmllanguage::typedEnums() +{ + QFETCH(QString, property); + QFETCH(double, value); + QQmlEngine e; + const QString qml = QLatin1String(R"( + import QtQml + import TypedEnums + ObjectWithEnums { + property real input: %2 + %1: input + g.%1: input + property real output1: %1 + property real output2: g.%1 + } + )").arg(property).arg(value, 0, 'f'); + QQmlComponent c(&engine); + c.setData(qml.toUtf8(), QUrl("enums.qml"_L1)); + QVERIFY2(c.isReady(), qPrintable(c.errorString())); + QScopedPointer<QObject> o(c.create()); + QVERIFY(!o.isNull()); + + // TODO: This silently fails for quint32, qint64 and quint64 because QMetaEnum cannot encode + // such values either. For the 64bit values we'll also need a better type than double + // inside QML. + QEXPECT_FAIL("E32U::E32UD", "Not supported", Abort); + QEXPECT_FAIL("E32U::E32UE", "Not supported", Abort); + QEXPECT_FAIL("E64U::E64UE", "Not supported", Abort); + + QCOMPARE(o->property("output1").toDouble(), value); + QCOMPARE(o->property("output2").toDouble(), value); +} + QTEST_MAIN(tst_qqmllanguage) #include "tst_qqmllanguage.moc" |