1 // RUN: %check_clang_tidy %s abseil-str-cat-append %t
2 
3 typedef unsigned __INT16_TYPE__ char16;
4 typedef unsigned __INT32_TYPE__ char32;
5 typedef __SIZE_TYPE__ size;
6 
7 namespace std {
8 template <typename T>
9 class allocator {};
10 template <typename T>
11 class char_traits {};
12 template <typename C, typename T, typename A>
13 struct basic_string {
14   typedef basic_string<C, T, A> _Type;
15   basic_string();
16   basic_string(const C* p, const A& a = A());
17 
18   const C* c_str() const;
19   const C* data() const;
20 
21   _Type& append(const C* s);
22   _Type& append(const C* s, size n);
23   _Type& assign(const C* s);
24   _Type& assign(const C* s, size n);
25 
26   int compare(const _Type&) const;
27   int compare(const C* s) const;
28   int compare(size pos, size len, const _Type&) const;
29   int compare(size pos, size len, const C* s) const;
30 
31   size find(const _Type& str, size pos = 0) const;
32   size find(const C* s, size pos = 0) const;
33   size find(const C* s, size pos, size n) const;
34 
35   _Type& insert(size pos, const _Type& str);
36   _Type& insert(size pos, const C* s);
37   _Type& insert(size pos, const C* s, size n);
38 
39   _Type& operator+=(const _Type& str);
40   _Type& operator+=(const C* s);
41   _Type& operator=(const _Type& str);
42   _Type& operator=(const C* s);
43 };
44 
45 typedef basic_string<char, std::char_traits<char>, std::allocator<char>> string;
46 typedef basic_string<wchar_t, std::char_traits<wchar_t>,
47                      std::allocator<wchar_t>>
48     wstring;
49 typedef basic_string<char16, std::char_traits<char16>, std::allocator<char16>>
50     u16string;
51 typedef basic_string<char32, std::char_traits<char32>, std::allocator<char32>>
52     u32string;
53 }  // namespace std
54 
55 std::string operator+(const std::string&, const std::string&);
56 std::string operator+(const std::string&, const char*);
57 std::string operator+(const char*, const std::string&);
58 
59 bool operator==(const std::string&, const std::string&);
60 bool operator==(const std::string&, const char*);
61 bool operator==(const char*, const std::string&);
62 
63 namespace llvm {
64 struct StringRef {
65   StringRef(const char* p);
66   StringRef(const std::string&);
67 };
68 }  // namespace llvm
69 
70 namespace absl {
71 
72 struct AlphaNum {
73   AlphaNum(int i);
74   AlphaNum(double f);
75   AlphaNum(const char* c_str);
76   AlphaNum(const std::string& str);
77 
78  private:
79   AlphaNum(const AlphaNum&);
80   AlphaNum& operator=(const AlphaNum&);
81 };
82 
83 std::string StrCat(const AlphaNum& A);
84 std::string StrCat(const AlphaNum& A, const AlphaNum& B);
85 
86 template <typename A>
Foo(A & a)87 void Foo(A& a) {
88   a = StrCat(a);
89 }
90 
Bar()91 void Bar() {
92   std::string A, B;
93   Foo<std::string>(A);
94 
95   std::string C = StrCat(A);
96   A = StrCat(A);
97   // CHECK-MESSAGES: [[@LINE-1]]:3: warning: call to 'absl::StrCat' has no effect
98   A = StrCat(A, B);
99 // CHECK-MESSAGES: [[@LINE-1]]:3: warning: call 'absl::StrAppend' instead of 'absl::StrCat' when appending to a string to avoid a performance penalty
100 // CHECK-FIXES: {{^}}  absl::StrAppend(&A, B);
101   B = StrCat(A, B);
102 
103 #define M(X) X = StrCat(X, A)
104   M(B);
105 // CHECK-MESSAGES: [[@LINE-1]]:5: warning: call 'absl::StrAppend' instead of 'absl::StrCat' when appending to a string to avoid a performance penalty
106 // CHECK-FIXES: #define M(X) X = StrCat(X, A)
107 }
108 
Regression_SelfAppend()109 void Regression_SelfAppend() {
110   std::string A;
111   A = StrCat(A, A);
112 }
113 
114 }  // namespace absl
115 
OutsideAbsl()116 void OutsideAbsl() {
117   std::string A, B;
118   A = absl::StrCat(A, B);
119 // CHECK-MESSAGES: [[@LINE-1]]:3: warning: call 'absl::StrAppend' instead of 'absl::StrCat' when appending to a string to avoid a performance penalty
120 // CHECK-FIXES: {{^}}  absl::StrAppend(&A, B);
121 }
122 
OutsideUsingAbsl()123 void OutsideUsingAbsl() {
124   std::string A, B;
125   using absl::StrCat;
126   A = StrCat(A, B);
127 // CHECK-MESSAGES: [[@LINE-1]]:3: warning: call 'absl::StrAppend' instead of 'absl::StrCat' when appending to a string to avoid a performance penalty
128 // CHECK-FIXES: {{^}}  absl::StrAppend(&A, B);
129 }
130