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: [{key: performance-faster-string-find.StringLikeClasses, \
5 // RUN: value: '::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
StringFind()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 // Doens'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 // Other methods that can also be replaced
67 Str.rfind("a");
68 // CHECK-MESSAGES: [[@LINE-1]]:13: warning: 'rfind' called with a string literal
69 // CHECK-FIXES: Str.rfind('a');
70 Str.find_first_of("a");
71 // CHECK-MESSAGES: [[@LINE-1]]:21: warning: 'find_first_of' called with a string
72 // CHECK-FIXES: Str.find_first_of('a');
73 Str.find_first_not_of("a");
74 // CHECK-MESSAGES: [[@LINE-1]]:25: warning: 'find_first_not_of' called with a
75 // CHECK-FIXES: Str.find_first_not_of('a');
76 Str.find_last_of("a");
77 // CHECK-MESSAGES: [[@LINE-1]]:20: warning: 'find_last_of' called with a string
78 // CHECK-FIXES: Str.find_last_of('a');
79 Str.find_last_not_of("a");
80 // CHECK-MESSAGES: [[@LINE-1]]:24: warning: 'find_last_not_of' called with a
81 // CHECK-FIXES: Str.find_last_not_of('a');
82
83 // std::wstring should work.
84 std::wstring WStr;
85 WStr.find(L"n");
86 // CHECK-MESSAGES: [[@LINE-1]]:13: warning: 'find' called with a string literal
87 // CHECK-FIXES: Str.find(L'n');
88 // Even with unicode that fits in one wide char.
89 WStr.find(L"\x3A9");
90 // CHECK-MESSAGES: [[@LINE-1]]:13: warning: 'find' called with a string literal
91 // CHECK-FIXES: Str.find(L'\x3A9');
92
93 // std::string_view and std::wstring_view should work.
94 std::string_view StrView;
95 StrView.find("n");
96 // CHECK-MESSAGES: [[@LINE-1]]:16: warning: 'find' called with a string literal
97 // CHECK-FIXES: StrView.find('n');
98 std::wstring_view WStrView;
99
100 WStrView.find(L"n");
101 // CHECK-MESSAGES: [[@LINE-1]]:17: warning: 'find' called with a string literal
102 // CHECK-FIXES: WStrView.find(L'n');
103 WStrView.find(L"\x3A9");
104 // CHECK-MESSAGES: [[@LINE-1]]:17: warning: 'find' called with a string literal
105 // CHECK-FIXES: WStrView.find(L'\x3A9');
106
107 // Also with other types, but only if it was specified in the options.
108 llvm::StringRef sr;
109 sr.find("x");
110 // CHECK-MESSAGES-CUSTOM: [[@LINE-1]]:11: warning: 'find' called with a string literal
111 // CHECK-FIXES-CUSTOM: sr.find('x');
112 NotStringRef nsr;
113 nsr.find("x");
114 }
115
116
117 template <typename T>
FindTemplateDependant(T value)118 int FindTemplateDependant(T value) {
119 return value.find("A");
120 }
121 template <typename T>
FindTemplateNotDependant(T pos)122 int FindTemplateNotDependant(T pos) {
123 return std::string().find("A", pos);
124 // CHECK-MESSAGES: [[@LINE-1]]:29: warning: 'find' called with a string literal
125 // CHECK-FIXES: return std::string().find('A', pos);
126 }
127
FindStr()128 int FindStr() {
129 return FindTemplateDependant(std::string()) + FindTemplateNotDependant(1);
130 }
131
132 #define STR_MACRO(str) str.find("A")
133 #define POS_MACRO(pos) std::string().find("A",pos)
134
Macros()135 int Macros() {
136 return STR_MACRO(std::string()) + POS_MACRO(1);
137 // CHECK-MESSAGES: [[@LINE-1]]:10: warning: 'find' called with a string literal
138 // CHECK-MESSAGES: [[@LINE-2]]:37: warning: 'find' called with a string literal
139 }
140