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
5namespace 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
38namespace 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
53std::string return_temporary();
54std::wstring return_wtemporary();
55
56#if defined(TEST_STDFORMAT)
57void 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
74void 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.
92std::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.
97std::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.
102std::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.
110std::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)
119void 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
136void 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.
154void 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.
159void 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.
164void 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.
172void 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.
183template<typename ...Args>
184std::string format(const char *, Args &&...);
185template<typename ...Args>
186std::string format(const wchar_t *, Args &&...);
187
188// This is not std::format, so it shouldn't be fixed.
189std::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.
194std::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)
200template<typename ...Args>
201void print(const char *, Args &&...);
202template<typename ...Args>
203void print(const wchar_t *, Args &&...);
204
205// This isn't std::print, so it shouldn't be fixed.
206void 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.
211void not_std_print2_wide(const std::string &s1) {
212 print(L"One: {}\n", s1.c_str());
213}
214#endif // TEST_STDPRINT
215

source code of clang-tools-extra/test/clang-tidy/checkers/readability/redundant-string-cstr-format.cpp