xref: /llvm-project/clang-tools-extra/test/clang-tidy/checkers/abseil/redundant-strcat-calls.cpp (revision ef5906989ae2004100ff56dc5ab59be2be9d5c99)
1 // RUN: %check_clang_tidy %s abseil-redundant-strcat-calls %t -- -- -isystem %clang_tidy_headers
2 #include <string>
3 
4 namespace absl {
5 
6 class string_view {
7  public:
8   typedef std::char_traits<char> traits_type;
9 
10   string_view();
11   string_view(const char *);
12   string_view(const std::string &);
13   string_view(const char *, int);
14   string_view(string_view, int);
15 
16   template <typename A>
17   explicit operator std::basic_string<char, traits_type, A>() const;
18 
19   const char *data() const;
20   int size() const;
21   int length() const;
22 };
23 
24 bool operator==(string_view A, string_view B);
25 
26 struct AlphaNum {
27   AlphaNum(int i);
28   AlphaNum(double f);
29   AlphaNum(const char *c_str);
30   AlphaNum(const std::string &str);
31   AlphaNum(const string_view &pc);
32 
33  private:
34   AlphaNum(const AlphaNum &);
35   AlphaNum &operator=(const AlphaNum &);
36 };
37 
38 std::string StrCat();
39 std::string StrCat(const AlphaNum &A);
40 std::string StrCat(const AlphaNum &A, const AlphaNum &B);
41 std::string StrCat(const AlphaNum &A, const AlphaNum &B, const AlphaNum &C);
42 std::string StrCat(const AlphaNum &A, const AlphaNum &B, const AlphaNum &C,
43                    const AlphaNum &D);
44 
45 // Support 5 or more arguments
46 template <typename... AV>
47 std::string StrCat(const AlphaNum &A, const AlphaNum &B, const AlphaNum &C,
48               const AlphaNum &D, const AlphaNum &E, const AV &... args);
49 
50 void StrAppend(std::string *Dest, const AlphaNum &A);
51 void StrAppend(std::string *Dest, const AlphaNum &A, const AlphaNum &B);
52 void StrAppend(std::string *Dest, const AlphaNum &A, const AlphaNum &B,
53                     const AlphaNum &C);
54 void StrAppend(std::string *Dest, const AlphaNum &A, const AlphaNum &B,
55                     const AlphaNum &C, const AlphaNum &D);
56 
57 // Support 5 or more arguments
58 template <typename... AV>
59 void StrAppend(std::string *Dest, const AlphaNum &A, const AlphaNum &B,
60                const AlphaNum &C, const AlphaNum &D, const AlphaNum &E,
61                const AV &... args);
62 
63 }  // namespace absl
64 
65 using absl::AlphaNum;
66 using absl::StrAppend;
67 using absl::StrCat;
68 
Positives()69 void Positives() {
70   std::string S = StrCat(1, StrCat("A", StrCat(1.1)));
71   // CHECK-MESSAGES: [[@LINE-1]]:19: warning: multiple calls to 'absl::StrCat' can be flattened into a single call
72   // CHECK-FIXES: string S = StrCat(1, "A", 1.1);
73 
74   S = StrCat(StrCat(StrCat(StrCat(StrCat(1)))));
75   // CHECK-MESSAGES: [[@LINE-1]]:7: warning: multiple calls to 'absl::StrCat' can be flattened into a single call
76   // CHECK-FIXES: S = StrCat(1);
77 
78   // TODO: should trigger. The issue here is that in the current
79   // implementation we ignore any StrCat with StrCat ancestors. Therefore
80   // inserting anything in between calls will disable triggering the deepest
81   // ones.
82   // s = StrCat(Identity(StrCat(StrCat(1, 2), StrCat(3, 4))));
83 
84   StrAppend(&S, 001, StrCat(1, 2, "3"), StrCat("FOO"));
85   // CHECK-MESSAGES: [[@LINE-1]]:3: warning: multiple calls to 'absl::StrCat' can be flattened into a single call
86   // CHECK-FIXES: StrAppend(&S, 001, 1, 2, "3", "FOO");
87 
88   StrAppend(&S, 001, StrCat(StrCat(1, 2), "3"), StrCat("FOO"));
89   // CHECK-MESSAGES: [[@LINE-1]]:3: warning: multiple calls to 'absl::StrCat' can be flattened into a single call
90   // CHECK-FIXES: StrAppend(&S, 001, 1, 2, "3", "FOO");
91 
92   // Too many args. Ignore for now.
93   S = StrCat(1, 2, StrCat(3, 4, 5, 6, 7), 8, 9, 10,
94              StrCat(11, 12, 13, 14, 15, 16, 17, 18), 19, 20, 21, 22, 23, 24, 25,
95              26, 27);
96   // CHECK-MESSAGES: :[[@LINE-3]]:7: warning: multiple calls to 'absl::StrCat' can be flattened into a single call
97   StrAppend(&S, StrCat(1, 2, 3, 4, 5), StrCat(6, 7, 8, 9, 10));
98   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: multiple calls to 'absl::StrCat' can be flattened into a single call
99   // CHECK-FIXES: StrAppend(&S, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
100 
101   StrCat(1, StrCat());
102   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: multiple calls to 'absl::StrCat' can be flattened into a single call
103 }
104 
Negatives()105 void Negatives() {
106   // One arg. It is used for conversion. Ignore.
107   std::string S = StrCat(1);
108 
109 #define A_MACRO(x, y, z) StrCat(x, y, z)
110   S = A_MACRO(1, 2, StrCat("A", "B"));
111 }
112