[clang-tidy] Fix redundant-string-init check with msvc 14 headers.
authorEtienne Bergeron <etienneb@google.com>
Tue, 22 Mar 2016 17:39:36 +0000 (17:39 +0000)
committerEtienne Bergeron <etienneb@google.com>
Tue, 22 Mar 2016 17:39:36 +0000 (17:39 +0000)
Summary:
The string constructors are not defined using optional parameters and are not recognized by the redundant-string-init checker.

The following patch fixes the redundant-string-init checker for the Visual Studio 14 headers file.
The matcher now accept both variant (with 1 and 2 parameters).

Also added new unittests.

Similar issue than: [[ http://reviews.llvm.org/D18285 | review ]]

In the xstring.h header, the constructors are defined this way:
```
basic_string(const _Myt& _Right) [...]
basic_string(const _Myt& _Right, const _Alloc& _Al) [...]
```

Reviewers: alexfh, hokein

Subscribers: cfe-commits

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

llvm-svn: 264069

clang-tools-extra/clang-tidy/readability/RedundantStringInitCheck.cpp
clang-tools-extra/test/clang-tidy/readability-redundant-string-init-msvc.cpp [new file with mode: 0644]
clang-tools-extra/test/clang-tidy/readability-redundant-string-init.cpp

index ad6c2cd..d49c55e 100644 (file)
@@ -20,31 +20,48 @@ namespace {
 
 AST_MATCHER(StringLiteral, lengthIsZero) { return Node.getLength() == 0; }
 
+AST_MATCHER_P(Expr, ignoringImplicit,
+              ast_matchers::internal::Matcher<Expr>, InnerMatcher) {
+  return InnerMatcher.matches(*Node.IgnoreImplicit(), Finder, Builder);
+}
+
 } // namespace
 
 void RedundantStringInitCheck::registerMatchers(MatchFinder *Finder) {
   if (!getLangOpts().CPlusPlus)
     return;
 
-  const auto StringCtorExpr = cxxConstructExpr(
-      hasDeclaration(cxxMethodDecl(hasName("basic_string"))),
-      argumentCountIs(2),
-      hasArgument(0, ignoringParenImpCasts(stringLiteral(lengthIsZero()))),
-      hasArgument(1, cxxDefaultArgExpr()));
+  // Match string constructor.
+  const auto StringConstructorExpr = expr(anyOf(
+      cxxConstructExpr(argumentCountIs(1),
+                       hasDeclaration(cxxMethodDecl(hasName("basic_string")))),
+      // If present, the second argument is the alloc object which must not
+      // be present explicitly.
+      cxxConstructExpr(argumentCountIs(2),
+                       hasDeclaration(cxxMethodDecl(hasName("basic_string"))),
+                       hasArgument(1, cxxDefaultArgExpr()))));
+
+  // Match a string constructor expression with an empty string literal.
+  const auto EmptyStringCtorExpr =
+      cxxConstructExpr(StringConstructorExpr,
+          hasArgument(0, ignoringParenImpCasts(
+                             stringLiteral(lengthIsZero()))));
+
+  const auto EmptyStringCtorExprWithTemporaries =
+      expr(ignoringImplicit(
+          cxxConstructExpr(StringConstructorExpr,
+              hasArgument(0, ignoringImplicit(EmptyStringCtorExpr)))));
 
-  // string foo = "";
-  // OR
-  // string bar("");
+  // Match a variable declaration with an empty string literal as initializer.
+  // Examples:
+  //     string foo = "";
+  //     string bar("");
   Finder->addMatcher(
       namedDecl(varDecl(hasType(cxxRecordDecl(hasName("basic_string"))),
                         hasInitializer(
-                            expr(anyOf(StringCtorExpr,
-                                       exprWithCleanups(has(expr(anyOf(
-                                           StringCtorExpr,
-                                           cxxConstructExpr(hasArgument(
-                                               0, cxxBindTemporaryExpr(has(
-                                                      StringCtorExpr))))))))))
-                                .bind("expr"))))
+                            expr(anyOf(EmptyStringCtorExpr,
+                                       EmptyStringCtorExprWithTemporaries))
+                            .bind("expr"))))
           .bind("decl"),
       this);
 }
diff --git a/clang-tools-extra/test/clang-tidy/readability-redundant-string-init-msvc.cpp b/clang-tools-extra/test/clang-tidy/readability-redundant-string-init-msvc.cpp
new file mode 100644 (file)
index 0000000..ac18017
--- /dev/null
@@ -0,0 +1,122 @@
+// RUN: %check_clang_tidy %s readability-redundant-string-init %t
+
+namespace std {
+template <typename T>
+class allocator {};
+template <typename T>
+class char_traits {};
+template <typename C, typename T = std::char_traits<C>, typename A = std::allocator<C>>
+struct basic_string {
+  basic_string();
+  basic_string(const basic_string&);
+  // MSVC headers define two constructors instead of using optional arguments.
+  basic_string(const C *);
+  basic_string(const C *, const A &);
+  ~basic_string();
+};
+typedef basic_string<char> string;
+typedef basic_string<wchar_t> wstring;
+}
+
+void f() {
+  std::string a = "";
+  // CHECK-MESSAGES: [[@LINE-1]]:15: warning: redundant string initialization [readability-redundant-string-init]
+  // CHECK-FIXES: std::string a;
+  std::string b("");
+  // CHECK-MESSAGES: [[@LINE-1]]:15: warning: redundant string initialization
+  // CHECK-FIXES: std::string b;
+  std::string c = R"()";
+  // CHECK-MESSAGES: [[@LINE-1]]:15: warning: redundant string initialization
+  // CHECK-FIXES: std::string c;
+  std::string d(R"()");
+  // CHECK-MESSAGES: [[@LINE-1]]:15: warning: redundant string initialization
+  // CHECK-FIXES: std::string d;
+
+  std::string u = "u";
+  std::string w("w");
+  std::string x = R"(x)";
+  std::string y(R"(y)");
+  std::string z;
+}
+
+void g() {
+  std::wstring a = L"";
+  // CHECK-MESSAGES: [[@LINE-1]]:16: warning: redundant string initialization
+  // CHECK-FIXES: std::wstring a;
+  std::wstring b(L"");
+  // CHECK-MESSAGES: [[@LINE-1]]:16: warning: redundant string initialization
+  // CHECK-FIXES: std::wstring b;
+  std::wstring c = LR"()";
+  // CHECK-MESSAGES: [[@LINE-1]]:16: warning: redundant string initialization
+  // CHECK-FIXES: std::wstring c;
+  std::wstring d(LR"()");
+  // CHECK-MESSAGES: [[@LINE-1]]:16: warning: redundant string initialization
+  // CHECK-FIXES: std::wstring d;
+
+  std::wstring u = L"u";
+  std::wstring w(L"w");
+  std::wstring x = LR"(x)";
+  std::wstring y(LR"(y)");
+  std::wstring z;
+}
+// RUN: %check_clang_tidy %s readability-redundant-string-init %t
+
+namespace std {
+template <typename T>
+class allocator {};
+template <typename T>
+class char_traits {};
+template <typename C, typename T = std::char_traits<C>, typename A = std::allocator<C>>
+struct basic_string {
+  basic_string();
+  basic_string(const basic_string&);
+  // MSVC headers define two constructors instead of using optional arguments.
+  basic_string(const C *);
+  basic_string(const C *, const A &);
+  ~basic_string();
+};
+typedef basic_string<char> string;
+typedef basic_string<wchar_t> wstring;
+}
+
+void f() {
+  std::string a = "";
+  // CHECK-MESSAGES: [[@LINE-1]]:15: warning: redundant string initialization [readability-redundant-string-init]
+  // CHECK-FIXES: std::string a;
+  std::string b("");
+  // CHECK-MESSAGES: [[@LINE-1]]:15: warning: redundant string initialization
+  // CHECK-FIXES: std::string b;
+  std::string c = R"()";
+  // CHECK-MESSAGES: [[@LINE-1]]:15: warning: redundant string initialization
+  // CHECK-FIXES: std::string c;
+  std::string d(R"()");
+  // CHECK-MESSAGES: [[@LINE-1]]:15: warning: redundant string initialization
+  // CHECK-FIXES: std::string d;
+
+  std::string u = "u";
+  std::string w("w");
+  std::string x = R"(x)";
+  std::string y(R"(y)");
+  std::string z;
+}
+
+void g() {
+  std::wstring a = L"";
+  // CHECK-MESSAGES: [[@LINE-1]]:16: warning: redundant string initialization
+  // CHECK-FIXES: std::wstring a;
+  std::wstring b(L"");
+  // CHECK-MESSAGES: [[@LINE-1]]:16: warning: redundant string initialization
+  // CHECK-FIXES: std::wstring b;
+  std::wstring c = LR"()";
+  // CHECK-MESSAGES: [[@LINE-1]]:16: warning: redundant string initialization
+  // CHECK-FIXES: std::wstring c;
+  std::wstring d(LR"()");
+  // CHECK-MESSAGES: [[@LINE-1]]:16: warning: redundant string initialization
+  // CHECK-FIXES: std::wstring d;
+
+  std::wstring u = L"u";
+  std::wstring w(L"w");
+  std::wstring x = LR"(x)";
+  std::wstring y(LR"(y)");
+  std::wstring z;
+}
index ec5af36..1ebba29 100644 (file)
@@ -84,3 +84,50 @@ void h() {
   // CHECK-MESSAGES: [[@LINE-1]]:3: warning: redundant string initialization
   // CHECK-FIXES: N
 }
+
+typedef std::string MyString;
+#define STRING MyString
+#define DECL_STRING(name, val) STRING name = val
+
+void i() {
+  MyString a = "";
+  // CHECK-MESSAGES: [[@LINE-1]]:12: warning: redundant string initialization
+  // CHECK-FIXES: MyString a;
+  STRING b = "";
+  // CHECK-MESSAGES: [[@LINE-1]]:10: warning: redundant string initialization
+  // CHECK-FIXES: STRING b;
+  MyString c = "" "" "";
+  // CHECK-MESSAGES: [[@LINE-1]]:12: warning: redundant string initialization
+  // CHECK-FIXES: MyString c;
+  STRING d = "" "" "";
+  // CHECK-MESSAGES: [[@LINE-1]]:10: warning: redundant string initialization
+  // CHECK-FIXES: STRING d;
+  DECL_STRING(e, "");
+  // CHECK-MESSAGES: [[@LINE-1]]:15: warning: redundant string initialization
+
+  MyString f = "u";
+  STRING g = "u";
+  DECL_STRING(h, "u");
+}
+
+#define EMPTY_STR ""
+void j() {
+  std::string a(EMPTY_STR);
+  // CHECK-MESSAGES: [[@LINE-1]]:15: warning: redundant string initialization
+  // CHECK-FIXES: std::string a;
+  std::string b = (EMPTY_STR);
+  // CHECK-MESSAGES: [[@LINE-1]]:15: warning: redundant string initialization
+  // CHECK-FIXES: std::string b;
+
+  std::string c(EMPTY_STR "u" EMPTY_STR);
+}
+
+void k() {
+  std::string a = "", b = "", c = "";
+  // CHECK-MESSAGES: [[@LINE-1]]:15: warning: redundant string initialization
+  // CHECK-MESSAGES: [[@LINE-2]]:23: warning: redundant string initialization
+  // CHECK-MESSAGES: [[@LINE-3]]:31: warning: redundant string initialization
+  // CHECK-FIXES: std::string a, b, c;
+
+  std::string d = "u", e = "u", f = "u";
+}