tst_QMetaObject: add a reproducer for overly eager QVector/QList replacement
The kludge that was added to argumentTypesFromString() for Qt 6 to support merging QVector into QList—specifically, the replacement of QVector< with QList<—was unfortunately not removed before the Qt 6.0 release. As a kludge, it has unintended consequences, as Thiago pointed out in a comment on a related patch. This change adds a reproducer that demonstrates cases where the kludge causes correct code to fail incorrectly. We need this test to ensure that we do not silently change behavior when deprecating and eventually removing the kludge. Adapt the MyQList normalization test, which was carefully written to avoid hitting the kludge, to use template arguments. This will allow it to trigger the buggy code path and avoid confusing the reader with the mention of a non-template MyQList, given that MyQList is now a template. Reported-by: Thiago Macieira <thiago.macieira@intel.com> Pick-to: 6.8 6.5 Task-number: QTBUG-135572 Change-Id: I91d769d494489fe63dbbb67f849b78fc7aa39ec6 Reviewed-by: Ahmad Samir <a.samirh78@gmail.com> (cherry picked from commit a97ac8507e39a421f530f5ad612a7e4bb58f6718) Reviewed-by: Marc Mutz <marc.mutz@qt.io> (cherry picked from commit fdc070c3b0bce2d7aa5c568cf45555a1697822d7) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
parent
b62e1c4794
commit
8848d58f29
@ -14,6 +14,9 @@
|
||||
#endif
|
||||
#include <private/qmetaobject_p.h>
|
||||
|
||||
#include <deque>
|
||||
#include <vector>
|
||||
|
||||
Q_DECLARE_METATYPE(const QMetaObject *)
|
||||
|
||||
#include "forwarddeclared.h"
|
||||
@ -49,6 +52,28 @@ public:
|
||||
Q_INVOKABLE MyGadget() {}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class MyQList
|
||||
{
|
||||
std::vector<T> m_data;
|
||||
public:
|
||||
MyQList(std::initializer_list<T> il) : m_data{il} {}
|
||||
|
||||
const std::vector<T> &data() const { return m_data; }
|
||||
std::vector<T> &data() { return m_data; }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class MyQVector
|
||||
{
|
||||
std::deque<T> m_data;
|
||||
public:
|
||||
MyQVector(std::initializer_list<T> il) : m_data{il} {}
|
||||
|
||||
const std::deque<T> &data() const { return m_data; }
|
||||
std::deque<T> &data() { return m_data; }
|
||||
};
|
||||
|
||||
namespace MyNamespace {
|
||||
// Used in tst_QMetaObject::checkScope
|
||||
class MyClass : public QObject
|
||||
@ -316,6 +341,7 @@ private slots:
|
||||
void normalizedType_data();
|
||||
void normalizedType();
|
||||
void customPropertyType();
|
||||
void customQVectorSuffix();
|
||||
void keysToValue_data();
|
||||
void keysToValue(); // Also keyToValue()
|
||||
void propertyNotify();
|
||||
@ -357,6 +383,8 @@ private slots:
|
||||
signals:
|
||||
void value6Changed();
|
||||
void value7Changed(const QString &);
|
||||
void myQListChanged(const MyQList<int> &);
|
||||
void myQVectorChanged(const MyQVector<double> &); // needs different template arg from MyQList!
|
||||
};
|
||||
|
||||
void tst_QMetaObject::stdSet()
|
||||
@ -2304,8 +2332,11 @@ void tst_QMetaObject::normalizedSignature_data()
|
||||
QTest::newRow("const13") << "void foo(const Foo<Bar>&)" << "void foo(Foo<Bar>)";
|
||||
QTest::newRow("const14") << "void foo(Foo<Bar>const&)" << "void foo(Foo<Bar>)";
|
||||
QTest::newRow("QVector") << "void foo(QVector<int>)" << "void foo(QList<int>)";
|
||||
QTest::newRow("QVector1") << "void foo(const Template<QVector, MyQList const>)"
|
||||
<< "void foo(Template<QList,const MyQList>)";
|
||||
QTest::newRow("QVector1") << "void foo(const Template<QVector, MyQList<int> const>)"
|
||||
<< "void foo(Template<QList,const MyQList<int>>)";
|
||||
QTest::newRow("MyQVector") << "void foo(MyQVector<int>)" << "void foo(MyQVector<int>)";
|
||||
QTest::newRow("MyQVector1") << "void foo(const Template<QVector, MyQVector<int> const>)"
|
||||
<< "void foo(Template<QList,const MyQVector<int>>)";
|
||||
|
||||
QTest::newRow("refref") << "const char* foo(const X &&,X const &&, const X* &&) && "
|
||||
<< "const char*foo(const X&&,const X&&,const X*&&)&&";
|
||||
@ -2428,6 +2459,22 @@ void tst_QMetaObject::customPropertyType()
|
||||
QCOMPARE(prop.metaType().id(), QMetaType::QVariantList);
|
||||
}
|
||||
|
||||
void tst_QMetaObject::customQVectorSuffix()
|
||||
{
|
||||
QObject ctx;
|
||||
QVERIFY(connect(this, SIGNAL(myQListChanged(MyQList<int>)),
|
||||
&ctx, SLOT(deleteLater()))); // just some compatible slot...
|
||||
|
||||
// QMetaObject internally does s/QVector</QList</ indiscriminently, so the
|
||||
// existing signal is not found:
|
||||
QEXPECT_FAIL("", "Qt 6 QVector -> QList kludge getting in the way", Continue);
|
||||
QTest::ignoreMessage(QtWarningMsg,
|
||||
QRegularExpression(R"(.*QObject::connect: No such signal )"
|
||||
R"(tst_QMetaObject.*::myQVectorChanged\(MyQVector<double>\).*)"_L1));
|
||||
QVERIFY(connect(this, SIGNAL(myQVectorChanged(MyQVector<double>)),
|
||||
&ctx, SLOT(deleteLater()))); // just some compatible slot...
|
||||
}
|
||||
|
||||
void tst_QMetaObject::keysToValue_data()
|
||||
{
|
||||
QTest::addColumn<QObject *>("object");
|
||||
@ -2802,10 +2849,11 @@ void tst_QMetaObject::indexOfMethod_data()
|
||||
QTest::addColumn<QObject *>("object");
|
||||
QTest::addColumn<QByteArray>("name");
|
||||
QTest::addColumn<bool>("isSignal");
|
||||
QTest::addColumn<bool>("found");
|
||||
|
||||
auto row = [this] (const char *fun, bool sig) {
|
||||
auto row = [this] (const char *fun, bool sig, bool found = true) {
|
||||
QObject *o = this;
|
||||
QTest::addRow("%s", fun) << o << QByteArray(fun) << sig;
|
||||
QTest::addRow("%s", fun) << o << QByteArray(fun) << sig << found;
|
||||
};
|
||||
|
||||
row("indexOfMethod_data()", false);
|
||||
@ -2814,6 +2862,9 @@ void tst_QMetaObject::indexOfMethod_data()
|
||||
row("value7Changed(QString)", true);
|
||||
row("destroyed()", true);
|
||||
row("destroyed(QObject*)", true);
|
||||
row("myQListChanged(MyQList<int>)", true);
|
||||
row("myQListChanged(MyQVector<int>)", true, false);
|
||||
row("myQVectorChanged(MyQVector<double>)", true);
|
||||
}
|
||||
|
||||
void tst_QMetaObject::indexOfMethod()
|
||||
@ -2821,9 +2872,16 @@ void tst_QMetaObject::indexOfMethod()
|
||||
QFETCH(QObject *, object);
|
||||
QFETCH(QByteArray, name);
|
||||
QFETCH(bool, isSignal);
|
||||
QFETCH(const bool, found);
|
||||
QEXPECT_FAIL("myQListChanged(MyQVector<int>)", "Qt 6 QVector -> QList kludge getting in the way", Abort);
|
||||
QEXPECT_FAIL("myQVectorChanged(MyQVector<double>)", "Qt 6 QVector -> QList kludge getting in the way", Abort);
|
||||
int idx = object->metaObject()->indexOfMethod(name);
|
||||
QVERIFY(idx >= 0);
|
||||
QCOMPARE(object->metaObject()->method(idx).methodSignature(), name);
|
||||
if (found)
|
||||
QVERIFY(idx >= 0);
|
||||
else
|
||||
QVERIFY(idx < 0);
|
||||
if (found)
|
||||
QCOMPARE(object->metaObject()->method(idx).methodSignature(), name);
|
||||
QCOMPARE(object->metaObject()->indexOfSlot(name), isSignal ? -1 : idx);
|
||||
QCOMPARE(object->metaObject()->indexOfSignal(name), !isSignal ? -1 : idx);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user