summaryrefslogtreecommitdiffstats
path: root/src/corelib/kernel/qvariant.cpp
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@qt.io>2020-07-14 12:26:16 +0200
committerLars Knoll <lars.knoll@qt.io>2020-08-24 00:18:24 +0200
commit9d36032370f7b81279ff8774afd7dea4ea57ee6a (patch)
treed750ccd6cd317f056d13495a03fde5881134ec89 /src/corelib/kernel/qvariant.cpp
parent2d3b31171d8fce2ab364ca2ceea4e75020933334 (diff)
Implement QMetaType::canConvert() and use it in QVariant
Use the fact that we return the conversion function as a lambda to find out reliably whether a conversion between two types can be done. This requires some minor adjustments to our tests: * Nothing can convert to an unknown type and vice versa * Adjust results to the fact that we don't convert from char to QString anymore (where the old method was incorrect) * QStringList->QString requires some adjustments, as we only convert if the string list has exactly one element. For now we return true in canConvert(), but the conversion behavior in this case is something we should rethink, as it is very surprising. Change-Id: I3f5f87ee9cb99d690f5a7d13b13d6a6313d8038e Reviewed-by: Maurice Kalinowski <maurice.kalinowski@qt.io>
Diffstat (limited to 'src/corelib/kernel/qvariant.cpp')
-rw-r--r--src/corelib/kernel/qvariant.cpp396
1 files changed, 4 insertions, 392 deletions
diff --git a/src/corelib/kernel/qvariant.cpp b/src/corelib/kernel/qvariant.cpp
index 4f0664dc285..c16e4a0e062 100644
--- a/src/corelib/kernel/qvariant.cpp
+++ b/src/corelib/kernel/qvariant.cpp
@@ -1962,219 +1962,17 @@ QVariantList QVariant::toList() const
return qVariantToHelper<QVariantList>(d);
}
-
-static const quint32 qCanConvertMatrix[QMetaType::LastCoreType + 1] =
-{
-/*Invalid*/ 0,
-
-/*Bool*/ 1 << QMetaType::Double | 1 << QMetaType::Int | 1 << QMetaType::UInt
- | 1 << QMetaType::LongLong | 1 << QMetaType::ULongLong | 1 << QMetaType::QByteArray
- | 1 << QMetaType::QString | 1 << QMetaType::QChar,
-
-/*Int*/ 1 << QMetaType::UInt | 1 << QMetaType::QString | 1 << QMetaType::Double
- | 1 << QMetaType::Bool | 1 << QMetaType::LongLong | 1 << QMetaType::ULongLong
- | 1 << QMetaType::QChar | 1 << QMetaType::QByteArray | 1 << QMetaType::Int,
-
-/*UInt*/ 1 << QMetaType::Int | 1 << QMetaType::QString | 1 << QMetaType::Double
- | 1 << QMetaType::Bool | 1 << QMetaType::LongLong | 1 << QMetaType::ULongLong
- | 1 << QMetaType::QChar | 1 << QMetaType::QByteArray,
-
-/*LLong*/ 1 << QMetaType::Int | 1 << QMetaType::QString | 1 << QMetaType::Double
- | 1 << QMetaType::Bool | 1 << QMetaType::UInt | 1 << QMetaType::ULongLong
- | 1 << QMetaType::QChar | 1 << QMetaType::QByteArray,
-
-/*ULlong*/ 1 << QMetaType::Int | 1 << QMetaType::QString | 1 << QMetaType::Double
- | 1 << QMetaType::Bool | 1 << QMetaType::UInt | 1 << QMetaType::LongLong
- | 1 << QMetaType::QChar | 1 << QMetaType::QByteArray,
-
-/*double*/ 1 << QMetaType::Int | 1 << QMetaType::QString | 1 << QMetaType::ULongLong
- | 1 << QMetaType::Bool | 1 << QMetaType::UInt | 1 << QMetaType::LongLong
- | 1 << QMetaType::QByteArray,
-
-/*QChar*/ 1 << QMetaType::Int | 1 << QMetaType::UInt | 1 << QMetaType::LongLong
- | 1 << QMetaType::ULongLong,
-
-/*QMap*/ 0,
-
-/*QList*/ 1 << QMetaType::QStringList,
-
-/*QString*/ 1 << QMetaType::QStringList | 1 << QMetaType::QByteArray | 1 << QMetaType::Int
- | 1 << QMetaType::UInt | 1 << QMetaType::Bool | 1 << QMetaType::Double
- | 1 << QMetaType::QDate | 1 << QMetaType::QTime | 1 << QMetaType::QDateTime
- | 1 << QMetaType::LongLong | 1 << QMetaType::ULongLong | 1 << QMetaType::QChar
- | 1 << QMetaType::QUrl | 1 << QMetaType::QUuid,
-
-/*QStringList*/ 1 << QMetaType::QVariantList | 1 << QMetaType::QString,
-
-/*QByteArray*/ 1 << QMetaType::QString | 1 << QMetaType::Int | 1 << QMetaType::UInt | 1 << QMetaType::Bool
- | 1 << QMetaType::Double | 1 << QMetaType::LongLong | 1 << QMetaType::ULongLong
- | 1 << QMetaType::QUuid,
-
-/*QBitArray*/ 0,
-
-/*QDate*/ 1 << QMetaType::QString | 1 << QMetaType::QDateTime,
-
-/*QTime*/ 1 << QMetaType::QString | 1 << QMetaType::QDateTime,
-
-/*QDateTime*/ 1 << QMetaType::QString | 1 << QMetaType::QDate,
-
-/*QUrl*/ 1 << QMetaType::QString,
-
-/*QLocale*/ 0,
-
-/*QRect*/ 1 << QMetaType::QRectF,
-
-/*QRectF*/ 1 << QMetaType::QRect,
-
-/*QSize*/ 1 << QMetaType::QSizeF,
-
-/*QSizeF*/ 1 << QMetaType::QSize,
-
-/*QLine*/ 1 << QMetaType::QLineF,
-
-/*QLineF*/ 1 << QMetaType::QLine,
-
-/*QPoint*/ 1 << QMetaType::QPointF,
-
-/*QPointF*/ 1 << QMetaType::QPoint,
-
-/*unused, was: QRegExp*/ 0,
-
-/*QHash*/ 0,
-
-/*QEasingCurve*/ 0,
-
-/*QUuid*/ 1 << QMetaType::QString | 1 << QMetaType::QByteArray,
-};
-static const size_t qCanConvertMatrixMaximumTargetType = 8 * sizeof(*qCanConvertMatrix);
-
-#ifndef QT_BOOTSTRAPPED
-/*
- Returns \c true if from inherits to.
-*/
-static bool canConvertMetaObject(const QMetaObject *from, const QMetaObject *to)
-{
- if (from && to == &QObject::staticMetaObject)
- return true;
-
- while (from) {
- if (from == to)
- return true;
- from = from->superClass();
- }
-
- return false;
-}
-#endif
-
-static bool canConvertMetaObject(int fromId, int toId, QObject *fromObject)
-{
-#ifndef QT_BOOTSTRAPPED
- QMetaType toType(toId);
- if ((QMetaType::typeFlags(fromId) & QMetaType::PointerToQObject) && (toType.flags() & QMetaType::PointerToQObject)) {
- if (!fromObject)
- return true;
- return canConvertMetaObject(fromObject->metaObject(), toType.metaObject());
- }
-#else
- Q_UNUSED(fromId);
- Q_UNUSED(toId);
- Q_UNUSED(fromObject);
-#endif
- return false;
-}
-
-
/*!
Returns \c true if the variant's type can be cast to the requested
type, \a targetTypeId. Such casting is done automatically when calling the
toInt(), toBool(), ... methods.
- The following casts are done automatically:
-
- \table
- \header \li Type \li Automatically Cast To
- \row \li \l QMetaType::Bool \li \l QMetaType::QChar, \l QMetaType::Double,
- \l QMetaType::Int, \l QMetaType::LongLong, \l QMetaType::QString,
- \l QMetaType::UInt, \l QMetaType::ULongLong
- \row \li \l QMetaType::QByteArray \li \l QMetaType::Double,
- \l QMetaType::Int, \l QMetaType::LongLong, \l QMetaType::QString,
- \l QMetaType::UInt, \l QMetaType::ULongLong, \l QMetaType::QUuid
- \row \li \l QMetaType::QChar \li \l QMetaType::Bool, \l QMetaType::Int,
- \l QMetaType::UInt, \l QMetaType::LongLong, \l QMetaType::ULongLong
- \row \li \l QMetaType::QColor \li \l QMetaType::QString
- \row \li \l QMetaType::QDate \li \l QMetaType::QDateTime,
- \l QMetaType::QString
- \row \li \l QMetaType::QDateTime \li \l QMetaType::QDate,
- \l QMetaType::QString, \l QMetaType::QTime
- \row \li \l QMetaType::Double \li \l QMetaType::Bool, \l QMetaType::Int,
- \l QMetaType::LongLong, \l QMetaType::QString, \l QMetaType::UInt,
- \l QMetaType::ULongLong
- \row \li \l QMetaType::QFont \li \l QMetaType::QString
- \row \li \l QMetaType::Int \li \l QMetaType::Bool, \l QMetaType::QChar,
- \l QMetaType::Double, \l QMetaType::LongLong, \l QMetaType::QString,
- \l QMetaType::UInt, \l QMetaType::ULongLong
- \row \li \l QMetaType::QKeySequence \li \l QMetaType::Int,
- \l QMetaType::QString
- \row \li \l QMetaType::QVariantList \li \l QMetaType::QStringList (if the
- list's items can be converted to QStrings)
- \row \li \l QMetaType::LongLong \li \l QMetaType::Bool,
- \l QMetaType::QByteArray, \l QMetaType::QChar, \l QMetaType::Double,
- \l QMetaType::Int, \l QMetaType::QString, \l QMetaType::UInt,
- \l QMetaType::ULongLong
- \row \li \l QMetaType::QPoint \li QMetaType::QPointF
- \row \li \l QMetaType::QRect \li QMetaType::QRectF
- \row \li \l QMetaType::QString \li \l QMetaType::Bool,
- \l QMetaType::QByteArray, \l QMetaType::QChar, \l QMetaType::QColor,
- \l QMetaType::QDate, \l QMetaType::QDateTime, \l QMetaType::Double,
- \l QMetaType::QFont, \l QMetaType::Int, \l QMetaType::QKeySequence,
- \l QMetaType::LongLong, \l QMetaType::QStringList, \l QMetaType::QTime,
- \l QMetaType::UInt, \l QMetaType::ULongLong, \l QMetaType::QUuid
- \row \li \l QMetaType::QStringList \li \l QMetaType::QVariantList,
- \l QMetaType::QString (if the list contains exactly one item)
- \row \li \l QMetaType::QTime \li \l QMetaType::QString
- \row \li \l QMetaType::UInt \li \l QMetaType::Bool, \l QMetaType::QChar,
- \l QMetaType::Double, \l QMetaType::Int, \l QMetaType::LongLong,
- \l QMetaType::QString, \l QMetaType::ULongLong
- \row \li \l QMetaType::ULongLong \li \l QMetaType::Bool,
- \l QMetaType::QChar, \l QMetaType::Double, \l QMetaType::Int,
- \l QMetaType::LongLong, \l QMetaType::QString, \l QMetaType::UInt
- \row \li \l QMetaType::QUuid \li \l QMetaType::QByteArray, \l QMetaType::QString
- \endtable
-
- A QVariant containing a pointer to a type derived from QObject will also return true for this
- function if a qobject_cast to the type described by \a targetTypeId would succeed. Note that
- this only works for QObject subclasses which use the Q_OBJECT macro.
-
- A QVariant containing a sequential container will also return true for this
- function if the \a targetTypeId is QVariantList. It is possible to iterate over
- the contents of the container without extracting it as a (copied) QVariantList:
-
- \snippet code/src_corelib_kernel_qvariant.cpp 9
-
- This requires that the value_type of the container is itself a metatype.
-
- Similarly, a QVariant containing a sequential container will also return true for this
- function the \a targetTypeId is QVariantHash or QVariantMap. It is possible to iterate over
- the contents of the container without extracting it as a (copied) QVariantHash or QVariantMap:
-
- \snippet code/src_corelib_kernel_qvariant.cpp 10
-
- \sa convert(), QSequentialIterable, Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE(), QAssociativeIterable,
- Q_DECLARE_ASSOCIATIVE_CONTAINER_METATYPE()
+ \sa QMetaType::canConvert()
*/
bool QVariant::canConvert(int targetTypeId) const
{
- if (d.typeId() == targetTypeId)
- return true;
-
-#if QT_CONFIG(itemmodel)
- if ((targetTypeId == QMetaType::QModelIndex
- && d.typeId() == QMetaType::QPersistentModelIndex)
- || (targetTypeId == QMetaType::QPersistentModelIndex
- && d.typeId() == QMetaType::QModelIndex))
+ if (d.typeId() == targetTypeId && targetTypeId != QMetaType::UnknownType)
return true;
-#endif
if (targetTypeId == QMetaType::QVariantList
&& (d.typeId() == QMetaType::QVariantList || d.typeId() == QMetaType::QStringList
@@ -2197,193 +1995,7 @@ bool QVariant::canConvert(int targetTypeId) const
return true;
}
- if ((d.typeId() >= QMetaType::LastCoreType|| targetTypeId >= QMetaType::LastCoreType)
- && QMetaType::hasRegisteredConverterFunction(d.typeId(), targetTypeId)) {
- return true;
- }
-
- // TODO Reimplement this function, currently it works but it is a historical mess.
- uint currentType = d.typeId();
- if (currentType == QMetaType::SChar || currentType == QMetaType::Char)
- currentType = QMetaType::UInt;
- if (targetTypeId == QMetaType::SChar || currentType == QMetaType::Char)
- targetTypeId = QMetaType::UInt;
- if (currentType == QMetaType::Short || currentType == QMetaType::UShort)
- currentType = QMetaType::Int;
- if (targetTypeId == QMetaType::Short || currentType == QMetaType::UShort)
- targetTypeId = QMetaType::Int;
- if (currentType == QMetaType::Float)
- currentType = QMetaType::Double;
- if (targetTypeId == QMetaType::Float)
- targetTypeId = QMetaType::Double;
-
- if (currentType == uint(targetTypeId))
- return true;
-
- if (targetTypeId < 0)
- return false;
- if (targetTypeId >= QMetaType::User) {
- if (QMetaType::typeFlags(targetTypeId) & QMetaType::IsEnumeration) {
- targetTypeId = QMetaType::Int;
- } else {
- return canConvertMetaObject(currentType, targetTypeId, d.get<QObject *>());
- }
- }
-
- if (currentType == QMetaType::QJsonValue || targetTypeId == QMetaType::QJsonValue) {
- switch (currentType == QMetaType::QJsonValue ? targetTypeId : currentType) {
- case QMetaType::Nullptr:
- case QMetaType::QString:
- case QMetaType::Bool:
- case QMetaType::Int:
- case QMetaType::UInt:
- case QMetaType::Double:
- case QMetaType::Float:
- case QMetaType::ULong:
- case QMetaType::Long:
- case QMetaType::LongLong:
- case QMetaType::ULongLong:
- case QMetaType::UShort:
- case QMetaType::UChar:
- case QMetaType::Char:
- case QMetaType::SChar:
- case QMetaType::Short:
- case QMetaType::QVariantList:
- case QMetaType::QVariantMap:
- case QMetaType::QVariantHash:
- case QMetaType::QCborValue:
- case QMetaType::QCborArray:
- case QMetaType::QCborMap:
- return true;
- default:
- return false;
- }
- }
- if (currentType == QMetaType::QJsonArray)
- return targetTypeId == QMetaType::QVariantList || targetTypeId == QMetaType::QCborValue
- || targetTypeId == QMetaType::QCborArray;
- if (currentType == QMetaType::QJsonObject)
- return targetTypeId == QMetaType::QVariantMap || targetTypeId == QMetaType::QVariantHash
- || targetTypeId == QMetaType::QCborValue || targetTypeId == QMetaType::QCborMap;
-
- if (currentType == QMetaType::QCborValue || targetTypeId == QMetaType::QCborValue) {
- switch (currentType == QMetaType::QCborValue ? targetTypeId : currentType) {
- case QMetaType::UnknownType:
- case QMetaType::Nullptr:
- case QMetaType::Bool:
- case QMetaType::Int:
- case QMetaType::UInt:
- case QMetaType::Double:
- case QMetaType::Float:
- case QMetaType::ULong:
- case QMetaType::Long:
- case QMetaType::LongLong:
- case QMetaType::ULongLong:
- case QMetaType::UShort:
- case QMetaType::UChar:
- case QMetaType::Char:
- case QMetaType::SChar:
- case QMetaType::Short:
- case QMetaType::QString:
- case QMetaType::QByteArray:
- case QMetaType::QDateTime:
- case QMetaType::QUrl:
-#if QT_CONFIG(regularexpression)
- case QMetaType::QRegularExpression:
-#endif
- case QMetaType::QUuid:
- case QMetaType::QVariantList:
- case QMetaType::QVariantMap:
- case QMetaType::QVariantHash:
- case QMetaType::QJsonValue:
- case QMetaType::QJsonArray:
- case QMetaType::QJsonObject:
- case QMetaType::QJsonDocument:
- case QMetaType::QCborArray:
- case QMetaType::QCborMap:
- case QMetaType::QCborSimpleType:
- return true;
- default:
- return false;
- }
- }
- if (currentType == QMetaType::QCborArray)
- return targetTypeId == QMetaType::QVariantList || targetTypeId == QMetaType::QCborValue
- || targetTypeId == QMetaType::QJsonArray;
- if (currentType == QMetaType::QCborMap)
- return targetTypeId == QMetaType::QVariantMap || targetTypeId == QMetaType::QVariantHash
- || targetTypeId == QMetaType::QCborValue || targetTypeId == QMetaType::QJsonObject;
-
- // FIXME It should be LastCoreType intead of Uuid
- if (currentType > int(QMetaType::QUuid) || targetTypeId > int(QMetaType::QUuid)) {
- switch (uint(targetTypeId)) {
- case QVariant::Int:
-#if QT_CONFIG(shortcut)
- if (currentType == QVariant::KeySequence)
- return true;
- Q_FALLTHROUGH();
-#endif
- case QVariant::UInt:
- case QVariant::LongLong:
- case QVariant::ULongLong:
- return currentType == QMetaType::ULong
- || currentType == QMetaType::Long
- || currentType == QMetaType::UShort
- || currentType == QMetaType::UChar
- || currentType == QMetaType::Char
- || currentType == QMetaType::SChar
- || currentType == QMetaType::Short
- || QMetaType::typeFlags(currentType) & QMetaType::IsEnumeration;
- case QVariant::Image:
- return currentType == QVariant::Pixmap || currentType == QVariant::Bitmap;
- case QVariant::Pixmap:
- return currentType == QVariant::Image || currentType == QVariant::Bitmap
- || currentType == QVariant::Brush;
- case QVariant::Bitmap:
- return currentType == QVariant::Pixmap || currentType == QVariant::Image;
- case QVariant::ByteArray:
- return currentType == QVariant::Color || currentType == QMetaType::Nullptr
- || ((QMetaType::typeFlags(currentType) & QMetaType::IsEnumeration) && QMetaType::metaObjectForType(currentType));
- case QVariant::String:
- return currentType == QVariant::Font
- || currentType == QVariant::Color || currentType == QMetaType::Nullptr
-#if QT_CONFIG(shortcut)
- || currentType == QVariant::KeySequence
-#endif
- || ((QMetaType::typeFlags(currentType) & QMetaType::IsEnumeration) && QMetaType::metaObjectForType(currentType));
-#if QT_CONFIG(shortcut)
- case QVariant::KeySequence:
- return currentType == QVariant::String || currentType == QVariant::Int;
-#endif
- case QVariant::Font:
- return currentType == QVariant::String;
- case QVariant::Color:
- return currentType == QVariant::String || currentType == QVariant::ByteArray
- || currentType == QVariant::Brush;
- case QVariant::Brush:
- return currentType == QVariant::Color || currentType == QVariant::Pixmap;
- case QMetaType::Long:
- case QMetaType::Char:
- case QMetaType::SChar:
- case QMetaType::UChar:
- case QMetaType::ULong:
- case QMetaType::Short:
- case QMetaType::UShort:
- return currentType == QVariant::Int
- || (currentType < qCanConvertMatrixMaximumTargetType
- && qCanConvertMatrix[QVariant::Int] & (1U << currentType))
- || QMetaType::typeFlags(currentType) & QMetaType::IsEnumeration;
- case QMetaType::QObjectStar:
- return canConvertMetaObject(currentType, targetTypeId, d.get<QObject *>());
- default:
- return false;
- }
- }
-
- if (targetTypeId == String && currentType == StringList)
- return d.get<QStringList>().count() == 1;
- return currentType < qCanConvertMatrixMaximumTargetType
- && qCanConvertMatrix[targetTypeId] & (1U << currentType);
+ return QMetaType::canConvert(d.type(), QMetaType(targetTypeId));
}
/*!
@@ -2409,7 +2021,7 @@ bool QVariant::canConvert(int targetTypeId) const
bool QVariant::convert(int targetTypeId)
{
if (d.typeId() == targetTypeId)
- return true;
+ return (targetTypeId != QMetaType::UnknownType);
QVariant oldValue = *this;