summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFabian Kosmale <fabian.kosmale@qt.io>2020-08-31 16:42:36 +0200
committerFabian Kosmale <fabian.kosmale@qt.io>2020-09-02 22:50:50 +0200
commit19874d6a6386b55fe502e3a36a9adb6813b315dc (patch)
tree57a54e2c0f8aa34bc744660e8d4f127f8689f6fd
parent3ddffd2d8b619863930854705ca5577c0389d65f (diff)
QVariant: Fix conversion code
Fixes: QTBUG-86330 Change-Id: Ib89dcf1195e0081b4c4e2845f90c52c612e5911a Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
-rw-r--r--src/corelib/kernel/qmetatype.cpp13
-rw-r--r--tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp38
2 files changed, 49 insertions, 2 deletions
diff --git a/src/corelib/kernel/qmetatype.cpp b/src/corelib/kernel/qmetatype.cpp
index a87b98b12d..95557bf021 100644
--- a/src/corelib/kernel/qmetatype.cpp
+++ b/src/corelib/kernel/qmetatype.cpp
@@ -2050,8 +2050,17 @@ bool QMetaType::convert(QMetaType fromType, const void *from, QMetaType toType,
// handle QObject conversion
if ((fromType.flags() & QMetaType::PointerToQObject) && (toType.flags() & QMetaType::PointerToQObject)) {
QObject *fromObject = *static_cast<QObject * const *>(from);
- *static_cast<QObject **>(to) = fromObject ? fromObject->metaObject()->cast(fromObject) : nullptr;
- return true;
+ // use dynamic metatype of from if possible
+ if (fromObject && fromObject->metaObject()->inherits(toType.metaObject())) {
+ *static_cast<QObject **>(to) = toType.metaObject()->cast(fromObject);
+ return true;
+ } else if (!fromObject) {
+ // if fromObject is null, use static fromType to check if conversion works
+ *static_cast<void **>(to) = nullptr;
+ return fromType.metaObject()->inherits(toType.metaObject());
+ } else {
+ return false;
+ }
}
#endif
diff --git a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp
index 48d68db298..8796589df3 100644
--- a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp
+++ b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp
@@ -221,6 +221,7 @@ private slots:
void compareCustomTypes() const;
void timeToDateTime() const;
void copyingUserTypes() const;
+ void valueClassHierarchyConversion() const;
void convertBoolToByteArray() const;
void convertBoolToByteArray_data() const;
void convertByteArrayToBool() const;
@@ -2894,6 +2895,43 @@ void tst_QVariant::copyingUserTypes() const
QCOMPARE(copiedType.myValue, 42);
}
+
+struct NonQObjectBase {};
+struct NonQObjectDerived : NonQObjectBase {};
+
+void tst_QVariant::valueClassHierarchyConversion() const
+{
+
+ {
+ // QVariant allows downcasting
+ QScopedPointer<CustomQObjectDerived> derived {new CustomQObjectDerived};
+ QVariant var = QVariant::fromValue(derived.get());
+ CustomQObject *object = var.value<CustomQObject *>();
+ QVERIFY(object);
+ }
+ {
+ // QVariant supports upcasting to the correct dynamic type for QObjects
+ QScopedPointer<CustomQObjectDerived> derived {new CustomQObjectDerived};
+ QVariant var = QVariant::fromValue<CustomQObject *>(derived.get());
+ CustomQObjectDerived *object = var.value<CustomQObjectDerived *>();
+ QVERIFY(object);
+ }
+ {
+ // QVariant forbids unsafe upcasting
+ QScopedPointer<CustomQObject> base {new CustomQObject};
+ QVariant var = QVariant::fromValue(base.get());
+ CustomQObjectDerived *object = var.value<CustomQObjectDerived *>();
+ QVERIFY(!object);
+ }
+ {
+ // QVariant does not support upcastingfor non-QObjects
+ QScopedPointer<NonQObjectDerived> derived {new NonQObjectDerived};
+ QVariant var = QVariant::fromValue<NonQObjectBase *>(derived.get());
+ NonQObjectDerived *object = var.value<NonQObjectDerived *>();
+ QVERIFY(!object);
+ }
+}
+
void tst_QVariant::convertBoolToByteArray() const
{
QFETCH(QByteArray, input);