Add a macro to disable only some 8 bit/16 bit string conversions

This is an opt-in trade-off between type safety and user
code convenience.

QT_NO_CAST_FROM_ASCII is highly beneficial to avoid unintended
conversions from 8 bit data with potentially "unsuitable"
encodings to QString. However, it has the undesirable side-effect
to require user code to wrap character and string literals
in QLatin1Char(...) and QLatin1String(...) or use similar
construction, cluttering the code significantly.

This patch introduces a QT_RESTRICTED_CAST_FROM_ASCII macro
that works almost as QT_NO_CAST_FROM_ASCII, except that it
enables the QChar(char) constructor and adds an additional
QString(const char (&ch)[N]) constructor that matches
C++ string literals, but no arbitrary character pointers.
This avoids a significant share of the need to clutter the
user code by only a slight relaxation of the type-safety.

[ChangeLog][QtCore][QString] Added QT_RESTRICTED_CAST_FROM_ASCII
macro as less intrusive alternative to QT_NO_CAST_FROM_ASCII.

Change-Id: Iac72f1f90f81fbcae9bfb1fe68b0fec6ffb36c50
Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@digia.com>
Reviewed-by: Kai Koehne <kai.koehne@digia.com>
Reviewed-by: Eike Ziller <eike.ziller@digia.com>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Reviewed-by: Olivier Goffart <ogoffart@woboq.com>
This commit is contained in:
hjk 2014-08-25 14:21:30 +02:00
parent 3759749466
commit 7dd394a16c
3 changed files with 58 additions and 15 deletions

View File

@ -83,7 +83,9 @@ public:
#ifndef QT_NO_CAST_FROM_ASCII
QT_ASCII_CAST_WARN Q_DECL_CONSTEXPR explicit QChar(char c) : ucs(uchar(c)) { }
#ifndef QT_RESTRICTED_CAST_FROM_ASCII
QT_ASCII_CAST_WARN Q_DECL_CONSTEXPR explicit QChar(uchar c) : ucs(c) { }
#endif
#endif
// Unicode information

View File

@ -731,13 +731,31 @@ inline char qToLower(char ch)
const QString::Null QString::null = { };
/*!
\macro QT_RESTRICTED_CAST_FROM_ASCII
\relates QString
Defining this macro disables most automatic conversions from source
literals and 8-bit data to unicode QStrings, but allows the use of
the \c{QChar(char)} and \c{QString(const char (&ch)[N]} constructors,
and the \c{QString::operator=(const char (&ch)[N])} assignment operator
giving most of the type-safety benefits of QT_NO_CAST_FROM_ASCII
but does not require user code to wrap character and string literals
with QLatin1Char, QLatin1String or similar.
Using this macro together with source strings outside the 7-bit range,
non-literals, or literals with embedded NUL characters is undefined.
\sa QT_NO_CAST_FROM_ASCII, QT_NO_CAST_TO_ASCII
*/
/*!
\macro QT_NO_CAST_FROM_ASCII
\relates QString
Disables automatic conversions from 8-bit strings (char *) to unicode QStrings
\sa QT_NO_CAST_TO_ASCII, QT_NO_CAST_FROM_BYTEARRAY
\sa QT_NO_CAST_TO_ASCII, QT_RESTRICTED_CAST_FROM_ASCII, QT_NO_CAST_FROM_BYTEARRAY
*/
/*!
@ -746,7 +764,7 @@ const QString::Null QString::null = { };
disables automatic conversion from QString to 8-bit strings (char *)
\sa QT_NO_CAST_FROM_ASCII, QT_NO_CAST_FROM_BYTEARRAY
\sa QT_NO_CAST_FROM_ASCII, QT_RESTRICTED_CAST_FROM_ASCII, QT_NO_CAST_FROM_BYTEARRAY
*/
/*!
@ -760,7 +778,7 @@ const QString::Null QString::null = { };
Note: This only works for compilers that support warnings for
deprecated API.
\sa QT_NO_CAST_TO_ASCII, QT_NO_CAST_FROM_ASCII
\sa QT_NO_CAST_TO_ASCII, QT_NO_CAST_FROM_ASCII, QT_RESTRICTED_CAST_FROM_ASCII
*/
/*!
@ -994,6 +1012,9 @@ const QString::Null QString::null = { };
\list
\li \c QT_NO_CAST_FROM_ASCII disables automatic conversions from
C string literals and pointers to Unicode.
\li \c QT_RESTRICTED_CAST_FROM_ASCII allows automatic conversions
from C characters and character arrays, but disables automatic
conversions from character pointers to Unicode.
\li \c QT_NO_CAST_TO_ASCII disables automatic conversion from QString
to C strings.
\endlist
@ -1311,6 +1332,12 @@ const QString::Null QString::null = { };
can be useful if you want to ensure that all user-visible strings
go through QObject::tr(), for example.
\note Defining QT_RESTRICTED_CAST_FROM_ASCII also disables
this constructor, but enables a \c{QString(const char (&ch)[N])}
constructor instead. Using non-literal input, or input with
embedded NUL characters, or non-7-bit characters is undefined
in this case.
\sa fromLatin1(), fromLocal8Bit(), fromUtf8()
*/
@ -1749,10 +1776,11 @@ QString &QString::operator=(const QString &other)
Assigns \a str to this string. The const char pointer is converted
to Unicode using the fromUtf8() function.
You can disable this operator by defining \c
QT_NO_CAST_FROM_ASCII when you compile your applications. This
can be useful if you want to ensure that all user-visible strings
You can disable this operator by defining \c QT_NO_CAST_FROM_ASCII
or \c QT_RESTRICTED_CAST_FROM_ASCII when you compile your applications.
This can be useful if you want to ensure that all user-visible strings
go through QObject::tr(), for example.
*/
/*! \fn QString &QString::operator=(char ch)

View File

@ -34,6 +34,10 @@
#ifndef QSTRING_H
#define QSTRING_H
#if defined(QT_NO_CAST_FROM_ASCII) && defined(QT_RESTRICTED_CAST_FROM_ASCII)
#error QT_NO_CAST_FROM_ASCII and QT_RESTRICTED_CAST_FROM_ASCII must not be defined at the same time
#endif
#include <QtCore/qchar.h>
#include <QtCore/qbytearray.h>
#include <QtCore/qrefcount.h>
@ -93,7 +97,7 @@ public:
inline bool operator>=(const QString &s) const;
inline bool operator<=(const QString &s) const;
#ifndef QT_NO_CAST_FROM_ASCII
#if !defined(QT_NO_CAST_FROM_ASCII) && !defined(QT_RESTRICTED_CAST_FROM_ASCII)
inline QT_ASCII_CAST_WARN bool operator==(const char *s) const;
inline QT_ASCII_CAST_WARN bool operator!=(const char *s) const;
inline QT_ASCII_CAST_WARN bool operator<(const char *s) const;
@ -107,7 +111,7 @@ public:
inline QT_ASCII_CAST_WARN bool operator>(const QByteArray &s) const;
inline QT_ASCII_CAST_WARN bool operator<=(const QByteArray &s) const;
inline QT_ASCII_CAST_WARN bool operator>=(const QByteArray &s) const;
#endif // QT_NO_CAST_FROM_ASCII
#endif // !defined(QT_NO_CAST_FROM_ASCII) && !defined(QT_RESTRICTED_CAST_FROM_ASCII)
private:
int m_size;
@ -623,7 +627,16 @@ public:
inline bool operator>=(QLatin1String s) const { return !operator<(s); }
// ASCII compatibility
#ifndef QT_NO_CAST_FROM_ASCII
#if defined(QT_RESTRICTED_CAST_FROM_ASCII)
template <int N>
inline QString(const char (&ch)[N])
: d(fromAscii_helper(ch, N - 1))
{}
template <int N>
inline QString &operator=(const char (&ch)[N])
{ return (*this = fromLatin1(ch, N - 1)); }
#endif
#if !defined(QT_NO_CAST_FROM_ASCII) && !defined(QT_RESTRICTED_CAST_FROM_ASCII)
inline QT_ASCII_CAST_WARN QString(const char *ch)
: d(fromAscii_helper(ch, ch ? int(strlen(ch)) : -1))
{}
@ -1116,7 +1129,7 @@ inline bool QLatin1String::operator>=(const QString &s) const
inline bool QLatin1String::operator<=(const QString &s) const
{ return s >= *this; }
#ifndef QT_NO_CAST_FROM_ASCII
#if !defined(QT_NO_CAST_FROM_ASCII) && !defined(QT_RESTRICTED_CAST_FROM_ASCII)
inline bool QString::operator==(const char *s) const
{ return QString::compare_helper(constData(), size(), s, -1) == 0; }
inline bool QString::operator!=(const char *s) const
@ -1207,7 +1220,7 @@ inline bool QByteArray::operator<=(const QString &s) const
{ return QString::compare_helper(s.constData(), s.size(), constData(), qstrnlen(constData(), size())) <= 0; }
inline bool QByteArray::operator>=(const QString &s) const
{ return QString::compare_helper(s.constData(), s.size(), constData(), qstrnlen(constData(), size())) >= 0; }
#endif // QT_NO_CAST_FROM_ASCII
#endif // !defined(QT_NO_CAST_FROM_ASCII) && !defined(QT_RESTRICTED_CAST_FROM_ASCII)
#ifndef QT_NO_CAST_TO_ASCII
inline QByteArray &QByteArray::append(const QString &s)
@ -1235,7 +1248,7 @@ inline const QString operator+(const QString &s1, QChar s2)
{ QString t(s1); t += s2; return t; }
inline const QString operator+(QChar s1, const QString &s2)
{ QString t(s1); t += s2; return t; }
# ifndef QT_NO_CAST_FROM_ASCII
# if !defined(QT_NO_CAST_FROM_ASCII) && !defined(QT_RESTRICTED_CAST_FROM_ASCII)
inline QT_ASCII_CAST_WARN const QString operator+(const QString &s1, const char *s2)
{ QString t(s1); t += QString::fromUtf8(s2); return t; }
inline QT_ASCII_CAST_WARN const QString operator+(const char *s1, const QString &s2)
@ -1388,7 +1401,7 @@ public:
inline const QChar at(int i) const
{ Q_ASSERT(uint(i) < uint(size())); return m_string->at(i + m_position); }
#ifndef QT_NO_CAST_FROM_ASCII
#if !defined(QT_NO_CAST_FROM_ASCII) && !defined(QT_RESTRICTED_CAST_FROM_ASCII)
// ASCII compatibility
inline QT_ASCII_CAST_WARN bool operator==(const char *s) const;
inline QT_ASCII_CAST_WARN bool operator!=(const char *s) const;
@ -1462,7 +1475,7 @@ inline bool operator<=(const QStringRef &s1, const QStringRef &s2)
inline bool operator>=(const QStringRef &s1, const QStringRef &s2)
{ return !(s1 < s2); }
#ifndef QT_NO_CAST_FROM_ASCII
#if !defined(QT_NO_CAST_FROM_ASCII) && !defined(QT_RESTRICTED_CAST_FROM_ASCII)
inline QT_ASCII_CAST_WARN bool QStringRef::operator==(const char *s) const
{ return QString::compare_helper(constData(), size(), s, -1) == 0; }
inline QT_ASCII_CAST_WARN bool QStringRef::operator!=(const char *s) const
@ -1488,7 +1501,7 @@ inline QT_ASCII_CAST_WARN bool operator>(const char *s1, const QStringRef &s2)
{ return QString::compare_helper(s2.constData(), s2.size(), s1, -1) <= 0; }
inline QT_ASCII_CAST_WARN bool operator>=(const char *s1, const QStringRef &s2)
{ return QString::compare_helper(s2.constData(), s2.size(), s1, -1) >= 0; }
#endif // QT_NO_CAST_FROM_ASCII
#endif // !defined(QT_NO_CAST_FROM_ASCII) && !defined(QT_RESTRICTED_CAST_FROM_ASCII)
inline int QString::compare(const QStringRef &s, Qt::CaseSensitivity cs) const
{ return QString::compare_helper(constData(), length(), s.constData(), s.length(), cs); }