1 // RUN: %check_clang_tidy -std=c++17 %s abseil-string-find-startswith %t -- \
2 // RUN: -config="{CheckOptions: \
3 // RUN: {abseil-string-find-startswith.StringLikeClasses: \
4 // RUN: '::std::basic_string;::std::basic_string_view;::basic_string'}}" \
5 // RUN: -- -isystem %clang_tidy_headers
6
7 #include <string>
8
9 using size_t = decltype(sizeof(int));
10
11 namespace std {
12 struct cxx_string {
13 int find(const char *s, int pos = 0);
14 int rfind(const char *s, int pos = npos);
15 static constexpr size_t npos = -1;
16 };
17 } // namespace std
18
19 struct basic_string : public std::cxx_string {
20 basic_string();
21 };
22 typedef basic_string global_string;
23
24 std::string foo(std::string);
25 std::string bar();
26
27 #define A_MACRO(x, y) ((x) == (y))
28
tests(std::string s,global_string s2,std::string_view sv)29 void tests(std::string s, global_string s2, std::string_view sv) {
30 s.find("a") == 0;
31 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use absl::StartsWith instead of find() == 0 [abseil-string-find-startswith]
32 // CHECK-FIXES: {{^[[:space:]]*}}absl::StartsWith(s, "a");{{$}}
33
34 s.find(s) == 0;
35 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use absl::StartsWith
36 // CHECK-FIXES: {{^[[:space:]]*}}absl::StartsWith(s, s);{{$}}
37
38 s.find("aaa") != 0;
39 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use !absl::StartsWith
40 // CHECK-FIXES: {{^[[:space:]]*}}!absl::StartsWith(s, "aaa");{{$}}
41
42 s.find(foo(foo(bar()))) != 0;
43 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use !absl::StartsWith
44 // CHECK-FIXES: {{^[[:space:]]*}}!absl::StartsWith(s, foo(foo(bar())));{{$}}
45
46 if (s.find("....") == 0) { /* do something */ }
47 // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use absl::StartsWith
48 // CHECK-FIXES: {{^[[:space:]]*}}if (absl::StartsWith(s, "....")) { /* do something */ }{{$}}
49
50 0 != s.find("a");
51 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use !absl::StartsWith
52 // CHECK-FIXES: {{^[[:space:]]*}}!absl::StartsWith(s, "a");{{$}}
53
54 s2.find("a") == 0;
55 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use absl::StartsWith
56 // CHECK-FIXES: {{^[[:space:]]*}}absl::StartsWith(s2, "a");{{$}}
57
58 s.rfind("a", 0) == 0;
59 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use absl::StartsWith instead of rfind() == 0 [abseil-string-find-startswith]
60 // CHECK-FIXES: {{^[[:space:]]*}}absl::StartsWith(s, "a");{{$}}
61
62 s.rfind(s, 0) == 0;
63 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use absl::StartsWith
64 // CHECK-FIXES: {{^[[:space:]]*}}absl::StartsWith(s, s);{{$}}
65
66 s.rfind("aaa", 0) != 0;
67 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use !absl::StartsWith
68 // CHECK-FIXES: {{^[[:space:]]*}}!absl::StartsWith(s, "aaa");{{$}}
69
70 s.rfind(foo(foo(bar())), 0) != 0;
71 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use !absl::StartsWith
72 // CHECK-FIXES: {{^[[:space:]]*}}!absl::StartsWith(s, foo(foo(bar())));{{$}}
73
74 if (s.rfind("....", 0) == 0) { /* do something */ }
75 // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use absl::StartsWith
76 // CHECK-FIXES: {{^[[:space:]]*}}if (absl::StartsWith(s, "....")) { /* do something */ }{{$}}
77
78 0 != s.rfind("a", 0);
79 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use !absl::StartsWith
80 // CHECK-FIXES: {{^[[:space:]]*}}!absl::StartsWith(s, "a");{{$}}
81
82 s2.rfind("a", 0) == 0;
83 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use absl::StartsWith
84 // CHECK-FIXES: {{^[[:space:]]*}}absl::StartsWith(s2, "a");{{$}}
85
86 sv.find("a") == 0;
87 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use absl::StartsWith
88 // CHECK-FIXES: {{^[[:space:]]*}}absl::StartsWith(sv, "a");{{$}}
89
90 sv.rfind("a", 0) != 0;
91 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use !absl::StartsWith
92 // CHECK-FIXES: {{^[[:space:]]*}}!absl::StartsWith(sv, "a");{{$}}
93
94 // expressions that don't trigger the check are here.
95 A_MACRO(s.find("a"), 0);
96 A_MACRO(s.rfind("a", 0), 0);
97 s.find("a", 1) == 0;
98 s.find("a", 1) == 1;
99 s.find("a") == 1;
100 s.rfind("a", 1) == 0;
101 s.rfind("a", 1) == 1;
102 s.rfind("a") == 0;
103 s.rfind("a") == 1;
104 }
105