summaryrefslogtreecommitdiffstats
path: root/src/corelib/kernel/qvariant.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/kernel/qvariant.cpp')
-rw-r--r--src/corelib/kernel/qvariant.cpp162
1 files changed, 145 insertions, 17 deletions
diff --git a/src/corelib/kernel/qvariant.cpp b/src/corelib/kernel/qvariant.cpp
index e6262124fb..b79716ff4c 100644
--- a/src/corelib/kernel/qvariant.cpp
+++ b/src/corelib/kernel/qvariant.cpp
@@ -470,6 +470,9 @@ static bool convert(const QVariant::Private *d, int t, void *result, bool *ok)
case QVariant::Uuid:
*str = v_cast<QUuid>(d)->toString();
break;
+ case QMetaType::Nullptr:
+ *str = QString();
+ break;
default:
#ifndef QT_NO_QOBJECT
{
@@ -652,6 +655,9 @@ static bool convert(const QVariant::Private *d, int t, void *result, bool *ok)
case QVariant::Uuid:
*ba = v_cast<QUuid>(d)->toByteArray();
break;
+ case QMetaType::Nullptr:
+ *ba = QByteArray();
+ break;
default:
#ifndef QT_NO_QOBJECT
{
@@ -938,6 +944,107 @@ static bool convert(const QVariant::Private *d, int t, void *result, bool *ok)
return false;
}
break;
+#ifndef QT_BOOTSTRAPPED
+ case QMetaType::QJsonValue:
+ switch (d->type) {
+ case QMetaType::Nullptr:
+ *static_cast<QJsonValue *>(result) = QJsonValue(QJsonValue::Null);
+ break;
+ case QVariant::Bool:
+ *static_cast<QJsonValue *>(result) = QJsonValue(d->data.b);
+ break;
+ 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:
+ *static_cast<QJsonValue *>(result) = QJsonValue(qConvertToRealNumber(d, ok));
+ Q_ASSERT(ok);
+ break;
+ case QVariant::String:
+ *static_cast<QJsonValue *>(result) = QJsonValue(*v_cast<QString>(d));
+ break;
+ case QVariant::StringList:
+ *static_cast<QJsonValue *>(result) = QJsonValue(QJsonArray::fromStringList(*v_cast<QStringList>(d)));
+ break;
+ case QVariant::List:
+ *static_cast<QJsonValue *>(result) = QJsonValue(QJsonArray::fromVariantList(*v_cast<QVariantList>(d)));
+ break;
+ case QVariant::Map:
+ *static_cast<QJsonValue *>(result) = QJsonValue(QJsonObject::fromVariantMap(*v_cast<QVariantMap>(d)));
+ break;
+ case QVariant::Hash:
+ *static_cast<QJsonValue *>(result) = QJsonValue(QJsonObject::fromVariantHash(*v_cast<QVariantHash>(d)));
+ break;
+ case QMetaType::QJsonObject:
+ *static_cast<QJsonValue *>(result) = *v_cast<QJsonObject>(d);
+ break;
+ case QMetaType::QJsonArray:
+ *static_cast<QJsonValue *>(result) = *v_cast<QJsonArray>(d);
+ break;
+ case QMetaType::QJsonDocument: {
+ QJsonDocument doc = *v_cast<QJsonDocument>(d);
+ *static_cast<QJsonValue *>(result) = doc.isArray() ? QJsonValue(doc.array()) : QJsonValue(doc.object());
+ break;
+ }
+ default:
+ *static_cast<QJsonValue *>(result) = QJsonValue(QJsonValue::Undefined);
+ return false;
+ }
+ break;
+ case QMetaType::QJsonArray:
+ switch (d->type) {
+ case QVariant::StringList:
+ *static_cast<QJsonArray *>(result) = QJsonArray::fromStringList(*v_cast<QStringList>(d));
+ break;
+ case QVariant::List:
+ *static_cast<QJsonArray *>(result) = QJsonArray::fromVariantList(*v_cast<QVariantList>(d));
+ break;
+ case QMetaType::QJsonValue:
+ if (!v_cast<QJsonValue>(d)->isArray())
+ return false;
+ *static_cast<QJsonArray *>(result) = v_cast<QJsonValue>(d)->toArray();
+ break;
+ case QMetaType::QJsonDocument:
+ if (!v_cast<QJsonDocument>(d)->isArray())
+ return false;
+ *static_cast<QJsonArray *>(result) = v_cast<QJsonDocument>(d)->array();
+ break;
+ default:
+ return false;
+ }
+ break;
+ case QMetaType::QJsonObject:
+ switch (d->type) {
+ case QVariant::Map:
+ *static_cast<QJsonObject *>(result) = QJsonObject::fromVariantMap(*v_cast<QVariantMap>(d));
+ break;
+ case QVariant::Hash:
+ *static_cast<QJsonObject *>(result) = QJsonObject::fromVariantHash(*v_cast<QVariantHash>(d));
+ break;
+ case QMetaType::QJsonValue:
+ if (!v_cast<QJsonValue>(d)->isObject())
+ return false;
+ *static_cast<QJsonObject *>(result) = v_cast<QJsonValue>(d)->toObject();
+ break;
+ case QMetaType::QJsonDocument:
+ if (v_cast<QJsonDocument>(d)->isArray())
+ return false;
+ *static_cast<QJsonObject *>(result) = v_cast<QJsonDocument>(d)->object();
+ break;
+ default:
+ return false;
+ }
+ break;
+#endif
default:
#ifndef QT_NO_QOBJECT
if (d->type == QVariant::String || d->type == QVariant::ByteArray) {
@@ -1076,7 +1183,17 @@ static void customClear(QVariant::Private *d)
static bool customIsNull(const QVariant::Private *d)
{
- return d->is_null;
+ if (d->is_null)
+ return true;
+ const char *const typeName = QMetaType::typeName(d->type);
+ if (Q_UNLIKELY(!typeName) && Q_LIKELY(!QMetaType::isRegistered(d->type)))
+ qFatal("QVariant::isNull: type %d unknown to QVariant.", d->type);
+ uint typeNameLen = qstrlen(typeName);
+ if (typeNameLen > 0 && typeName[typeNameLen - 1] == '*') {
+ const void *d_ptr = d->is_shared ? d->data.shared->ptr : &(d->data.ptr);
+ return *static_cast<void *const *>(d_ptr) == nullptr;
+ }
+ return false;
}
static bool customCompare(const QVariant::Private *a, const QVariant::Private *b)
@@ -1358,7 +1475,11 @@ Q_CORE_EXPORT void QVariantPrivate::registerHandler(const int /* Modules::Names
/*!
\fn QVariant::QVariant(Type type)
- Constructs a null variant of type \a type.
+ Constructs an uninitialized variant of type \a type. This will create a
+ variant in a special null state that if accessed will return a default
+ constructed value of the \a type.
+
+ \sa isNull()
*/
@@ -3106,8 +3227,8 @@ bool QVariant::canConvert(int targetTypeId) const
}
}
- if (currentType == QMetaType::QJsonValue) {
- switch (targetTypeId) {
+ if (currentType == QMetaType::QJsonValue || targetTypeId == QMetaType::QJsonValue) {
+ switch (currentType == QMetaType::QJsonValue ? targetTypeId : currentType) {
case QMetaType::Nullptr:
case QMetaType::QString:
case QMetaType::Bool:
@@ -3163,11 +3284,11 @@ bool QVariant::canConvert(int targetTypeId) const
case QVariant::Bitmap:
return currentType == QVariant::Pixmap || currentType == QVariant::Image;
case QVariant::ByteArray:
- return currentType == QVariant::Color
+ return currentType == QVariant::Color || currentType == QMetaType::Nullptr
|| ((QMetaType::typeFlags(currentType) & QMetaType::IsEnumeration) && QMetaType::metaObjectForType(currentType));
case QVariant::String:
return currentType == QVariant::KeySequence || currentType == QVariant::Font
- || currentType == QVariant::Color
+ || currentType == QVariant::Color || currentType == QMetaType::Nullptr
|| ((QMetaType::typeFlags(currentType) & QMetaType::IsEnumeration) && QMetaType::metaObjectForType(currentType));
case QVariant::KeySequence:
return currentType == QVariant::String || currentType == QVariant::Int;
@@ -3204,17 +3325,20 @@ bool QVariant::canConvert(int targetTypeId) const
/*!
Casts the variant to the requested type, \a targetTypeId. If the cast cannot be
- done, the variant is cleared. Returns \c true if the current type of
- the variant was successfully cast; otherwise returns \c false.
+ done, the variant is still changed to the requested type, but is left in a cleared
+ null state similar to that constructed by QVariant(Type).
+
+ Returns \c true if the current type of the variant was successfully cast;
+ otherwise returns \c false.
A QVariant containing a pointer to a type derived from QObject will also convert
and 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.
- \warning For historical reasons, converting a null QVariant results
- in a null value of the desired type (e.g., an empty string for
- QString) and a result of false.
+ \note converting QVariants that are null due to not being initialized or having
+ failed a previous conversion will always fail, changing the type, remaining null,
+ and returning \c false.
\sa canConvert(), clear()
*/
@@ -3231,7 +3355,8 @@ bool QVariant::convert(int targetTypeId)
return false;
create(targetTypeId, 0);
- if (oldValue.isNull())
+ // Fail if the value is not initialized or was forced null by a previous failed convert.
+ if (oldValue.d.is_null)
return false;
if ((QMetaType::typeFlags(oldValue.userType()) & QMetaType::PointerToQObject) && (QMetaType::typeFlags(targetTypeId) & QMetaType::PointerToQObject)) {
@@ -3631,12 +3756,15 @@ void* QVariant::data()
/*!
Returns \c true if this is a null variant, false otherwise. A variant is
- considered null if it contains a default constructed value or a built-in
- type instance that has an isNull method, in which case the result
- would be the same as calling isNull on the wrapped object.
+ considered null if it contains no initialized value, or the contained value
+ is a null pointer or is an instance of a built-in type that has an isNull
+ method, in which case the result would be the same as calling isNull on the
+ wrapped object.
+
+ \warning Null variants is not a single state and two null variants may easily
+ return \c false on the == operator if they do not contain similar null values.
- \warning The result of the function doesn't affect == operator, which means
- that two values can be equal even if one of them is null and another is not.
+ \sa QVariant(Type), convert(int)
*/
bool QVariant::isNull() const
{