1// RUN: %check_clang_tidy --match-partial-fixes \
2// RUN: -std=c++20 %s modernize-use-std-format %t -- \
3// RUN: -config="{CheckOptions: {modernize-use-std-format.StrictMode: true}}" \
4// RUN: -- -isystem %clang_tidy_headers \
5// RUN: -DPRI_CMDLINE_MACRO="\"s\"" \
6// RUN: -D__PRI_CMDLINE_MACRO="\"s\""
7// RUN: %check_clang_tidy --match-partial-fixes \
8// RUN: -std=c++20 %s modernize-use-std-format %t -- \
9// RUN: -config="{CheckOptions: {modernize-use-std-format.StrictMode: false}}" \
10// RUN: -- -isystem %clang_tidy_headers \
11// RUN: -DPRI_CMDLINE_MACRO="\"s\"" \
12// RUN: -D__PRI_CMDLINE_MACRO="\"s\""
13#include <string>
14// CHECK-FIXES: #include <format>
15#include <inttypes.h>
16
17namespace absl
18{
19template <typename S, typename... Args>
20std::string StrFormat(const S &format, const Args&... args);
21} // namespace absl
22
23template <typename T>
24struct iterator {
25 T *operator->();
26 T &operator*();
27};
28
29std::string StrFormat_simple() {
30 return absl::StrFormat(format: "Hello");
31 // CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
32 // CHECK-FIXES: return std::format("Hello");
33}
34
35std::string StrFormat_complex(const char *name, double value) {
36 return absl::StrFormat(format: "'%s'='%f'", args: name, args: value);
37 // CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
38 // CHECK-FIXES: return std::format("'{}'='{:f}'", name, value);
39}
40
41std::string StrFormat_integer_conversions() {
42 return absl::StrFormat(format: "int:%d int:%d char:%c char:%c", args: 65, args: 'A', args: 66, args: 'B');
43 // CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
44 // CHECK-FIXES: return std::format("int:{} int:{:d} char:{:c} char:{}", 65, 'A', 66, 'B');
45}
46
47// FormatConverter is capable of removing newlines from the end of the format
48// string. Ensure that isn't incorrectly happening for std::format.
49std::string StrFormat_no_newline_removal() {
50 return absl::StrFormat(format: "a line\n");
51 // CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
52 // CHECK-FIXES: return std::format("a line\n");
53}
54
55// FormatConverter is capable of removing newlines from the end of the format
56// string. Ensure that isn't incorrectly happening for std::format.
57std::string StrFormat_cstr_removal(const std::string &s1, const std::string *s2) {
58 return absl::StrFormat(format: "%s %s %s %s", args: s1.c_str(), args: s1.data(), args: s2->c_str(), args: s2->data());
59 // CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
60 // CHECK-FIXES: return std::format("{} {} {} {}", s1, s1, *s2, *s2);
61}
62
63std::string StrFormat_strict_conversion() {
64 const unsigned char uc = 'A';
65 return absl::StrFormat(format: "Integer %hhd from unsigned char\n", args: uc);
66 // CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
67 // CHECK-FIXES: return std::format("Integer {} from unsigned char\n", uc);
68}
69
70std::string StrFormat_field_width_and_precision() {
71 auto s1 = absl::StrFormat(format: "width only:%*d width and precision:%*.*f precision only:%.*f", args: 3, args: 42, args: 4, args: 2, args: 3.14159265358979323846, args: 5, args: 2.718);
72 // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
73 // CHECK-FIXES: std::format("width only:{:{}} width and precision:{:{}.{}f} precision only:{:.{}f}", 42, 3, 3.14159265358979323846, 4, 2, 2.718, 5);
74
75 auto s2 = absl::StrFormat(format: "width and precision positional:%1$*2$.*3$f after", args: 3.14159265358979323846, args: 4, args: 2);
76 // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
77 // CHECK-FIXES: std::format("width and precision positional:{0:{1}.{2}f} after", 3.14159265358979323846, 4, 2);
78
79 const int width = 10, precision = 3;
80 const unsigned int ui1 = 42, ui2 = 43, ui3 = 44;
81 auto s3 = absl::StrFormat(format: "casts width only:%*d width and precision:%*.*d precision only:%.*d\n", args: 3, args: ui1, args: 4, args: 2, args: ui2, args: 5, args: ui3);
82 // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
83 // CHECK-FIXES-NOTSTRICT: std::format("casts width only:{:{}} width and precision:{:{}.{}} precision only:{:.{}}", ui1, 3, ui2, 4, 2, ui3, 5);
84 // CHECK-FIXES-STRICT: std::format("casts width only:{:{}} width and precision:{:{}.{}} precision only:{:.{}}", static_cast<int>(ui1), 3, static_cast<int>(ui2), 4, 2, static_cast<int>(ui3), 5);
85
86 auto s4 = absl::StrFormat(format: "c_str removal width only:%*s width and precision:%*.*s precision only:%.*s", args: 3, args: s1.c_str(), args: 4, args: 2, args: s2.c_str(), args: 5, args: s3.c_str());
87 // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
88 // CHECK-FIXES: std::format("c_str removal width only:{:>{}} width and precision:{:>{}.{}} precision only:{:.{}}", s1, 3, s2, 4, 2, s3, 5);
89
90 const std::string *ps1 = &s1, *ps2 = &s2, *ps3 = &s3;
91 auto s5 = absl::StrFormat(format: "c_str() removal pointer width only:%-*s width and precision:%-*.*s precision only:%-.*s", args: 3, args: ps1->c_str(), args: 4, args: 2, args: ps2->c_str(), args: 5, args: ps3->c_str());
92 // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
93 // CHECK-FIXES: std::format("c_str() removal pointer width only:{:{}} width and precision:{:{}.{}} precision only:{:.{}}", *ps1, 3, *ps2, 4, 2, *ps3, 5);
94
95 iterator<std::string> is1, is2, is3;
96 auto s6 = absl::StrFormat(format: "c_str() removal iterator width only:%-*s width and precision:%-*.*s precision only:%-.*s", args: 3, args: is1->c_str(), args: 4, args: 2, args: is2->c_str(), args: 5, args: is3->c_str());
97 // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
98 // CHECK-FIXES: std::format("c_str() removal iterator width only:{:{}} width and precision:{:{}.{}} precision only:{:.{}}", *is1, 3, *is2, 4, 2, *is3, 5);
99
100 return s1 + s2 + s3 + s4 + s5 + s6;
101}
102
103void StrFormat_macros() {
104 // The function call is replaced even though it comes from a macro.
105#define FORMAT absl::StrFormat
106 auto s1 = FORMAT(format: "Hello %d", args: 42);
107 // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
108 // CHECK-FIXES: std::format("Hello {}", 42);
109
110 // Arguments that are macros aren't replaced with their value, even if they are rearranged.
111#define VALUE 3.14159265358979323846
112#define WIDTH 10
113#define PRECISION 4
114 auto s3 = absl::StrFormat(format: "Hello %*.*f", WIDTH, PRECISION, VALUE);
115 // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
116 // CHECK-FIXES: std::format("Hello {:{}.{}f}", VALUE, WIDTH, PRECISION);
117
118 const uint64_t u64 = 42;
119 const uint32_t u32 = 32;
120 std::string s;
121
122 auto s4 = absl::StrFormat(format: "Replaceable macro at end %" PRIu64, args: u64);
123 // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
124 // CHECK-FIXES: std::format("Replaceable macro at end {}", u64);
125
126 auto s5 = absl::StrFormat(format: "Replaceable macros in middle %" PRIu64 " %" PRIu32 "\n", args: u64, args: u32);
127 // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
128 // CHECK-FIXES: std::format("Replaceable macros in middle {} {}\n", u64, u32);
129
130// These need PRI and __PRI prefixes so that the check get as far as looking for
131// where the macro comes from.
132#define PRI_FMT_MACRO "s"
133#define __PRI_FMT_MACRO "s"
134
135 auto s6 = absl::StrFormat(format: "Unreplaceable macro at end %" PRI_FMT_MACRO, args: s.c_str());
136 // CHECK-MESSAGES: [[@LINE-1]]:13: warning: unable to use 'std::format' instead of 'StrFormat' because format string contains unreplaceable macro 'PRI_FMT_MACRO' [modernize-use-std-format]
137
138 auto s7 = absl::StrFormat(__PRI_FMT_MACRO " Unreplaceable macro at beginning %s", args: s);
139 // CHECK-MESSAGES: [[@LINE-1]]:13: warning: unable to use 'std::format' instead of 'StrFormat' because format string contains unreplaceable macro '__PRI_FMT_MACRO' [modernize-use-std-format]
140
141 auto s8 = absl::StrFormat(format: "Unreplacemable macro %" PRI_FMT_MACRO " in the middle", args: s);
142 // CHECK-MESSAGES: [[@LINE-1]]:13: warning: unable to use 'std::format' instead of 'StrFormat' because format string contains unreplaceable macro 'PRI_FMT_MACRO' [modernize-use-std-format]
143
144 auto s9 = absl::StrFormat(format: "First macro is replaceable %" PRIu64 " but second one is not %" __PRI_FMT_MACRO, args: u64, args: s);
145 // CHECK-MESSAGES: [[@LINE-1]]:13: warning: unable to use 'std::format' instead of 'StrFormat' because format string contains unreplaceable macro '__PRI_FMT_MACRO' [modernize-use-std-format]
146
147 // Needs a PRI prefix so that we get as far as looking for where the macro comes from
148 auto s10 = absl::StrFormat(" macro from command line %" PRI_CMDLINE_MACRO, s);
149 // CHECK-MESSAGES: [[@LINE-1]]:14: warning: unable to use 'std::format' instead of 'StrFormat' because format string contains unreplaceable macro 'PRI_CMDLINE_MACRO' [modernize-use-std-format]
150
151 // Needs a __PRI prefix so that we get as far as looking for where the macro comes from
152 auto s11 = absl::StrFormat(" macro from command line %" __PRI_CMDLINE_MACRO, s);
153 // CHECK-MESSAGES: [[@LINE-1]]:14: warning: unable to use 'std::format' instead of 'StrFormat' because format string contains unreplaceable macro '__PRI_CMDLINE_MACRO' [modernize-use-std-format]
154
155 // We ought to be able to fix this since the macro surrounds the whole call
156 // and therefore can't change the format string independently. This is
157 // required to be able to fix calls inside Catch2 macros for example.
158#define SURROUND_ALL(x) x
159 auto s12 = SURROUND_ALL(absl::StrFormat("Macro surrounding entire invocation %" PRIu64, u64));
160 // CHECK-MESSAGES: [[@LINE-1]]:27: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
161 // CHECK-FIXES: auto s12 = SURROUND_ALL(std::format("Macro surrounding entire invocation {}", u64));
162
163 // But having that surrounding macro shouldn't stop us ignoring an
164 // unreplaceable macro elsewhere.
165 auto s13 = SURROUND_ALL(absl::StrFormat("Macro surrounding entire invocation with unreplaceable macro %" PRI_FMT_MACRO, s));
166 // CHECK-MESSAGES: [[@LINE-1]]:27: warning: unable to use 'std::format' instead of 'StrFormat' because format string contains unreplaceable macro 'PRI_FMT_MACRO' [modernize-use-std-format]
167
168 // At the moment at least the check will replace occurrences where the
169 // function name is the result of expanding a macro.
170#define SURROUND_FUNCTION_NAME(x) absl:: x
171 auto s14 = SURROUND_FUNCTION_NAME(StrFormat)(format: "Hello %d", args: 4442);
172 // CHECK-MESSAGES: [[@LINE-1]]:14: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format]
173 // CHECK-FIXES: auto s14 = std::format("Hello {}", 4442);
174
175 // We can't safely fix occurrences where the macro may affect the format
176 // string differently in different builds.
177#define SURROUND_FORMAT(x) "!" x
178 auto s15 = absl::StrFormat(SURROUND_FORMAT("Hello %d"), args: 4443);
179 // CHECK-MESSAGES: [[@LINE-1]]:14: warning: unable to use 'std::format' instead of 'StrFormat' because format string contains unreplaceable macro 'SURROUND_FORMAT' [modernize-use-std-format]
180}
181

source code of clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-format.cpp