[clang-tidy] Add support for different char-types for the readability-redundant-strin...
authorEtienne Bergeron <etienneb@google.com>
Thu, 24 Mar 2016 19:42:36 +0000 (19:42 +0000)
committerEtienne Bergeron <etienneb@google.com>
Thu, 24 Mar 2016 19:42:36 +0000 (19:42 +0000)
Summary:
The current checker is able to recognize std::string but does not recognize other string variants.
This patch is adding the support for any string defined with basic_string without considering the
the underlying char type.

The most common variant is: 'std::wstring' based on 'wchar_t'.

There are also other string variants added to the standard: u16string, u32string, etc...

Reviewers: alexfh

Subscribers: mamai, dblaikie, cfe-commits

Differential Revision: http://reviews.llvm.org/D18412

llvm-svn: 264325

clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.cpp
clang-tools-extra/test/clang-tidy/readability-redundant-string-cstr.cpp

index 64a7b61..13a330b 100644 (file)
@@ -65,14 +65,6 @@ formatDereference(const ast_matchers::MatchFinder::MatchResult &Result,
   return (llvm::Twine("*") + Text).str();
 }
 
-const char StringConstructor[] =
-    "::std::basic_string<char, std::char_traits<char>, std::allocator<char> >"
-    "::basic_string";
-
-const char StringCStrMethod[] =
-    "::std::basic_string<char, std::char_traits<char>, std::allocator<char> >"
-    "::c_str";
-
 } // end namespace
 
 namespace tidy {
@@ -85,23 +77,31 @@ void RedundantStringCStrCheck::registerMatchers(
   if (!getLangOpts().CPlusPlus)
     return;
 
+  // Match expressions of type 'string' or 'string*'.
+  const auto StringDecl =
+      cxxRecordDecl(hasName("::std::basic_string"));
+  const auto StringExpr =
+      expr(anyOf(hasType(StringDecl),
+                 hasType(qualType(pointsTo(StringDecl)))));
+
   // Match string constructor.
   const auto StringConstructorExpr = expr(anyOf(
       cxxConstructExpr(
           argumentCountIs(1),
-          hasDeclaration(cxxMethodDecl(hasName(StringConstructor)))),
+          hasDeclaration(cxxMethodDecl(hasName("basic_string")))),
       cxxConstructExpr(
           argumentCountIs(2),
-          hasDeclaration(cxxMethodDecl(hasName(StringConstructor))),
+          hasDeclaration(cxxMethodDecl(hasName("basic_string"))),
           // If present, the second argument is the alloc object which must not
           // be present explicitly.
           hasArgument(1, cxxDefaultArgExpr()))));
 
   // Match a call to the string 'c_str()' method.
-  const auto StringCStrCallExpr = cxxMemberCallExpr(
-                            callee(memberExpr().bind("member")),
-                            callee(cxxMethodDecl(hasName(StringCStrMethod))),
-                            on(expr().bind("arg"))).bind("call");
+  const auto StringCStrCallExpr =
+      cxxMemberCallExpr(on(StringExpr.bind("arg")),
+                        callee(memberExpr().bind("member")),
+                        callee(cxxMethodDecl(hasName("c_str"))))
+          .bind("call");
 
   Finder->addMatcher(
       cxxConstructExpr(StringConstructorExpr,
index e6f6328..2bac1c4 100644 (file)
@@ -12,7 +12,11 @@ struct basic_string {
   const C *c_str() const;
 };
 typedef basic_string<char, std::char_traits<char>, std::allocator<char>> string;
+typedef basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t>> wstring;
+typedef basic_string<char16_t, std::char_traits<char16_t>, std::allocator<char16_t>> u16string;
+typedef basic_string<char32_t, std::char_traits<char32_t>, std::allocator<char32_t>> u32string;
 }
+
 namespace llvm {
 struct StringRef {
   StringRef(const char *p);
@@ -20,6 +24,8 @@ struct StringRef {
 };
 }
 
+// Tests for std::string.
+
 void f1(const std::string &s) {
   f1(s.c_str());
   // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: redundant call to `c_str()` [readability-redundant-string-cstr]
@@ -39,3 +45,47 @@ void f3(const llvm::StringRef &r) {
   // CHECK-FIXES: {{^  }}std::string s;{{$}}
   // CHECK-FIXES-NEXT: {{^  }}f3(s);{{$}}
 }
+void f4(const std::string &s) {
+  const std::string* ptr = &s;
+  f1(ptr->c_str());
+  // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: redundant call to `c_str()` [readability-redundant-string-cstr]
+  // CHECK-FIXES: {{^  }}f1(*ptr);{{$}}
+}
+
+// Tests for std::wstring.
+
+void g1(const std::wstring &s) {
+  g1(s.c_str());
+  // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: redundant call to `c_str()` [readability-redundant-string-cstr]
+  // CHECK-FIXES: {{^  }}g1(s);{{$}}
+}
+
+// Tests for std::u16string.
+
+void h1(const std::u16string &s) {
+  h1(s.c_str());
+  // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: redundant call to `c_str()` [readability-redundant-string-cstr]
+  // CHECK-FIXES: {{^  }}h1(s);{{$}}
+}
+
+// Tests for std::u32string.
+
+void k1(const std::u32string &s) {
+  k1(s.c_str());
+  // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: redundant call to `c_str()` [readability-redundant-string-cstr]
+  // CHECK-FIXES: {{^  }}k1(s);{{$}}
+}
+
+// Tests on similar classes that aren't good candidates for this checker.
+
+struct NotAString {
+  NotAString();
+  NotAString(const NotAString&);
+  const char *c_str() const;
+};
+
+void dummy(const char*) {}
+
+void invalid(const NotAString &s) {
+  dummy(s.c_str());
+}