1 | // RUN: %check_clang_tidy %s abseil-string-find-str-contains %t -- |
2 | |
3 | using size_t = decltype(sizeof(int)); |
4 | |
5 | namespace std { |
6 | |
7 | // Lightweight standin for std::string. |
8 | template <typename C> |
9 | class basic_string { |
10 | public: |
11 | basic_string(); |
12 | basic_string(const basic_string &); |
13 | basic_string(const C *); |
14 | ~basic_string(); |
15 | int find(basic_string s, int pos = 0); |
16 | int find(const C *s, int pos = 0); |
17 | int find(const C *s, int pos, int n); |
18 | int find(char c, int pos = 0); |
19 | static constexpr size_t npos = -1; |
20 | }; |
21 | typedef basic_string<char> string; |
22 | |
23 | // Lightweight standin for std::string_view. |
24 | template <typename C> |
25 | class basic_string_view { |
26 | public: |
27 | basic_string_view(); |
28 | basic_string_view(const basic_string_view &); |
29 | basic_string_view(const C *); |
30 | ~basic_string_view(); |
31 | int find(basic_string_view s, int pos = 0); |
32 | int find(const C *s, int pos = 0); |
33 | int find(const C *s, int pos, int n); |
34 | int find(char c, int pos = 0); |
35 | static constexpr size_t npos = -1; |
36 | }; |
37 | typedef basic_string_view<char> string_view; |
38 | |
39 | } // namespace std |
40 | |
41 | namespace absl { |
42 | |
43 | // Lightweight standin for absl::string_view. |
44 | class string_view { |
45 | public: |
46 | string_view(); |
47 | string_view(const string_view &); |
48 | string_view(const char *); |
49 | ~string_view(); |
50 | int find(string_view s, int pos = 0); |
51 | int find(const char *s, int pos = 0); |
52 | int find(const char *s, int pos, int n); |
53 | int find(char c, int pos = 0); |
54 | static constexpr size_t npos = -1; |
55 | }; |
56 | |
57 | } // namespace absl |
58 | |
59 | // Functions that take and return our various string-like types. |
60 | std::string foo_ss(std::string); |
61 | std::string_view foo_ssv(std::string_view); |
62 | absl::string_view foo_asv(absl::string_view); |
63 | std::string bar_ss(); |
64 | std::string_view bar_ssv(); |
65 | absl::string_view bar_asv(); |
66 | |
67 | // Confirms that find==npos and find!=npos work for each supported type, when |
68 | // npos comes from the correct type. |
69 | void basic_tests() { |
70 | std::string ss; |
71 | ss.find(s: "a" ) == std::string::npos; |
72 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use !absl::StrContains instead of find() == npos |
73 | // CHECK-FIXES: {{^[[:space:]]*}}!absl::StrContains(ss, "a");{{$}} |
74 | |
75 | ss.find(s: "a" ) != std::string::npos; |
76 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use absl::StrContains instead of find() != npos |
77 | // CHECK-FIXES: {{^[[:space:]]*}}absl::StrContains(ss, "a");{{$}} |
78 | |
79 | std::string::npos != ss.find(s: "a" ); |
80 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use absl::StrContains instead of |
81 | // CHECK-FIXES: {{^[[:space:]]*}}absl::StrContains(ss, "a");{{$}} |
82 | |
83 | std::string_view ssv; |
84 | ssv.find(s: "a" ) == std::string_view::npos; |
85 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use !absl::StrContains instead of |
86 | // CHECK-FIXES: {{^[[:space:]]*}}!absl::StrContains(ssv, "a");{{$}} |
87 | |
88 | ssv.find(s: "a" ) != std::string_view::npos; |
89 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use absl::StrContains instead of |
90 | // CHECK-FIXES: {{^[[:space:]]*}}absl::StrContains(ssv, "a");{{$}} |
91 | |
92 | std::string_view::npos != ssv.find(s: "a" ); |
93 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use absl::StrContains instead of |
94 | // CHECK-FIXES: {{^[[:space:]]*}}absl::StrContains(ssv, "a");{{$}} |
95 | |
96 | absl::string_view asv; |
97 | asv.find(s: "a" ) == absl::string_view::npos; |
98 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use !absl::StrContains instead of |
99 | // CHECK-FIXES: {{^[[:space:]]*}}!absl::StrContains(asv, "a");{{$}} |
100 | |
101 | asv.find(s: "a" ) != absl::string_view::npos; |
102 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use absl::StrContains instead of |
103 | // CHECK-FIXES: {{^[[:space:]]*}}absl::StrContains(asv, "a");{{$}} |
104 | |
105 | absl::string_view::npos != asv.find(s: "a" ); |
106 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use absl::StrContains instead of |
107 | // CHECK-FIXES: {{^[[:space:]]*}}absl::StrContains(asv, "a");{{$}} |
108 | } |
109 | |
110 | // Confirms that it works even if you mix-and-match the type for find and for |
111 | // npos. (One of the reasons for this checker is to clean up cases that |
112 | // accidentally mix-and-match like this. absl::StrContains is less |
113 | // error-prone.) |
114 | void mismatched_npos() { |
115 | std::string ss; |
116 | ss.find(s: "a" ) == std::string_view::npos; |
117 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use !absl::StrContains instead of |
118 | // CHECK-FIXES: {{^[[:space:]]*}}!absl::StrContains(ss, "a");{{$}} |
119 | |
120 | ss.find(s: "a" ) != absl::string_view::npos; |
121 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use absl::StrContains instead of |
122 | // CHECK-FIXES: {{^[[:space:]]*}}absl::StrContains(ss, "a");{{$}} |
123 | |
124 | std::string_view ssv; |
125 | ssv.find(s: "a" ) == absl::string_view::npos; |
126 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use !absl::StrContains instead of |
127 | // CHECK-FIXES: {{^[[:space:]]*}}!absl::StrContains(ssv, "a");{{$}} |
128 | |
129 | ssv.find(s: "a" ) != std::string::npos; |
130 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use absl::StrContains instead of |
131 | // CHECK-FIXES: {{^[[:space:]]*}}absl::StrContains(ssv, "a");{{$}} |
132 | |
133 | absl::string_view asv; |
134 | asv.find(s: "a" ) == std::string::npos; |
135 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use !absl::StrContains instead of |
136 | // CHECK-FIXES: {{^[[:space:]]*}}!absl::StrContains(asv, "a");{{$}} |
137 | |
138 | asv.find(s: "a" ) != std::string_view::npos; |
139 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use absl::StrContains instead of |
140 | // CHECK-FIXES: {{^[[:space:]]*}}absl::StrContains(asv, "a");{{$}} |
141 | } |
142 | |
143 | // Confirms that it works even when the needle or the haystack are more |
144 | // complicated expressions. |
145 | void subexpression_tests() { |
146 | std::string ss, ss2; |
147 | foo_ss(ss).find(s: ss2) == std::string::npos; |
148 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use !absl::StrContains instead of |
149 | // CHECK-FIXES: {{^[[:space:]]*}}!absl::StrContains(foo_ss(ss), ss2);{{$}} |
150 | |
151 | ss.find(s: foo_ss(ss2)) != std::string::npos; |
152 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use absl::StrContains instead of |
153 | // CHECK-FIXES: {{^[[:space:]]*}}absl::StrContains(ss, foo_ss(ss2));{{$}} |
154 | |
155 | foo_ss(bar_ss()).find(s: foo_ss(ss2)) != std::string::npos; |
156 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use absl::StrContains instead of |
157 | // CHECK-FIXES: {{^[[:space:]]*}}absl::StrContains(foo_ss(bar_ss()), foo_ss(ss2));{{$}} |
158 | |
159 | std::string_view ssv, ssv2; |
160 | foo_ssv(ssv).find(s: ssv2) == std::string_view::npos; |
161 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use !absl::StrContains instead of |
162 | // CHECK-FIXES: {{^[[:space:]]*}}!absl::StrContains(foo_ssv(ssv), ssv2);{{$}} |
163 | |
164 | ssv.find(s: foo_ssv(ssv2)) != std::string_view::npos; |
165 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use absl::StrContains instead of |
166 | // CHECK-FIXES: {{^[[:space:]]*}}absl::StrContains(ssv, foo_ssv(ssv2));{{$}} |
167 | |
168 | foo_ssv(bar_ssv()).find(s: foo_ssv(ssv2)) != std::string_view::npos; |
169 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use absl::StrContains instead of |
170 | // CHECK-FIXES: {{^[[:space:]]*}}absl::StrContains(foo_ssv(bar_ssv()), foo_ssv(ssv2));{{$}} |
171 | |
172 | absl::string_view asv, asv2; |
173 | foo_asv(asv).find(s: asv2) == absl::string_view::npos; |
174 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use !absl::StrContains instead of |
175 | // CHECK-FIXES: {{^[[:space:]]*}}!absl::StrContains(foo_asv(asv), asv2);{{$}} |
176 | |
177 | asv.find(s: foo_asv(asv2)) != absl::string_view::npos; |
178 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use absl::StrContains instead of |
179 | // CHECK-FIXES: {{^[[:space:]]*}}absl::StrContains(asv, foo_asv(asv2));{{$}} |
180 | |
181 | foo_asv(bar_asv()).find(s: foo_asv(asv2)) != absl::string_view::npos; |
182 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use absl::StrContains instead of |
183 | // CHECK-FIXES: {{^[[:space:]]*}}absl::StrContains(foo_asv(bar_asv()), foo_asv(asv2));{{$}} |
184 | } |
185 | |
186 | // Confirms that it works with string literal, char* and const char* parameters. |
187 | void string_literal_and_char_ptr_tests() { |
188 | char *c = nullptr; |
189 | const char *cc = nullptr; |
190 | |
191 | std::string ss; |
192 | ss.find(s: "c" ) == std::string::npos; |
193 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use !absl::StrContains instead of |
194 | // CHECK-FIXES: {{^[[:space:]]*}}!absl::StrContains(ss, "c");{{$}} |
195 | |
196 | ss.find(s: c) == std::string::npos; |
197 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use !absl::StrContains instead of |
198 | // CHECK-FIXES: {{^[[:space:]]*}}!absl::StrContains(ss, c);{{$}} |
199 | |
200 | ss.find(s: cc) == std::string::npos; |
201 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use !absl::StrContains instead of |
202 | // CHECK-FIXES: {{^[[:space:]]*}}!absl::StrContains(ss, cc);{{$}} |
203 | |
204 | std::string_view ssv; |
205 | ssv.find(s: "c" ) == std::string_view::npos; |
206 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use !absl::StrContains instead of |
207 | // CHECK-FIXES: {{^[[:space:]]*}}!absl::StrContains(ssv, "c");{{$}} |
208 | |
209 | ssv.find(s: c) == std::string_view::npos; |
210 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use !absl::StrContains instead of |
211 | // CHECK-FIXES: {{^[[:space:]]*}}!absl::StrContains(ssv, c);{{$}} |
212 | |
213 | ssv.find(s: cc) == std::string_view::npos; |
214 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use !absl::StrContains instead of |
215 | // CHECK-FIXES: {{^[[:space:]]*}}!absl::StrContains(ssv, cc);{{$}} |
216 | |
217 | absl::string_view asv; |
218 | asv.find(s: "c" ) == absl::string_view::npos; |
219 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use !absl::StrContains instead of |
220 | // CHECK-FIXES: {{^[[:space:]]*}}!absl::StrContains(asv, "c");{{$}} |
221 | |
222 | asv.find(s: c) == absl::string_view::npos; |
223 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use !absl::StrContains instead of |
224 | // CHECK-FIXES: {{^[[:space:]]*}}!absl::StrContains(asv, c);{{$}} |
225 | |
226 | asv.find(s: cc) == absl::string_view::npos; |
227 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use !absl::StrContains instead of |
228 | // CHECK-FIXES: {{^[[:space:]]*}}!absl::StrContains(asv, cc);{{$}} |
229 | } |
230 | |
231 | void char_param_tests() { |
232 | std::string ss; |
233 | ss.find(c: 'c') == std::string::npos; |
234 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use !absl::StrContains instead of |
235 | // CHECK-FIXES: {{^[[:space:]]*}}!absl::StrContains(ss, 'c');{{$}} |
236 | |
237 | std::string_view ssv; |
238 | ssv.find(c: 'c') == std::string_view::npos; |
239 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use !absl::StrContains instead of |
240 | // CHECK-FIXES: {{^[[:space:]]*}}!absl::StrContains(ssv, 'c');{{$}} |
241 | |
242 | absl::string_view asv; |
243 | asv.find(c: 'c') == absl::string_view::npos; |
244 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use !absl::StrContains instead of |
245 | // CHECK-FIXES: {{^[[:space:]]*}}!absl::StrContains(asv, 'c');{{$}} |
246 | } |
247 | |
248 | #define FOO(a, b, c, d) ((a).find(b) == std::string::npos ? (c) : (d)) |
249 | |
250 | // Confirms that it does not match when a macro would be "torn" by the fix. |
251 | void no_tearing_macros() { |
252 | std::string h = "helo" ; |
253 | FOO(h, "x" , 5, 6); |
254 | } |
255 | |
256 | // Confirms that it does not match when the pos parameter is non-zero. |
257 | void no_nonzero_pos() { |
258 | std::string ss; |
259 | ss.find(s: "a" , pos: 1) == std::string::npos; |
260 | |
261 | std::string_view ssv; |
262 | ssv.find(s: "a" , pos: 2) == std::string_view::npos; |
263 | |
264 | absl::string_view asv; |
265 | asv.find(s: "a" , pos: 3) == std::string_view::npos; |
266 | } |
267 | |
268 | // Confirms that it does not match when the count parameter is present. |
269 | void no_count() { |
270 | std::string ss; |
271 | ss.find(s: "a" , pos: 0, n: 1) == std::string::npos; |
272 | |
273 | std::string_view ssv; |
274 | ssv.find(s: "a" , pos: 0, n: 1) == std::string_view::npos; |
275 | |
276 | absl::string_view asv; |
277 | asv.find(s: "a" , pos: 0, n: 1) == std::string_view::npos; |
278 | } |
279 | |
280 | // Confirms that it does not match when it's compared to something other than |
281 | // npos, even if the value is the same as npos. |
282 | void no_non_npos() { |
283 | std::string ss; |
284 | ss.find(s: "a" ) == 0; |
285 | ss.find(s: "a" ) == 1; |
286 | ss.find(s: "a" ) == -1; |
287 | |
288 | std::string_view ssv; |
289 | ssv.find(s: "a" ) == 0; |
290 | ssv.find(s: "a" ) == 1; |
291 | ssv.find(s: "a" ) == -1; |
292 | |
293 | absl::string_view asv; |
294 | asv.find(s: "a" ) == 0; |
295 | asv.find(s: "a" ) == 1; |
296 | asv.find(s: "a" ) == -1; |
297 | } |
298 | |
299 | // Confirms that it does not match if the two operands are the same. |
300 | void no_symmetric_operands() { |
301 | std::string ss; |
302 | ss.find(s: "a" ) == ss.find(s: "a" ); |
303 | std::string::npos == std::string::npos; |
304 | } |
305 | |