aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper.cpp98
-rw-r--r--tests/auto/qml/qqmlecmascript/testtypes.h20
-rw-r--r--tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp41
3 files changed, 120 insertions, 39 deletions
diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp
index 517fbab6f1..40398cb648 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper.cpp
+++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp
@@ -1585,17 +1585,17 @@ static int MatchScore(const QV4::Value &actual, QMetaType conversionMetaType)
else if (v.canConvert(conversionMetaType))
return 5;
return 10;
- } else if (conversionType == QMetaType::QJsonObject) {
- return 5;
- } else if (conversionType == qMetaTypeId<QJSValue>()) {
- return 0;
- } else {
- return 10;
}
- } else {
- return 10;
+ if (conversionType == QMetaType::QJsonObject)
+ return 5;
+ if (conversionType == qMetaTypeId<QJSValue>())
+ return 0;
+ if (conversionType == QMetaType::QVariantMap)
+ return 5;
}
+
+ return 10;
}
static int numDefinedArguments(QV4::CallData *callArgs)
@@ -1708,46 +1708,66 @@ static const QQmlPropertyData *ResolveOverloaded(
const QQmlPropertyData *best = nullptr;
int bestParameterScore = INT_MAX;
- int bestMatchScore = INT_MAX;
+ int bestMaxMatchScore = INT_MAX;
+ int bestSumMatchScore = INT_MAX;
QV4::Scope scope(engine);
QV4::ScopedValue v(scope);
for (int i = 0; i < methodCount; ++i) {
const QQmlPropertyData *attempt = methods + i;
- QQmlMetaObject::ArgTypeStorage storage;
- int methodArgumentCount = 0;
- if (attempt->hasArguments()) {
- if (attempt->isConstructor()) {
- if (!object.constructorParameterTypes(attempt->coreIndex(), &storage, nullptr))
- continue;
- } else {
- if (!object.methodParameterTypes(attempt->coreIndex(), &storage, nullptr))
- continue;
- }
- methodArgumentCount = storage.size();
- }
- if (methodArgumentCount > argumentCount)
- continue; // We don't have sufficient arguments to call this method
+ // QQmlV4Function overrides anything that doesn't provide the exact number of arguments
+ int methodParameterScore = 1;
+ // QQmlV4Function overrides the "no idea" option, which is 10
+ int maxMethodMatchScore = 9;
+ // QQmlV4Function cannot provide a best sum of match scores as we don't match the arguments
+ int sumMethodMatchScore = bestSumMatchScore;
- int methodParameterScore = definedArgumentCount - methodArgumentCount;
- if (methodParameterScore > bestParameterScore)
- continue; // We already have a better option
+ if (!attempt->isV4Function()) {
+ QQmlMetaObject::ArgTypeStorage storage;
+ int methodArgumentCount = 0;
+ if (attempt->hasArguments()) {
+ if (attempt->isConstructor()) {
+ if (!object.constructorParameterTypes(attempt->coreIndex(), &storage, nullptr))
+ continue;
+ } else {
+ if (!object.methodParameterTypes(attempt->coreIndex(), &storage, nullptr))
+ continue;
+ }
+ methodArgumentCount = storage.size();
+ }
- int methodMatchScore = 0;
- for (int ii = 0; ii < methodArgumentCount; ++ii) {
- methodMatchScore += MatchScore((v = QV4::Value::fromStaticValue(callArgs->args[ii])),
- storage[ii]);
+ if (methodArgumentCount > argumentCount)
+ continue; // We don't have sufficient arguments to call this method
+
+ methodParameterScore = (definedArgumentCount == methodArgumentCount)
+ ? 0
+ : (definedArgumentCount - methodArgumentCount + 1);
+ if (methodParameterScore > bestParameterScore)
+ continue; // We already have a better option
+
+ maxMethodMatchScore = 0;
+ sumMethodMatchScore = 0;
+ for (int ii = 0; ii < methodArgumentCount; ++ii) {
+ const int score = MatchScore((v = QV4::Value::fromStaticValue(callArgs->args[ii])),
+ storage[ii]);
+ maxMethodMatchScore = qMax(maxMethodMatchScore, score);
+ sumMethodMatchScore += score;
+ }
}
- if (bestParameterScore > methodParameterScore || bestMatchScore > methodMatchScore) {
+ if (bestParameterScore > methodParameterScore || bestMaxMatchScore > maxMethodMatchScore
+ || (bestParameterScore == methodParameterScore
+ && bestMaxMatchScore == maxMethodMatchScore
+ && bestSumMatchScore > sumMethodMatchScore)) {
best = attempt;
bestParameterScore = methodParameterScore;
- bestMatchScore = methodMatchScore;
+ bestMaxMatchScore = maxMethodMatchScore;
+ bestSumMatchScore = sumMethodMatchScore;
}
- if (bestParameterScore == 0 && bestMatchScore == 0)
+ if (bestParameterScore == 0 && bestMaxMatchScore == 0)
break; // We can't get better than that
};
@@ -2259,6 +2279,12 @@ ReturnedValue QObjectMethod::callInternal(const Value *thisObject, const Value *
return call();
};
+ if (d()->methodCount != 1) {
+ method = ResolveOverloaded(object, d()->methods, d()->methodCount, v4, callData);
+ if (method == nullptr)
+ return Encode::undefined();
+ }
+
if (method->isV4Function()) {
return doCall([&]() {
QV4::ScopedValue rv(scope, QV4::Value::undefinedValue());
@@ -2272,12 +2298,6 @@ ReturnedValue QObjectMethod::callInternal(const Value *thisObject, const Value *
});
}
- if (d()->methodCount != 1) {
- method = ResolveOverloaded(object, d()->methods, d()->methodCount, v4, callData);
- if (method == nullptr)
- return Encode::undefined();
- }
-
return doCall([&]() { return CallPrecise(object, *method, v4, callData); });
}
diff --git a/tests/auto/qml/qqmlecmascript/testtypes.h b/tests/auto/qml/qqmlecmascript/testtypes.h
index 59e0a9cb65..99fc6c96ab 100644
--- a/tests/auto/qml/qqmlecmascript/testtypes.h
+++ b/tests/auto/qml/qqmlecmascript/testtypes.h
@@ -891,6 +891,26 @@ public:
Q_INVOKABLE void method_unknown(NonRegisteredType) { invoke(28); }
+ Q_INVOKABLE void method_overload2(QQmlV4Function *v)
+ {
+ invoke(31);
+ QV4::Scope scope(v->v4engine());
+ for (int i = 0, end = v->length(); i != end; ++i) {
+ QV4::ScopedValue v4Value(scope, (*v)[i]);
+ m_actuals.append(v->v4engine()->toVariant(v4Value, QMetaType()));
+ }
+ }
+ Q_INVOKABLE void method_overload2(const QVariantList &list)
+ {
+ invoke(32);
+ m_actuals << QVariant(list);
+ }
+ Q_INVOKABLE void method_overload2(const QVariantMap &map) { invoke(33); m_actuals << map; }
+ Q_INVOKABLE void method_overload2(int a) { invoke(34); m_actuals << a; }
+ Q_INVOKABLE void method_overload2(int a, int b) { invoke(35); m_actuals << a << b; }
+ Q_INVOKABLE void method_overload2(QString a) { invoke(36); m_actuals << a; }
+ Q_INVOKABLE void method_overload2() { invoke(37); }
+
private:
friend class MyInvokableBaseObject;
void invoke(int idx) { if (m_invoked != -1) m_invokedError = true; m_invoked = idx;}
diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
index 98b08a0e23..47d3aee5da 100644
--- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
+++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
@@ -3345,6 +3345,47 @@ void tst_qqmlecmascript::callQtInvokables()
QJSValue callback = qvariant_cast<QJSValue>(o->actuals().at(1));
QVERIFY(!callback.isNull());
QVERIFY(callback.isCallable());
+
+ o->reset();
+ QVERIFY(EVALUATE_VALUE("object.method_overload2('foo', 12, [1, 2, 3])", QV4::Primitive::undefinedValue()));
+ QCOMPARE(o->error(), false);
+ QCOMPARE(o->invoked(), 31);
+ QCOMPARE(o->actuals().count(), 3);
+ QCOMPARE(qvariant_cast<QString>(o->actuals().at(0)), QStringLiteral("foo"));
+ QCOMPARE(qvariant_cast<int>(o->actuals().at(1)), 12);
+ QCOMPARE(qvariant_cast<QVariantList>(o->actuals().at(2)), (QVariantList {1.0, 2.0, 3.0}));
+
+ o->reset();
+ QVERIFY(EVALUATE_VALUE("object.method_overload2(11, 12, {a: 1, b: 2})", QV4::Primitive::undefinedValue()));
+ QCOMPARE(o->error(), false);
+ QCOMPARE(o->invoked(), 31);
+ QCOMPARE(o->actuals().count(), 3);
+ QCOMPARE(qvariant_cast<int>(o->actuals().at(0)), 11);
+ QCOMPARE(qvariant_cast<int>(o->actuals().at(1)), 12);
+ QCOMPARE(qvariant_cast<QVariantMap>(o->actuals().at(2)),
+ (QVariantMap { {QStringLiteral("a"), 1.0}, {QStringLiteral("b"), 2.0}, }));
+
+ o->reset();
+ QVERIFY(EVALUATE_VALUE("object.method_overload2([1, 'bar', 0.2])",
+ QV4::Primitive::undefinedValue()));
+ QCOMPARE(o->error(), false);
+ QCOMPARE(o->invoked(), 32);
+ QCOMPARE(o->actuals().count(), 1);
+ QCOMPARE(qvariant_cast<QVariantList>(o->actuals().at(0)),
+ (QVariantList {1.0, QStringLiteral("bar"), 0.2}));
+
+ o->reset();
+ QVERIFY(EVALUATE_VALUE("object.method_overload2({one: 1, two: 'bar', three: 0.2})",
+ QV4::Primitive::undefinedValue()));
+ QCOMPARE(o->error(), false);
+ QCOMPARE(o->invoked(), 33);
+ QCOMPARE(o->actuals().count(), 1);
+ QCOMPARE(qvariant_cast<QVariantMap>(o->actuals().at(0)),
+ (QVariantMap {
+ {QStringLiteral("one"), 1.0},
+ {QStringLiteral("two"), QStringLiteral("bar")},
+ {QStringLiteral("three"), 0.2}
+ }));
}
void tst_qqmlecmascript::resolveClashingProperties()