QString: toward UTF-8 arg() support [3½/4]: port unary arg() to QAnyStringView

Before porting multi-arg() to QAnyStringView, first port the unary
arg() overloads for symmetry reasons (unlike the views, multi-arg() on
QString is only considered for more than one argument().

This causes tension with the other arg() overloads, so finally make
the overload set a sane one by using constrained templates instead of
overloaded regular functions. This also solves the following problems:

- that char16_t and char8_t didn't match the char-ish overloads, but
  the integer-ish ones,

- that arg('a') matched the char overload (and therefore printed a
  character 'a') while arg('a', 2, 16) was ambiguous and arg('a', 2,
  16, QChar('0')) called the integral overload, printing the numeric
  value instead,

- that arg(qfloat16) was ambiguous when QFLOAT16_IS_NATIVE

- that using u' ' as `fillChar` sometimes caused ambiguities (and you
  had to use ' '_L1 instead).

Needed to explicitly exclude wchar_t from the is_string_like arg()
overload, to at least keep existing behavior and not make matters
worse by treating wchar_t as a string-like on Windows and as
integer-like on Unix :( We'll hopefully still fix QTBUG-126054 before
this is relased.

[ChangeLog][QtCore][Potentially Source-Incompatible Changes] The
QString::arg() overloads have been redesigned. Character-like types
(char, char16_t, char8_t, wchar_t (still subject to QTBUG-126054 at
the time of writing), char32_t) now always output the character, not
its numeric value. In particular, char16_t and char arguments now
match the string-ish arg() overload (and therefore don't provide a
`base` argument anymore. A backwards-compatible fix is to cast char,
char16_t, and wchar_t arguments to uint. This also fixes the ambiguity
errors you may have seen when using a char16_t as `fillChar`.

[ChangeLog][QtCore][QString] Unary arg() now accepts QAnyStringView
(incl. QUtf8StringView).

Fixes: QTBUG-125588
Fixes: QTBUG-126053
Fixes: QTBUG-126055
Task-number: QTBUG-126054
Change-Id: If0bfd92e15952738f3870a540f52a7cc470b047f
Reviewed-by: Ivan Solovev <ivan.solovev@qt.io>
This commit is contained in:
Marc Mutz 2024-05-22 14:29:30 +02:00
parent 2eeb35539c
commit 563ed822f8
9 changed files with 168 additions and 211 deletions

View File

@ -104,7 +104,7 @@ QString XmlOutput::doConversion(const QString &text)
output += QLatin1String("&gt;");
} else {
if (c.unicode() < 0x20) {
output += QString("&#x%1;").arg(c.unicode(), 2, 16, QLatin1Char('0'));
output += QString("&#x%1;").arg(ushort{c.unicode()}, 2, 16, QLatin1Char('0'));
} else {
output += c;
}

View File

@ -1276,6 +1276,46 @@ QByteArray QMetaEnum::valueToKeys(int value) const
#include "qstring.h"
QString QString::arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const
{
return arg_impl(a, fieldWidth, base, fillChar);
}
QString QString::arg(qulonglong a, int fieldWidth, int base, QChar fillChar) const
{
return arg_impl(a, fieldWidth, base, fillChar);
}
QString QString::arg(double a, int fieldWidth, char format, int precision, QChar fillChar) const
{
return arg_impl(a, fieldWidth, format, precision, fillChar);
}
QString QString::arg(char a, int fieldWidth, QChar fillChar) const
{
return arg_impl(QAnyStringView(a), fieldWidth, fillChar);
}
QString QString::arg(QChar a, int fieldWidth, QChar fillChar) const
{
return arg_impl(QAnyStringView{a}, fieldWidth, fillChar);
}
QString QString::arg(const QString &a, int fieldWidth, QChar fillChar) const
{
return arg_impl(qToAnyStringViewIgnoringNull(a), fieldWidth, fillChar);
}
QString QString::arg(QStringView a, int fieldWidth, QChar fillChar) const
{
return arg_impl(QAnyStringView(a), fieldWidth, fillChar);
}
QString QString::arg(QLatin1StringView a, int fieldWidth, QChar fillChar) const
{
return arg(QAnyStringView(a), fieldWidth, fillChar);
}
QString QtPrivate::argToQString(QStringView pattern, size_t n, const ArgBase **args)
{
return argToQString(QAnyStringView{pattern}, n, args);

View File

@ -8723,42 +8723,7 @@ static QString replaceArgEscapes(QStringView s, const ArgEscapeData &d, qsizetyp
}
/*!
Returns a copy of this string with the lowest numbered place marker
replaced by string \a a, i.e., \c %1, \c %2, ..., \c %99.
\a fieldWidth specifies the minimum amount of space that argument \a
a shall occupy. If \a a requires less space than \a fieldWidth, it
is padded to \a fieldWidth with character \a fillChar. A positive
\a fieldWidth produces right-aligned text. A negative \a fieldWidth
produces left-aligned text.
This example shows how we might create a \c status string for
reporting progress while processing a list of files:
\snippet qstring/main.cpp 11
First, \c arg(i) replaces \c %1. Then \c arg(total) replaces \c
%2. Finally, \c arg(fileName) replaces \c %3.
One advantage of using arg() over asprintf() is that the order of the
numbered place markers can change, if the application's strings are
translated into other languages, but each arg() will still replace
the lowest numbered unreplaced place marker, no matter where it
appears. Also, if place marker \c %i appears more than once in the
string, the arg() replaces all of them.
If there is no unreplaced place marker remaining, a warning message
is output and the result is undefined. Place marker numbers must be
in the range 1 to 99.
*/
QString QString::arg(const QString &a, int fieldWidth, QChar fillChar) const
{
return arg(qToStringViewIgnoringNull(a), fieldWidth, fillChar);
}
/*!
\overload
\since 5.10
\fn template <typename T, if_string_like<T> = true> QString QString::arg(const T &a, int fieldWidth, QChar fillChar) const
Returns a copy of this string with the lowest-numbered place-marker
replaced by string \a a, i.e., \c %1, \c %2, ..., \c %99.
@ -8787,8 +8752,14 @@ QString QString::arg(const QString &a, int fieldWidth, QChar fillChar) const
If there is no unreplaced place-marker remaining, a warning message
is printed and the result is undefined. Place-marker numbers must be
in the range 1 to 99.
\note In Qt versions prior to 6.9, this function was overloaded on
\c{char}, QChar, QString, QStringView, and QLatin1StringView and in some
cases, \c{wchar_t} and \c{char16_t} arguments would resolve to the integer
overloads. In Qt versions prior to 5.10, this function lacked the
QStringView and QLatin1StringView overloads.
*/
QString QString::arg(QStringView a, int fieldWidth, QChar fillChar) const
QString QString::arg_impl(QAnyStringView a, int fieldWidth, QChar fillChar) const
{
ArgEscapeData d = findArgEscapes(*this);
@ -8797,40 +8768,28 @@ QString QString::arg(QStringView a, int fieldWidth, QChar fillChar) const
qUtf16Printable(a.toString()));
return *this;
}
return replaceArgEscapes(*this, d, fieldWidth, a, a, fillChar);
struct {
QVarLengthArray<char16_t> out;
QStringView operator()(QStringView in) noexcept { return in; }
QStringView operator()(QLatin1StringView in)
{
out.resize(in.size());
qt_from_latin1(out.data(), in.data(), size_t(in.size()));
return out;
}
QStringView operator()(QUtf8StringView in)
{
out.resize(in.size());
return QStringView{out.data(), QUtf8::convertToUnicode(out.data(), in)};
}
} convert;
QStringView sv = a.visit(std::ref(convert));
return replaceArgEscapes(*this, d, fieldWidth, sv, sv, fillChar);
}
/*!
\overload
\since 5.10
Returns a copy of this string with the lowest-numbered place-marker
replaced by the Latin-1 string viewed by \a a, i.e., \c %1, \c %2, ..., \c %99.
\a fieldWidth specifies the minimum amount of space that \a a
shall occupy. If \a a requires less space than \a fieldWidth, it
is padded to \a fieldWidth with character \a fillChar. A positive
\a fieldWidth produces right-aligned text. A negative \a fieldWidth
produces left-aligned text.
One advantage of using arg() over asprintf() is that the order of the
numbered place markers can change, if the application's strings are
translated into other languages, but each arg() will still replace
the lowest-numbered unreplaced place-marker, no matter where it
appears. Also, if place-marker \c %i appears more than once in the
string, arg() replaces all of them.
If there is no unreplaced place-marker remaining, a warning message
is printed and the result is undefined. Place-marker numbers must be
in the range 1 to 99.
*/
QString QString::arg(QLatin1StringView a, int fieldWidth, QChar fillChar) const
{
QVarLengthArray<char16_t> utf16 = qt_from_latin1_to_qvla(a);
return arg(QStringView(utf16.data(), utf16.size()), fieldWidth, fillChar);
}
/*! \fn QString QString::arg(int a, int fieldWidth, int base, QChar fillChar) const
\fn template <typename T, if_integral_non_char<T> = true> QString QString::arg(T a, int fieldWidth, int base, QChar fillChar) const
\overload arg()
The \a a argument is expressed in base \a base, which is 10 by
@ -8851,73 +8810,13 @@ QString QString::arg(QLatin1StringView a, int fieldWidth, QChar fillChar) const
\snippet qstring/main.cpp 12
\snippet qstring/main.cpp 14
\sa {Number Formats}
*/
/*! \fn QString QString::arg(uint a, int fieldWidth, int base, QChar fillChar) const
\overload arg()
The \a base argument specifies the base to use when converting the
integer \a a into a string. The base must be between 2 and 36.
\note In Qt versions prior to 6.9, this function was overloaded on various
integral types and sometimes incorrectly accepted \c char and \c char16_t
arguments.
\sa {Number Formats}
*/
/*! \fn QString QString::arg(long a, int fieldWidth, int base, QChar fillChar) const
\overload arg()
\a fieldWidth specifies the minimum amount of space that \a a is
padded to and filled with the character \a fillChar. A positive
value produces right-aligned text; a negative value produces
left-aligned text.
The \a a argument is expressed in the given \a base, which is 10 by
default and must be between 2 and 36.
The '%' can be followed by an 'L', in which case the sequence is
replaced with a localized representation of \a a. The conversion
uses the default locale. The default locale is determined from the
system's locale settings at application startup. It can be changed
using QLocale::setDefault(). The 'L' flag is ignored if \a base is
not 10.
\snippet qstring/main.cpp 12
\snippet qstring/main.cpp 14
\sa {Number Formats}
*/
/*!
\fn QString QString::arg(ulong a, int fieldWidth, int base, QChar fillChar) const
\overload arg()
\a fieldWidth specifies the minimum amount of space that \a a is
padded to and filled with the character \a fillChar. A positive
value produces right-aligned text; a negative value produces
left-aligned text.
The \a base argument specifies the base to use when converting the
integer \a a to a string. The base must be between 2 and 36, with 8
giving octal, 10 decimal, and 16 hexadecimal numbers.
\sa {Number Formats}
*/
/*!
\overload arg()
\a fieldWidth specifies the minimum amount of space that \a a is
padded to and filled with the character \a fillChar. A positive
value produces right-aligned text; a negative value produces
left-aligned text.
The \a base argument specifies the base to use when converting the
integer \a a into a string. The base must be between 2 and 36, with
8 giving octal, 10 decimal, and 16 hexadecimal numbers.
\sa {Number Formats}
*/
QString QString::arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const
QString QString::arg_impl(qlonglong a, int fieldWidth, int base, QChar fillChar) const
{
ArgEscapeData d = findArgEscapes(*this);
@ -8949,21 +8848,7 @@ QString QString::arg(qlonglong a, int fieldWidth, int base, QChar fillChar) cons
return replaceArgEscapes(*this, d, fieldWidth, arg, localeArg, fillChar);
}
/*!
\overload arg()
\a fieldWidth specifies the minimum amount of space that \a a is
padded to and filled with the character \a fillChar. A positive
value produces right-aligned text; a negative value produces
left-aligned text.
The \a base argument specifies the base to use when converting the
integer \a a into a string. \a base must be between 2 and 36, with 8
giving octal, 10 decimal, and 16 hexadecimal numbers.
\sa {Number Formats}
*/
QString QString::arg(qulonglong a, int fieldWidth, int base, QChar fillChar) const
QString QString::arg_impl(qulonglong a, int fieldWidth, int base, QChar fillChar) const
{
ArgEscapeData d = findArgEscapes(*this);
@ -8996,57 +8881,7 @@ QString QString::arg(qulonglong a, int fieldWidth, int base, QChar fillChar) con
}
/*!
\overload arg()
\fn QString QString::arg(short a, int fieldWidth, int base, QChar fillChar) const
\a fieldWidth specifies the minimum amount of space that \a a is
padded to and filled with the character \a fillChar. A positive
value produces right-aligned text; a negative value produces
left-aligned text.
The \a base argument specifies the base to use when converting the
integer \a a into a string. The base must be between 2 and 36, with
8 giving octal, 10 decimal, and 16 hexadecimal numbers.
\sa {Number Formats}
*/
/*!
\fn QString QString::arg(ushort a, int fieldWidth, int base, QChar fillChar) const
\overload arg()
\a fieldWidth specifies the minimum amount of space that \a a is
padded to and filled with the character \a fillChar. A positive
value produces right-aligned text; a negative value produces
left-aligned text.
The \a base argument specifies the base to use when converting the
integer \a a into a string. The base must be between 2 and 36, with
8 giving octal, 10 decimal, and 16 hexadecimal numbers.
\sa {Number Formats}
*/
/*!
\overload arg()
*/
QString QString::arg(QChar a, int fieldWidth, QChar fillChar) const
{
return arg(QStringView{&a, 1}, fieldWidth, fillChar);
}
/*!
\overload arg()
The \a a argument is interpreted as a Latin-1 character.
*/
QString QString::arg(char a, int fieldWidth, QChar fillChar) const
{
return arg(QLatin1Char(a), fieldWidth, fillChar);
}
/*!
\fn template <typename T, if_floating_point<T> = true> QString QString::arg(T a, int fieldWidth, char format, int precision, QChar fillChar) const
\overload arg()
Argument \a a is formatted according to the specified \a format and
@ -9059,9 +8894,12 @@ QString QString::arg(char a, int fieldWidth, QChar fillChar) const
\snippet code/src_corelib_text_qstring.cpp 2
\note In Qt versions prior to 6.9, this function was a regular function
taking \c double.
\sa QLocale::toString(), QLocale::FloatingPointPrecisionOption, {Number Formats}
*/
QString QString::arg(double a, int fieldWidth, char format, int precision, QChar fillChar) const
QString QString::arg_impl(double a, int fieldWidth, char format, int precision, QChar fillChar) const
{
ArgEscapeData d = findArgEscapes(*this);

View File

@ -43,6 +43,7 @@ class tst_QString;
QT_BEGIN_NAMESPACE
class qfloat16;
class QRegularExpression;
class QRegularExpressionMatch;
class QString;
@ -56,6 +57,17 @@ using IsCompatibleChar32TypeHelper =
template <typename Char>
using IsCompatibleChar32Type
= IsCompatibleChar32TypeHelper<q20::remove_cvref_t<Char>>;
// hack to work around ushort/uchar etc being treated as both characters and
// integers, depending on which Qt API you look at:
template <typename T> struct treat_as_integral_arg : std::false_type {};
template <> struct treat_as_integral_arg<unsigned short> : std::true_type {};
template <> struct treat_as_integral_arg< signed short> : std::true_type {};
template <> struct treat_as_integral_arg<unsigned char> : std::true_type {};
template <> struct treat_as_integral_arg< signed char> : std::true_type {};
// QTBUG-126054, keep until we can fix it for all platforms, not just Windows
// (where wchar_t does convert to QAnyStringView):
template <> struct treat_as_integral_arg<wchar_t> : std::true_type {};
}
// Qt 4.x compatibility
@ -147,6 +159,37 @@ class Q_CORE_EXPORT QString
std::is_same<Char, QLatin1Char> // special case
>;
template <typename T>
using is_string_like = std::conjunction<
std::negation<QtPrivate::treat_as_integral_arg<std::remove_cv_t<T>>>, // used to be integral, so keep
std::is_convertible<T, QAnyStringView>
>;
template <typename T>
using if_string_like = std::enable_if_t<is_string_like<T>::value, bool>;
template <typename T>
using is_floating_point_like = std::disjunction<
#if QFLOAT16_IS_NATIVE
std::is_same<q20::remove_cvref_t<T>, QtPrivate::NativeFloat16Type>,
#endif
std::is_same<q20::remove_cvref_t<T>, qfloat16>,
std::is_floating_point<T>
>;
template <typename T>
using if_floating_point = std::enable_if_t<is_floating_point_like<T>::value, bool>;
template <typename T>
using if_integral_non_char = std::enable_if_t<std::conjunction_v<
std::disjunction< // unlike is_integral, also covers unscoped enums
std::is_convertible<T, qulonglong>,
std::is_convertible<T, qlonglong>
>,
std::negation<is_floating_point_like<T>>, // has its own overload
std::negation<is_string_like<T>> // ditto
>, bool>;
template <typename Iterator>
static constexpr bool is_compatible_iterator_v = std::conjunction_v<
std::is_convertible<
@ -238,6 +281,7 @@ public:
[[nodiscard]] inline QChar back() const { return at(size() - 1); }
[[nodiscard]] inline QChar &back();
#if QT_CORE_REMOVED_SINCE(6, 9)
[[nodiscard]] QString arg(qlonglong a, int fieldwidth=0, int base=10,
QChar fillChar = u' ') const;
[[nodiscard]] QString arg(qulonglong a, int fieldwidth=0, int base=10,
@ -266,7 +310,33 @@ public:
QChar fillChar = u' ') const;
[[nodiscard]] QString arg(QLatin1StringView a, int fieldWidth = 0,
QChar fillChar = u' ') const;
#endif
template <typename T, if_integral_non_char<T> = true>
[[nodiscard]] QString arg(T a, int fieldWidth = 0, int base = 10,
QChar fillChar = u' ') const
{
if constexpr (std::is_signed_v<T>)
return arg_impl(qlonglong(a), fieldWidth, base, fillChar);
else
return arg_impl(qulonglong(a), fieldWidth, base, fillChar);
}
template <typename T, if_floating_point<T> = true>
[[nodiscard]] QString arg(T a, int fieldWidth = 0, char format = 'g', int precision = -1,
QChar fillChar = u' ') const
{ return arg_impl(double(a), fieldWidth, format, precision, fillChar); }
template <typename T, if_string_like<T> = true>
[[nodiscard]] QString arg(const T &a, int fieldWidth = 0, QChar fillChar = u' ') const
{ return arg_impl(QAnyStringView(a), fieldWidth, fillChar); }
private:
QString arg_impl(qlonglong a, int fieldwidth, int base, QChar fillChar) const;
QString arg_impl(qulonglong a, int fieldwidth, int base, QChar fillChar) const;
QString arg_impl(double a, int fieldWidth, char format, int precision, QChar fillChar) const;
QString arg_impl(QAnyStringView a, int fieldWidth, QChar fillChar) const;
template <typename T>
using is_convertible_to_view_or_qstring = std::disjunction<
std::is_convertible<T, QString>,
@ -1277,6 +1347,7 @@ QString &QString::setNum(ulong n, int base)
{ return setNum(qulonglong(n), base); }
QString &QString::setNum(float n, char f, int prec)
{ return setNum(double(n),f,prec); }
#if QT_CORE_REMOVED_SINCE(6, 9)
QString QString::arg(int a, int fieldWidth, int base, QChar fillChar) const
{ return arg(qlonglong(a), fieldWidth, base, fillChar); }
QString QString::arg(uint a, int fieldWidth, int base, QChar fillChar) const
@ -1289,6 +1360,7 @@ QString QString::arg(short a, int fieldWidth, int base, QChar fillChar) const
{ return arg(qlonglong(a), fieldWidth, base, fillChar); }
QString QString::arg(ushort a, int fieldWidth, int base, QChar fillChar) const
{ return arg(qulonglong(a), fieldWidth, base, fillChar); }
#endif // QT_CORE_REMOVED_SINCE
QString QString::section(QChar asep, qsizetype astart, qsizetype aend, SectionFlags aflags) const
{ return section(QString(asep), astart, aend, aflags); }

View File

@ -723,7 +723,8 @@ void tst_QUrlInternal::encodingRecodeInvalidUtf8()
output += input;
for (int i = int(strlen(QTest::currentDataTag())); i < output.size(); ++i) {
QVERIFY2(output.at(i).unicode() < 0x80 || output.at(i) == QChar::ReplacementCharacter,
qPrintable(QString("Character at i == %1 was U+%2").arg(i).arg(output.at(i).unicode(), 4, 16, QLatin1Char('0'))));
qPrintable(QString("Character at i == %1 was U+%2").arg(i)
.arg(ushort{output.at(i).unicode()}, 4, 16, u'0')));
}
}

View File

@ -183,7 +183,7 @@ QByteArray verifyZeroTermination(const QByteArray &ba)
if ('\0' != baTerminator)
return QString::fromUtf8(
"*** Result ('%1') not null-terminated: 0x%2 ***").arg(QString::fromUtf8(ba))
.arg(baTerminator, 2, 16, QChar('0')).toUtf8();
.arg(int(baTerminator), 2, 16, QChar('0')).toUtf8();
// Skip mutating checks on shared strings
if (baDataPtr->isShared())

View File

@ -740,7 +740,7 @@ QString verifyZeroTermination(const QString &str)
if (QChar(u'\0') != strTerminator)
return QString::fromLatin1(
"*** Result ('%1') not null-terminated: 0x%2 ***").arg(str)
.arg(strTerminator.unicode(), 4, 16, QChar(u'0'));
.arg(ushort{strTerminator.unicode()}, 4, 16, QChar(u'0'));
// Skip mutating checks on shared strings
if (strDataPtr->isShared())
@ -6609,6 +6609,7 @@ void tst_QString::arg()
QCOMPARE(s4.arg(empty), "[]"_L1);
QCOMPARE(s4.arg(QStringView()), "[]"_L1);
QCOMPARE(s4.arg(QStringView(u"")), "[]"_L1);
QCOMPARE(s4.arg(u8""), "[]"_L1);
QCOMPARE(s4.arg(foo), "[foo]"_L1);
QCOMPARE( s5.arg(QLatin1String("foo")), QLatin1String("[foo]") );
@ -6696,13 +6697,10 @@ void tst_QString::arg()
// FP overloads
QCOMPARE(s4.arg(2.25), QLatin1String("[2.25]"));
QCOMPARE(s4.arg(3.75f), QLatin1String("[3.75]"));
#if !QFLOAT16_IS_NATIVE // QTBUG-126055
QCOMPARE(s4.arg(qfloat16{4.125f}), QLatin1String("[4.125]"));
#endif
// char-ish overloads
QCOMPARE(s4.arg('\xE4'), QStringView(u"[ä]"));
QEXPECT_FAIL("", "QTBUG-125588", Continue);
QCOMPARE(s4.arg(u'ø'), QStringView(u"[ø]"));
#ifdef Q_OS_WIN
QCOMPARE(QLatin1String("[%1]").arg(L'ø'), QStringView(u"[ø]"));
@ -6713,8 +6711,6 @@ void tst_QString::arg()
#ifndef QT_NO_CAST_FROM_ASCII
QCOMPARE(QLatin1String("[%1]").arg(u8'a'), QLatin1String("[a]"));
#endif
#else
QEXPECT_FAIL("", "QTBUG-126053", Continue);
#endif
QCOMPARE(s4.arg(u8'a'), QLatin1String("[a]"));
@ -6743,12 +6739,14 @@ void tst_QString::arg()
QCOMPARE(u"%2%1"_s.arg(QStringView()), "%2"_L1);
QCOMPARE(u"%2%1"_s.arg(QStringView(u"")), "%2"_L1);
QCOMPARE(u"%1"_s.arg(u"hello"_s, -10), "hello "_L1);
QCOMPARE(u"%1"_s.arg(QUtf8StringView{u8"ä"}, -3), u"ä ");
QCOMPARE(u"%1"_s.arg("hello"_L1, -5), "hello"_L1);
QCOMPARE(u"%1"_s.arg(u"hello", -2), "hello"_L1);
QCOMPARE(u"%1"_s.arg(u"hello"_s, 0), "hello"_L1);
QCOMPARE(u"%1"_s.arg("hello"_L1, 2), "hello"_L1);
QCOMPARE(u"%1"_s.arg(u"hello", 5), "hello"_L1);
QCOMPARE(u"%1"_s.arg(u"hello"_s, 10), " hello"_L1);
QCOMPARE(u"%1"_s.arg(QUtf8StringView{u8"ä"}, 3), u" ä");
QCOMPARE(u"%1%1"_s.arg(u"hello"_s), "hellohello"_L1);
QCOMPARE(u"%2%1"_s.arg(u"hello"_s), "%2hello"_L1);

View File

@ -558,8 +558,18 @@ private Q_SLOTS:
void arg1_QString_QStringView() { arg1_impl<QString, QStringView>(); }
void arg1_QString_QLatin1StringView_data() { arg1_data(); }
void arg1_QString_QLatin1StringView() { arg1_impl<QString, QLatin1StringView>(); }
void arg1_QString_QUtf8StringView_data() { arg1_data(); }
void arg1_QString_QUtf8StringView() { arg1_impl<QString, QUtf8StringView>(); }
void arg1_QString_QAnyStringViewUsingL1_data() { arg1_data(); }
void arg1_QString_QAnyStringViewUsingL1() { arg1_impl<QString, QAnyStringViewUsingL1>(); }
void arg1_QString_QAnyStringViewUsingU8_data() { arg1_data(); }
void arg1_QString_QAnyStringViewUsingU8() { arg1_impl<QString, QAnyStringViewUsingU8>(); }
void arg1_QString_QAnyStringViewUsingU16_data() { arg1_data(); }
void arg1_QString_QAnyStringViewUsingU16() { arg1_impl<QString, QAnyStringViewUsingU16>(); }
void arg1_QString_QByteArray_data() { arg1_data(); }
void arg1_QString_QByteArray() { arg1_impl<QString, QByteArray>(); }
void arg1_QString_QByteArrayView_data() { arg1_data(); }
void arg1_QString_QByteArrayView() { arg1_impl<QString, QByteArrayView>(); }
void arg1_QString_const_char_star_data() { arg1_data(); }
void arg1_QString_const_char_star() { arg1_impl<QString, const char*>(); }
void arg1_QString_const_char8_t_star_data() { arg1_data(); }
@ -576,8 +586,6 @@ private Q_SLOTS:
void arg1_QString_QLatin1Char() { arg1_impl<QString, QLatin1Char>(); }
void arg1_QString_char16_t_data() { arg1_data(false); }
void arg1_QString_char16_t() {
QEXPECT_FAIL("%1/a", "QTBUG-125588", Continue);
QEXPECT_FAIL("%1/ä", "QTBUG-125588", Continue);
arg1_impl<QString, char16_t>();
}

View File

@ -72,7 +72,7 @@ static void verifyCharClassPattern(QString str, qulonglong pattern,
};
QVERIFY2(isSet == test,
qPrintable(QString("Character #%1: 0x%2, isSet: %3")
.arg(i).arg(str[i].unicode(), 0, 16).arg(isSet)));
.arg(i).arg(ushort{str[i].unicode()}, 0, 16).arg(isSet)));
}
}