diff options
Diffstat (limited to 'clang-tools-extra/test/clang-tidy')
-rw-r--r-- | clang-tools-extra/test/clang-tidy/abseil-redundant-strcat-calls.cpp | 188 |
1 files changed, 188 insertions, 0 deletions
diff --git a/clang-tools-extra/test/clang-tidy/abseil-redundant-strcat-calls.cpp b/clang-tools-extra/test/clang-tidy/abseil-redundant-strcat-calls.cpp new file mode 100644 index 00000000000..2d723797143 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/abseil-redundant-strcat-calls.cpp @@ -0,0 +1,188 @@ +// RUN: %check_clang_tidy %s abseil-redundant-strcat-calls %t + +int strlen(const char *); + +// Here we mimic the hierarchy of ::string. +// We need to do so because we are matching on the fully qualified name of the +// methods. +struct __sso_string_base {}; +namespace __gnu_cxx { +template <typename A, typename B, typename C, typename D = __sso_string_base> +class __versa_string { + public: + const char *c_str() const; + const char *data() const; + int size() const; + int capacity() const; + int length() const; + bool empty() const; + char &operator[](int); + void clear(); + void resize(int); + int compare(const __versa_string &) const; +}; +} // namespace __gnu_cxx + +namespace std { +template <typename T> +class char_traits {}; +template <typename T> +class allocator {}; +} // namespace std + +template <typename A, typename B = std::char_traits<A>, + typename C = std::allocator<A>> +class basic_string : public __gnu_cxx::__versa_string<A, B, C> { + public: + basic_string(); + basic_string(const basic_string &); + basic_string(const char *, C = C()); + basic_string(const char *, int, C = C()); + basic_string(const basic_string &, int, int, C = C()); + ~basic_string(); + + basic_string &operator+=(const basic_string &); +}; + +template <typename A, typename B, typename C> +basic_string<A, B, C> operator+(const basic_string<A, B, C> &, + const basic_string<A, B, C> &); +template <typename A, typename B, typename C> +basic_string<A, B, C> operator+(const basic_string<A, B, C> &, const char *); + +typedef basic_string<char> string; + +bool operator==(const string &, const string &); +bool operator==(const string &, const char *); +bool operator==(const char *, const string &); + +bool operator!=(const string &, const string &); +bool operator<(const string &, const string &); +bool operator>(const string &, const string &); +bool operator<=(const string &, const string &); +bool operator>=(const string &, const string &); + +namespace std { +template <typename _CharT, typename _Traits = char_traits<_CharT>, + typename _Alloc = allocator<_CharT>> +class basic_string; + +template <typename _CharT, typename _Traits, typename _Alloc> +class basic_string { + public: + basic_string(); + basic_string(const basic_string &); + basic_string(const char *, const _Alloc & = _Alloc()); + basic_string(const char *, int, const _Alloc & = _Alloc()); + basic_string(const basic_string &, int, int, const _Alloc & = _Alloc()); + ~basic_string(); + + basic_string &operator+=(const basic_string &); + + unsigned size() const; + unsigned length() const; + bool empty() const; +}; + +typedef basic_string<char> string; +} // namespace std + +namespace absl { + +class string_view { + public: + typedef std::char_traits<char> traits_type; + + string_view(); + string_view(const char *); + string_view(const string &); + string_view(const char *, int); + string_view(string_view, int); + + template <typename A> + explicit operator ::basic_string<char, traits_type, A>() const; + + const char *data() const; + int size() const; + int length() const; +}; + +bool operator==(string_view A, string_view B); + +struct AlphaNum { + AlphaNum(int i); + AlphaNum(double f); + AlphaNum(const char *c_str); + AlphaNum(const string &str); + AlphaNum(const string_view &pc); + + private: + AlphaNum(const AlphaNum &); + AlphaNum &operator=(const AlphaNum &); +}; + +string StrCat(const AlphaNum &A); +string StrCat(const AlphaNum &A, const AlphaNum &B); +string StrCat(const AlphaNum &A, const AlphaNum &B, const AlphaNum &C); +string StrCat(const AlphaNum &A, const AlphaNum &B, const AlphaNum &C, + const AlphaNum &D); + +// Support 5 or more arguments +template <typename... AV> +string StrCat(const AlphaNum &A, const AlphaNum &B, const AlphaNum &C, + const AlphaNum &D, const AlphaNum &E, const AV &... args); + +void StrAppend(string *Dest, const AlphaNum &A); +void StrAppend(string *Dest, const AlphaNum &A, const AlphaNum &B); +void StrAppend(string *Dest, const AlphaNum &A, const AlphaNum &B, + const AlphaNum &C); +void StrAppend(string *Dest, const AlphaNum &A, const AlphaNum &B, + const AlphaNum &C, const AlphaNum &D); + +// Support 5 or more arguments +template <typename... AV> +void StrAppend(string *Dest, const AlphaNum &A, const AlphaNum &B, + const AlphaNum &C, const AlphaNum &D, const AlphaNum &E, + const AV &... args); + +} // namespace absl + +using absl::AlphaNum; +using absl::StrAppend; +using absl::StrCat; + +void Positives() { + string S = StrCat(1, StrCat("A", StrCat(1.1))); + // CHECK-MESSAGES: [[@LINE-1]]:14: warning: multiple calls to 'absl::StrCat' can be flattened into a single call + + S = StrCat(StrCat(StrCat(StrCat(StrCat(1))))); + // CHECK-MESSAGES: [[@LINE-1]]:7: warning: multiple calls to 'absl::StrCat' can be flattened into a single call + + // TODO: should trigger. The issue here is that in the current + // implementation we ignore any StrCat with StrCat ancestors. Therefore + // inserting anything in between calls will disable triggering the deepest + // ones. + // s = StrCat(Identity(StrCat(StrCat(1, 2), StrCat(3, 4)))); + + StrAppend(&S, 001, StrCat(1, 2, "3"), StrCat("FOO")); + // CHECK-MESSAGES: [[@LINE-1]]:3: warning: multiple calls to 'absl::StrCat' can be flattened into a single call + + StrAppend(&S, 001, StrCat(StrCat(1, 2), "3"), StrCat("FOO")); + // CHECK-MESSAGES: [[@LINE-1]]:3: warning: multiple calls to 'absl::StrCat' can be flattened into a single call + + // Too many args. Ignore for now. + S = StrCat(1, 2, StrCat(3, 4, 5, 6, 7), 8, 9, 10, + StrCat(11, 12, 13, 14, 15, 16, 17, 18), 19, 20, 21, 22, 23, 24, 25, + 26, 27); + // CHECK-MESSAGES: :[[@LINE-3]]:7: warning: multiple calls to 'absl::StrCat' can be flattened into a single call + StrAppend(&S, StrCat(1, 2, 3, 4, 5), StrCat(6, 7, 8, 9, 10)); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: multiple calls to 'absl::StrCat' can be flattened into a single call +} + +void Negatives() { + // One arg. It is used for conversion. Ignore. + string S = StrCat(1); + +#define A_MACRO(x, y, z) StrCat(x, y, z) + S = A_MACRO(1, 2, StrCat("A", "B")); +} |