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