tst_qstringapisymmetry: add qCompareThreeWay() checks

Check that all string-like types implement compareThreeWay() as a
(hidden) friend function.

This test revealed some problems: because QByteArrayView is implicitly
constructible from QLatin1StringView, the qCompareThreeWay() call
sometimes picked the compareThreeWay() overloads with QByteArrayView
instead of picking the "reversed" overloads that use QLatin1StringView.
This was leading to wrong results, because QByteArrayView is
interpreted as utf-8 data, not latin-1.

Explicitly add the missing compareThreeWay() and comparesEqual()
overloads.

Note that relational operators were never affected by this problem,
because in C++17 mode we explicitly generate the reversed versions,
and in C++20 mode the compiler does that for us.

Task-number: QTBUG-117661
Change-Id: Ia96af59c60ebf2fae6cf2a49231d6b6f401aceaa
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
bb10
Ivan Solovev 2024-03-05 12:28:26 +01:00
parent fff6562f8c
commit aab82ff367
2 changed files with 24 additions and 0 deletions

View File

@ -283,6 +283,16 @@ public:
}
Q_DECLARE_STRONGLY_ORDERED(QLatin1StringView, QStringView)
// Reversed helper methods for QStringView <> QLatin1StringView comparison.
// If we do not provide them explicitly, QStringView <> QByteArrayView
// overloads will be selected, which will provide wrong results, because
// they will convert from utf-8
friend bool comparesEqual(const QStringView &lhs, const QLatin1StringView &rhs) noexcept
{ return comparesEqual(rhs, lhs); }
friend Qt::strong_ordering
compareThreeWay(const QStringView &lhs, const QLatin1StringView &rhs) noexcept
{ return QtOrderingPrivate::reversed(compareThreeWay(rhs, lhs)); }
private:
friend bool comparesEqual(const QLatin1StringView &lhs, const QByteArrayView &rhs) noexcept
{ return equal_helper(lhs, rhs.data(), rhs.size()); }
@ -293,6 +303,15 @@ private:
return Qt::compareThreeWay(res, 0);
}
// Reversed helper methods for QByteArrayView <> QLatin1StringView comparison.
// If we do not provide them explicitly, QByteArrayView <> QByteArrayView
// overloads will be selected, which will provide wrong results
friend bool comparesEqual(const QByteArrayView &lhs, const QLatin1StringView &rhs) noexcept
{ return comparesEqual(rhs, lhs); }
friend Qt::strong_ordering
compareThreeWay(const QByteArrayView &lhs, const QLatin1StringView &rhs) noexcept
{ return QtOrderingPrivate::reversed(compareThreeWay(rhs, lhs)); }
public:
#if !defined(QT_NO_CAST_FROM_ASCII) && !defined(QT_RESTRICTED_CAST_FROM_ASCII)
Q_DECLARE_STRONGLY_ORDERED(QLatin1StringView, QByteArrayView, QT_ASCII_CAST_WARN)

View File

@ -1360,6 +1360,11 @@ void tst_QStringApiSymmetry::compare_impl() const
CHECK(<=);
CHECK(>=);
#undef CHECK
// Test that all string-like types implemente compareThreeWay() as a friend
// function.
const Qt::strong_ordering expectedOrdering =
Qt::compareThreeWay(caseSensitiveCompareResult, 0);
QCOMPARE_EQ(qCompareThreeWay(lhs, rhs), expectedOrdering);
}
template <typename LHS, typename RHS>