1 | // RUN: %check_clang_tidy -check-suffix=STDFORMAT -std=c++20 %s readability-redundant-string-cstr %t -- -- -isystem %clang_tidy_headers -DTEST_STDFORMAT |
2 | // RUN: %check_clang_tidy -check-suffixes=STDFORMAT,STDPRINT -std=c++2b %s readability-redundant-string-cstr %t -- -- -isystem %clang_tidy_headers -DTEST_STDFORMAT -DTEST_STDPRINT |
3 | #include <string> |
4 | |
5 | namespace std { |
6 | template<typename T> |
7 | struct type_identity { using type = T; }; |
8 | template<typename T> |
9 | using type_identity_t = typename type_identity<T>::type; |
10 | |
11 | template <typename CharT, typename... Args> |
12 | struct basic_format_string { |
13 | consteval basic_format_string(const CharT *format) : str(format) {} |
14 | basic_string_view<CharT, std::char_traits<CharT>> str; |
15 | }; |
16 | |
17 | template<typename... Args> |
18 | using format_string = basic_format_string<char, type_identity_t<Args>...>; |
19 | |
20 | template<typename... Args> |
21 | using wformat_string = basic_format_string<wchar_t, type_identity_t<Args>...>; |
22 | |
23 | #if defined(TEST_STDFORMAT) |
24 | template<typename ...Args> |
25 | std::string format(format_string<Args...>, Args &&...); |
26 | template<typename ...Args> |
27 | std::string format(wformat_string<Args...>, Args &&...); |
28 | #endif // TEST_STDFORMAT |
29 | |
30 | #if defined(TEST_STDPRINT) |
31 | template<typename ...Args> |
32 | void print(format_string<Args...>, Args &&...); |
33 | template<typename ...Args> |
34 | void print(wformat_string<Args...>, Args &&...); |
35 | #endif // TEST_STDPRINT |
36 | } |
37 | |
38 | namespace notstd { |
39 | #if defined(TEST_STDFORMAT) |
40 | template<typename ...Args> |
41 | std::string format(const char *, Args &&...); |
42 | template<typename ...Args> |
43 | std::string format(const wchar_t *, Args &&...); |
44 | #endif // TEST_STDFORMAT |
45 | #if defined(TEST_STDPRINT) |
46 | template<typename ...Args> |
47 | void print(const char *, Args &&...); |
48 | template<typename ...Args> |
49 | void print(const wchar_t *, Args &&...); |
50 | #endif // TEST_STDPRINT |
51 | } |
52 | |
53 | std::string return_temporary(); |
54 | std::wstring return_wtemporary(); |
55 | |
56 | #if defined(TEST_STDFORMAT) |
57 | void std_format(const std::string &s1, const std::string &s2, const std::string &s3) { |
58 | auto r1 = std::format("One:{}\n" , s1.c_str()); |
59 | // CHECK-MESSAGES-STDFORMAT: :[[@LINE-1]]:37: warning: redundant call to 'c_str' [readability-redundant-string-cstr] |
60 | // CHECK-FIXES-STDFORMAT: {{^ }}auto r1 = std::format("One:{}\n", s1); |
61 | |
62 | auto r2 = std::format("One:{} Two:{} Three:{} Four:{}\n" , s1.c_str(), s2, s3.c_str(), return_temporary().c_str()); |
63 | // CHECK-MESSAGES-STDFORMAT: :[[@LINE-1]]:61: warning: redundant call to 'c_str' [readability-redundant-string-cstr] |
64 | // CHECK-MESSAGES-STDFORMAT: :[[@LINE-2]]:77: warning: redundant call to 'c_str' [readability-redundant-string-cstr] |
65 | // CHECK-MESSAGES-STDFORMAT: :[[@LINE-3]]:89: warning: redundant call to 'c_str' [readability-redundant-string-cstr] |
66 | // CHECK-FIXES-STDFORMAT: {{^ }}auto r2 = std::format("One:{} Two:{} Three:{} Four:{}\n", s1, s2, s3, return_temporary()); |
67 | |
68 | using namespace std; |
69 | auto r3 = format("Four:{}\n" , s1.c_str()); |
70 | // CHECK-MESSAGES-STDFORMAT: :[[@LINE-1]]:33: warning: redundant call to 'c_str' [readability-redundant-string-cstr] |
71 | // CHECK-FIXES-STDFORMAT: {{^ }}auto r3 = format("Four:{}\n", s1); |
72 | } |
73 | |
74 | void std_format_wide(const std::wstring &s1, const std::wstring &s2, const std::wstring &s3) { |
75 | auto r1 = std::format(L"One:{}\n" , s1.c_str()); |
76 | // CHECK-MESSAGES-STDFORMAT: :[[@LINE-1]]:38: warning: redundant call to 'c_str' [readability-redundant-string-cstr] |
77 | // CHECK-FIXES-STDFORMAT: {{^ }}auto r1 = std::format(L"One:{}\n", s1); |
78 | |
79 | auto r2 = std::format(L"One:{} Two:{} Three:{} Four:{}\n" , s1.c_str(), s2, s3.c_str(), return_wtemporary().c_str()); |
80 | // CHECK-MESSAGES-STDFORMAT: :[[@LINE-1]]:62: warning: redundant call to 'c_str' [readability-redundant-string-cstr] |
81 | // CHECK-MESSAGES-STDFORMAT: :[[@LINE-2]]:78: warning: redundant call to 'c_str' [readability-redundant-string-cstr] |
82 | // CHECK-MESSAGES-STDFORMAT: :[[@LINE-3]]:90: warning: redundant call to 'c_str' [readability-redundant-string-cstr] |
83 | // CHECK-FIXES-STDFORMAT: {{^ }}auto r2 = std::format(L"One:{} Two:{} Three:{} Four:{}\n", s1, s2, s3, return_wtemporary()); |
84 | |
85 | using namespace std; |
86 | auto r3 = format(L"Four:{}\n" , s1.c_str()); |
87 | // CHECK-MESSAGES-STDFORMAT: :[[@LINE-1]]:34: warning: redundant call to 'c_str' [readability-redundant-string-cstr] |
88 | // CHECK-FIXES-STDFORMAT: {{^ }}auto r3 = format(L"Four:{}\n", s1); |
89 | } |
90 | |
91 | // There's are c_str() calls here, so it shouldn't be touched. |
92 | std::string std_format_no_cstr(const std::string &s1, const std::string &s2) { |
93 | return std::format("One: {}, Two: {}\n" , s1, s2); |
94 | } |
95 | |
96 | // There's are c_str() calls here, so it shouldn't be touched. |
97 | std::string std_format_no_cstr_wide(const std::string &s1, const std::string &s2) { |
98 | return std::format(L"One: {}, Two: {}\n" , s1, s2); |
99 | } |
100 | |
101 | // This is not std::format, so it shouldn't be fixed. |
102 | std::string not_std_format(const std::string &s1) { |
103 | return notstd::format("One: {}\n" , s1.c_str()); |
104 | |
105 | using namespace notstd; |
106 | format("One: {}\n" , s1.c_str()); |
107 | } |
108 | |
109 | // This is not std::format, so it shouldn't be fixed. |
110 | std::string not_std_format_wide(const std::string &s1) { |
111 | return notstd::format(L"One: {}\n" , s1.c_str()); |
112 | |
113 | using namespace notstd; |
114 | format(L"One: {}\n" , s1.c_str()); |
115 | } |
116 | #endif // TEST_STDFORMAT |
117 | |
118 | #if defined(TEST_STDPRINT) |
119 | void std_print(const std::string &s1, const std::string &s2, const std::string &s3) { |
120 | std::print("One:{}\n" , s1.c_str()); |
121 | // CHECK-MESSAGES-STDPRINT: :[[@LINE-1]]:26: warning: redundant call to 'c_str' [readability-redundant-string-cstr] |
122 | // CHECK-FIXES-STDPRINT: {{^ }}std::print("One:{}\n", s1); |
123 | |
124 | std::print("One:{} Two:{} Three:{} Four:{}\n" , s1.c_str(), s2, s3.c_str(), return_temporary().c_str()); |
125 | // CHECK-MESSAGES-STDPRINT: :[[@LINE-1]]:50: warning: redundant call to 'c_str' [readability-redundant-string-cstr] |
126 | // CHECK-MESSAGES-STDPRINT: :[[@LINE-2]]:66: warning: redundant call to 'c_str' [readability-redundant-string-cstr] |
127 | // CHECK-MESSAGES-STDPRINT: :[[@LINE-3]]:78: warning: redundant call to 'c_str' [readability-redundant-string-cstr] |
128 | // CHECK-FIXES-STDPRINT: {{^ }}std::print("One:{} Two:{} Three:{} Four:{}\n", s1, s2, s3, return_temporary()); |
129 | |
130 | using namespace std; |
131 | print("Four:{}\n" , s1.c_str()); |
132 | // CHECK-MESSAGES-STDPRINT: :[[@LINE-1]]:22: warning: redundant call to 'c_str' [readability-redundant-string-cstr] |
133 | // CHECK-FIXES-STDPRINT: {{^ }}print("Four:{}\n", s1); |
134 | } |
135 | |
136 | void std_print_wide(const std::wstring &s1, const std::wstring &s2, const std::wstring &s3) { |
137 | std::print(L"One:{}\n" , s1.c_str()); |
138 | // CHECK-MESSAGES-STDPRINT: :[[@LINE-1]]:27: warning: redundant call to 'c_str' [readability-redundant-string-cstr] |
139 | // CHECK-FIXES-STDPRINT: {{^ }}std::print(L"One:{}\n", s1); |
140 | |
141 | std::print(L"One:{} Two:{} Three:{} Four:{}\n" , s1.c_str(), s2, s3.c_str(), return_wtemporary().c_str()); |
142 | // CHECK-MESSAGES-STDPRINT: :[[@LINE-1]]:51: warning: redundant call to 'c_str' [readability-redundant-string-cstr] |
143 | // CHECK-MESSAGES-STDPRINT: :[[@LINE-2]]:67: warning: redundant call to 'c_str' [readability-redundant-string-cstr] |
144 | // CHECK-MESSAGES-STDPRINT: :[[@LINE-3]]:79: warning: redundant call to 'c_str' [readability-redundant-string-cstr] |
145 | // CHECK-FIXES-STDPRINT: {{^ }}std::print(L"One:{} Two:{} Three:{} Four:{}\n", s1, s2, s3, return_wtemporary()); |
146 | |
147 | using namespace std; |
148 | print(L"Four:{}\n" , s1.c_str()); |
149 | // CHECK-MESSAGES-STDPRINT: :[[@LINE-1]]:23: warning: redundant call to 'c_str' [readability-redundant-string-cstr] |
150 | // CHECK-FIXES-STDPRINT: {{^ }}print(L"Four:{}\n", s1); |
151 | } |
152 | |
153 | // There's no c_str() call here, so it shouldn't be touched. |
154 | void std_print_no_cstr(const std::string &s1, const std::string &s2) { |
155 | std::print("One: {}, Two: {}\n" , s1, s2); |
156 | } |
157 | |
158 | // There's no c_str() call here, so it shouldn't be touched. |
159 | void std_print_no_cstr_wide(const std::wstring &s1, const std::wstring &s2) { |
160 | std::print(L"One: {}, Two: {}\n" , s1, s2); |
161 | } |
162 | |
163 | // This isn't std::print, so it shouldn't be fixed. |
164 | void not_std_print(const std::string &s1) { |
165 | notstd::print("One: {}\n" , s1.c_str()); |
166 | |
167 | using namespace notstd; |
168 | print("One: {}\n" , s1.c_str()); |
169 | } |
170 | |
171 | // This isn't std::print, so it shouldn't be fixed. |
172 | void not_std_print_wide(const std::string &s1) { |
173 | notstd::print(L"One: {}\n" , s1.c_str()); |
174 | |
175 | using namespace notstd; |
176 | print(L"One: {}\n" , s1.c_str()); |
177 | } |
178 | #endif // TEST_STDPRINT |
179 | |
180 | #if defined(TEST_STDFORMAT) |
181 | // We can't declare these earlier since they make the "using namespace std" |
182 | // tests ambiguous. |
183 | template<typename ...Args> |
184 | std::string format(const char *, Args &&...); |
185 | template<typename ...Args> |
186 | std::string format(const wchar_t *, Args &&...); |
187 | |
188 | // This is not std::format, so it shouldn't be fixed. |
189 | std::string not_std_format2(const std::wstring &s1) { |
190 | return format("One: {}\n" , s1.c_str()); |
191 | } |
192 | |
193 | // This is not std::format, so it shouldn't be fixed. |
194 | std::string not_std_format2_wide(const std::wstring &s1) { |
195 | return format(L"One: {}\n" , s1.c_str()); |
196 | } |
197 | #endif // TEST_STDFORMAT |
198 | |
199 | #if defined(TEST_STDPRINT) |
200 | template<typename ...Args> |
201 | void print(const char *, Args &&...); |
202 | template<typename ...Args> |
203 | void print(const wchar_t *, Args &&...); |
204 | |
205 | // This isn't std::print, so it shouldn't be fixed. |
206 | void not_std_print2(const std::string &s1) { |
207 | print("One: {}\n" , s1.c_str()); |
208 | } |
209 | |
210 | // This isn't std::print, so it shouldn't be fixed. |
211 | void not_std_print2_wide(const std::string &s1) { |
212 | print(L"One: {}\n" , s1.c_str()); |
213 | } |
214 | #endif // TEST_STDPRINT |
215 | |