summaryrefslogtreecommitdiffstats
path: root/src/corelib
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
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')
-rw-r--r--src/corelib/kernel/qmetatype.cpp40
-rw-r--r--src/corelib/kernel/qmetatype_p.h1
-rw-r--r--src/corelib/kernel/qvariant.cpp14
3 files changed, 49 insertions, 6 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
diff --git a/src/corelib/kernel/qmetatype_p.h b/src/corelib/kernel/qmetatype_p.h
index 16270bc374..2b533608be 100644
--- a/src/corelib/kernel/qmetatype_p.h
+++ b/src/corelib/kernel/qmetatype_p.h
@@ -233,6 +233,7 @@ static const QT_PREPEND_NAMESPACE(QtPrivate::QMetaTypeInterface) *getInterfaceFr
case QMetaType::MetaTypeName: \
return QtMetaTypePrivate::getInterfaceFromType<RealName>();
+const char *typedefNameForType(const QtPrivate::QMetaTypeInterface *type_d);
} //namespace QtMetaTypePrivate
QT_END_NAMESPACE
diff --git a/src/corelib/kernel/qvariant.cpp b/src/corelib/kernel/qvariant.cpp
index b34da6ca18..b942ac50c7 100644
--- a/src/corelib/kernel/qvariant.cpp
+++ b/src/corelib/kernel/qvariant.cpp
@@ -1,7 +1,7 @@
/****************************************************************************
**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Copyright (C) 2018 Intel Corporation.
+** Copyright (C) 2021 The Qt Company Ltd.
+** Copyright (C) 2021 Intel Corporation.
** Copyright (C) 2015 Olivier Goffart <ogoffart@woboq.com>
** Contact: https://www.qt.io/licensing/
**
@@ -1314,13 +1314,17 @@ void QVariant::save(QDataStream &s) const
}
}
const char *typeName = nullptr;
- if (saveAsUserType)
- typeName = d.type().name();
+ if (saveAsUserType) {
+ if (s.version() < QDataStream::Qt_6_0)
+ typeName = QtMetaTypePrivate::typedefNameForType(d.type().d_ptr);
+ if (!typeName)
+ typeName = d.type().name();
+ }
s << typeId;
if (s.version() >= QDataStream::Qt_4_2)
s << qint8(d.is_null);
if (typeName)
- s << d.type().name();
+ s << typeName;
if (!isValid()) {
if (s.version() < QDataStream::Qt_5_0)