Handle enum values of -1 correctly.
authorMichael Brasser <michael.brasser@nokia.com>
Thu, 21 Jun 2012 23:23:26 +0000 (09:23 +1000)
committerQt by Nokia <qt-info@nokia.com>
Fri, 22 Jun 2012 04:54:59 +0000 (06:54 +0200)
This was already handled correctly most places; now the
remaining cases (using an enum in ListModel, and assigning
an enum to an integer property) should also work correctly.

Task-number: QTBUG-21679
Change-Id: Ibff13f0b94da94b18e2e3bae4aa6ba44e0fa944b
Reviewed-by: Chris Adams <christopher.adams@nokia.com>
src/qml/qml/qqmlcompiler.cpp
src/qml/qml/qqmlcompiler_p.h
src/qml/qml/qqmlcustomparser.cpp
src/qml/qml/qqmlcustomparser_p.h
src/qml/qml/qquicklistmodel.cpp
tests/auto/qml/qqmlecmascript/data/enums.3.qml
tests/auto/qml/qqmlecmascript/testtypes.h
tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
tests/auto/qml/qquicklistmodel/tst_qquicklistmodel.cpp

index 5df02d0..2bb99dd 100644 (file)
@@ -2517,8 +2517,9 @@ bool QQmlCompiler::testQualifiedEnumAssignment(QQmlScript::Property *prop,
 
     if (isIntProp) {
         // Allow enum assignment to ints.
-        int enumval = evaluateEnum(typeName, enumValue.toUtf8());
-        if (enumval != -1) {
+        bool ok;
+        int enumval = evaluateEnum(typeName, enumValue.toUtf8(), &ok);
+        if (ok) {
             v->type = Value::Literal;
             v->value = QQmlScript::Variant((double)enumval);
             *isAssignment = true;
@@ -2565,8 +2566,10 @@ bool QQmlCompiler::testQualifiedEnumAssignment(QQmlScript::Property *prop,
 }
 
 // Similar logic to above, but not knowing target property.
-int QQmlCompiler::evaluateEnum(const QHashedStringRef &scope, const QByteArray& enumValue) const
+int QQmlCompiler::evaluateEnum(const QHashedStringRef &scope, const QByteArray& enumValue, bool *ok) const
 {
+    Q_ASSERT_X(ok, "QQmlCompiler::evaluateEnum", "ok must not be a null pointer");
+    *ok = false;
     QQmlType *type = 0;
     if (scope != QLatin1String("Qt")) {
         unit->imports().resolveType(scope, &type, 0, 0, 0, 0);
@@ -2577,9 +2580,8 @@ int QQmlCompiler::evaluateEnum(const QHashedStringRef &scope, const QByteArray&
     const QMetaObject *mo = type ? type->metaObject() : StaticQtMetaObject::get();
     int i = mo->enumeratorCount();
     while (i--) {
-        bool ok;
-        int v = mo->enumerator(i).keyToValue(enumValue.constData(), &ok);
-        if (ok)
+        int v = mo->enumerator(i).keyToValue(enumValue.constData(), ok);
+        if (*ok)
             return v;
     }
     return -1;
index 4b730c2..b919b53 100644 (file)
@@ -295,7 +295,7 @@ public:
     static bool isAttachedPropertyName(const QHashedStringRef &);
     static bool isSignalPropertyName(const QHashedStringRef &);
 
-    int evaluateEnum(const QHashedStringRef &scope, const QByteArray& enumValue) const; // for QQmlCustomParser::evaluateEnum
+    int evaluateEnum(const QHashedStringRef &scope, const QByteArray& enumValue, bool *ok) const; // for QQmlCustomParser::evaluateEnum
     const QMetaObject *resolveType(const QString& name) const; // for QQmlCustomParser::resolveType
     int rewriteBinding(const QQmlScript::Variant& value, const QString& name); // for QQmlCustomParser::rewriteBinding
     QString rewriteSignalHandler(const QQmlScript::Variant& value, const QString &name);  // for QQmlCustomParser::rewriteSignalHandler
index f020376..7c7a2f5 100644 (file)
@@ -279,18 +279,22 @@ void QQmlCustomParser::error(const QQmlCustomParserNode& node, const QString& de
 }
 
 /*!
-    If \a script is a simply enum expression (eg. Text.AlignLeft),
-    returns the integer equivalent (eg. 1).
+    If \a script is a simple enum expression (eg. Text.AlignLeft),
+    returns the integer equivalent (eg. 1), and sets \a ok to true.
 
-    Otherwise, returns -1.
+    Otherwise sets \a ok to false.
+
+    A valid \a ok must be provided, or the function will assert.
 */
-int QQmlCustomParser::evaluateEnum(const QByteArray& script) const
+int QQmlCustomParser::evaluateEnum(const QByteArray& script, bool *ok) const
 {
+    Q_ASSERT_X(ok, "QQmlCustomParser::evaluateEnum", "ok must not be a null pointer");
+    *ok = false;
     int dot = script.indexOf('.');
     if (dot == -1)
         return -1;
 
-    return compiler->evaluateEnum(QString::fromUtf8(script.left(dot)), script.mid(dot+1));
+    return compiler->evaluateEnum(QString::fromUtf8(script.left(dot)), script.mid(dot+1), ok);
 }
 
 /*!
index 0207797..b8cc9f7 100644 (file)
@@ -137,7 +137,7 @@ protected:
     void error(const QQmlCustomParserProperty&, const QString& description);
     void error(const QQmlCustomParserNode&, const QString& description);
 
-    int evaluateEnum(const QByteArray&) const;
+    int evaluateEnum(const QByteArray&, bool *ok) const;
 
     const QMetaObject *resolveType(const QString&) const;
 
index 461d4d8..52ef2ab 100644 (file)
@@ -2229,8 +2229,9 @@ bool QQuickListModelParser::compileProperty(const QQmlCustomParserProperty &prop
                     d[0] = char(QQmlScript::Variant::Invalid); // marks empty list
                 } else {
                     QByteArray script = variant.asScript().toUtf8();
-                    int v = evaluateEnum(script);
-                    if (v<0) {
+                    bool ok;
+                    int v = evaluateEnum(script, &ok);
+                    if (!ok) {
                         using namespace QQmlJS;
                         AST::Node *node = variant.asAST();
                         AST::StringLiteral *literal = 0;
index c77d635..fd3432f 100644 (file)
@@ -19,6 +19,9 @@ Item {
     property int h: Namespace.MyQmlObject.EnumValue3
     property int i: Namespace.MyQmlObject.EnumValue4
 
+    // -1 enum
+    property int j: MyQmlObject.EnumValue5
+
     // Count the onChanged signals to see whether
     // they're assigned as literals or via bindings
     property int ac: 0
@@ -29,6 +32,7 @@ Item {
     property int fc: 0
     property int hc: 0
     property int ic: 0
+    property int jc: 0
 
     onAChanged: ac++
     onBChanged: bc++
@@ -38,4 +42,5 @@ Item {
     onFChanged: fc++
     onHChanged: hc++
     onIChanged: ic++
+    onJChanged: jc++
 }
index 8f3804a..ab44d59 100644 (file)
@@ -111,7 +111,7 @@ public:
     MyQmlObject(): myinvokableObject(0), m_methodCalled(false), m_methodIntCalled(false), m_object(0), m_value(0), m_resetProperty(13), m_intProperty(0), m_buttons(0) {}
 
     enum MyEnum { EnumValue1 = 0, EnumValue2 = 1 };
-    enum MyEnum2 { EnumValue3 = 2, EnumValue4 = 3 };
+    enum MyEnum2 { EnumValue3 = 2, EnumValue4 = 3, EnumValue5 = -1 };
 
     bool trueProperty() const { return true; }
     bool falseProperty() const { return false; }
index d344758..c429ffa 100644 (file)
@@ -983,6 +983,7 @@ void tst_qqmlecmascript::enums()
     QCOMPARE(object->property("f").toInt(), 3);
     QCOMPARE(object->property("h").toInt(), 2);
     QCOMPARE(object->property("i").toInt(), 3);
+    QCOMPARE(object->property("j").toInt(), -1);
 
     // count of change signals
     QCOMPARE(object->property("ac").toInt(), 0);
@@ -993,6 +994,7 @@ void tst_qqmlecmascript::enums()
     QCOMPARE(object->property("fc").toInt(), 0);
     QCOMPARE(object->property("hc").toInt(), 1); // namespace -> binding
     QCOMPARE(object->property("ic").toInt(), 1); // namespace -> binding
+    QCOMPARE(object->property("jc").toInt(), 0);
 
     delete object;
     }
index 4c4aa48..89e8886 100644 (file)
@@ -41,6 +41,7 @@
 #include <qtest.h>
 #include <QtQuick/private/qquickitem_p.h>
 #include <QtQuick/private/qquicktext_p.h>
+#include <QtQuick/private/qquickanimation_p.h>
 #include <QtQml/private/qqmlengine_p.h>
 #include <QtQml/private/qquicklistmodel_p.h>
 #include <QtQml/private/qqmlexpression_p.h>
@@ -228,6 +229,11 @@ void tst_qquicklistmodel::static_types_data()
         << QVariant(double(Qt::AlignBottom))
         << QString();
 
+    QTest::newRow("negative enum")
+        << "ListElement { foo: Animation.Infinite }"
+        << QVariant(double(QQuickAbstractAnimation::Infinite))
+        << QString();
+
     QTest::newRow("role error")
         << "ListElement { foo: 1 } ListElement { foo: 'string' }"
         << QVariant()