1// RUN: %check_clang_tidy %s readability-redundant-string-cstr %t -- -- -isystem %clang_tidy_headers
2#include <string>
3
4template <typename T>
5struct iterator {
6 T *operator->();
7 T &operator*();
8};
9
10namespace llvm {
11struct StringRef {
12 StringRef(const char *p);
13 StringRef(const std::string &);
14};
15}
16
17// Tests for std::string.
18
19void f1(const std::string &s) {
20 f1(s: 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: s.data());
24 // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: redundant call to 'data' [readability-redundant-string-cstr]
25 // CHECK-FIXES: {{^ }}f1(s);{{$}}
26}
27void f2(const llvm::StringRef r) {
28 std::string s;
29 f2(r: 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}
34void f3(const llvm::StringRef &r) {
35 std::string s;
36 f3(r: 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}
41void f4(const std::string &s) {
42 const std::string* ptr = &s;
43 f1(s: 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}
47void f5(const std::string &s) {
48 std::string tmp;
49 tmp.append(s: s.c_str());
50 // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: redundant call {{.*}}
51 // CHECK-FIXES: {{^ }}tmp.append(s);{{$}}
52 tmp.assign(s: s.c_str());
53 // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: redundant call {{.*}}
54 // CHECK-FIXES: {{^ }}tmp.assign(s);{{$}}
55
56 if (tmp.compare(s: 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(pos: 1, n1: 2, s: 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: 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: s.c_str(), pos: 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: s.c_str(), pos: 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(pos: 1, s: 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}
100void f6(const std::string &s) {
101 std::string tmp;
102 tmp.append(s: s.c_str(), n: 2);
103 tmp.assign(s: s.c_str(), n: 2);
104
105 if (tmp.compare(str: s) == 0) return;
106 if (tmp.compare(pos: 1, n: 2, str: 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: s.c_str(), pos: 2, n: 4) == 0) return;
117
118 tmp.insert(pos1: 1, str: s);
119 tmp.insert(pos: 1, s: s.c_str(), n: 2);
120}
121void f7(std::string_view sv) {
122 std::string s;
123 f7(sv: 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(sv: 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
133void g1(const std::wstring &s) {
134 g1(s: 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}
138void g2(std::wstring_view sv) {
139 std::wstring s;
140 g2(sv: 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(sv: 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
150void h1(const std::u16string &s) {
151 h1(s: 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}
155void h2(std::u16string_view sv) {
156 std::u16string s;
157 h2(sv: 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(sv: 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
167void k1(const std::u32string &s) {
168 k1(s: 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}
172void k2(std::u32string_view sv) {
173 std::u32string s;
174 k2(sv: 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(sv: 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
184struct NotAString {
185 NotAString();
186 NotAString(const NotAString&);
187 const char *c_str() const;
188};
189
190void dummy(const char*) {}
191
192void invalid(const NotAString &s) {
193 dummy(s.c_str());
194}
195
196// Test for rvalue std::string.
197void 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->
212void 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
236namespace PR45286 {
237struct Foo {
238 void func(const std::string &) {}
239 void func2(std::string &&) {}
240};
241
242void 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

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