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