Index: clang-tidy/readability/RedundantStringInitCheck.cpp =================================================================== --- clang-tidy/readability/RedundantStringInitCheck.cpp +++ clang-tidy/readability/RedundantStringInitCheck.cpp @@ -20,31 +20,48 @@ AST_MATCHER(StringLiteral, lengthIsZero) { return Node.getLength() == 0; } +AST_MATCHER_P(Expr, ignoringImplicit, + ast_matchers::internal::Matcher, 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())); - - // string foo = ""; - // OR - // string bar(""); + // 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))))); + + // 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); } Index: test/clang-tidy/readability-redundant-string-init-msvc.cpp =================================================================== --- /dev/null +++ test/clang-tidy/readability-redundant-string-init-msvc.cpp @@ -0,0 +1,122 @@ +// RUN: %check_clang_tidy %s readability-redundant-string-init %t + +namespace std { +template +class allocator {}; +template +class char_traits {}; +template , typename A = std::allocator> +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 string; +typedef basic_string 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 +class allocator {}; +template +class char_traits {}; +template , typename A = std::allocator> +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 string; +typedef basic_string 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: test/clang-tidy/readability-redundant-string-init.cpp =================================================================== --- test/clang-tidy/readability-redundant-string-init.cpp +++ test/clang-tidy/readability-redundant-string-init.cpp @@ -84,3 +84,50 @@ // 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"; +}