diff --git a/src/corelib/kernel/qmetatype.cpp b/src/corelib/kernel/qmetatype.cpp index 356a675517..5c1e4b4ddd 100644 --- a/src/corelib/kernel/qmetatype.cpp +++ b/src/corelib/kernel/qmetatype.cpp @@ -37,6 +37,8 @@ ** ****************************************************************************/ +#include + #include "qmetatype.h" #include "qmetatype_p.h" #include "qobjectdefs.h" @@ -2416,6 +2418,50 @@ const QMetaObject *metaObjectForQWidget() return nullptr; return qMetaObjectWidgetsHelper; } + +void qt5CompatibilityHookPostRegister(int id, const QByteArray &normalizedTypeName) +{ + // In Qt6 QList got typedef'ed to QVector. To keep runtime behavior compatibility + // with Qt5 we install corresponding aliases. For example if one register + // QVector> + // we need to register the type plus all possible aliases: + // QVector> + // QList> + // QList> + // ### Qt6 TODO This is slow, as it allocates couple of strings we would need to + // if def this call with something like QT_NO_QLIST + const char *vectorName = "QVector<"; + const char *listName = "QList<"; + + auto isSubstringOfAType = [](char c) { return c != ' ' && c != ',' && c != '<'; }; + QVarLengthArray indexes; + + for (auto containerName: {vectorName, listName}) { + for (int i = normalizedTypeName.indexOf(containerName, 0); i != -1; i = normalizedTypeName.indexOf(containerName, i + 1)) { + if (!i || (i > 0 && !isSubstringOfAType(normalizedTypeName[i - 1]))) + indexes.append(i); + } + } + // To avoid problems with the constantly changing size we start replacements + // from the end of normalizedTypeName + std::sort(indexes.rbegin(), indexes.rend()); + + for (quint64 combination = 1; ; ++combination) { + std::bitset<64> bits(combination); + QByteArray name = normalizedTypeName; + for (auto j = 0; j < indexes.size(); ++j) { + if (bits.test(j)) { + auto i = indexes[j]; + auto replaceFrom = normalizedTypeName[i + 1] == 'V' ? vectorName : listName; + auto replaceTo = normalizedTypeName[i + 1] == 'V' ? listName : vectorName; + name.replace(i, sizeof(replaceFrom), replaceTo); + } + } + QMetaType::registerNormalizedTypedef(name, id); + if (bits.count() >= size_t(indexes.size())) + break; + } +} } namespace QtMetaTypePrivate { diff --git a/src/corelib/kernel/qmetatype.h b/src/corelib/kernel/qmetatype.h index 7b985be9fd..f6fe62e164 100644 --- a/src/corelib/kernel/qmetatype.h +++ b/src/corelib/kernel/qmetatype.h @@ -1645,6 +1645,23 @@ namespace QtPrivate static bool registerConverter(int) { return false; } }; + template + struct Qt5CompatibilityHook + { + static inline void postRegister(int, const QByteArray &) {}; + }; + + Q_CORE_EXPORT void qt5CompatibilityHookPostRegister(int id, const QByteArray &normalizedTypeName); + + template + struct Qt5CompatibilityHook> + { + static inline void postRegister(int id, const QByteArray &normalizedTypeName) + { + qt5CompatibilityHookPostRegister(id, normalizedTypeName); + } + }; + Q_CORE_EXPORT bool isBuiltinType(const QByteArray &type); } // namespace QtPrivate @@ -1771,6 +1788,7 @@ int qRegisterNormalizedMetaType(const QT_PREPEND_NAMESPACE(QByteArray) &normaliz QtPrivate::AssociativeContainerConverterHelper::registerConverter(id); QtPrivate::MetaTypePairHelper::registerConverter(id); QtPrivate::MetaTypeSmartPointerHelper::registerConverter(id); + QtPrivate::Qt5CompatibilityHook::postRegister(id, normalizedTypeName); } return id; diff --git a/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp b/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp index 2a4ee55fa8..d300c31001 100644 --- a/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp +++ b/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp @@ -572,12 +572,14 @@ void tst_QMetaType::typeName_data() QTest::newRow("124125534") << 124125534 << QString(); // automatic registration - QTest::newRow("QList") << ::qMetaTypeId >() << QString::fromLatin1("QList"); QTest::newRow("QHash") << ::qMetaTypeId >() << QString::fromLatin1("QHash"); QTest::newRow("QMap") << ::qMetaTypeId >() << QString::fromLatin1("QMap"); - QTest::newRow("QVector>") << ::qMetaTypeId > >() << QString::fromLatin1("QVector >"); QTest::newRow("QVector>") << ::qMetaTypeId > >() << QString::fromLatin1("QVector >"); + // automatic registration with automatic QList to QVector aliasing + QTest::newRow("QList") << ::qMetaTypeId >() << QString::fromLatin1("QVector"); + QTest::newRow("QVector>") << ::qMetaTypeId > >() << QString::fromLatin1("QVector >"); + QTest::newRow("CustomQObject*") << ::qMetaTypeId() << QString::fromLatin1("CustomQObject*"); QTest::newRow("CustomGadget") << ::qMetaTypeId() << QString::fromLatin1("CustomGadget"); QTest::newRow("CustomGadget*") << ::qMetaTypeId() << QString::fromLatin1("CustomGadget*");