diff options
Diffstat (limited to 'src/qml/qml/qqmlcustomparser.cpp')
-rw-r--r-- | src/qml/qml/qqmlcustomparser.cpp | 63 |
1 files changed, 50 insertions, 13 deletions
diff --git a/src/qml/qml/qqmlcustomparser.cpp b/src/qml/qml/qqmlcustomparser.cpp index fba805f084..ca3985bd92 100644 --- a/src/qml/qml/qqmlcustomparser.cpp +++ b/src/qml/qml/qqmlcustomparser.cpp @@ -1,6 +1,7 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +#include "qml/qqmlpropertyvalidator_p.h" #include "qqmlcustomparser_p.h" #include <private/qv4compileddata_p.h> @@ -81,7 +82,7 @@ void QQmlCustomParser::error(const QV4::CompiledData::Location &location, const A valid \a ok must be provided, or the function will assert. */ -int QQmlCustomParser::evaluateEnum(const QByteArray& script, bool *ok) const +int QQmlCustomParser::evaluateEnum(const QString &script, bool *ok) const { Q_ASSERT_X(ok, "QQmlCustomParser::evaluateEnum", "ok must not be a null pointer"); *ok = false; @@ -91,7 +92,7 @@ int QQmlCustomParser::evaluateEnum(const QByteArray& script, bool *ok) const // * <TypeName>.<ScopedEnumName>.<EnumValue> auto nextDot = [&](int dot) { - const int nextDot = script.indexOf('.', dot + 1); + const int nextDot = script.indexOf(u'.', dot + 1); return (nextDot == script.length() - 1) ? -1 : nextDot; }; @@ -99,7 +100,7 @@ int QQmlCustomParser::evaluateEnum(const QByteArray& script, bool *ok) const if (dot == -1) return -1; - QString scope = QString::fromUtf8(script.left(dot)); + const QString scope = script.left(dot); if (scope != QLatin1String("Qt")) { if (imports.isNull()) @@ -108,23 +109,35 @@ int QQmlCustomParser::evaluateEnum(const QByteArray& script, bool *ok) const if (imports.isT1()) { QQmlImportNamespace *ns = nullptr; - if (!imports.asT1()->resolveType(scope, &type, nullptr, &ns)) + + // Pass &recursionDetected to resolveType because that implicitly allows recursion. + // This way we can find the QQmlType of the document we're currently validating. + bool recursionDetected = false; + + if (!imports.asT1()->resolveType( + scope, &type, nullptr, &ns, nullptr, + QQmlType::AnyRegistrationType, &recursionDetected)) { return -1; + } + if (!type.isValid() && ns != nullptr) { dot = nextDot(dot); - if (dot == -1 || !imports.asT1()->resolveType(QString::fromUtf8(script.left(dot)), - &type, nullptr, nullptr)) { + if (dot == -1 || !imports.asT1()->resolveType( + script.left(dot), &type, nullptr, nullptr, nullptr, + QQmlType::AnyRegistrationType, &recursionDetected)) { return -1; } } } else { - QQmlTypeNameCache::Result result = imports.asT2()->query(scope); + // Allow recursion so that we can find enums from the same document. + const QQmlTypeNameCache::Result result + = imports.asT2()->query<QQmlImport::AllowRecursion>(scope); if (result.isValid()) { type = result.type; } else if (result.importNamespace) { dot = nextDot(dot); if (dot != -1) - type = imports.asT2()->query(QString::fromUtf8(script.left(dot))).type; + type = imports.asT2()->query<QQmlImport::AllowRecursion>(script.left(dot)).type; } } @@ -133,19 +146,43 @@ int QQmlCustomParser::evaluateEnum(const QByteArray& script, bool *ok) const const int dot2 = nextDot(dot); const bool dot2Valid = (dot2 != -1); - QByteArray enumValue = script.mid(dot2Valid ? dot2 + 1 : dot + 1); - QByteArray scopedEnumName = (dot2Valid ? script.mid(dot + 1, dot2 - dot - 1) : QByteArray()); + const QString enumValue = script.mid(dot2Valid ? dot2 + 1 : dot + 1); + const QString scopedEnumName = dot2Valid ? script.mid(dot + 1, dot2 - dot - 1) : QString(); + + // If we're currently validating the same document, we won't be able to find its enums using + // the QQmlType. However, we do have the property cache already, and that one contains the + // enums. + const QUrl documentUrl = validator ? validator->documentSourceUrl() : QUrl(); + if (documentUrl.isValid() && documentUrl == type.sourceUrl()) { + const QQmlPropertyCache::ConstPtr rootCache = validator->rootPropertyCache(); + const int count = rootCache->qmlEnumCount(); + for (int ii = 0; ii < count; ++ii) { + const QQmlEnumData *enumData = rootCache->qmlEnum(ii); + if (!scopedEnumName.isEmpty() && scopedEnumName != enumData->name) + continue; + + for (int jj = 0; jj < enumData->values.count(); ++jj) { + const QQmlEnumValue value = enumData->values.at(jj); + if (value.namedValue == enumValue) { + *ok = true; + return value.value; + } + } + } + return -1; + } + if (!scopedEnumName.isEmpty()) return type.scopedEnumValue(engine, scopedEnumName, enumValue, ok); else - return type.enumValue(engine, QHashedCStringRef(enumValue.constData(), enumValue.length()), ok); + return type.enumValue(engine, enumValue, ok); } - QByteArray enumValue = script.mid(dot + 1); + const QString enumValue = script.mid(dot + 1); const QMetaObject *mo = &Qt::staticMetaObject; int i = mo->enumeratorCount(); while (i--) { - int v = mo->enumerator(i).keyToValue(enumValue.constData(), ok); + int v = mo->enumerator(i).keyToValue(enumValue.toUtf8().constData(), ok); if (*ok) return v; } |