diff --git a/src/corelib/kernel/qmetaobject.cpp b/src/corelib/kernel/qmetaobject.cpp index accefb1ec4..cb63718680 100644 --- a/src/corelib/kernel/qmetaobject.cpp +++ b/src/corelib/kernel/qmetaobject.cpp @@ -1338,6 +1338,27 @@ QByteArray QMetaObject::normalizedSignature(const char *method) enum { MaximumParamCount = 11 }; // up to 10 arguments + 1 return value +/*! + Returns the signatures of all methods whose name matches \a nonExistentMember, + or an empty QByteArray if there are no matches. +*/ +static inline QByteArray findMethodCandidates(const QMetaObject *metaObject, const char *nonExistentMember) +{ + QByteArray candidateMessage; + // Prevent full string comparison in every iteration. + const QByteArray memberByteArray = nonExistentMember; + for (int i = 0; i < metaObject->methodCount(); ++i) { + const QMetaMethod method = metaObject->method(i); + if (method.name() == memberByteArray) + candidateMessage.append(" " + method.methodSignature() + '\n'); + } + if (!candidateMessage.isEmpty()) { + candidateMessage.prepend("\nCandidates are:\n"); + candidateMessage.chop(1); + } + return candidateMessage; +} + /*! Invokes the \a member (a signal or a slot name) on the object \a obj. Returns \c true if the member could be invoked. Returns \c false @@ -1455,8 +1476,9 @@ bool QMetaObject::invokeMethod(QObject *obj, } if (idx < 0 || idx >= meta->methodCount()) { - qWarning("QMetaObject::invokeMethod: No such method %s::%s", - meta->className(), sig.constData()); + // This method doesn't belong to us; print out a nice warning with candidates. + qWarning("QMetaObject::invokeMethod: No such method %s::%s%s", + meta->className(), sig.constData(), findMethodCandidates(meta, member).constData()); return false; } QMetaMethod method = meta->method(idx); diff --git a/tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp b/tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp index 09084578ab..a920ea7a01 100644 --- a/tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp +++ b/tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp @@ -561,9 +561,11 @@ void tst_QMetaObject::invokeMetaMember() QVERIFY(!QMetaObject::invokeMethod(&obj, "doesNotExist")); QTest::ignoreMessage(QtWarningMsg, "QMetaObject::invokeMethod: No such method QtTestObject::sl1(QString)(QString)"); QVERIFY(!QMetaObject::invokeMethod(&obj, "sl1(QString)", Q_ARG(QString, "arg"))); - QTest::ignoreMessage(QtWarningMsg, "QMetaObject::invokeMethod: No such method QtTestObject::sl3(QString)"); + QTest::ignoreMessage(QtWarningMsg, "QMetaObject::invokeMethod: No such method QtTestObject::sl3(QString)\n" + "Candidates are:\n sl3(QString,QString,QString)"); QVERIFY(!QMetaObject::invokeMethod(&obj, "sl3", Q_ARG(QString, "arg"))); - QTest::ignoreMessage(QtWarningMsg, "QMetaObject::invokeMethod: No such method QtTestObject::sl1(QString,QString,QString)"); + QTest::ignoreMessage(QtWarningMsg, "QMetaObject::invokeMethod: No such method QtTestObject::sl1(QString,QString,QString)\n" + "Candidates are:\n sl1(QString)"); QVERIFY(!QMetaObject::invokeMethod(&obj, "sl1", Q_ARG(QString, "arg"), Q_ARG(QString, "arg"), Q_ARG(QString, "arg"))); //should not have changed since last test. @@ -747,9 +749,11 @@ void tst_QMetaObject::invokeBlockingQueuedMetaMember() QVERIFY(!QMetaObject::invokeMethod(&obj, "doesNotExist", Qt::BlockingQueuedConnection)); QTest::ignoreMessage(QtWarningMsg, "QMetaObject::invokeMethod: No such method QtTestObject::sl1(QString)(QString)"); QVERIFY(!QMetaObject::invokeMethod(&obj, "sl1(QString)", Qt::BlockingQueuedConnection, Q_ARG(QString, "arg"))); - QTest::ignoreMessage(QtWarningMsg, "QMetaObject::invokeMethod: No such method QtTestObject::sl3(QString)"); + QTest::ignoreMessage(QtWarningMsg, "QMetaObject::invokeMethod: No such method QtTestObject::sl3(QString)\n" + "Candidates are:\n sl3(QString,QString,QString)"); QVERIFY(!QMetaObject::invokeMethod(&obj, "sl3", Qt::BlockingQueuedConnection, Q_ARG(QString, "arg"))); - QTest::ignoreMessage(QtWarningMsg, "QMetaObject::invokeMethod: No such method QtTestObject::sl1(QString,QString,QString)"); + QTest::ignoreMessage(QtWarningMsg, "QMetaObject::invokeMethod: No such method QtTestObject::sl1(QString,QString,QString)\n" + "Candidates are:\n sl1(QString)"); QVERIFY(!QMetaObject::invokeMethod(&obj, "sl1", Qt::BlockingQueuedConnection, Q_ARG(QString, "arg"), Q_ARG(QString, "arg"), Q_ARG(QString, "arg"))); //should not have changed since last test.