1// RUN: %check_clang_tidy -std=c++20 %s modernize-use-starts-ends-with %t -- \
2// RUN: -- -isystem %clang_tidy_headers
3
4#include <string.h>
5#include <string>
6
7std::string foo(std::string);
8std::string bar();
9
10class sub_string : public std::string {};
11class sub_sub_string : public sub_string {};
12
13struct string_like {
14 bool starts_with(const char *s) const;
15 size_t find(const char *s, size_t pos = 0) const;
16};
17
18struct string_like_camel {
19 bool startsWith(const char *s) const;
20 size_t find(const char *s, size_t pos = 0) const;
21};
22
23struct prefer_underscore_version {
24 bool starts_with(const char *s) const;
25 bool startsWith(const char *s) const;
26 size_t find(const char *s, size_t pos = 0) const;
27};
28
29struct prefer_underscore_version_flip {
30 bool startsWith(const char *s) const;
31 bool starts_with(const char *s) const;
32 size_t find(const char *s, size_t pos = 0) const;
33};
34
35struct prefer_underscore_version_inherit : public string_like {
36 bool startsWith(const char *s) const;
37};
38
39void test(std::string s, std::string_view sv, sub_string ss, sub_sub_string sss,
40 string_like sl, string_like_camel slc, prefer_underscore_version puv,
41 prefer_underscore_version_flip puvf,
42 prefer_underscore_version_inherit puvi) {
43 s.find(s: "a") == 0;
44 // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use starts_with instead of find() == 0
45 // CHECK-FIXES: s.starts_with("a");
46
47 (((((s)).find(s: "a")))) == ((0));
48 // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use starts_with
49 // CHECK-FIXES: ((s)).starts_with("a");
50
51 (s + "a").find(s: "a") == ((0));
52 // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use starts_with
53 // CHECK-FIXES: (s + "a").starts_with("a");
54
55 s.find(str: s) == 0;
56 // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use starts_with
57 // CHECK-FIXES: s.starts_with(s);
58
59 s.find(s: "aaa") != 0;
60 // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use starts_with
61 // CHECK-FIXES: !s.starts_with("aaa");
62
63 s.find(str: foo(foo(bar()))) != 0;
64 // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use starts_with
65 // CHECK-FIXES: !s.starts_with(foo(foo(bar())));
66
67 if (s.find(s: "....") == 0) { /* do something */ }
68 // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use starts_with
69 // CHECK-FIXES: if (s.starts_with("...."))
70
71 0 != s.find(s: "a");
72 // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use starts_with
73 // CHECK-FIXES: !s.starts_with("a");
74
75 s.rfind(s: "a", pos: 0) == 0;
76 // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use starts_with instead of rfind() == 0
77 // CHECK-FIXES: s.starts_with("a");
78
79 s.rfind(str: s, pos: 0) == 0;
80 // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use starts_with
81 // CHECK-FIXES: s.starts_with(s);
82
83 s.rfind(s: "aaa", pos: 0) != 0;
84 // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use starts_with
85 // CHECK-FIXES: !s.starts_with("aaa");
86
87 s.rfind(str: foo(foo(bar())), pos: 0) != 0;
88 // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use starts_with
89 // CHECK-FIXES: !s.starts_with(foo(foo(bar())));
90
91 if (s.rfind(s: "....", pos: 0) == 0) { /* do something */ }
92 // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use starts_with
93 // CHECK-FIXES: if (s.starts_with("...."))
94
95 0 != s.rfind(s: "a", pos: 0);
96 // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use starts_with
97 // CHECK-FIXES: !s.starts_with("a");
98
99 #define STR(x) std::string(x)
100 0 == STR(s).find(s: "a");
101 // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use starts_with
102 // CHECK-FIXES: STR(s).starts_with("a");
103
104 #define STRING s
105 if (0 == STRING.find(s: "ala")) { /* do something */}
106 // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use starts_with
107 // CHECK-FIXES: if (STRING.starts_with("ala"))
108
109 #define FIND find
110 s.FIND(s: "a") == 0;
111 // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use starts_with
112 // CHECK-FIXES: s.starts_with("a")
113
114 #define PREFIX "a"
115 s.find(PREFIX) == 0;
116 // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use starts_with
117 // CHECK-FIXES: s.starts_with(PREFIX)
118
119 #define ZERO 0
120 s.find(s: "a") == ZERO;
121 // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use starts_with
122 // CHECK-FIXES: s.starts_with("a")
123
124 sv.find(str: "a") == 0;
125 // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use starts_with
126 // CHECK-FIXES: sv.starts_with("a");
127
128 sv.rfind(str: "a", pos: 0) != 0;
129 // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use starts_with
130 // CHECK-FIXES: !sv.starts_with("a");
131
132 ss.find(s: "a") == 0;
133 // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use starts_with
134 // CHECK-FIXES: ss.starts_with("a");
135
136 sss.find(s: "a") == 0;
137 // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use starts_with
138 // CHECK-FIXES: ss.starts_with("a");
139
140 sl.find(s: "a") == 0;
141 // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use starts_with
142 // CHECK-FIXES: sl.starts_with("a");
143
144 slc.find(s: "a") == 0;
145 // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use startsWith
146 // CHECK-FIXES: slc.startsWith("a");
147
148 puv.find(s: "a") == 0;
149 // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use starts_with
150 // CHECK-FIXES: puv.starts_with("a");
151
152 puvf.find(s: "a") == 0;
153 // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use starts_with
154 // CHECK-FIXES: puvf.starts_with("a");
155
156 // Here, the subclass has startsWith, the superclass has starts_with.
157 // We prefer the version from the subclass.
158 puvi.find(s: "a") == 0;
159 // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use startsWith
160 // CHECK-FIXES: puvi.startsWith("a");
161
162 s.compare(pos: 0, n1: 1, s: "a") == 0;
163 // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use starts_with instead of compare() == 0
164 // CHECK-FIXES: s.starts_with("a");
165
166 s.compare(pos: 0, n1: 1, s: "a") != 0;
167 // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use starts_with instead of compare() != 0
168 // CHECK-FIXES: !s.starts_with("a");
169
170 s.compare(pos: 0, n1: strlen(s: "a"), s: "a") == 0;
171 // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use starts_with
172 // CHECK-FIXES: s.starts_with("a");
173
174 s.compare(pos: 0, std::n1: strlen(s: "a"), s: "a") == 0;
175 // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use starts_with
176 // CHECK-FIXES: s.starts_with("a");
177
178 s.compare(pos: 0, std::n1: strlen(s: ("a")), s: "a") == 0;
179 // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use starts_with
180 // CHECK-FIXES: s.starts_with("a");
181
182 s.compare(pos: 0, std::n1: strlen(s: ("a")), s: (("a"))) == 0;
183 // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use starts_with
184 // CHECK-FIXES: s.starts_with("a");
185
186 s.compare(pos: 0, n: s.size(), str: s) == 0;
187 // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use starts_with
188 // CHECK-FIXES: s.starts_with(s);
189
190 s.compare(pos: 0, n: s.length(), str: s) == 0;
191 // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use starts_with
192 // CHECK-FIXES: s.starts_with(s);
193
194 0 != s.compare(pos: 0, n: sv.length(), svt: sv);
195 // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use starts_with
196 // CHECK-FIXES: s.starts_with(sv);
197
198 #define LENGTH(x) (x).length()
199 s.compare(pos: 0, LENGTH(s), str: s) == 0;
200 // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use starts_with
201 // CHECK-FIXES: s.starts_with(s);
202
203 s.compare(ZERO, LENGTH(s), str: s) == ZERO;
204 // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use starts_with
205 // CHECK-FIXES: s.starts_with(s);
206
207 s.compare(ZERO, LENGTH(sv), svt: sv) != 0;
208 // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use starts_with
209 // CHECK-FIXES: !s.starts_with(sv);
210
211 // Expressions that don't trigger the check are here.
212 #define EQ(x, y) ((x) == (y))
213 EQ(s.find("a"), 0);
214
215 #define DOTFIND(x, y) (x).find(y)
216 DOTFIND(s, "a") == 0;
217
218 #define STARTS_WITH_COMPARE(x, y) (x).compare(0, (x).size(), (y))
219 STARTS_WITH_COMPARE(s, s) == 0;
220
221 s.compare(pos: 0, n1: 1, s: "ab") == 0;
222}
223

source code of clang-tools-extra/test/clang-tidy/checkers/modernize/use-starts-ends-with.cpp