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