summaryrefslogtreecommitdiffstats
path: root/src/corelib/kernel/qmetatype.cpp
diff options
context:
space:
mode:
authorThiago Macieira <thiago.macieira@intel.com>2021-09-27 18:27:15 -0700
committerIvan Solovev <ivan.solovev@qt.io>2021-12-17 17:54:05 +0100
commit46dc8e453ae1d0c1eb749cfebe686995f3a6cfd0 (patch)
treed7893f8e2ce0a0b1d1d8cb5dffd2aebe1c8de48c /src/corelib/kernel/qmetatype.cpp
parentaf36675afd4300387390ceaba35a81994751cb75 (diff)
QVariant: use a typedef name when saving user types to QDataStream
Due to the way Qt 5 and 6 registered type names, they end up producing different type names for the same content for a typedef. For example, because Q_DECLARE_METATYPE can't manage a comma (it's a macro), users are forced to write something like: using MyTypeMap = QMap<QString, MyType> Q_DECLARE_METATYPE(MyTypeMap) Qt 5's Q_DECLARE_METATYPE's argument "MyTypeMap" was the only name we knew about the type, so that's what got saved in the stream. However, Qt 6 QtPrivate::typenameHelper is much more clever and obtains the name from the compiler itself, so it "sees through" the typedef and registers "QMap<QString,MyType>" as the official type name. If another library/plugin has a different typedef name for the same type (e.g., StringTypeMap), it's indeterminate which type gets saved and will even change from run to run (depends on the QHash order). [ChangeLog][QtCore][QDataStream] If QDataStream is used with a QDataStream::Version < Qt_6_0 to serialize a user type that was registered via a typedef with the metatype system, the typedef's name is used in the stream instead of the non-typedef name. This restores compatibility with Qt 5, allowing existing content to read the same QDataStreams; reading from older Qt 6 versions should not be affected. (Note: if more than one typedef name is registered, it's indetermine which name gets used) Fixes: QTBUG-96916 Pick-to: 6.3 6.2 Change-Id: I2bbf422288924c198645fffd16a8d811aa58201e Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Lars Knoll <lars.knoll@qt.io>
Diffstat (limited to 'src/corelib/kernel/qmetatype.cpp')
-rw-r--r--src/corelib/kernel/qmetatype.cpp40
1 files changed, 39 insertions, 1 deletions
diff --git a/src/corelib/kernel/qmetatype.cpp b/src/corelib/kernel/qmetatype.cpp
index 9494ff84f9..476234d7c5 100644
--- a/src/corelib/kernel/qmetatype.cpp
+++ b/src/corelib/kernel/qmetatype.cpp
@@ -1,6 +1,8 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2021 The Qt Company Ltd.
+** Copyright (C) 2021 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com
+** Copyright (C) 2021 Intel Corporation.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
@@ -179,6 +181,42 @@ Q_GLOBAL_STATIC(QMetaTypeCustomRegistry, customTypeRegistry)
} // namespace
+// used by QVariant::save(): returns the name used in the Q_DECLARE_METATYPE
+// macro (one of them, indetermine which one)
+const char *QtMetaTypePrivate::typedefNameForType(const QtPrivate::QMetaTypeInterface *type_d)
+{
+ const char *name = nullptr;
+ QMetaTypeCustomRegistry *r = customTypeRegistry;
+ if (!r)
+ return name;
+
+ QByteArrayView officialName(type_d->name);
+ QReadLocker l(&r->lock);
+ auto it = r->aliases.constBegin();
+ auto end = r->aliases.constEnd();
+ for ( ; it != end; ++it) {
+ if (it.value() != type_d)
+ continue;
+ if (it.key() == officialName)
+ continue; // skip the official name
+ name = it.key().constData();
+ break;
+ }
+
+#ifndef QT_NO_DEBUG
+ QByteArrayList otherNames;
+ for ( ; it != end; ++it) {
+ if (it.value() == type_d)
+ otherNames << it.key();
+ }
+ if (!otherNames.isEmpty())
+ qWarning("QMetaType: type %s has more than one typedef alias: %s, %s",
+ type_d->name, name, otherNames.join(", ").constData());
+#endif
+
+ return name;
+}
+
/*!
\macro Q_DECLARE_OPAQUE_POINTER(PointerType)
\relates QMetaType