diff options
-rw-r--r-- | src/qml/common/qqmlsignalnames.cpp | 19 | ||||
-rw-r--r-- | src/qml/common/qqmlsignalnames_p.h | 3 | ||||
-rw-r--r-- | src/qml/qml/qqmlproperty.cpp | 30 | ||||
-rw-r--r-- | tests/auto/qml/qqmlconnections/data/badSignalHandlerName.qml | 15 | ||||
-rw-r--r-- | tests/auto/qml/qqmlconnections/tst_qqmlconnections.cpp | 21 |
5 files changed, 81 insertions, 7 deletions
diff --git a/src/qml/common/qqmlsignalnames.cpp b/src/qml/common/qqmlsignalnames.cpp index e66c26d4e2..d2a23205a6 100644 --- a/src/qml/common/qqmlsignalnames.cpp +++ b/src/qml/common/qqmlsignalnames.cpp @@ -191,6 +191,25 @@ std::optional<QString> QQmlSignalNames::handlerNameToSignalName(QStringView hand /*! \internal +Returns a signal name from \a handlerName string. Do not use it on changed handlers, see +changedHandlerNameToSignalName for that! Accepts improperly capitalized handler names and +incorrectly resolves signal names that start with '_' or '$'. +*/ +std::optional<QString> QQmlSignalNames::badHandlerNameToSignalName(QStringView handler) +{ + if (handler.size() <= StrlenOn || !handler.startsWith(On)) + return {}; + + QString signalName = handler.sliced(StrlenOn).toString(); + + // This is quite wrong. But we need it for backwards compatibility. + signalName.front() = signalName.front().toLower(); + + return signalName; +} + +/*! +\internal Returns a signal name from \a changedHandlerName string. Makes sure not to lowercase the 'C' from Changed. */ diff --git a/src/qml/common/qqmlsignalnames_p.h b/src/qml/common/qqmlsignalnames_p.h index 753f2ca97a..9c3d192666 100644 --- a/src/qml/common/qqmlsignalnames_p.h +++ b/src/qml/common/qqmlsignalnames_p.h @@ -49,6 +49,9 @@ public: static bool isHandlerName(QStringView signalName); static QString addPrefixToPropertyName(QStringView prefix, QStringView propertyName); + + // ### Qt7: remove this + static std::optional<QString> badHandlerNameToSignalName(QStringView handler); }; QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp index 7437eefa85..099512192f 100644 --- a/src/qml/qml/qqmlproperty.cpp +++ b/src/qml/qml/qqmlproperty.cpp @@ -381,11 +381,11 @@ void QQmlPropertyPrivate::initProperty(QObject *obj, const QString &name, }; const QString terminalString = terminal.toString(); - if (auto signalName = QQmlSignalNames::handlerNameToSignalName(terminalString)) { + const auto findSignal = [&](const QString &signalName) { if (ddata && ddata->propertyCache) { // Try method - const QQmlPropertyData *d = - ddata->propertyCache->property(*signalName, currentObject, context); + const QQmlPropertyData *d + = ddata->propertyCache->property(signalName, currentObject, context); // ### Qt7: This code treats methods as signals. It should use d->isSignal(). // That would be a change in behavior, though. Right now you can construct a @@ -396,13 +396,29 @@ void QQmlPropertyPrivate::initProperty(QObject *obj, const QString &name, if (d) { object = currentObject; core = *d; - return; + return true; } - if (findChangeSignal(terminalString)) - return; - } else if (findSignalInMetaObject(signalName->toUtf8())) { + return findChangeSignal(terminalString); + } + + return findSignalInMetaObject(signalName.toUtf8()); + }; + + auto signalName = QQmlSignalNames::handlerNameToSignalName(terminalString); + if (signalName) { + if (findSignal(*signalName)) return; + } else { + signalName = QQmlSignalNames::badHandlerNameToSignalName(terminalString); + if (signalName) { + qWarning() + << terminalString + << "is not a properly capitalized signal handler name." + << QQmlSignalNames::signalNameToHandlerName(*signalName) + << "would be correct."; + if (findSignal(*signalName)) + return; } } diff --git a/tests/auto/qml/qqmlconnections/data/badSignalHandlerName.qml b/tests/auto/qml/qqmlconnections/data/badSignalHandlerName.qml new file mode 100644 index 0000000000..921787aa36 --- /dev/null +++ b/tests/auto/qml/qqmlconnections/data/badSignalHandlerName.qml @@ -0,0 +1,15 @@ +import QtQml + +QtObject { + id: root + signal _foo + + property int handled: 0 + + property Connections c: Connections { + target: root + function on_Foo() { root.handled += 1 } + function on_foo() { root.handled += 2 } + } +} + diff --git a/tests/auto/qml/qqmlconnections/tst_qqmlconnections.cpp b/tests/auto/qml/qqmlconnections/tst_qqmlconnections.cpp index 61102798e7..adbaffb1ce 100644 --- a/tests/auto/qml/qqmlconnections/tst_qqmlconnections.cpp +++ b/tests/auto/qml/qqmlconnections/tst_qqmlconnections.cpp @@ -55,6 +55,7 @@ private slots: void bindToPropertyWithUnderscoreChangeHandler(); void invalidTarget(); + void badSignalHandlerName(); private: QQmlEngine engine; void prefixes(); @@ -461,6 +462,26 @@ void tst_qqmlconnections::invalidTarget() QTRY_VERIFY(root->objectName().isEmpty()); } +void tst_qqmlconnections::badSignalHandlerName() +{ + QQmlEngine engine; + QQmlComponent component(&engine, testFileUrl("badSignalHandlerName.qml")); + QVERIFY2(component.isReady(), qPrintable(component.errorString())); + + QTest::ignoreMessage( + QtWarningMsg, + "\"on_foo\" is not a properly capitalized signal handler name. " + "\"on_Foo\" would be correct."); + + QScopedPointer<QObject> root(component.create()); + QVERIFY(!root.isNull()); + + QCOMPARE(root->property("handled").toInt(), 0); + QMetaObject::invokeMethod(root.data(), "_foo"); + QCOMPARE(root->property("handled").toInt(), 3); +} + + QTEST_MAIN(tst_qqmlconnections) #include "tst_qqmlconnections.moc" |