diff options
author | Thiago Macieira <thiago.macieira@intel.com> | 2021-09-27 18:27:15 -0700 |
---|---|---|
committer | Ivan Solovev <ivan.solovev@qt.io> | 2021-12-17 17:54:05 +0100 |
commit | 46dc8e453ae1d0c1eb749cfebe686995f3a6cfd0 (patch) | |
tree | d7893f8e2ce0a0b1d1d8cb5dffd2aebe1c8de48c /src/corelib/kernel/qmetatype.cpp | |
parent | af36675afd4300387390ceaba35a81994751cb75 (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.cpp | 40 |
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 |