Fix user defined conversions to numeric types

The old code was completely broken. It did dereference
val for user types, but val does in this case only contain
garbage. Instead use the pointer to the correct data.

Change-Id: I20ccf0bfa3dd3774c787d08c51cc8dd7b1ec9a1a
Reviewed-by: Jędrzej Nowacki <jedrzej.nowacki@digia.com>
This commit is contained in:
Lars Knoll 2014-09-09 12:18:55 +02:00
parent df25927a68
commit 6316a681f3
2 changed files with 94 additions and 2 deletions

View File

@ -2462,9 +2462,8 @@ inline T qNumVariantToHelper(const QVariant::Private &d,
T ret = 0;
if ((d.type >= QMetaType::User || t >= QMetaType::User)
&& QMetaType::convert(&val, d.type, &ret, t)) {
&& QMetaType::convert(constData(d), d.type, &ret, t))
return ret;
}
if (!handlerManager[d.type]->convert(&d, t, &ret, ok) && ok)
*ok = false;

View File

@ -224,6 +224,7 @@ private slots:
void moreCustomTypes();
void movabilityTest();
void variantInVariant();
void userConversion();
void forwardDeclare();
void debugStream_data();
@ -3312,6 +3313,98 @@ void tst_QVariant::variantInVariant()
QCOMPARE(qvariant_cast<QVariant>(var9), var1);
}
struct Convertible {
double d;
operator int() const { return (int)d; }
operator double() const { return d; }
operator QString() const { return QString::number(d); }
};
Q_DECLARE_METATYPE(Convertible);
struct BigConvertible {
double d;
double dummy;
double dummy2;
operator int() const { return (int)d; }
operator double() const { return d; }
operator QString() const { return QString::number(d); }
};
Q_DECLARE_METATYPE(BigConvertible);
Q_STATIC_ASSERT(sizeof(BigConvertible) > sizeof(QVariant));
void tst_QVariant::userConversion()
{
{
QVERIFY(!(QMetaType::hasRegisteredConverterFunction<int, Convertible>()));
QVERIFY(!(QMetaType::hasRegisteredConverterFunction<double, Convertible>()));
QVERIFY(!(QMetaType::hasRegisteredConverterFunction<QString, Convertible>()));
Convertible c = { 123 };
QVariant v = qVariantFromValue(c);
bool ok;
v.toInt(&ok);
QVERIFY(!ok);
v.toDouble(&ok);
QVERIFY(!ok);
QString s = v.toString();
QVERIFY(s.isEmpty());
QMetaType::registerConverter<Convertible, int>();
QMetaType::registerConverter<Convertible, double>();
QMetaType::registerConverter<Convertible, QString>();
int i = v.toInt(&ok);
QVERIFY(ok);
QCOMPARE(i, 123);
double d = v.toDouble(&ok);
QVERIFY(ok);
QCOMPARE(d, 123.);
s = v.toString();
QCOMPARE(s, QString::fromLatin1("123"));
}
{
QVERIFY(!(QMetaType::hasRegisteredConverterFunction<int, BigConvertible>()));
QVERIFY(!(QMetaType::hasRegisteredConverterFunction<double, BigConvertible>()));
QVERIFY(!(QMetaType::hasRegisteredConverterFunction<QString, BigConvertible>()));
BigConvertible c = { 123, 0, 0 };
QVariant v = qVariantFromValue(c);
bool ok;
v.toInt(&ok);
QVERIFY(!ok);
v.toDouble(&ok);
QVERIFY(!ok);
QString s = v.toString();
QVERIFY(s.isEmpty());
QMetaType::registerConverter<BigConvertible, int>();
QMetaType::registerConverter<BigConvertible, double>();
QMetaType::registerConverter<BigConvertible, QString>();
int i = v.toInt(&ok);
QVERIFY(ok);
QCOMPARE(i, 123);
double d = v.toDouble(&ok);
QVERIFY(ok);
QCOMPARE(d, 123.);
s = v.toString();
QCOMPARE(s, QString::fromLatin1("123"));
}
}
class Forward;
Q_DECLARE_OPAQUE_POINTER(Forward*)
Q_DECLARE_METATYPE(Forward*)