summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarc Mutz <[email protected]>2025-06-02 17:25:40 +0200
committerMarc Mutz <[email protected]>2025-06-06 22:16:36 +0200
commita97ac8507e39a421f530f5ad612a7e4bb58f6718 (patch)
tree855595d187f000c2d7b46528121b8d8867eecffb
parent99ad6a51a595430c75323c4d5c2ecbc7fbd8d7f0 (diff)
tst_QMetaObject: add a reproducer for overly eager QVector/QList replacementHEADdev
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 <[email protected]> Pick-to: 6.10 6.9 6.8 6.5 Task-number: QTBUG-135572 Change-Id: I91d769d494489fe63dbbb67f849b78fc7aa39ec6 Reviewed-by: Ahmad Samir <[email protected]>
-rw-r--r--tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp70
1 files changed, 64 insertions, 6 deletions
diff --git a/tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp b/tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp
index 07bd4a12a51..f714ce8f23e 100644
--- a/tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp
+++ b/tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp
@@ -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();
@@ -361,6 +387,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()
@@ -2309,8 +2337,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*&&)&&";
@@ -2433,6 +2464,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");
@@ -2807,10 +2854,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);
@@ -2819,6 +2867,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()
@@ -2826,9 +2877,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);
}