1 // RUN: %check_clang_tidy %s readability-redundant-string-cstr %t -- -- -isystem %clang_tidy_headers
2 #include <string>
3
4 template <typename T>
5 struct iterator {
6 T *operator->();
7 T &operator*();
8 };
9
10 namespace llvm {
11 struct StringRef {
12 StringRef(const char *p);
13 StringRef(const std::string &);
14 };
15 }
16
17 // Tests for std::string.
18
f1(const std::string & s)19 void f1(const std::string &s) {
20 f1(s.c_str());
21 // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
22 // CHECK-FIXES: {{^ }}f1(s);{{$}}
23 f1(s.data());
24 // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: redundant call to 'data' [readability-redundant-string-cstr]
25 // CHECK-FIXES: {{^ }}f1(s);{{$}}
26 }
f2(const llvm::StringRef r)27 void f2(const llvm::StringRef r) {
28 std::string s;
29 f2(s.c_str());
30 // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: redundant call {{.*}}
31 // CHECK-FIXES: {{^ }}std::string s;{{$}}
32 // CHECK-FIXES-NEXT: {{^ }}f2(s);{{$}}
33 }
f3(const llvm::StringRef & r)34 void f3(const llvm::StringRef &r) {
35 std::string s;
36 f3(s.c_str());
37 // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: redundant call {{.*}}
38 // CHECK-FIXES: {{^ }}std::string s;{{$}}
39 // CHECK-FIXES-NEXT: {{^ }}f3(s);{{$}}
40 }
f4(const std::string & s)41 void f4(const std::string &s) {
42 const std::string* ptr = &s;
43 f1(ptr->c_str());
44 // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
45 // CHECK-FIXES: {{^ }}f1(*ptr);{{$}}
46 }
f5(const std::string & s)47 void f5(const std::string &s) {
48 std::string tmp;
49 tmp.append(s.c_str());
50 // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: redundant call {{.*}}
51 // CHECK-FIXES: {{^ }}tmp.append(s);{{$}}
52 tmp.assign(s.c_str());
53 // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: redundant call {{.*}}
54 // CHECK-FIXES: {{^ }}tmp.assign(s);{{$}}
55
56 if (tmp.compare(s.c_str()) == 0) return;
57 // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: redundant call {{.*}}
58 // CHECK-FIXES: {{^ }}if (tmp.compare(s) == 0) return;{{$}}
59
60 if (tmp.compare(1, 2, s.c_str()) == 0) return;
61 // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: redundant call {{.*}}
62 // CHECK-FIXES: {{^ }}if (tmp.compare(1, 2, s) == 0) return;{{$}}
63
64 if (tmp.find(s.c_str()) == 0) return;
65 // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: redundant call {{.*}}
66 // CHECK-FIXES: {{^ }}if (tmp.find(s) == 0) return;{{$}}
67
68 if (tmp.find(s.c_str(), 2) == 0) return;
69 // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: redundant call {{.*}}
70 // CHECK-FIXES: {{^ }}if (tmp.find(s, 2) == 0) return;{{$}}
71
72 if (tmp.find(s.c_str(), 2) == 0) return;
73 // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: redundant call {{.*}}
74 // CHECK-FIXES: {{^ }}if (tmp.find(s, 2) == 0) return;{{$}}
75
76 tmp.insert(1, s.c_str());
77 // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: redundant call {{.*}}
78 // CHECK-FIXES: {{^ }}tmp.insert(1, s);{{$}}
79
80 tmp = s.c_str();
81 // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: redundant call {{.*}}
82 // CHECK-FIXES: {{^ }}tmp = s;{{$}}
83
84 tmp += s.c_str();
85 // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: redundant call {{.*}}
86 // CHECK-FIXES: {{^ }}tmp += s;{{$}}
87
88 if (tmp == s.c_str()) return;
89 // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: redundant call {{.*}}
90 // CHECK-FIXES: {{^ }}if (tmp == s) return;{{$}}
91
92 tmp = s + s.c_str();
93 // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: redundant call {{.*}}
94 // CHECK-FIXES: {{^ }}tmp = s + s;{{$}}
95
96 tmp = s.c_str() + s;
97 // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: redundant call {{.*}}
98 // CHECK-FIXES: {{^ }}tmp = s + s;{{$}}
99 }
f6(const std::string & s)100 void f6(const std::string &s) {
101 std::string tmp;
102 tmp.append(s.c_str(), 2);
103 tmp.assign(s.c_str(), 2);
104
105 if (tmp.compare(s) == 0) return;
106 if (tmp.compare(1, 2, s) == 0) return;
107
108 tmp = s;
109 tmp += s;
110
111 if (tmp == s)
112 return;
113
114 tmp = s + s;
115
116 if (tmp.find(s.c_str(), 2, 4) == 0) return;
117
118 tmp.insert(1, s);
119 tmp.insert(1, s.c_str(), 2);
120 }
f7(std::string_view sv)121 void f7(std::string_view sv) {
122 std::string s;
123 f7(s.c_str());
124 // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
125 // CHECK-FIXES: {{^ }}f7(s);{{$}}
126 f7(s.data());
127 // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: redundant call to 'data' [readability-redundant-string-cstr]
128 // CHECK-FIXES: {{^ }}f7(s);{{$}}
129 }
130
131 // Tests for std::wstring.
132
g1(const std::wstring & s)133 void g1(const std::wstring &s) {
134 g1(s.c_str());
135 // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
136 // CHECK-FIXES: {{^ }}g1(s);{{$}}
137 }
g2(std::wstring_view sv)138 void g2(std::wstring_view sv) {
139 std::wstring s;
140 g2(s.c_str());
141 // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
142 // CHECK-FIXES: {{^ }}g2(s);{{$}}
143 g2(s.data());
144 // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: redundant call to 'data' [readability-redundant-string-cstr]
145 // CHECK-FIXES: {{^ }}g2(s);{{$}}
146 }
147
148 // Tests for std::u16string.
149
h1(const std::u16string & s)150 void h1(const std::u16string &s) {
151 h1(s.c_str());
152 // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
153 // CHECK-FIXES: {{^ }}h1(s);{{$}}
154 }
h2(std::u16string_view sv)155 void h2(std::u16string_view sv) {
156 std::u16string s;
157 h2(s.c_str());
158 // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
159 // CHECK-FIXES: {{^ }}h2(s);{{$}}
160 h2(s.data());
161 // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: redundant call to 'data' [readability-redundant-string-cstr]
162 // CHECK-FIXES: {{^ }}h2(s);{{$}}
163 }
164
165 // Tests for std::u32string.
166
k1(const std::u32string & s)167 void k1(const std::u32string &s) {
168 k1(s.c_str());
169 // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
170 // CHECK-FIXES: {{^ }}k1(s);{{$}}
171 }
k2(std::u32string_view sv)172 void k2(std::u32string_view sv) {
173 std::u32string s;
174 k2(s.c_str());
175 // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
176 // CHECK-FIXES: {{^ }}k2(s);{{$}}
177 k2(s.data());
178 // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: redundant call to 'data' [readability-redundant-string-cstr]
179 // CHECK-FIXES: {{^ }}k2(s);{{$}}
180 }
181
182 // Tests on similar classes that aren't good candidates for this checker.
183
184 struct NotAString {
185 NotAString();
186 NotAString(const NotAString&);
187 const char *c_str() const;
188 };
189
dummy(const char *)190 void dummy(const char*) {}
191
invalid(const NotAString & s)192 void invalid(const NotAString &s) {
193 dummy(s.c_str());
194 }
195
196 // Test for rvalue std::string.
m1(std::string &&)197 void m1(std::string&&) {
198 std::string s;
199
200 m1(s.c_str());
201
202 void (*m1p1)(std::string&&);
203 m1p1 = m1;
204 m1p1(s.c_str());
205
206 using m1tp = void (*)(std::string &&);
207 m1tp m1p2 = m1;
208 m1p2(s.c_str());
209 }
210
211 // Test for overloaded operator->
it(iterator<std::string> i)212 void it(iterator<std::string> i)
213 {
214 std::string tmp;
215 tmp = i->c_str();
216 // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
217 // CHECK-FIXES: {{^ }}tmp = *i;{{$}}
218
219 // An unlikely situation and the outcome is not ideal, but at least the fix doesn't generate broken code.
220 tmp = i.operator->()->c_str();
221 // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
222 // CHECK-FIXES: {{^ }}tmp = *i.operator->();{{$}}
223
224 // The fix contains an unnecessary set of parentheses, but these have no effect.
225 iterator<std::string> *pi = &i;
226 tmp = (*pi)->c_str();
227 // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
228 // CHECK-FIXES: {{^ }}tmp = *(*pi);{{$}}
229
230 // An unlikely situation, but at least the fix doesn't generate broken code.
231 tmp = pi->operator->()->c_str();
232 // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
233 // CHECK-FIXES: {{^ }}tmp = *pi->operator->();{{$}}
234 }
235
236 namespace PR45286 {
237 struct Foo {
funcPR45286::Foo238 void func(const std::string &) {}
func2PR45286::Foo239 void func2(std::string &&) {}
240 };
241
bar()242 void bar() {
243 std::string Str{"aaa"};
244 Foo Foo;
245 Foo.func(Str.c_str());
246 // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
247 // CHECK-FIXES: {{^ }}Foo.func(Str);{{$}}
248
249 // Ensure it doesn't transform Binding to r values
250 Foo.func2(Str.c_str());
251
252 // Ensure its not confused by parens
253 Foo.func((Str.c_str()));
254 // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
255 // CHECK-FIXES: {{^ }}Foo.func((Str));{{$}}
256 Foo.func2((Str.c_str()));
257 }
258 } // namespace PR45286
259