1// RUN: %check_clang_tidy %s abseil-redundant-strcat-calls %t -- -- -isystem %clang_tidy_headers
2#include <string>
3
4namespace absl {
5
6class 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
24bool operator==(string_view A, string_view B);
25
26struct 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
38std::string StrCat();
39std::string StrCat(const AlphaNum &A);
40std::string StrCat(const AlphaNum &A, const AlphaNum &B);
41std::string StrCat(const AlphaNum &A, const AlphaNum &B, const AlphaNum &C);
42std::string StrCat(const AlphaNum &A, const AlphaNum &B, const AlphaNum &C,
43 const AlphaNum &D);
44
45// Support 5 or more arguments
46template <typename... AV>
47std::string StrCat(const AlphaNum &A, const AlphaNum &B, const AlphaNum &C,
48 const AlphaNum &D, const AlphaNum &E, const AV &... args);
49
50void StrAppend(std::string *Dest, const AlphaNum &A);
51void StrAppend(std::string *Dest, const AlphaNum &A, const AlphaNum &B);
52void StrAppend(std::string *Dest, const AlphaNum &A, const AlphaNum &B,
53 const AlphaNum &C);
54void StrAppend(std::string *Dest, const AlphaNum &A, const AlphaNum &B,
55 const AlphaNum &C, const AlphaNum &D);
56
57// Support 5 or more arguments
58template <typename... AV>
59void 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
65using absl::AlphaNum;
66using absl::StrAppend;
67using absl::StrCat;
68
69void Positives() {
70 std::string S = StrCat(A: 1, B: StrCat(A: "A", B: StrCat(A: 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(A: StrCat(A: StrCat(A: StrCat(A: StrCat(A: 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(Dest: &S, A: 001, B: StrCat(A: 1, B: 2, C: "3"), C: StrCat(A: "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(Dest: &S, A: 001, B: StrCat(A: StrCat(A: 1, B: 2), B: "3"), C: StrCat(A: "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(A: 1, B: 2, C: StrCat(A: 3, B: 4, C: 5, D: 6, E: 7), D: 8, E: 9, args: 10,
94 args: StrCat(A: 11, B: 12, C: 13, D: 14, E: 15, args: 16, args: 17, args: 18), args: 19, args: 20, args: 21, args: 22, args: 23, args: 24, args: 25,
95 args: 26, args: 27);
96 // CHECK-MESSAGES: :[[@LINE-3]]:7: warning: multiple calls to 'absl::StrCat' can be flattened into a single call
97 StrAppend(Dest: &S, A: StrCat(A: 1, B: 2, C: 3, D: 4, E: 5), B: StrCat(A: 6, B: 7, C: 8, D: 9, E: 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(A: 1, B: StrCat());
102 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: multiple calls to 'absl::StrCat' can be flattened into a single call
103}
104
105void Negatives() {
106 // One arg. It is used for conversion. Ignore.
107 std::string S = StrCat(A: 1);
108
109#define A_MACRO(x, y, z) StrCat(x, y, z)
110 S = A_MACRO(1, 2, StrCat("A", "B"));
111}
112

source code of clang-tools-extra/test/clang-tidy/checkers/abseil/redundant-strcat-calls.cpp