aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/jsruntime/qv4qobjectwrapper.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/jsruntime/qv4qobjectwrapper.cpp')
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper.cpp103
1 files changed, 83 insertions, 20 deletions
diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp
index abe7a96512..b771a938e4 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper.cpp
+++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp
@@ -1711,8 +1711,19 @@ int MatchVariant(QMetaType conversionMetaType, Retrieve &&retrieve) {
return 1;
}
- if (QMetaType::canConvert(type, conversionMetaType))
+ if (QMetaType::canConvert(type, conversionMetaType)) {
+ if (conversionMetaType == QMetaType::fromType<QJSValue>()
+ || conversionMetaType == QMetaType::fromType<double>()
+ || conversionMetaType == QMetaType::fromType<QString>()) {
+ // Unspecific conversions receive lower score. You can convert anything
+ // to QString or double via toString() and valueOf(), respectively.
+ // And anything can be wrapped into QJSValue, but that's inefficient.
+ return 6;
+ }
+
+ // We have an explicitly defined conversion method to a non-boring type.
return 5;
+ }
return 10;
};
@@ -1726,6 +1737,33 @@ int MatchVariant(QMetaType conversionMetaType, Retrieve &&retrieve) {
static int MatchScore(const Value &actual, QMetaType conversionMetaType)
{
const int conversionType = conversionMetaType.id();
+ const auto convertibleScore = [&](QMetaType actualType) {
+ // There are a number of things we can do in JavaScript to subvert this, but
+ // if the conversion is not explicitly defined in C++, we don't want to prioritize it.
+ if (!QMetaType::canConvert(actualType, conversionMetaType))
+ return 10;
+
+ // You can convert anything to QJSValue, but that's inefficient.
+ // If we have a better option, we should use it.
+ if (conversionMetaType == QMetaType::fromType<QJSValue>())
+ return 9;
+
+ // You can also convert anything to QVariant, but that's also suboptimal.
+ // You can convert anything to string or double via toString() and valueOf().
+ // Those are also rather unspecific.
+ switch (conversionType) {
+ case QMetaType::QVariant:
+ case QMetaType::Double:
+ case QMetaType::QString:
+ return 9;
+ default:
+ break;
+ }
+
+ // We have an explicitly defined conversion method to a non-boring type.
+ return 8;
+ };
+
if (actual.isNumber()) {
switch (conversionType) {
case QMetaType::Double:
@@ -1751,7 +1789,9 @@ static int MatchScore(const Value &actual, QMetaType conversionMetaType)
case QMetaType::QJsonValue:
return 5;
default:
- return 10;
+ return convertibleScore(actual.isInteger()
+ ? QMetaType::fromType<int>()
+ : QMetaType::fromType<double>());
}
} else if (actual.isString()) {
switch (conversionType) {
@@ -1761,8 +1801,21 @@ static int MatchScore(const Value &actual, QMetaType conversionMetaType)
return 5;
case QMetaType::QUrl:
return 6; // we like to convert strings to URLs in QML
- default:
+ case QMetaType::Double:
+ case QMetaType::Float:
+ case QMetaType::LongLong:
+ case QMetaType::ULongLong:
+ case QMetaType::Int:
+ case QMetaType::UInt:
+ case QMetaType::Short:
+ case QMetaType::UShort:
+ case QMetaType::Char:
+ case QMetaType::UChar:
+ // QMetaType can natively convert strings to numbers.
+ // However, in the general case it's of course extremely lossy.
return 10;
+ default:
+ return convertibleScore(QMetaType::fromType<QString>());
}
} else if (actual.isBoolean()) {
switch (conversionType) {
@@ -1771,7 +1824,7 @@ static int MatchScore(const Value &actual, QMetaType conversionMetaType)
case QMetaType::QJsonValue:
return 5;
default:
- return 10;
+ return convertibleScore(QMetaType::fromType<bool>());
}
} else if (actual.as<DateObject>()) {
switch (conversionType) {
@@ -1782,23 +1835,26 @@ static int MatchScore(const Value &actual, QMetaType conversionMetaType)
case QMetaType::QTime:
return 2;
default:
- return 10;
+ return convertibleScore(QMetaType::fromType<QDateTime>());
}
} else if (actual.as<RegExpObject>()) {
switch (conversionType) {
#if QT_CONFIG(regularexpression)
case QMetaType::QRegularExpression:
return 0;
-#endif
default:
- return 10;
+ return convertibleScore(QMetaType::fromType<QRegularExpression>());
+#else
+ default:
+ return convertibleScore(QMetaType());
+#endif
}
} else if (actual.as<ArrayBuffer>()) {
switch (conversionType) {
case QMetaType::QByteArray:
return 0;
default:
- return 10;
+ return convertibleScore(QMetaType::fromType<QByteArray>());
}
} else if (actual.as<ArrayObject>()) {
switch (conversionType) {
@@ -1813,7 +1869,7 @@ static int MatchScore(const Value &actual, QMetaType conversionMetaType)
case QMetaType::QVector3D:
return 7;
default:
- return 10;
+ return convertibleScore(QMetaType());
}
} else if (actual.isNull()) {
switch (conversionType) {
@@ -1826,7 +1882,7 @@ static int MatchScore(const Value &actual, QMetaType conversionMetaType)
if (conversionMetaType.flags().testFlag(QMetaType::IsPointer))
return 0;
else
- return 10;
+ return convertibleScore(QMetaType());
}
}
} else if (const Object *obj = actual.as<Object>()) {
@@ -1849,7 +1905,8 @@ static int MatchScore(const Value &actual, QMetaType conversionMetaType)
return 0;
}
}
- return 10;
+
+ return convertibleScore(QMetaType::fromType<QObject *>());
}
if (const QQmlTypeWrapper *wrapper = obj->as<QQmlTypeWrapper>()) {
@@ -1871,14 +1928,15 @@ static int MatchScore(const Value &actual, QMetaType conversionMetaType)
}
}
- return 10;
+ return convertibleScore(QMetaType());
}
if (const Sequence *sequence = obj->as<Sequence>()) {
- if (SequencePrototype::metaTypeForSequence(sequence) == conversionMetaType)
+ const QMetaType sequenceType = SequencePrototype::metaTypeForSequence(sequence);
+ if (sequenceType == conversionMetaType)
return 1;
- else
- return 10;
+
+ return convertibleScore(sequenceType);
}
if (const QQmlValueTypeWrapper *wrapper = obj->as<QQmlValueTypeWrapper>()) {
@@ -1889,15 +1947,20 @@ static int MatchScore(const Value &actual, QMetaType conversionMetaType)
});
}
- if (conversionType == QMetaType::QJsonObject)
- return 5;
- if (conversionType == qMetaTypeId<QJSValue>())
+ if (conversionMetaType == QMetaType::fromType<QJSValue>())
return 0;
- if (conversionType == QMetaType::QVariantMap)
+
+ switch (conversionType) {
+ case QMetaType::QJsonObject:
+ case QMetaType::QVariantMap:
return 5;
+ default:
+ break;
+ }
+
}
- return 10;
+ return convertibleScore(QMetaType());
}
static int numDefinedArguments(CallData *callArgs)