aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkh1 <karsten.heimrich@digia.com>2014-06-04 13:17:30 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2014-06-04 18:52:58 +0200
commit0f9cf70501fdcf60d87615b3f998c85f134948ac (patch)
tree880891b10c44647226682c660dd1811ce6722443
parent297ee9cc2cfbc9e797aee3ce660484f682bb4e61 (diff)
Fix method overload calling of Qt slots from JavaScript
After commit ac57f185d1a2203cd4b585df7bd7af01c3ec33ed we succeed in selecting the correct overload based on the supplied arguments. However when calling slots on objects without a property cache, we end up using the local "dummy" variable to store the synthetic propert data. We also store the currently best patch in the "best" variable, which is a _pointer_ to the property data of the match. Suppose we have 5 overloads to choose from, we find that the 3rd is the best. Then we try the fourth but find it unsufficient and break out of the loop. Unfortunately the "dummy" property data at this point contains the data of the fourth (wrong) overload, and our best match variable points to it. So then when we finally call the method, we do it based on the wrong property data. The easy patch is to simply copy the few bytes of property data, so "best" is stored by value instead of pointer. Change-Id: Ie2ebbdb88a117770b6c7b9490e1c634077020e9d Reviewed-by: Karsten Heimrich <karsten.heimrich@digia.com>
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper.cpp8
-rw-r--r--tests/auto/qml/qjsengine/tst_qjsengine.cpp49
2 files changed, 53 insertions, 4 deletions
diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp
index b61be913a6..a02424a3dc 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper.cpp
+++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp
@@ -1407,7 +1407,7 @@ static QV4::ReturnedValue CallOverloaded(QObject *object, const QQmlPropertyData
{
int argumentCount = callArgs->argc;
- const QQmlPropertyData *best = 0;
+ QQmlPropertyData best;
int bestParameterScore = INT_MAX;
int bestMatchScore = INT_MAX;
@@ -1453,7 +1453,7 @@ static QV4::ReturnedValue CallOverloaded(QObject *object, const QQmlPropertyData
methodMatchScore += MatchScore((v = callArgs->args[ii]), methodArgTypes[ii]);
if (bestParameterScore > methodParameterScore || bestMatchScore > methodMatchScore) {
- best = attempt;
+ best = *attempt;
bestParameterScore = methodParameterScore;
bestMatchScore = methodMatchScore;
}
@@ -1463,10 +1463,10 @@ static QV4::ReturnedValue CallOverloaded(QObject *object, const QQmlPropertyData
} while((attempt = RelatedMethod(object, attempt, dummy)) != 0);
- if (best) {
+ if (best.isValid()) {
if (valueTypeObject)
valueTypeObject->setValue(valueTypeValue);
- return CallPrecise(object, *best, engine, callArgs);
+ return CallPrecise(object, best, engine, callArgs);
} else {
QString error = QLatin1String("Unable to determine callable overload. Candidates are:");
const QQmlPropertyData *candidate = &data;
diff --git a/tests/auto/qml/qjsengine/tst_qjsengine.cpp b/tests/auto/qml/qjsengine/tst_qjsengine.cpp
index 17acb4fd32..51cd69998a 100644
--- a/tests/auto/qml/qjsengine/tst_qjsengine.cpp
+++ b/tests/auto/qml/qjsengine/tst_qjsengine.cpp
@@ -187,6 +187,7 @@ signals:
void slotWithSingleArgCalled(const QString &arg);
void slotWithArgumentsCalled(const QString &arg1, const QString &arg2, const QString &arg3);
void slotWithOverloadedArgumentsCalled(const QString &arg, Qt::KeyboardModifier modifier, Qt::KeyboardModifiers moreModifiers);
+ void slotWithTwoOverloadedArgumentsCalled(const QString &arg, Qt::KeyboardModifiers moreModifiers, Qt::KeyboardModifier modifier);
public slots:
void slotToCall() { emit slotWithoutArgCalled(); }
@@ -199,6 +200,10 @@ public slots:
{
emit slotWithOverloadedArgumentsCalled(arg, modifier, blah);
}
+ void slotToCallTwoDefault(const QString &arg, Qt::KeyboardModifiers modifiers = Qt::ShiftModifier | Qt::ControlModifier, Qt::KeyboardModifier modifier = Qt::AltModifier)
+ {
+ emit slotWithTwoOverloadedArgumentsCalled(arg, modifiers, modifier);
+ }
};
void tst_QJSEngine::callQObjectSlot()
@@ -256,6 +261,50 @@ void tst_QJSEngine::callQObjectSlot()
QCOMPARE(int(qvariant_cast<Qt::KeyboardModifiers>(arguments.at(2))), int(Qt::ShiftModifier));
}
+
+ {
+ QSignalSpy spy(&dummy, SIGNAL(slotWithTwoOverloadedArgumentsCalled(QString, Qt::KeyboardModifiers, Qt::KeyboardModifier)));
+ QJSValue v = eng.evaluate(QStringLiteral("dummy.slotToCallTwoDefault('arg', %1);").arg(QString::number(Qt::MetaModifier | Qt::KeypadModifier)));
+ QCOMPARE(spy.count(), 1);
+
+ const QList<QVariant> arguments = spy.first();
+ QCOMPARE(arguments.at(0).toString(), QString("arg"));
+ QCOMPARE(int(qvariant_cast<Qt::KeyboardModifiers>(arguments.at(1))), int(Qt::MetaModifier | Qt::KeypadModifier));
+ QCOMPARE(int(qvariant_cast<Qt::KeyboardModifier>(arguments.at(2))), int(Qt::AltModifier));
+ }
+
+ QJSValue jsArray = eng.newArray();
+ jsArray.setProperty(QStringLiteral("MetaModifier"), QJSValue(Qt::MetaModifier));
+ jsArray.setProperty(QStringLiteral("ShiftModifier"), QJSValue(Qt::ShiftModifier));
+ jsArray.setProperty(QStringLiteral("ControlModifier"), QJSValue(Qt::ControlModifier));
+ jsArray.setProperty(QStringLiteral("KeypadModifier"), QJSValue(Qt::KeypadModifier));
+
+ QJSValue value = eng.newQObject(new QObject);
+ value.setPrototype(jsArray);
+ eng.globalObject().setProperty(QStringLiteral("Qt"), value);
+
+ {
+ QSignalSpy spy(&dummy, SIGNAL(slotWithOverloadedArgumentsCalled(QString, Qt::KeyboardModifier, Qt::KeyboardModifiers)));
+ QJSValue v = eng.evaluate(QStringLiteral("dummy.slotToCall('arg', Qt.ControlModifier);"));
+ QCOMPARE(spy.count(), 1);
+
+ const QList<QVariant> arguments = spy.first();
+ QCOMPARE(arguments.at(0).toString(), QString("arg"));
+ QCOMPARE(arguments.at(1).toInt(), int(Qt::ControlModifier));
+ QCOMPARE(int(qvariant_cast<Qt::KeyboardModifiers>(arguments.at(2))), int(Qt::ShiftModifier));
+ }
+
+ {
+ QSignalSpy spy(&dummy, SIGNAL(slotWithTwoOverloadedArgumentsCalled(QString, Qt::KeyboardModifiers, Qt::KeyboardModifier)));
+ QJSValue v = eng.evaluate(QStringLiteral("dummy.slotToCallTwoDefault('arg', Qt.MetaModifier | Qt.KeypadModifier);"));
+ QCOMPARE(spy.count(), 1);
+
+ const QList<QVariant> arguments = spy.first();
+ QCOMPARE(arguments.at(0).toString(), QString("arg"));
+ QCOMPARE(int(qvariant_cast<Qt::KeyboardModifiers>(arguments.at(1))), int(Qt::MetaModifier | Qt::KeypadModifier));
+ QCOMPARE(int(qvariant_cast<Qt::KeyboardModifier>(arguments.at(2))), int(Qt::AltModifier));
+ }
+
}
void tst_QJSEngine::constructWithParent()