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