diff --git a/clang-tools-extra/clang-tidy/readability/RedundantStringInitCheck.cpp b/clang-tools-extra/clang-tidy/readability/RedundantStringInitCheck.cpp index d49c55e8f1f1..2997e5d2555a 100644 --- a/clang-tools-extra/clang-tidy/readability/RedundantStringInitCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/RedundantStringInitCheck.cpp @@ -1,79 +1,80 @@ //===- RedundantStringInitCheck.cpp - clang-tidy ----------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "RedundantStringInitCheck.h" #include "clang/ASTMatchers/ASTMatchers.h" using namespace clang::ast_matchers; namespace clang { namespace tidy { namespace readability { namespace { 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; // 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(EmptyStringCtorExpr, EmptyStringCtorExprWithTemporaries)) - .bind("expr")))) + .bind("expr"))), + unless(parmVarDecl())) .bind("decl"), this); } void RedundantStringInitCheck::check(const MatchFinder::MatchResult &Result) { const auto *CtorExpr = Result.Nodes.getNodeAs("expr"); const auto *Decl = Result.Nodes.getNodeAs("decl"); diag(CtorExpr->getExprLoc(), "redundant string initialization") << FixItHint::CreateReplacement(CtorExpr->getSourceRange(), Decl->getName()); } } // namespace readability } // namespace tidy } // namespace clang diff --git a/clang-tools-extra/test/clang-tidy/readability-redundant-string-init.cpp b/clang-tools-extra/test/clang-tidy/readability-redundant-string-init.cpp index 1ebba2987cb0..4455ad44d050 100644 --- a/clang-tools-extra/test/clang-tidy/readability-redundant-string-init.cpp +++ b/clang-tools-extra/test/clang-tidy/readability-redundant-string-init.cpp @@ -1,133 +1,140 @@ // 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&); basic_string(const C *, const A &a = 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; } template void templ() { std::string s = ""; // CHECK-MESSAGES: [[@LINE-1]]:15: warning: redundant string initialization // CHECK-FIXES: std::string s; } #define M(x) x #define N { std::string s = ""; } // CHECK-FIXES: #define N { std::string s = ""; } void h() { templ(); templ(); M({ std::string s = ""; }) // CHECK-MESSAGES: [[@LINE-1]]:19: warning: redundant string initialization // CHECK-FIXES: M({ std::string s; }) N // CHECK-MESSAGES: [[@LINE-1]]:3: warning: redundant string initialization // CHECK-FIXES: N N // 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"; } + +// These cases should not generate warnings. +extern void Param1(std::string param = ""); +extern void Param2(const std::string& param = ""); +void Param3(std::string param = "") {} +void Param4(STRING param = "") {} +