// RUN: %check_clang_tidy %s performance-prefer-single-char-overloads %t -- -- -fno-delayed-template-parsing // RUN: %check_clang_tidy -check-suffix=CUSTOM %s performance-prefer-single-char-overloads %t -- \ // RUN: -config="{CheckOptions: \ // RUN: {performance-prefer-single-char-overloads.StringLikeClasses: \ // RUN: '::llvm::StringRef;'}}" -- -fno-delayed-template-parsing #include namespace llvm { struct StringRef { int find(const char *) const; }; } // namespace llvm struct NotStringRef { int find(const char *); }; template struct Wrapper { T value; }; void StringFind() { std::string Str; Str.find("a"); // CHECK-MESSAGES: [[@LINE-1]]:12: warning: 'find' called with a string literal consisting of a single character; consider using the more efficient overload accepting a character [performance-prefer-single-char-overloads] // CHECK-FIXES: Str.find('a'); // Works with the pos argument. Str.find("a", 1); // CHECK-MESSAGES: [[@LINE-1]]:12: warning: 'find' called with a string literal // CHECK-FIXES: Str.find('a', 1); // Doesn't work with strings smaller or larger than 1 char. Str.find(""); Str.find("ab"); // Doesn't do anything with the 3 argument overload. Str.find("a", 1, 1); // Single quotes are escaped properly Str.find("'"); // CHECK-MESSAGES: [[@LINE-1]]:12: warning: 'find' called with a string literal // CHECK-FIXES: Str.find('\''); Str.find("\'"); // CHECK-MESSAGES: [[@LINE-1]]:12: warning: 'find' called with a string literal // CHECK-FIXES: Str.find('\''); // Other methods that can also be replaced Str.rfind("a"); // CHECK-MESSAGES: [[@LINE-1]]:13: warning: 'rfind' called with a string literal // CHECK-FIXES: Str.rfind('a'); Str.find_first_of("a"); // CHECK-MESSAGES: [[@LINE-1]]:21: warning: 'find_first_of' called with a string // CHECK-FIXES: Str.find_first_of('a'); Str.find_first_not_of("a"); // CHECK-MESSAGES: [[@LINE-1]]:25: warning: 'find_first_not_of' called with a // CHECK-FIXES: Str.find_first_not_of('a'); Str.find_last_of("a"); // CHECK-MESSAGES: [[@LINE-1]]:20: warning: 'find_last_of' called with a string // CHECK-FIXES: Str.find_last_of('a'); Str.find_last_not_of("a"); // CHECK-MESSAGES: [[@LINE-1]]:24: warning: 'find_last_not_of' called with a // CHECK-FIXES: Str.find_last_not_of('a'); Str.starts_with("a"); // CHECK-MESSAGES: [[@LINE-1]]:19: warning: 'starts_with' called with a // CHECK-FIXES: Str.starts_with('a'); Str.ends_with("a"); // CHECK-MESSAGES: [[@LINE-1]]:17: warning: 'ends_with' called with a string // CHECK-FIXES: Str.ends_with('a'); Str.contains("a"); // CHECK-MESSAGES: [[@LINE-1]]:16: warning: 'contains' called with a // CHECK-FIXES: Str.contains('a'); Str += "a"; // CHECK-MESSAGES: [[@LINE-1]]:10: warning: 'operator+=' called with a // CHECK-FIXES: Str += 'a'; ((Str += "a") += "b") += "c"; // CHECK-MESSAGES: [[@LINE-1]]:12: warning: 'operator+=' called with a // CHECK-MESSAGES: [[@LINE-2]]:20: warning: 'operator+=' called with a // CHECK-MESSAGES: [[@LINE-3]]:28: warning: 'operator+=' called with a // CHECK-FIXES: ((Str += 'a') += 'b') += 'c'; Str.operator+=("a"); // CHECK-MESSAGES: [[@LINE-1]]:18: warning: 'operator+=' called with a // CHECK-FIXES: Str.operator+=('a'); // std::wstring should work. std::wstring WStr; WStr.find(L"n"); // CHECK-MESSAGES: [[@LINE-1]]:13: warning: 'find' called with a string literal // CHECK-FIXES: WStr.find(L'n'); // Even with unicode that fits in one wide char. WStr.find(L"\x3A9"); // CHECK-MESSAGES: [[@LINE-1]]:13: warning: 'find' called with a string literal // CHECK-FIXES: WStr.find(L'\x3A9'); // std::string_view and std::wstring_view should work. std::string_view StrView; StrView.find("n"); // CHECK-MESSAGES: [[@LINE-1]]:16: warning: 'find' called with a string literal // CHECK-FIXES: StrView.find('n'); std::wstring_view WStrView; WStrView.find(L"n"); // CHECK-MESSAGES: [[@LINE-1]]:17: warning: 'find' called with a string literal // CHECK-FIXES: WStrView.find(L'n'); WStrView.find(L"\x3A9"); // CHECK-MESSAGES: [[@LINE-1]]:17: warning: 'find' called with a string literal // CHECK-FIXES: WStrView.find(L'\x3A9'); // Also with other types, but only if it was specified in the options. llvm::StringRef sr; sr.find("x"); // CHECK-MESSAGES-CUSTOM: [[@LINE-1]]:11: warning: 'find' called with a string literal // CHECK-FIXES-CUSTOM: sr.find('x'); NotStringRef nsr; nsr.find("x"); } template int FindTemplateDependent(T value) { return value.find("A"); } template int FindTemplateDependent1(T pos) { // Ignored since the type of `pos` is dependent, the call cannot be completely resolved without instantiating the template. return std::string().find("A", pos); } template int FindTemplateNonDependent() { return std::string().find("A"); // CHECK-MESSAGES: [[@LINE-1]]:29: warning: 'find' called with a string literal // CHECK-FIXES: return std::string().find('A'); } int FindStr() { return FindTemplateDependent(std::string()) + FindTemplateDependent1(1); } #define STR_MACRO(str) str.find("A") #define POS_MACRO(pos) std::string().find("A",pos) int Macros() { return STR_MACRO(std::string()) + POS_MACRO(1); // CHECK-MESSAGES: [[@LINE-1]]:10: warning: 'find' called with a string literal // CHECK-MESSAGES: [[@LINE-2]]:37: warning: 'find' called with a string literal } void SubstitutedTemplateType() { Wrapper().value.find("a"); // CHECK-MESSAGES: [[@LINE-1]]:37: warning: 'find' called with a string literal // CHECK-FIXES: Wrapper().value.find('a'); }