Modify rules S6185,S6484,S6494,S6495: RSPEC improvements (CPP-5056) (#3816)
This commit is contained in:
parent
18f43c5f7f
commit
b46c38154d
@ -9,7 +9,7 @@ Before {cpp}20, one popular way to obtain the same result was the conversion of
|
||||
``++std::format++`` is strictly superior. It is more efficient because it constructs the string in-place instead of copying substrings one by one. It is also often shorter and easier to read because the format pattern is presented in a single piece and not scattered across the concatenation expression.
|
||||
|
||||
|
||||
This rule reports string concatenation cases that can be replaced by ``++std::format++`` and gain in speed and readability.
|
||||
This rule reports string concatenation cases that can be replaced by ``++std::format++`` to improve performance and readability.
|
||||
|
||||
|
||||
=== Noncompliant code example
|
||||
@ -31,3 +31,19 @@ std::string greeting(int n) {
|
||||
}
|
||||
----
|
||||
|
||||
== Resources
|
||||
|
||||
=== Documentation
|
||||
|
||||
* {cpp} reference - https://en.cppreference.com/w/cpp/utility/format/format[`std::format`]
|
||||
* {cpp} reference - https://en.cppreference.com/w/cpp/string/basic_string/to_string[``++std::to_string++``]
|
||||
|
||||
=== Articles & blog posts
|
||||
|
||||
* {cpp} Stories - https://www.cppstories.com/2022/custom-stdformat-cpp20/[Formatting Custom types with std::format from {cpp}20]
|
||||
|
||||
=== Related rules
|
||||
|
||||
* S6484 - Concatenated "std::format" outputs should be replaced by a single invocation
|
||||
* S6494 - {cpp} formatting functions should be used instead of C printf-like functions
|
||||
* S6495 - "std::format" should be used instead of standard output manipulators
|
||||
|
@ -1,12 +1,12 @@
|
||||
== Why is this an issue?
|
||||
|
||||
`std::format` accepts a format string composed of ordinary text and replacement fields (surrounded with `{}`) that are replaced with a textual representation of the next `std::format` arguments.
|
||||
`std::format` accepts a format string composed of ordinary text and replacement fields (surrounded with `{}`) that are replaced with a textual representation of the remaining `std::format` arguments.
|
||||
This allows generating a complex string with a single invocation of `std::format`.
|
||||
|
||||
Since calls to `std::format` produce string objects, it is possible to concatenate them with other string objects or string literals.
|
||||
However, compared to a single `std::format` invocation with an adjusted format string, this concatenation is inefficient and less readable.
|
||||
|
||||
This rule raises an issue when a concatenation an `std::format` invocation can be replaced with a simple `std::format` invocation.
|
||||
This rule raises an issue when the concatenation performed on the result of `std::format` can be replaced with a single `std::format` invocation.
|
||||
|
||||
=== Noncompliant code example
|
||||
|
||||
@ -16,6 +16,16 @@ void formatExamples(std::string str, char const* cstr, int i) {
|
||||
std::string s1 = "You have been greeted " + std::format("{}", i) + " times."; // Noncompliant
|
||||
std::string s2 = "Hello " + std::format("{:*^20}", str) + "! " + std::format("{:->15}", cstr) + '.'; // Noncompliant
|
||||
}
|
||||
----
|
||||
|
||||
=== Compliant solution
|
||||
|
||||
[source,cpp]
|
||||
----
|
||||
void formatExamples(std::string str, char const* cstr, int i) {
|
||||
std::string s1 = std::format("You have been greeted {} times.", i); // Compliant
|
||||
std::string s2 = std::format("Hello {:*^20}! {:->15}.", str, cstr); // Compliant
|
||||
}
|
||||
|
||||
std::string fullName(std::string name, std::string secondName, std::string surname, std::size_t number) {
|
||||
// Compliant, as the formatted output depends on runtime properties
|
||||
@ -29,14 +39,18 @@ std::string fullName(std::string name, std::string secondName, std::string surna
|
||||
}
|
||||
----
|
||||
|
||||
=== Compliant solution
|
||||
== Resources
|
||||
|
||||
[source,cpp]
|
||||
----
|
||||
void formatExamples(std::string str, char const* cstr, int i) {
|
||||
std::string s1 = std::format("You have been greeted {} times.", i); // Compliant
|
||||
std::string s2 = std::format("Hello {:*^20}! {:->15}.", str, cstr); // Compliant
|
||||
std::string s3 = std::format("Welcome {:*^20}! {:->15}.", str, cstr); // Compliant
|
||||
}
|
||||
----
|
||||
=== Documentation
|
||||
|
||||
* {cpp} reference - https://en.cppreference.com/w/cpp/utility/format/format[`std::format`]
|
||||
|
||||
=== Articles & blog posts
|
||||
|
||||
* {cpp} Stories - https://www.cppstories.com/2022/custom-stdformat-cpp20/[Formatting Custom types with std::format from {cpp}20]
|
||||
|
||||
=== Related rules
|
||||
|
||||
* S6185 - "std::format" should be used instead of string concatenation and "std::to_string"
|
||||
* S6494 - {cpp} formatting functions should be used instead of C printf-like functions
|
||||
* S6495 - "std::format" should be used instead of standard output manipulators
|
||||
|
@ -2,13 +2,10 @@
|
||||
|
||||
In contrast to C printf-like functions, {cpp} provides safer and more robust interfaces for performing text formatting:
|
||||
|
||||
* The `std::format` interface family ({cpp}20) allows formatting text into a string
|
||||
* The `std::print` interface family ({cpp}23) allows printing formatted text
|
||||
* The `std::format` interface family ({cpp}20) allows formatting text into a string.
|
||||
* The `std::print` interface family ({cpp}23) allows printing formatted text.
|
||||
|
||||
Firstly, {cpp} formatting facilities perform validation of the format string against the type
|
||||
of the formatted argument. If the validation fails, it is reported as a compilation error
|
||||
for the calls of `std::print` and `std::format`.
|
||||
In addition `std::vformat`, `std::vprint_unicode`, and `std::vprint_nonunicode` report validation failures by throwing an instance of `std::format_error`.
|
||||
{cpp} formatting facilities perform validation of the format string against the type of the formatted argument. If the validation fails, it is reported as a compilation error for the calls of `std::print` and `std::format`. When the format string is not available at compile-time, `std::vformat`, `std::vprint_unicode`, and `std::vprint_nonunicode` can be used. They will report failures at runtime by throwing an instance of `std::format_error`.
|
||||
|
||||
Secondly, the relation between the type and format specifier is more abstract.
|
||||
In particular, `{:d}` can be used to format any integer type, regardless of its size and signedness.
|
||||
@ -17,8 +14,7 @@ Furthermore, `{}` can be used for any type with default format spec, which makes
|
||||
|
||||
Finally, the text formatting API was designed with adaptability in mind:
|
||||
|
||||
* Formatting of user-defined types is possible with the dedicated format specification via
|
||||
`std::formatter` specializations.
|
||||
* Formatting of user-defined types is possible with the dedicated format specification via `std::formatter` specializations.
|
||||
|
||||
* The string formatting API provides functions for:
|
||||
- receiving the formatted text by return - `std::format`.
|
||||
@ -35,15 +31,18 @@ This rule raises issues for calls of the `printf`, `fprintf`, `sprintf` and `snp
|
||||
|
||||
[source,cpp]
|
||||
----
|
||||
void printFunc(char* out, size_t n) {
|
||||
sprintf(out, "%u %s", 10u, “text”); // Noncompliant
|
||||
void printTextIntoBuffer(char* out) {
|
||||
// Assumes the buffer pointed-to by out is large enough
|
||||
sprintf(out, "%u %s", 10u, "text"); // Noncompliant
|
||||
}
|
||||
|
||||
void printTextIntoSizedBuffer(char* out, size_t n) {
|
||||
std::snprintf(out, n, "%i %% %LG", 10, 10.0L); // Noncompliant
|
||||
}
|
||||
|
||||
void printFile(FILE* f) {
|
||||
// Since C++23
|
||||
printf("%i", 10); // Noncompliant
|
||||
std::fprintf(f, "%f", 10.0); // Noncompliant
|
||||
void printToFile(FILE* f) {
|
||||
printf("%i", 10); // Noncompliant since C++23
|
||||
std::fprintf(f, "%f", 10.0); // Noncompliant since C++23
|
||||
}
|
||||
----
|
||||
|
||||
@ -51,18 +50,21 @@ void printFile(FILE* f) {
|
||||
|
||||
[source,cpp]
|
||||
----
|
||||
void printFunc(char* out) {
|
||||
std::format_to(out, “{:d} {:s}”, 10u, text); // Compliant
|
||||
// or
|
||||
std::format_to(out, “{} {}”, 10u, text); // Compliant
|
||||
|
||||
std::format_to_n(out, ”{:d} % {:G}”, 10, 10.0L); // Compliant
|
||||
// or
|
||||
std::format_to_n(out, ”{} % {:G}”, 10, 10.0L); // Compliant
|
||||
void printTextIntoBuffer(char* out) {
|
||||
// Assumes the buffer pointed-to by out is large enough
|
||||
std::format_to(out, "{} {}", 10u, "text"); // Compliant
|
||||
}
|
||||
// The function can also be redesigned to deal with memory allocation
|
||||
// and return a string:
|
||||
std::string getText() {
|
||||
return std::format("{} {}", 10u, "text"); // Compliant
|
||||
}
|
||||
|
||||
void printFile(FILE* f) {
|
||||
// Since C++23
|
||||
void printTextIntoSizedBuffer(char* out, size_t n) {
|
||||
std::format_to_n(out, n, "{} % {:G}", 10, 10.0L); // Compliant
|
||||
}
|
||||
|
||||
void printToFile(FILE* f) {
|
||||
std::print("{}", 10); // Compliant
|
||||
std::print(f, "{}", 10.0); // Compliant
|
||||
}
|
||||
@ -70,8 +72,7 @@ void printFile(FILE* f) {
|
||||
|
||||
=== Exceptions
|
||||
|
||||
The rule does not raise an issue if the format string passed to a printf-like function is computed dynamically
|
||||
instead of being spelled in the source code:
|
||||
The rule does not raise an issue if the format string passed to a printf-like function is computed dynamically instead of being spelled in the source code:
|
||||
|
||||
[source,cpp]
|
||||
----
|
||||
@ -80,20 +81,24 @@ char const* localizedFormatString(unsigned id);
|
||||
snprintf(buffer, localizedFormatString(123), 10, 20)
|
||||
----
|
||||
|
||||
While `std::vformat` may be used in such cases, it would require a change of the format string,
|
||||
which may not be actionable.
|
||||
While `std::vformat` may be used in such cases, it requires changing the format string, which may not be actionable.
|
||||
|
||||
|
||||
== Resources
|
||||
|
||||
=== Documentation
|
||||
|
||||
* {cpp} reference - https://en.cppreference.com/w/cpp/utility/format/format[`std::format`]
|
||||
* {cpp} reference - https://en.cppreference.com/w/cpp/io/print[`std::print`]
|
||||
* {cpp} reference - https://en.cppreference.com/w/cpp/header/format[`<format>`]
|
||||
* {cpp} reference - https://en.cppreference.com/w/cpp/header/print[`<print>`]
|
||||
* {cpp} reference - https://en.cppreference.com/w/cpp/io/basic_ostream/print[`std::print(std::ostream)`]
|
||||
* {cpp} reference - https://en.cppreference.com/w/cpp/utility/format/format_to[`std::format_to`]
|
||||
* {cpp} reference - https://en.cppreference.com/w/cpp/utility/format/format_to_n[`std::format_to_n`]
|
||||
* {cpp} reference - https://en.cppreference.com/w/cpp/io/vprint_unicode[`std::vprint_unicode`]
|
||||
* {cpp} reference - https://en.cppreference.com/w/cpp/io/vprint_nonunicode[`std::vprint_nonunicode`]
|
||||
* {cpp} reference - https://en.cppreference.com/w/cpp/io/basic_ostream/vprint_unicode[`std::vprint_unicode(std::ostream)`]
|
||||
* {cpp} reference - https://en.cppreference.com/w/cpp/io/basic_ostream/vprint_nonunicode[`std::vprint_nonunicode(std::ostream)`]
|
||||
|
||||
|
||||
=== Articles & blog posts
|
||||
|
||||
* {cpp} Stories - https://www.cppstories.com/2022/custom-stdformat-cpp20/[Formatting Custom types with std::format from {cpp}20]
|
||||
|
||||
=== Related rules
|
||||
|
||||
* S6185 - "std::format" should be used instead of string concatenation and "std::to_string"
|
||||
* S6484 - Concatenated "std::format" outputs should be replaced by a single invocation
|
||||
* S6495 - "std::format" should be used instead of standard output manipulators
|
||||
|
@ -1,13 +1,11 @@
|
||||
== Why is this an issue?
|
||||
|
||||
{cpp}20 introduces a new text formatting API with the ``<format>`` header,
|
||||
joining the ``printf`` family of functions -- inherited from C -- and ``iostreams``.
|
||||
``std::format`` combines the convenience of ``printf``, separating formatting and
|
||||
arguments, with the type-safety of ``iostreams``.
|
||||
{cpp}20 introduces a new text formatting API with the ``<format>`` header, in addition to the ``printf`` funciton family -- inherited from C -- and ``iostreams``.
|
||||
``std::format`` combines the convenience of ``printf``, separating formatting and arguments, with the type-safety of ``iostreams``.
|
||||
|
||||
Before {cpp}20, if you wanted to format an output stream, you had to use standard manipulators that control the output streams.
|
||||
This approach is very verbose, is often stateful, and is not thread-safe. That is why we recommend replacing them with ``std::format``
|
||||
when possible.
|
||||
This approach is very verbose, is often stateful, and is not thread-safe.
|
||||
That is why we recommend replacing them with ``std::format`` when possible.
|
||||
|
||||
Some manipulators will have a temporary effect on the output. For example, ``std::setw``. This is due to the resetting of the width property of the stream when most of the ``operator<<`` is called.
|
||||
Other manipulators will have a lasting effect on the output. For example, ``std::boolalpha``. It will set the ``boolalpha`` flag of the output stream without resetting it.
|
||||
@ -71,3 +69,20 @@ void printQuoted(std::string_view s) {
|
||||
std::cout << std::quoted(s, '$', '-');
|
||||
}
|
||||
----
|
||||
|
||||
== Resources
|
||||
|
||||
=== Documentation
|
||||
|
||||
* {cpp} reference - https://en.cppreference.com/w/cpp/utility/format/format[`std::format`]
|
||||
* {cpp} reference - https://en.cppreference.com/w/cpp/header/iomanip[`<iomanip>`]
|
||||
|
||||
=== Articles & blog posts
|
||||
|
||||
* {cpp} Stories - https://www.cppstories.com/2022/custom-stdformat-cpp20/[Formatting Custom types with std::format from {cpp}20]
|
||||
|
||||
=== Related rules
|
||||
|
||||
* S6185 - "std::format" should be used instead of string concatenation and "std::to_string"
|
||||
* S6484 - Concatenated "std::format" outputs should be replaced by a single invocation
|
||||
* S6494 - {cpp} formatting functions should be used instead of C printf-like functions
|
||||
|
Loading…
x
Reference in New Issue
Block a user