1 | // RUN: %check_clang_tidy %s performance-faster-string-find %t |
2 | // RUN: %check_clang_tidy -check-suffix=CUSTOM %s performance-faster-string-find %t -- \ |
3 | // RUN: -config="{CheckOptions: \ |
4 | // RUN: {performance-faster-string-find.StringLikeClasses: \ |
5 | // RUN: '::llvm::StringRef;'}}" |
6 | |
7 | namespace std { |
8 | template <typename Char> |
9 | struct basic_string { |
10 | int find(const Char *, int = 0) const; |
11 | int find(const Char *, int, int) const; |
12 | int rfind(const Char *) const; |
13 | int find_first_of(const Char *) const; |
14 | int find_first_not_of(const Char *) const; |
15 | int find_last_of(const Char *) const; |
16 | int find_last_not_of(const Char *) const; |
17 | }; |
18 | |
19 | typedef basic_string<char> string; |
20 | typedef basic_string<wchar_t> wstring; |
21 | |
22 | template <typename Char> |
23 | struct basic_string_view { |
24 | int find(const Char *, int = 0) const; |
25 | int find(const Char *, int, int) const; |
26 | int rfind(const Char *) const; |
27 | int find_first_of(const Char *) const; |
28 | int find_first_not_of(const Char *) const; |
29 | int find_last_of(const Char *) const; |
30 | int find_last_not_of(const Char *) const; |
31 | }; |
32 | |
33 | typedef basic_string_view<char> string_view; |
34 | typedef basic_string_view<wchar_t> wstring_view; |
35 | } // namespace std |
36 | |
37 | namespace llvm { |
38 | struct StringRef { |
39 | int find(const char *) const; |
40 | }; |
41 | } // namespace llvm |
42 | |
43 | struct NotStringRef { |
44 | int find(const char *); |
45 | }; |
46 | |
47 | void StringFind() { |
48 | std::string Str; |
49 | |
50 | Str.find("a" ); |
51 | // CHECK-MESSAGES: [[@LINE-1]]:12: warning: 'find' called with a string literal consisting of a single character; consider using the more effective overload accepting a character [performance-faster-string-find] |
52 | // CHECK-FIXES: Str.find('a'); |
53 | |
54 | // Works with the pos argument. |
55 | Str.find("a" , 1); |
56 | // CHECK-MESSAGES: [[@LINE-1]]:12: warning: 'find' called with a string literal |
57 | // CHECK-FIXES: Str.find('a', 1); |
58 | |
59 | // Doesn't work with strings smaller or larger than 1 char. |
60 | Str.find("" ); |
61 | Str.find("ab" ); |
62 | |
63 | // Doesn't do anything with the 3 argument overload. |
64 | Str.find("a" , 1, 1); |
65 | |
66 | // Single quotes are escaped properly |
67 | Str.find("'" ); |
68 | // CHECK-MESSAGES: [[@LINE-1]]:12: warning: 'find' called with a string literal |
69 | // CHECK-FIXES: Str.find('\''); |
70 | Str.find("\'" ); |
71 | // CHECK-MESSAGES: [[@LINE-1]]:12: warning: 'find' called with a string literal |
72 | // CHECK-FIXES: Str.find('\''); |
73 | |
74 | // Other methods that can also be replaced |
75 | Str.rfind("a" ); |
76 | // CHECK-MESSAGES: [[@LINE-1]]:13: warning: 'rfind' called with a string literal |
77 | // CHECK-FIXES: Str.rfind('a'); |
78 | Str.find_first_of("a" ); |
79 | // CHECK-MESSAGES: [[@LINE-1]]:21: warning: 'find_first_of' called with a string |
80 | // CHECK-FIXES: Str.find_first_of('a'); |
81 | Str.find_first_not_of("a" ); |
82 | // CHECK-MESSAGES: [[@LINE-1]]:25: warning: 'find_first_not_of' called with a |
83 | // CHECK-FIXES: Str.find_first_not_of('a'); |
84 | Str.find_last_of("a" ); |
85 | // CHECK-MESSAGES: [[@LINE-1]]:20: warning: 'find_last_of' called with a string |
86 | // CHECK-FIXES: Str.find_last_of('a'); |
87 | Str.find_last_not_of("a" ); |
88 | // CHECK-MESSAGES: [[@LINE-1]]:24: warning: 'find_last_not_of' called with a |
89 | // CHECK-FIXES: Str.find_last_not_of('a'); |
90 | |
91 | // std::wstring should work. |
92 | std::wstring WStr; |
93 | WStr.find(L"n" ); |
94 | // CHECK-MESSAGES: [[@LINE-1]]:13: warning: 'find' called with a string literal |
95 | // CHECK-FIXES: Str.find(L'n'); |
96 | // Even with unicode that fits in one wide char. |
97 | WStr.find(L"\x3A9" ); |
98 | // CHECK-MESSAGES: [[@LINE-1]]:13: warning: 'find' called with a string literal |
99 | // CHECK-FIXES: Str.find(L'\x3A9'); |
100 | |
101 | // std::string_view and std::wstring_view should work. |
102 | std::string_view StrView; |
103 | StrView.find("n" ); |
104 | // CHECK-MESSAGES: [[@LINE-1]]:16: warning: 'find' called with a string literal |
105 | // CHECK-FIXES: StrView.find('n'); |
106 | std::wstring_view WStrView; |
107 | |
108 | WStrView.find(L"n" ); |
109 | // CHECK-MESSAGES: [[@LINE-1]]:17: warning: 'find' called with a string literal |
110 | // CHECK-FIXES: WStrView.find(L'n'); |
111 | WStrView.find(L"\x3A9" ); |
112 | // CHECK-MESSAGES: [[@LINE-1]]:17: warning: 'find' called with a string literal |
113 | // CHECK-FIXES: WStrView.find(L'\x3A9'); |
114 | |
115 | // Also with other types, but only if it was specified in the options. |
116 | llvm::StringRef sr; |
117 | sr.find("x" ); |
118 | // CHECK-MESSAGES-CUSTOM: [[@LINE-1]]:11: warning: 'find' called with a string literal |
119 | // CHECK-FIXES-CUSTOM: sr.find('x'); |
120 | NotStringRef nsr; |
121 | nsr.find("x" ); |
122 | } |
123 | |
124 | |
125 | template <typename T> |
126 | int FindTemplateDependant(T value) { |
127 | return value.find("A" ); |
128 | } |
129 | template <typename T> |
130 | int FindTemplateNotDependant(T pos) { |
131 | return std::string().find("A" , pos); |
132 | // CHECK-MESSAGES: [[@LINE-1]]:29: warning: 'find' called with a string literal |
133 | // CHECK-FIXES: return std::string().find('A', pos); |
134 | } |
135 | |
136 | int FindStr() { |
137 | return FindTemplateDependant(value: std::string()) + FindTemplateNotDependant(pos: 1); |
138 | } |
139 | |
140 | #define STR_MACRO(str) str.find("A") |
141 | #define POS_MACRO(pos) std::string().find("A",pos) |
142 | |
143 | int Macros() { |
144 | return STR_MACRO(std::string()) + POS_MACRO(1); |
145 | // CHECK-MESSAGES: [[@LINE-1]]:10: warning: 'find' called with a string literal |
146 | // CHECK-MESSAGES: [[@LINE-2]]:37: warning: 'find' called with a string literal |
147 | } |
148 | |