From e90705687f5faba41d9a8544c875d8c6b1cedbdc Mon Sep 17 00:00:00 2001 From: Ahmad Samir Date: Mon, 30 Oct 2023 13:02:03 +0200 Subject: [PATCH] QMetaEnum: refactor keysToValue - Show warning messages for malformed keys string - Use QBAV instead of QL1SV, some methods in the public API may get QU8SV overloads in later commits - Extend unittests; also rename the unittest, it's really testing key(s)ToValue() Change-Id: Iec944ef4c2c5d18ab038cb933e954cf50c912523 Reviewed-by: Fabian Kosmale --- src/corelib/kernel/qmetaobject.cpp | 51 ++++++++++++++++++- .../kernel/qmetaobject/tst_qmetaobject.cpp | 30 +++++++++-- 2 files changed, 76 insertions(+), 5 deletions(-) diff --git a/src/corelib/kernel/qmetaobject.cpp b/src/corelib/kernel/qmetaobject.cpp index 6c3f3a54f0..1c7536eb09 100644 --- a/src/corelib/kernel/qmetaobject.cpp +++ b/src/corelib/kernel/qmetaobject.cpp @@ -3240,6 +3240,51 @@ const char *QMetaEnum::valueToKey(int value) const return nullptr; } +static bool parseEnumFlags(QByteArrayView v, QVarLengthArray &list) +{ + v = v.trimmed(); + if (v.empty()) { + qWarning("QMetaEnum::keysToValue: empty keys string."); + return false; + } + + qsizetype sep = v.indexOf('|', 0); + if (sep == 0) { + qWarning("QMetaEnum::keysToValue: malformed keys string, starts with '|', \"%s\"", + v.constData()); + return false; + } + + if (sep == -1) { // One flag + list.push_back(v); + return true; + } + + if (v.endsWith('|')) { + qWarning("QMetaEnum::keysToValue: malformed keys string, ends with '|', \"%s\"", + v.constData()); + return false; + } + + const auto begin = v.begin(); + const auto end = v.end(); + auto b = begin; + for (; b != end && sep != -1; sep = v.indexOf('|', sep)) { + list.push_back({b, begin + sep}); + ++sep; // Skip over '|' + b = begin + sep; + if (*b == '|') { + qWarning("QMetaEnum::keysToValue: malformed keys string, has two consecutive '|': " + "\"%s\"", v.constData()); + return false; + } + } + + // The rest of the string + list.push_back({b, end}); + return true; +} + /*! Returns the value derived from combining together the values of the \a keys using the OR operator, or -1 if \a keys is not @@ -3266,7 +3311,11 @@ int QMetaEnum::keysToValue(const char *keys, bool *ok) const }; int value = 0; - for (const QLatin1StringView &untrimmed : qTokenize(QLatin1StringView{keys}, u'|')) { + QVarLengthArray list; + const bool r = parseEnumFlags(QByteArrayView{keys}, list); + if (!r) + return -1; + for (const auto &untrimmed : list) { const auto parsed = parse_scope(untrimmed.trimmed()); if (parsed.scope && *parsed.scope != objectClassName(mobj)) return -1; // wrong type name in qualified name diff --git a/tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp b/tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp index aed8e48afe..362f2707e7 100644 --- a/tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp +++ b/tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp @@ -312,8 +312,8 @@ private slots: void normalizedType_data(); void normalizedType(); void customPropertyType(); - void checkScope_data(); - void checkScope(); + void keysToValue_data(); + void keysToValue(); // Also keyToValue() void propertyNotify(); void propertyConstant(); void propertyFinal(); @@ -2339,7 +2339,7 @@ void tst_QMetaObject::customPropertyType() QCOMPARE(prop.metaType().id(), QMetaType::QVariantList); } -void tst_QMetaObject::checkScope_data() +void tst_QMetaObject::keysToValue_data() { QTest::addColumn("object"); QTest::addColumn("name"); @@ -2353,7 +2353,7 @@ void tst_QMetaObject::checkScope_data() } -void tst_QMetaObject::checkScope() +void tst_QMetaObject::keysToValue() { QFETCH(QObject *, object); QFETCH(QByteArray, name); @@ -2419,6 +2419,28 @@ void tst_QMetaObject::checkScope() QCOMPARE(mf.keysToValue("MyNamespace::" + name + "::MyFlag2|MyNamespace::" + name + "::MyFlag2", &ok), 2); QCOMPARE(ok, true); QCOMPARE(QLatin1String(mf.valueToKeys(3)), QLatin1String("MyFlag1|MyFlag2")); + + // Test flags with extra '|' + QTest::ignoreMessage(QtWarningMsg, + QRegularExpression(u"QMetaEnum::keysToValue: malformed keys string, ends with '|'.+"_s)); + QCOMPARE(mf.keysToValue("MyFlag1|MyFlag2|", &ok), -1); + QCOMPARE(ok, false); + + QTest::ignoreMessage(QtWarningMsg, + QRegularExpression(u"QMetaEnum::keysToValue: malformed keys string, starts with '|'.+"_s)); + QCOMPARE(mf.keysToValue("|MyFlag1|MyFlag2|", &ok), -1); + QCOMPARE(ok, false); + + QTest::ignoreMessage(QtWarningMsg, + QRegularExpression( + u"QMetaEnum::keysToValue: malformed keys string, has two consecutive '|'.+"_s)); + QCOMPARE(mf.keysToValue("MyFlag1||MyFlag2", &ok), -1); + QCOMPARE(ok, false); + + // Test empty string + QTest::ignoreMessage(QtWarningMsg, "QMetaEnum::keysToValue: empty keys string."); + QCOMPARE(mf.keysToValue("", &ok), -1); + QCOMPARE(ok, false); } void tst_QMetaObject::propertyNotify()