305 lines · cpp
1// RUN: %check_clang_tidy %s abseil-string-find-str-contains %t --2 3using size_t = decltype(sizeof(int));4 5namespace std {6 7// Lightweight standin for std::string.8template <typename C>9class basic_string {10public: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};21typedef basic_string<char> string;22 23// Lightweight standin for std::string_view.24template <typename C>25class basic_string_view {26public: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};37typedef basic_string_view<char> string_view;38 39} // namespace std40 41namespace absl {42 43// Lightweight standin for absl::string_view.44class string_view {45public: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 absl58 59// Functions that take and return our various string-like types.60std::string foo_ss(std::string);61std::string_view foo_ssv(std::string_view);62absl::string_view foo_asv(absl::string_view);63std::string bar_ss();64std::string_view bar_ssv();65absl::string_view bar_asv();66 67// Confirms that find==npos and find!=npos work for each supported type, when68// npos comes from the correct type.69void basic_tests() {70 std::string ss;71 ss.find("a") == std::string::npos;72 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use !absl::StrContains instead of find() == npos73 // CHECK-FIXES: !absl::StrContains(ss, "a");74 75 ss.find("a") != std::string::npos;76 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use absl::StrContains instead of find() != npos77 // CHECK-FIXES: absl::StrContains(ss, "a");78 79 std::string::npos != ss.find("a");80 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use absl::StrContains instead of81 // CHECK-FIXES: absl::StrContains(ss, "a");82 83 std::string_view ssv;84 ssv.find("a") == std::string_view::npos;85 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use !absl::StrContains instead of86 // CHECK-FIXES: !absl::StrContains(ssv, "a");87 88 ssv.find("a") != std::string_view::npos;89 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use absl::StrContains instead of90 // CHECK-FIXES: absl::StrContains(ssv, "a");91 92 std::string_view::npos != ssv.find("a");93 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use absl::StrContains instead of94 // CHECK-FIXES: absl::StrContains(ssv, "a");95 96 absl::string_view asv;97 asv.find("a") == absl::string_view::npos;98 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use !absl::StrContains instead of99 // CHECK-FIXES: !absl::StrContains(asv, "a");100 101 asv.find("a") != absl::string_view::npos;102 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use absl::StrContains instead of103 // CHECK-FIXES: absl::StrContains(asv, "a");104 105 absl::string_view::npos != asv.find("a");106 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use absl::StrContains instead of107 // CHECK-FIXES: absl::StrContains(asv, "a");108}109 110// Confirms that it works even if you mix-and-match the type for find and for111// npos. (One of the reasons for this checker is to clean up cases that112// accidentally mix-and-match like this. absl::StrContains is less113// error-prone.)114void mismatched_npos() {115 std::string ss;116 ss.find("a") == std::string_view::npos;117 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use !absl::StrContains instead of118 // CHECK-FIXES: !absl::StrContains(ss, "a");119 120 ss.find("a") != absl::string_view::npos;121 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use absl::StrContains instead of122 // CHECK-FIXES: absl::StrContains(ss, "a");123 124 std::string_view ssv;125 ssv.find("a") == absl::string_view::npos;126 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use !absl::StrContains instead of127 // CHECK-FIXES: !absl::StrContains(ssv, "a");128 129 ssv.find("a") != std::string::npos;130 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use absl::StrContains instead of131 // CHECK-FIXES: absl::StrContains(ssv, "a");132 133 absl::string_view asv;134 asv.find("a") == std::string::npos;135 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use !absl::StrContains instead of136 // CHECK-FIXES: !absl::StrContains(asv, "a");137 138 asv.find("a") != std::string_view::npos;139 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use absl::StrContains instead of140 // CHECK-FIXES: absl::StrContains(asv, "a");141}142 143// Confirms that it works even when the needle or the haystack are more144// complicated expressions.145void subexpression_tests() {146 std::string ss, ss2;147 foo_ss(ss).find(ss2) == std::string::npos;148 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use !absl::StrContains instead of149 // CHECK-FIXES: !absl::StrContains(foo_ss(ss), ss2);150 151 ss.find(foo_ss(ss2)) != std::string::npos;152 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use absl::StrContains instead of153 // CHECK-FIXES: absl::StrContains(ss, foo_ss(ss2));154 155 foo_ss(bar_ss()).find(foo_ss(ss2)) != std::string::npos;156 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use absl::StrContains instead of157 // CHECK-FIXES: absl::StrContains(foo_ss(bar_ss()), foo_ss(ss2));158 159 std::string_view ssv, ssv2;160 foo_ssv(ssv).find(ssv2) == std::string_view::npos;161 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use !absl::StrContains instead of162 // CHECK-FIXES: !absl::StrContains(foo_ssv(ssv), ssv2);163 164 ssv.find(foo_ssv(ssv2)) != std::string_view::npos;165 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use absl::StrContains instead of166 // CHECK-FIXES: absl::StrContains(ssv, foo_ssv(ssv2));167 168 foo_ssv(bar_ssv()).find(foo_ssv(ssv2)) != std::string_view::npos;169 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use absl::StrContains instead of170 // CHECK-FIXES: absl::StrContains(foo_ssv(bar_ssv()), foo_ssv(ssv2));171 172 absl::string_view asv, asv2;173 foo_asv(asv).find(asv2) == absl::string_view::npos;174 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use !absl::StrContains instead of175 // CHECK-FIXES: !absl::StrContains(foo_asv(asv), asv2);176 177 asv.find(foo_asv(asv2)) != absl::string_view::npos;178 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use absl::StrContains instead of179 // CHECK-FIXES: absl::StrContains(asv, foo_asv(asv2));180 181 foo_asv(bar_asv()).find(foo_asv(asv2)) != absl::string_view::npos;182 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use absl::StrContains instead of183 // CHECK-FIXES: absl::StrContains(foo_asv(bar_asv()), foo_asv(asv2));184}185 186// Confirms that it works with string literal, char* and const char* parameters.187void string_literal_and_char_ptr_tests() {188 char *c = nullptr;189 const char *cc = nullptr;190 191 std::string ss;192 ss.find("c") == std::string::npos;193 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use !absl::StrContains instead of194 // CHECK-FIXES: !absl::StrContains(ss, "c");195 196 ss.find(c) == std::string::npos;197 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use !absl::StrContains instead of198 // CHECK-FIXES: !absl::StrContains(ss, c);199 200 ss.find(cc) == std::string::npos;201 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use !absl::StrContains instead of202 // CHECK-FIXES: !absl::StrContains(ss, cc);203 204 std::string_view ssv;205 ssv.find("c") == std::string_view::npos;206 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use !absl::StrContains instead of207 // CHECK-FIXES: !absl::StrContains(ssv, "c");208 209 ssv.find(c) == std::string_view::npos;210 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use !absl::StrContains instead of211 // CHECK-FIXES: !absl::StrContains(ssv, c);212 213 ssv.find(cc) == std::string_view::npos;214 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use !absl::StrContains instead of215 // CHECK-FIXES: !absl::StrContains(ssv, cc);216 217 absl::string_view asv;218 asv.find("c") == absl::string_view::npos;219 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use !absl::StrContains instead of220 // CHECK-FIXES: !absl::StrContains(asv, "c");221 222 asv.find(c) == absl::string_view::npos;223 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use !absl::StrContains instead of224 // CHECK-FIXES: !absl::StrContains(asv, c);225 226 asv.find(cc) == absl::string_view::npos;227 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use !absl::StrContains instead of228 // CHECK-FIXES: !absl::StrContains(asv, cc);229}230 231void char_param_tests() {232 std::string ss;233 ss.find('c') == std::string::npos;234 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use !absl::StrContains instead of235 // CHECK-FIXES: !absl::StrContains(ss, 'c');236 237 std::string_view ssv;238 ssv.find('c') == std::string_view::npos;239 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use !absl::StrContains instead of240 // CHECK-FIXES: !absl::StrContains(ssv, 'c');241 242 absl::string_view asv;243 asv.find('c') == absl::string_view::npos;244 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use !absl::StrContains instead of245 // CHECK-FIXES: !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.251void 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.257void no_nonzero_pos() {258 std::string ss;259 ss.find("a", 1) == std::string::npos;260 261 std::string_view ssv;262 ssv.find("a", 2) == std::string_view::npos;263 264 absl::string_view asv;265 asv.find("a", 3) == std::string_view::npos;266}267 268// Confirms that it does not match when the count parameter is present.269void no_count() {270 std::string ss;271 ss.find("a", 0, 1) == std::string::npos;272 273 std::string_view ssv;274 ssv.find("a", 0, 1) == std::string_view::npos;275 276 absl::string_view asv;277 asv.find("a", 0, 1) == std::string_view::npos;278}279 280// Confirms that it does not match when it's compared to something other than281// npos, even if the value is the same as npos.282void no_non_npos() {283 std::string ss;284 ss.find("a") == 0;285 ss.find("a") == 1;286 ss.find("a") == -1;287 288 std::string_view ssv;289 ssv.find("a") == 0;290 ssv.find("a") == 1;291 ssv.find("a") == -1;292 293 absl::string_view asv;294 asv.find("a") == 0;295 asv.find("a") == 1;296 asv.find("a") == -1;297}298 299// Confirms that it does not match if the two operands are the same.300void no_symmetric_operands() {301 std::string ss;302 ss.find("a") == ss.find("a");303 std::string::npos == std::string::npos;304}305