diff options
author | Michael Brasser <mbrasser@ford.com> | 2017-04-13 17:10:45 -0500 |
---|---|---|
committer | Michael Brasser <michael.brasser@live.com> | 2017-05-03 11:38:21 +0000 |
commit | aae18aa05719c4b750905f467f42002f4cea1516 (patch) | |
tree | 167e75ae3aa157b47fccd75266ba40aa0325b63a /src/qml/compiler | |
parent | f7656d06c0d2095a8d8dd3b930e48dc98996634f (diff) |
C++11 scoped enum support for QML
[ChangeLog][QtQml] Support C++11 scoped enums in QML. These can now be
accessed as <TypeName>.<EnumName>.<EnumValue>
Change-Id: I29bd3f16e980f3e6f1b2390b5a8e9e8e999952a3
Task-number: QTBUG-54961
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
Diffstat (limited to 'src/qml/compiler')
-rw-r--r-- | src/qml/compiler/qqmlirbuilder.cpp | 37 | ||||
-rw-r--r-- | src/qml/compiler/qqmltypecompiler.cpp | 45 | ||||
-rw-r--r-- | src/qml/compiler/qqmltypecompiler_p.h | 2 |
3 files changed, 71 insertions, 13 deletions
diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp index 218f5675dc..de04116a6b 100644 --- a/src/qml/compiler/qqmlirbuilder.cpp +++ b/src/qml/compiler/qqmlirbuilder.cpp @@ -1687,6 +1687,7 @@ enum MetaObjectResolverFlags { }; static void initMetaObjectResolver(QV4::IR::MemberExpressionResolver *resolver, QQmlPropertyCache *metaObject); +static void initScopedEnumResolver(QV4::IR::MemberExpressionResolver *resolver, QQmlType *qmlType, int index); static QV4::IR::DiscoveredType resolveQmlType(QQmlEnginePrivate *qmlEngine, const QV4::IR::MemberExpressionResolver *resolver, @@ -1702,6 +1703,14 @@ static QV4::IR::DiscoveredType resolveQmlType(QQmlEnginePrivate *qmlEngine, if (ok) { member->setEnumValue(value); return QV4::IR::SInt32Type; + } else { + int index = type->scopedEnumIndex(qmlEngine, *member->name, &ok); + if (ok) { + auto newResolver = resolver->owner->New<QV4::IR::MemberExpressionResolver>(); + newResolver->owner = resolver->owner; + initScopedEnumResolver(newResolver, type, index); + return QV4::IR::DiscoveredType(newResolver); + } } } @@ -1885,6 +1894,34 @@ static void initMetaObjectResolver(QV4::IR::MemberExpressionResolver *resolver, resolver->flags = 0; } +static QV4::IR::DiscoveredType resolveScopedEnum(QQmlEnginePrivate *qmlEngine, + const QV4::IR::MemberExpressionResolver *resolver, + QV4::IR::Member *member) +{ + if (!member->name->constData()->isUpper()) + return QV4::IR::VarType; + + QQmlType *type = static_cast<QQmlType*>(resolver->data); + int index = resolver->flags; + + bool ok = false; + int value = type->scopedEnumValue(qmlEngine, index, *member->name, &ok); + if (!ok) + return QV4::IR::VarType; + member->setEnumValue(value); + return QV4::IR::SInt32Type; +} + +static void initScopedEnumResolver(QV4::IR::MemberExpressionResolver *resolver, QQmlType *qmlType, int index) +{ + Q_ASSERT(resolver); + + resolver->resolveMember = &resolveScopedEnum; + resolver->data = qmlType; + resolver->extraData = 0; + resolver->flags = index; +} + #endif // V4_BOOTSTRAP void JSCodeGen::beginFunctionBodyHook() diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp index d1d22be0ac..c09fde86f1 100644 --- a/src/qml/compiler/qqmltypecompiler.cpp +++ b/src/qml/compiler/qqmltypecompiler.cpp @@ -591,21 +591,32 @@ bool QQmlEnumTypeResolver::tryQualifiedEnumAssignment(const QmlIR::Object *obj, if (!string.constData()->isUpper()) return true; + // we support one or two '.' in the enum phrase: + // * <TypeName>.<EnumValue> + // * <TypeName>.<ScopedEnumName>.<EnumValue> + int dot = string.indexOf(QLatin1Char('.')); if (dot == -1 || dot == string.length()-1) return true; - if (string.indexOf(QLatin1Char('.'), dot+1) != -1) - return true; + int dot2 = string.indexOf(QLatin1Char('.'), dot+1); + if (dot2 != -1 && dot2 != string.length()-1) { + if (!string.at(dot+1).isUpper()) + return true; + if (string.indexOf(QLatin1Char('.'), dot2+1) != -1) + return true; + } QHashedStringRef typeName(string.constData(), dot); const bool isQtObject = (typeName == QLatin1String("Qt")); - const QStringRef enumValue = string.midRef(dot + 1); + const QStringRef scopedEnumName = (dot2 != -1 ? string.midRef(dot + 1, dot2 - dot - 1) : QStringRef()); + // ### consider supporting scoped enums in Qt namespace + const QStringRef enumValue = string.midRef(!isQtObject && dot2 != -1 ? dot2 + 1 : dot + 1); - if (isIntProp) { + if (isIntProp) { // ### C++11 allows enums to be other integral types. Should we support other integral types here? // Allow enum assignment to ints. bool ok; - int enumval = evaluateEnum(typeName.toString(), enumValue.toUtf8(), &ok); + int enumval = evaluateEnum(typeName.toString(), scopedEnumName, enumValue, &ok); if (ok) { if (!assignEnumToBinding(binding, enumValue, enumval, isQtObject)) return false; @@ -623,18 +634,25 @@ bool QQmlEnumTypeResolver::tryQualifiedEnumAssignment(const QmlIR::Object *obj, auto *tr = resolvedTypes->value(obj->inheritedTypeNameIndex); if (type && tr && tr->type == type) { + // When these two match, we can short cut the search QMetaProperty mprop = propertyCache->firstCppMetaObject()->property(prop->coreIndex()); + QMetaEnum menum = mprop.enumerator(); + QByteArray enumName = enumValue.toUtf8(); + if (menum.isScoped() && !scopedEnumName.isEmpty() && enumName != scopedEnumName.toUtf8()) + return true; - // When these two match, we can short cut the search if (mprop.isFlagType()) { - value = mprop.enumerator().keysToValue(enumValue.toUtf8().constData(), &ok); + value = menum.keysToValue(enumName.constData(), &ok); } else { - value = mprop.enumerator().keyToValue(enumValue.toUtf8().constData(), &ok); + value = menum.keyToValue(enumName.constData(), &ok); } } else { // Otherwise we have to search the whole type if (type) { - value = type->enumValue(compiler->enginePrivate(), QHashedStringRef(enumValue), &ok); + if (!scopedEnumName.isEmpty()) + value = type->scopedEnumValue(compiler->enginePrivate(), scopedEnumName, enumValue, &ok); + else + value = type->enumValue(compiler->enginePrivate(), QHashedStringRef(enumValue), &ok); } else { QByteArray enumName = enumValue.toUtf8(); const QMetaObject *metaObject = StaticQtMetaObject::get(); @@ -651,7 +669,7 @@ bool QQmlEnumTypeResolver::tryQualifiedEnumAssignment(const QmlIR::Object *obj, return assignEnumToBinding(binding, enumValue, value, isQtObject); } -int QQmlEnumTypeResolver::evaluateEnum(const QString &scope, const QByteArray &enumValue, bool *ok) const +int QQmlEnumTypeResolver::evaluateEnum(const QString &scope, const QStringRef &enumName, const QStringRef &enumValue, bool *ok) const { Q_ASSERT_X(ok, "QQmlEnumTypeResolver::evaluateEnum", "ok must not be a null pointer"); *ok = false; @@ -661,13 +679,16 @@ int QQmlEnumTypeResolver::evaluateEnum(const QString &scope, const QByteArray &e imports->resolveType(scope, &type, 0, 0, 0); if (!type) return -1; - return type->enumValue(compiler->enginePrivate(), QHashedCStringRef(enumValue.constData(), enumValue.length()), ok); + if (!enumName.isEmpty()) + return type->scopedEnumValue(compiler->enginePrivate(), enumName, enumValue, ok); + return type->enumValue(compiler->enginePrivate(), QHashedStringRef(enumValue.constData(), enumValue.length()), ok); } const QMetaObject *mo = StaticQtMetaObject::get(); int i = mo->enumeratorCount(); + const QByteArray ba = enumValue.toUtf8(); while (i--) { - int v = mo->enumerator(i).keyToValue(enumValue.constData(), ok); + int v = mo->enumerator(i).keyToValue(ba.constData(), ok); if (*ok) return v; } diff --git a/src/qml/compiler/qqmltypecompiler_p.h b/src/qml/compiler/qqmltypecompiler_p.h index 79fc073d8b..76aa422fc5 100644 --- a/src/qml/compiler/qqmltypecompiler_p.h +++ b/src/qml/compiler/qqmltypecompiler_p.h @@ -209,7 +209,7 @@ private: bool tryQualifiedEnumAssignment(const QmlIR::Object *obj, const QQmlPropertyCache *propertyCache, const QQmlPropertyData *prop, QmlIR::Binding *binding); - int evaluateEnum(const QString &scope, const QByteArray &enumValue, bool *ok) const; + int evaluateEnum(const QString &scope, const QStringRef &enumName, const QStringRef &enumValue, bool *ok) const; const QVector<QmlIR::Object*> &qmlObjects; |