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