QmlCompiler: Use actual type of enums, rather than int
Now that the type is available from qmltypes we can just use it. Task-number: QTBUG-112180 Change-Id: I315372da0925f19c209f676226f450863b0d3ea5 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io> Reviewed-by: Sami Shalayel <sami.shalayel@qt.io> Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
This commit is contained in:
parent
9088125f14
commit
f10630aa03
|
@ -145,6 +145,7 @@ struct Q_QML_PRIVATE_EXPORT Lookup {
|
|||
Heap::InternalClass *ic;
|
||||
quintptr unused;
|
||||
ReturnedValue encodedEnumValue;
|
||||
const QtPrivate::QMetaTypeInterface *metaType;
|
||||
} qmlEnumValueLookup;
|
||||
struct {
|
||||
Heap::InternalClass *ic;
|
||||
|
|
|
@ -1020,9 +1020,41 @@ static bool isTypeCompatible(QMetaType lookupType, QMetaType propertyType)
|
|||
|
||||
if (!foundMetaObject)
|
||||
return false;
|
||||
} else if (lookupType == QMetaType::fromType<int>()
|
||||
&& propertyType.flags() & QMetaType::IsEnumeration) {
|
||||
return true;
|
||||
} else if (propertyType.flags() & QMetaType::IsEnumeration) {
|
||||
if (propertyType == lookupType)
|
||||
return true;
|
||||
|
||||
// You can pass the underlying type of an enum.
|
||||
// We don't want to check for the actual underlying type because
|
||||
// moc and qmltyperegistrar are not very precise about it. Especially
|
||||
// the long and longlong types can be ambiguous.
|
||||
|
||||
const bool isUnsigned = propertyType.flags() & QMetaType::IsUnsignedEnumeration;
|
||||
switch (propertyType.sizeOf()) {
|
||||
case 1:
|
||||
return isUnsigned
|
||||
? lookupType == QMetaType::fromType<quint8>()
|
||||
: lookupType == QMetaType::fromType<qint8>();
|
||||
case 2:
|
||||
return isUnsigned
|
||||
? lookupType == QMetaType::fromType<ushort>()
|
||||
: lookupType == QMetaType::fromType<short>();
|
||||
case 4:
|
||||
// The default type, if moc doesn't know the actual enum type, is int.
|
||||
// However, the compiler can still decide to encode the enum in uint.
|
||||
// Therefore, we also accept int for uint enums.
|
||||
// TODO: This is technically UB.
|
||||
return isUnsigned
|
||||
? (lookupType == QMetaType::fromType<int>()
|
||||
|| lookupType == QMetaType::fromType<uint>())
|
||||
: lookupType == QMetaType::fromType<int>();
|
||||
case 8:
|
||||
return isUnsigned
|
||||
? lookupType == QMetaType::fromType<qulonglong>()
|
||||
: lookupType == QMetaType::fromType<qlonglong>();
|
||||
}
|
||||
|
||||
return false;
|
||||
} else if (propertyType != lookupType) {
|
||||
return false;
|
||||
}
|
||||
|
@ -1776,13 +1808,44 @@ void AOTCompiledContext::initGetValueLookup(
|
|||
engine->handle()->throwTypeError();
|
||||
}
|
||||
|
||||
bool AOTCompiledContext::getEnumLookup(uint index, int *target) const
|
||||
bool AOTCompiledContext::getEnumLookup(uint index, void *target) const
|
||||
{
|
||||
QV4::Lookup *l = compilationUnit->runtimeLookups + index;
|
||||
if (l->getter != QV4::QQmlTypeWrapper::lookupEnumValue)
|
||||
return false;
|
||||
*target = l->qmlEnumValueLookup.encodedEnumValue;
|
||||
return true;
|
||||
const bool isUnsigned
|
||||
= l->qmlEnumValueLookup.metaType->flags & QMetaType::IsUnsignedEnumeration;
|
||||
const QV4::ReturnedValue encoded = l->qmlEnumValueLookup.encodedEnumValue;
|
||||
switch (l->qmlEnumValueLookup.metaType->size) {
|
||||
case 1:
|
||||
if (isUnsigned)
|
||||
*static_cast<quint8 *>(target) = encoded;
|
||||
else
|
||||
*static_cast<qint8 *>(target) = encoded;
|
||||
return true;
|
||||
case 2:
|
||||
if (isUnsigned)
|
||||
*static_cast<quint16 *>(target) = encoded;
|
||||
else
|
||||
*static_cast<qint16 *>(target) = encoded;
|
||||
return true;
|
||||
case 4:
|
||||
if (isUnsigned)
|
||||
*static_cast<quint32 *>(target) = encoded;
|
||||
else
|
||||
*static_cast<qint32 *>(target) = encoded;
|
||||
return true;
|
||||
case 8:
|
||||
if (isUnsigned)
|
||||
*static_cast<quint64 *>(target) = encoded;
|
||||
else
|
||||
*static_cast<qint64 *>(target) = encoded;
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void AOTCompiledContext::initGetEnumLookup(
|
||||
|
@ -1798,8 +1861,9 @@ void AOTCompiledContext::initGetEnumLookup(
|
|||
return;
|
||||
}
|
||||
const int enumIndex = metaObject->indexOfEnumerator(enumerator);
|
||||
const int value = metaObject->enumerator(enumIndex).keyToValue(enumValue);
|
||||
l->qmlEnumValueLookup.encodedEnumValue = value;
|
||||
const QMetaEnum metaEnum = metaObject->enumerator(enumIndex);
|
||||
l->qmlEnumValueLookup.encodedEnumValue = metaEnum.keyToValue(enumValue);
|
||||
l->qmlEnumValueLookup.metaType = metaEnum.metaType().iface();
|
||||
l->getter = QV4::QQmlTypeWrapper::lookupEnumValue;
|
||||
}
|
||||
|
||||
|
|
|
@ -703,7 +703,7 @@ namespace QQmlPrivate
|
|||
bool getValueLookup(uint index, void *value, void *target) const;
|
||||
void initGetValueLookup(uint index, const QMetaObject *metaObject, QMetaType type) const;
|
||||
|
||||
bool getEnumLookup(uint index, int *target) const;
|
||||
bool getEnumLookup(uint index, void *target) const;
|
||||
void initGetEnumLookup(uint index, const QMetaObject *metaObject,
|
||||
const char *enumerator, const char *enumValue) const;
|
||||
|
||||
|
|
|
@ -478,11 +478,10 @@ void QQmlJSImporter::processImport(const QQmlJSScope::Import &importDescription,
|
|||
// only happen when enumerations are involved, thus the strategy is to
|
||||
// resolve enumerations (which can potentially create new child scopes)
|
||||
// before resolving the type fully
|
||||
const QQmlJSScope::ConstPtr intType = tempTypes.cppNames.type(u"int"_s).scope;
|
||||
const QQmlJSScope::ConstPtr arrayType = tempTypes.cppNames.type(u"Array"_s).scope;
|
||||
for (auto it = import.objects.begin(); it != import.objects.end(); ++it) {
|
||||
if (!it->scope.factory()) {
|
||||
QQmlJSScope::resolveEnums(it->scope, intType);
|
||||
QQmlJSScope::resolveEnums(it->scope, tempTypes.cppNames);
|
||||
QQmlJSScope::resolveList(it->scope, arrayType);
|
||||
}
|
||||
}
|
||||
|
@ -522,7 +521,7 @@ QQmlJSImporter::AvailableTypes QQmlJSImporter::builtinImportHelper()
|
|||
if (m_builtins)
|
||||
return *m_builtins;
|
||||
|
||||
AvailableTypes builtins(ImportedTypes(ImportedTypes::INTERNAL, {}, {}, {}));
|
||||
AvailableTypes builtins(ImportedTypes(ImportedTypes::INTERNAL, {}, {}));
|
||||
|
||||
Import result;
|
||||
result.name = QStringLiteral("QML");
|
||||
|
@ -579,12 +578,10 @@ QQmlJSImporter::AvailableTypes QQmlJSImporter::builtinImportHelper()
|
|||
Q_ASSERT(intType);
|
||||
Q_ASSERT(arrayType);
|
||||
|
||||
m_builtins = AvailableTypes(ImportedTypes(
|
||||
ImportedTypes::INTERNAL, builtins.cppNames.types(),
|
||||
intType, arrayType));
|
||||
m_builtins->qmlNames =
|
||||
ImportedTypes(ImportedTypes::QML, builtins.qmlNames.types(),
|
||||
intType, arrayType);
|
||||
m_builtins = AvailableTypes(
|
||||
ImportedTypes(ImportedTypes::INTERNAL, builtins.cppNames.types(), arrayType));
|
||||
m_builtins->qmlNames
|
||||
= ImportedTypes(ImportedTypes::QML, builtins.qmlNames.types(), arrayType);
|
||||
|
||||
processImport(builtinImport, result, &(*m_builtins));
|
||||
|
||||
|
@ -703,9 +700,7 @@ bool QQmlJSImporter::importHelper(const QString &module, AvailableTypes *types,
|
|||
|
||||
auto cacheTypes = QSharedPointer<QQmlJSImporter::AvailableTypes>(
|
||||
new QQmlJSImporter::AvailableTypes(
|
||||
ImportedTypes(
|
||||
ImportedTypes::INTERNAL, {},
|
||||
types->cppNames.intType(), types->cppNames.arrayType())));
|
||||
ImportedTypes(ImportedTypes::INTERNAL, {}, types->cppNames.arrayType())));
|
||||
m_cachedImportTypes[cacheKey] = cacheTypes;
|
||||
|
||||
const QPair<QString, QTypeRevision> importId { module, version };
|
||||
|
@ -822,8 +817,7 @@ QQmlJSImporter::ImportedTypes QQmlJSImporter::importDirectory(
|
|||
const AvailableTypes builtins = builtinImportHelper();
|
||||
QQmlJSImporter::AvailableTypes types(
|
||||
ImportedTypes(
|
||||
ImportedTypes::INTERNAL, {},
|
||||
builtins.cppNames.intType(), builtins.cppNames.arrayType()));
|
||||
ImportedTypes::INTERNAL, {}, builtins.cppNames.arrayType()));
|
||||
importHelper(directory, &types, prefix, QTypeRevision(), false, true);
|
||||
return types.qmlNames;
|
||||
}
|
||||
|
|
|
@ -92,8 +92,7 @@ private:
|
|||
{
|
||||
AvailableTypes(ImportedTypes builtins)
|
||||
: cppNames(std::move(builtins))
|
||||
, qmlNames(QQmlJSScope::ContextualTypes::QML, {},
|
||||
cppNames.intType(), cppNames.arrayType())
|
||||
, qmlNames(QQmlJSScope::ContextualTypes::QML, {}, cppNames.arrayType())
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -77,7 +77,6 @@ QQmlJSImportVisitor::QQmlJSImportVisitor(
|
|||
m_logger(logger),
|
||||
m_rootScopeImports(
|
||||
QQmlJSImporter::ImportedTypes::QML, {},
|
||||
importer->builtinInternalNames().intType(),
|
||||
importer->builtinInternalNames().arrayType())
|
||||
{
|
||||
m_currentScope->setScopeType(QQmlJSScope::JSFunctionScope);
|
||||
|
|
|
@ -576,7 +576,7 @@ QTypeRevision QQmlJSScope::resolveTypes(
|
|||
const auto resolveAll = [](const QQmlJSScope::Ptr &self,
|
||||
const QQmlJSScope::ContextualTypes &contextualTypes,
|
||||
QSet<QString> *usedTypes) {
|
||||
resolveEnums(self, contextualTypes.intType());
|
||||
resolveEnums(self, contextualTypes, usedTypes);
|
||||
resolveList(self, contextualTypes.arrayType());
|
||||
return resolveType(self, contextualTypes, usedTypes);
|
||||
};
|
||||
|
@ -601,7 +601,9 @@ void QQmlJSScope::resolveNonEnumTypes(
|
|||
resolveEnums() will create a QQmlJSMetaEnum copy for the alias in case the 'self'-scope already
|
||||
does not have an enum called like the alias.
|
||||
*/
|
||||
void QQmlJSScope::resolveEnums(const QQmlJSScope::Ptr &self, const QQmlJSScope::ConstPtr &intType)
|
||||
void QQmlJSScope::resolveEnums(
|
||||
const QQmlJSScope::Ptr &self, const QQmlJSScope::ContextualTypes &contextualTypes,
|
||||
QSet<QString> *usedTypes)
|
||||
{
|
||||
// temporary hash to avoid messing up m_enumerations while iterators are active on it
|
||||
QHash<QString, QQmlJSMetaEnum> toBeAppended;
|
||||
|
@ -609,12 +611,17 @@ void QQmlJSScope::resolveEnums(const QQmlJSScope::Ptr &self, const QQmlJSScope::
|
|||
++it) {
|
||||
if (it->type())
|
||||
continue;
|
||||
Q_ASSERT(intType); // We need an "int" type to resolve enums
|
||||
QQmlJSScope::Ptr enumScope = QQmlJSScope::create();
|
||||
reparent(self, enumScope);
|
||||
enumScope->m_scopeType = EnumScope;
|
||||
enumScope->setBaseTypeName(QStringLiteral("int"));
|
||||
enumScope->m_baseType.scope = intType;
|
||||
|
||||
QString typeName = it->typeName();
|
||||
if (typeName.isEmpty())
|
||||
typeName = QStringLiteral("int");
|
||||
enumScope->setBaseTypeName(typeName);
|
||||
const auto type = findType(typeName, contextualTypes, usedTypes);
|
||||
enumScope->m_baseType = { type.scope, type.revision };
|
||||
|
||||
enumScope->m_semantics = AccessSemantics::Value;
|
||||
enumScope->m_internalName = self->internalName() + QStringLiteral("::") + it->name();
|
||||
if (QString alias = it->alias(); !alias.isEmpty()
|
||||
|
@ -658,7 +665,7 @@ void QQmlJSScope::resolveList(const QQmlJSScope::Ptr &self, const QQmlJSScope::C
|
|||
const QQmlJSImportedScope array = {arrayType, QTypeRevision()};
|
||||
QQmlJSScope::ContextualTypes contextualTypes(
|
||||
QQmlJSScope::ContextualTypes::INTERNAL, { { self->internalName(), element }, },
|
||||
QQmlJSScope::ConstPtr(), arrayType);
|
||||
arrayType);
|
||||
QQmlJSScope::resolveTypes(listType, contextualTypes);
|
||||
|
||||
Q_ASSERT(listType->valueType() == self);
|
||||
|
@ -1097,7 +1104,7 @@ void QDeferredFactory<QQmlJSScope>::populate(const QSharedPointer<QQmlJSScope> &
|
|||
typeReader(scope);
|
||||
m_importer->m_globalWarnings.append(typeReader.errors());
|
||||
scope->setInternalName(internalName());
|
||||
QQmlJSScope::resolveEnums(scope, m_importer->builtinInternalNames().intType());
|
||||
QQmlJSScope::resolveEnums(scope, m_importer->builtinInternalNames());
|
||||
QQmlJSScope::resolveList(scope, m_importer->builtinInternalNames().arrayType());
|
||||
|
||||
if (m_isSingleton && !scope->isSingleton()) {
|
||||
|
|
|
@ -216,16 +216,13 @@ public:
|
|||
ContextualTypes(
|
||||
CompileContext context,
|
||||
const QHash<QString, ImportedScope<ConstPtr>> types,
|
||||
const QQmlJSScope::ConstPtr &intType,
|
||||
const QQmlJSScope::ConstPtr &arrayType)
|
||||
: m_types(types)
|
||||
, m_context(context)
|
||||
, m_intType(intType)
|
||||
, m_arrayType(arrayType)
|
||||
{}
|
||||
|
||||
CompileContext context() const { return m_context; }
|
||||
ConstPtr intType() const { return m_intType; }
|
||||
ConstPtr arrayType() const { return m_arrayType; }
|
||||
|
||||
bool hasType(const QString &name) const { return m_types.contains(name); }
|
||||
|
@ -606,7 +603,8 @@ QT_WARNING_POP
|
|||
const QQmlJSScope::Ptr &self, const QQmlJSScope::ContextualTypes &contextualTypes,
|
||||
QSet<QString> *usedTypes = nullptr);
|
||||
static void resolveEnums(
|
||||
const QQmlJSScope::Ptr &self, const QQmlJSScope::ConstPtr &intType);
|
||||
const QQmlJSScope::Ptr &self, const QQmlJSScope::ContextualTypes &contextualTypes,
|
||||
QSet<QString> *usedTypes = nullptr);
|
||||
static void resolveList(
|
||||
const QQmlJSScope::Ptr &self, const QQmlJSScope::ConstPtr &arrayType);
|
||||
static void resolveGeneralizedGroup(
|
||||
|
|
|
@ -11,4 +11,9 @@ QtObject {
|
|||
readonly property FooThing fighter: root.f.get(Foo.Fighter)
|
||||
readonly property FooThing bar: root.f.get(Foo.Component)
|
||||
}
|
||||
|
||||
property int a: FooFactory.B
|
||||
property int b: f.t8
|
||||
property int c: FooFactory.D
|
||||
property int d: f.t16
|
||||
}
|
||||
|
|
|
@ -45,8 +45,23 @@ class FooThingWrapper {
|
|||
class FooFactory : public QObject {
|
||||
Q_OBJECT
|
||||
QML_ELEMENT
|
||||
Q_PROPERTY(T8 t8 READ t8 CONSTANT FINAL)
|
||||
Q_PROPERTY(T16 t16 READ t16 CONSTANT FINAL)
|
||||
|
||||
public:
|
||||
enum T8: qint8 {
|
||||
A, B, C
|
||||
};
|
||||
Q_ENUM(T8)
|
||||
|
||||
enum T16: qint16 {
|
||||
D = 500, E, F
|
||||
};
|
||||
Q_ENUM(T16)
|
||||
|
||||
T8 t8() const { return C; }
|
||||
T16 t16() const { return E; }
|
||||
|
||||
Q_INVOKABLE Foo* get(Foo::Type type) const { return new Foo(type); }
|
||||
};
|
||||
|
||||
|
|
|
@ -2981,6 +2981,11 @@ void tst_QmlCppCodegen::enumProblems()
|
|||
Foo *fighter = inner->property("fighter").value<Foo *>();
|
||||
QVERIFY(fighter);
|
||||
QCOMPARE(fighter->type(), Foo::Fighter);
|
||||
|
||||
QCOMPARE(outer->property("a").toInt(), FooFactory::B);
|
||||
QCOMPARE(outer->property("b").toInt(), FooFactory::C);
|
||||
QCOMPARE(outer->property("c").toInt(), FooFactory::D);
|
||||
QCOMPARE(outer->property("d").toInt(), FooFactory::E);
|
||||
}
|
||||
|
||||
void tst_QmlCppCodegen::enumConversion()
|
||||
|
|
Loading…
Reference in New Issue