1 // RUN: %check_clang_tidy %s performance-faster-string-find %t -- \
2 // RUN:   -config="{CheckOptions: \
3 // RUN:             [{key: performance-faster-string-find.StringLikeClasses, \
4 // RUN:               value: 'std::basic_string; ::llvm::StringRef;'}]}" --
5 
6 namespace std {
7 template <typename Char>
8 struct basic_string {
9   int find(const Char *, int = 0) const;
10   int find(const Char *, int, int) const;
11   int rfind(const Char *) const;
12   int find_first_of(const Char *) const;
13   int find_first_not_of(const Char *) const;
14   int find_last_of(const Char *) const;
15   int find_last_not_of(const Char *) const;
16 };
17 
18 typedef basic_string<char> string;
19 typedef basic_string<wchar_t> wstring;
20 }  // namespace std
21 
22 namespace llvm {
23 struct StringRef {
24   int find(const char *) const;
25 };
26 }  // namespace llvm
27 
28 struct NotStringRef {
29   int find(const char *);
30 };
31 
StringFind()32 void StringFind() {
33   std::string Str;
34 
35   Str.find("a");
36   // 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]
37   // CHECK-FIXES: Str.find('a');
38 
39   // Works with the pos argument.
40   Str.find("a", 1);
41   // CHECK-MESSAGES: [[@LINE-1]]:12: warning: 'find' called with a string literal
42   // CHECK-FIXES: Str.find('a', 1);
43 
44   // Doens't work with strings smaller or larger than 1 char.
45   Str.find("");
46   Str.find("ab");
47 
48   // Doesn't do anything with the 3 argument overload.
49   Str.find("a", 1, 1);
50 
51   // Other methods that can also be replaced
52   Str.rfind("a");
53   // CHECK-MESSAGES: [[@LINE-1]]:13: warning: 'rfind' called with a string literal
54   // CHECK-FIXES: Str.rfind('a');
55   Str.find_first_of("a");
56   // CHECK-MESSAGES: [[@LINE-1]]:21: warning: 'find_first_of' called with a string
57   // CHECK-FIXES: Str.find_first_of('a');
58   Str.find_first_not_of("a");
59   // CHECK-MESSAGES: [[@LINE-1]]:25: warning: 'find_first_not_of' called with a
60   // CHECK-FIXES: Str.find_first_not_of('a');
61   Str.find_last_of("a");
62   // CHECK-MESSAGES: [[@LINE-1]]:20: warning: 'find_last_of' called with a string
63   // CHECK-FIXES: Str.find_last_of('a');
64   Str.find_last_not_of("a");
65   // CHECK-MESSAGES: [[@LINE-1]]:24: warning: 'find_last_not_of' called with a
66   // CHECK-FIXES: Str.find_last_not_of('a');
67 
68   // std::wstring should work.
69   std::wstring WStr;
70   WStr.find(L"n");
71   // CHECK-MESSAGES: [[@LINE-1]]:13: warning: 'find' called with a string literal
72   // CHECK-FIXES: Str.find(L'n');
73   // Even with unicode that fits in one wide char.
74   WStr.find(L"\x3A9");
75   // CHECK-MESSAGES: [[@LINE-1]]:13: warning: 'find' called with a string literal
76   // CHECK-FIXES: Str.find(L'\x3A9');
77 
78   // Also with other types, but only if it was specified in the options.
79   llvm::StringRef sr;
80   sr.find("x");
81   // CHECK-MESSAGES: [[@LINE-1]]:11: warning: 'find' called with a string literal
82   // CHECK-FIXES: sr.find('x');
83   NotStringRef nsr;
84   nsr.find("x");
85 }
86 
87 
88 template <typename T>
FindTemplateDependant(T value)89 int FindTemplateDependant(T value) {
90   return value.find("A");
91 }
92 template <typename T>
FindTemplateNotDependant(T pos)93 int FindTemplateNotDependant(T pos) {
94   return std::string().find("A", pos);
95   // CHECK-MESSAGES: [[@LINE-1]]:29: warning: 'find' called with a string literal
96   // CHECK-FIXES: return std::string().find('A', pos);
97 }
98 
FindStr()99 int FindStr() {
100   return FindTemplateDependant(std::string()) + FindTemplateNotDependant(1);
101 }
102 
103 #define STR_MACRO(str) str.find("A")
104 #define POS_MACRO(pos) std::string().find("A",pos)
105 
Macros()106 int Macros() {
107   return STR_MACRO(std::string()) + POS_MACRO(1);
108   // CHECK-MESSAGES: [[@LINE-1]]:10: warning: 'find' called with a string literal
109   // CHECK-MESSAGES: [[@LINE-2]]:37: warning: 'find' called with a string literal
110 }
111