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