10 #include "../utils/Matchers.h"
11 #include "../utils/OptionsUtils.h"
12 #include "clang/ASTMatchers/ASTMatchers.h"
19 namespace readability {
23 static ast_matchers::internal::Matcher<NamedDecl>
25 return ast_matchers::internal::Matcher<NamedDecl>(
26 new ast_matchers::internal::HasNameMatcher(std::move(Names)));
29 static std::vector<std::string>
31 std::vector<std::string> Result;
32 Result.reserve(Names.size());
33 for (
const std::string &
Name : Names) {
34 std::string::size_type ColonPos =
Name.rfind(
':');
36 Name.substr(ColonPos == std::string::npos ? 0 : ColonPos + 1));
41 static const CXXConstructExpr *
43 const Expr *InitExpr = CtorInit.getInit();
44 if (
const auto *CleanUpExpr = dyn_cast<ExprWithCleanups>(InitExpr))
45 InitExpr = CleanUpExpr->getSubExpr();
46 return dyn_cast<CXXConstructExpr>(InitExpr);
49 static llvm::Optional<SourceRange>
52 for (
const Expr *Arg : Construct.arguments()) {
54 B = Arg->getBeginLoc();
55 if (Arg->getEndLoc().isValid())
58 if (B.isInvalid() ||
E.isInvalid())
60 return SourceRange(B,
E);
63 RedundantStringInitCheck::RedundantStringInitCheck(StringRef
Name,
75 const auto hasStringCtorName =
79 const auto StringConstructorExpr = expr(
80 anyOf(cxxConstructExpr(argumentCountIs(1),
81 hasDeclaration(cxxMethodDecl(hasStringCtorName))),
84 cxxConstructExpr(argumentCountIs(2),
85 hasDeclaration(cxxMethodDecl(hasStringCtorName)),
86 hasArgument(1, cxxDefaultArgExpr()))));
89 const auto EmptyStringCtorExpr = cxxConstructExpr(
90 StringConstructorExpr,
91 hasArgument(0, ignoringParenImpCasts(stringLiteral(hasSize(0)))));
93 const auto EmptyStringCtorExprWithTemporaries =
94 cxxConstructExpr(StringConstructorExpr,
95 hasArgument(0, ignoringImplicit(EmptyStringCtorExpr)));
97 const auto StringType = hasType(hasUnqualifiedDesugaredType(
98 recordType(hasDeclaration(cxxRecordDecl(hasStringTypeName)))));
99 const auto EmptyStringInit =
100 traverse(ast_type_traits::TK_AsIs, expr(ignoringImplicit(
101 anyOf(EmptyStringCtorExpr, EmptyStringCtorExprWithTemporaries))));
108 traverse(ast_type_traits::TK_AsIs,
109 namedDecl(varDecl(StringType, hasInitializer(EmptyStringInit))
111 unless(parmVarDecl()))),
115 namedDecl(fieldDecl(StringType, hasInClassInitializer(EmptyStringInit))
125 forField(allOf(StringType, optionally(hasInClassInitializer(
126 EmptyStringInit.bind(
"empty_init"))))),
127 withInitializer(EmptyStringInit))
133 if (
const auto *VDecl = Result.Nodes.getNodeAs<VarDecl>(
"vardecl")) {
136 SourceRange ReplaceRange(VDecl->getLocation(), VDecl->getEndLoc());
137 diag(VDecl->getLocation(),
"redundant string initialization")
138 << FixItHint::CreateReplacement(ReplaceRange, VDecl->getName());
140 if (
const auto *FDecl = Result.Nodes.getNodeAs<FieldDecl>(
"fieldDecl")) {
143 SourceRange ReplaceRange(FDecl->getLocation(), FDecl->getEndLoc());
144 diag(FDecl->getLocation(),
"redundant string initialization")
145 << FixItHint::CreateReplacement(ReplaceRange, FDecl->getName());
147 if (
const auto *CtorInit =
148 Result.Nodes.getNodeAs<CXXCtorInitializer>(
"ctorInit")) {
149 if (
const FieldDecl *Member = CtorInit->getMember()) {
150 if (!Member->hasInClassInitializer() ||
151 Result.Nodes.getNodeAs<Expr>(
"empty_init")) {
156 diag(CtorInit->getMemberLocation(),
"redundant string initialization")
157 << FixItHint::CreateRemoval(CtorInit->getSourceRange());
164 if (llvm::Optional<SourceRange> RemovalRange =
166 diag(CtorInit->getMemberLocation(),
"redundant string initialization")
167 << FixItHint::CreateRemoval(*RemovalRange);