259 lines · cpp
1// RUN: %check_clang_tidy %s readability-redundant-string-cstr %t -- -- -isystem %clang_tidy_headers2#include <string>3 4template <typename T>5struct iterator {6 T *operator->();7 T &operator*();8};9 10namespace llvm {11struct StringRef {12 StringRef(const char *p);13 StringRef(const std::string &);14};15}16 17// Tests for std::string.18 19void f1(const std::string &s) {20 f1(s.c_str());21 // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: redundant call to 'c_str' [readability-redundant-string-cstr]22 // CHECK-FIXES: f1(s);23 f1(s.data());24 // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: redundant call to 'data' [readability-redundant-string-cstr]25 // CHECK-FIXES: f1(s);26}27void f2(const llvm::StringRef r) {28 std::string s;29 f2(s.c_str());30 // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: redundant call {{.*}}31 // CHECK-FIXES: std::string s;32 // CHECK-FIXES-NEXT: f2(s);33}34void f3(const llvm::StringRef &r) {35 std::string s;36 f3(s.c_str());37 // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: redundant call {{.*}}38 // CHECK-FIXES: std::string s;39 // CHECK-FIXES-NEXT: f3(s);40}41void f4(const std::string &s) {42 const std::string* ptr = &s;43 f1(ptr->c_str());44 // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: redundant call to 'c_str' [readability-redundant-string-cstr]45 // CHECK-FIXES: f1(*ptr);46}47void f5(const std::string &s) {48 std::string tmp;49 tmp.append(s.c_str());50 // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: redundant call {{.*}}51 // CHECK-FIXES: tmp.append(s);52 tmp.assign(s.c_str());53 // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: redundant call {{.*}}54 // CHECK-FIXES: tmp.assign(s);55 56 if (tmp.compare(s.c_str()) == 0) return;57 // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: redundant call {{.*}}58 // CHECK-FIXES: if (tmp.compare(s) == 0) return;59 60 if (tmp.compare(1, 2, s.c_str()) == 0) return;61 // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: redundant call {{.*}}62 // CHECK-FIXES: if (tmp.compare(1, 2, s) == 0) return;63 64 if (tmp.find(s.c_str()) == 0) return;65 // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: redundant call {{.*}}66 // CHECK-FIXES: if (tmp.find(s) == 0) return;67 68 if (tmp.find(s.c_str(), 2) == 0) return;69 // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: redundant call {{.*}}70 // CHECK-FIXES: if (tmp.find(s, 2) == 0) return;71 72 if (tmp.find(s.c_str(), 2) == 0) return;73 // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: redundant call {{.*}}74 // CHECK-FIXES: if (tmp.find(s, 2) == 0) return;75 76 tmp.insert(1, s.c_str());77 // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: redundant call {{.*}}78 // CHECK-FIXES: tmp.insert(1, s);79 80 tmp = s.c_str();81 // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: redundant call {{.*}}82 // CHECK-FIXES: tmp = s;83 84 tmp += s.c_str();85 // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: redundant call {{.*}}86 // CHECK-FIXES: tmp += s;87 88 if (tmp == s.c_str()) return;89 // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: redundant call {{.*}}90 // CHECK-FIXES: if (tmp == s) return;91 92 tmp = s + s.c_str();93 // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: redundant call {{.*}}94 // CHECK-FIXES: tmp = s + s;95 96 tmp = s.c_str() + s;97 // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: redundant call {{.*}}98 // CHECK-FIXES: tmp = s + s;99}100void f6(const std::string &s) {101 std::string tmp;102 tmp.append(s.c_str(), 2);103 tmp.assign(s.c_str(), 2);104 105 if (tmp.compare(s) == 0) return;106 if (tmp.compare(1, 2, s) == 0) return;107 108 tmp = s;109 tmp += s;110 111 if (tmp == s)112 return;113 114 tmp = s + s;115 116 if (tmp.find(s.c_str(), 2, 4) == 0) return;117 118 tmp.insert(1, s);119 tmp.insert(1, s.c_str(), 2);120}121void f7(std::string_view sv) {122 std::string s;123 f7(s.c_str());124 // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: redundant call to 'c_str' [readability-redundant-string-cstr]125 // CHECK-FIXES: f7(s);126 f7(s.data());127 // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: redundant call to 'data' [readability-redundant-string-cstr]128 // CHECK-FIXES: f7(s);129}130 131// Tests for std::wstring.132 133void g1(const std::wstring &s) {134 g1(s.c_str());135 // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: redundant call to 'c_str' [readability-redundant-string-cstr]136 // CHECK-FIXES: g1(s);137}138void g2(std::wstring_view sv) {139 std::wstring s;140 g2(s.c_str());141 // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: redundant call to 'c_str' [readability-redundant-string-cstr]142 // CHECK-FIXES: g2(s);143 g2(s.data());144 // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: redundant call to 'data' [readability-redundant-string-cstr]145 // CHECK-FIXES: g2(s);146}147 148// Tests for std::u16string.149 150void h1(const std::u16string &s) {151 h1(s.c_str());152 // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: redundant call to 'c_str' [readability-redundant-string-cstr]153 // CHECK-FIXES: h1(s);154}155void h2(std::u16string_view sv) {156 std::u16string s;157 h2(s.c_str());158 // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: redundant call to 'c_str' [readability-redundant-string-cstr]159 // CHECK-FIXES: h2(s);160 h2(s.data());161 // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: redundant call to 'data' [readability-redundant-string-cstr]162 // CHECK-FIXES: h2(s);163}164 165// Tests for std::u32string.166 167void k1(const std::u32string &s) {168 k1(s.c_str());169 // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: redundant call to 'c_str' [readability-redundant-string-cstr]170 // CHECK-FIXES: k1(s);171}172void k2(std::u32string_view sv) {173 std::u32string s;174 k2(s.c_str());175 // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: redundant call to 'c_str' [readability-redundant-string-cstr]176 // CHECK-FIXES: k2(s);177 k2(s.data());178 // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: redundant call to 'data' [readability-redundant-string-cstr]179 // CHECK-FIXES: k2(s);180}181 182// Tests on similar classes that aren't good candidates for this checker.183 184struct NotAString {185 NotAString();186 NotAString(const NotAString&);187 const char *c_str() const;188};189 190void dummy(const char*) {}191 192void invalid(const NotAString &s) {193 dummy(s.c_str());194}195 196// Test for rvalue std::string.197void m1(std::string&&) {198 std::string s;199 200 m1(s.c_str());201 202 void (*m1p1)(std::string&&);203 m1p1 = m1;204 m1p1(s.c_str());205 206 using m1tp = void (*)(std::string &&);207 m1tp m1p2 = m1;208 m1p2(s.c_str()); 209}210 211// Test for overloaded operator->212void it(iterator<std::string> i)213{214 std::string tmp;215 tmp = i->c_str();216 // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: redundant call to 'c_str' [readability-redundant-string-cstr]217 // CHECK-FIXES: tmp = *i;218 219 // An unlikely situation and the outcome is not ideal, but at least the fix doesn't generate broken code.220 tmp = i.operator->()->c_str();221 // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: redundant call to 'c_str' [readability-redundant-string-cstr]222 // CHECK-FIXES: tmp = *i.operator->();223 224 // The fix contains an unnecessary set of parentheses, but these have no effect.225 iterator<std::string> *pi = &i;226 tmp = (*pi)->c_str();227 // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: redundant call to 'c_str' [readability-redundant-string-cstr]228 // CHECK-FIXES: tmp = *(*pi);229 230 // An unlikely situation, but at least the fix doesn't generate broken code.231 tmp = pi->operator->()->c_str();232 // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: redundant call to 'c_str' [readability-redundant-string-cstr]233 // CHECK-FIXES: tmp = *pi->operator->();234}235 236namespace PR45286 {237struct Foo {238 void func(const std::string &) {}239 void func2(std::string &&) {}240};241 242void bar() {243 std::string Str{"aaa"};244 Foo Foo;245 Foo.func(Str.c_str());246 // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: redundant call to 'c_str' [readability-redundant-string-cstr]247 // CHECK-FIXES: Foo.func(Str);248 249 // Ensure it doesn't transform Binding to r values250 Foo.func2(Str.c_str());251 252 // Ensure its not confused by parens253 Foo.func((Str.c_str()));254 // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: redundant call to 'c_str' [readability-redundant-string-cstr]255 // CHECK-FIXES: Foo.func((Str));256 Foo.func2((Str.c_str()));257}258} // namespace PR45286259