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 {
basic_format_stringstd::basic_format_string13 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)
std_format(const std::string & s1,const std::string & s2,const std::string & s3)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
std_format_wide(const std::wstring & s1,const std::wstring & s2,const std::wstring & s3)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.
std_format_no_cstr(const std::string & s1,const std::string & s2)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.
std_format_no_cstr_wide(const std::string & s1,const std::string & s2)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.
not_std_format(const std::string & s1)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.
not_std_format_wide(const std::string & s1)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)
std_print(const std::string & s1,const std::string & s2,const std::string & s3)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
std_print_wide(const std::wstring & s1,const std::wstring & s2,const std::wstring & s3)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.
std_print_no_cstr(const std::string & s1,const std::string & s2)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.
std_print_no_cstr_wide(const std::wstring & s1,const std::wstring & s2)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.
not_std_print(const std::string & s1)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.
not_std_print_wide(const std::string & s1)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.
not_std_format2(const std::wstring & s1)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.
not_std_format2_wide(const std::wstring & s1)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.
not_std_print2(const std::string & s1)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.
not_std_print2_wide(const std::string & s1)211 void not_std_print2_wide(const std::string &s1) {
212 print(L"One: {}\n", s1.c_str());
213 }
214 #endif // TEST_STDPRINT
215