10 #include "../utils/OptionsUtils.h"
19 return Node.hasExplicitTemplateArgs();
22 const auto DefaultContainersWithPushBack =
23 "::std::vector; ::std::list; ::std::deque";
24 const auto DefaultSmartPointers =
25 "::std::shared_ptr; ::std::unique_ptr; ::std::auto_ptr; ::std::weak_ptr";
26 const auto DefaultTupleTypes =
"::std::pair; ::std::tuple";
27 const auto DefaultTupleMakeFunctions =
"::std::make_pair; ::std::make_tuple";
32 "IgnoreImplicitConstructors", false)),
34 "ContainersWithPushBack", DefaultContainersWithPushBack))),
36 Options.get(
"SmartPointers", DefaultSmartPointers))),
38 Options.get(
"TupleTypes", DefaultTupleTypes))),
40 Options.get(
"TupleMakeFunctions", DefaultTupleMakeFunctions))) {}
51 auto CallPushBack = cxxMemberCallExpr(
52 hasDeclaration(functionDecl(hasName(
"push_back"))),
53 on(hasType(cxxRecordDecl(hasAnyName(SmallVector<StringRef, 5>(
54 ContainersWithPushBack.begin(), ContainersWithPushBack.end()))))));
60 auto IsCtorOfSmartPtr = hasDeclaration(cxxConstructorDecl(ofClass(hasAnyName(
61 SmallVector<StringRef, 5>(SmartPointers.begin(), SmartPointers.end())))));
64 auto BitFieldAsArgument = hasAnyArgument(
65 ignoringImplicit(memberExpr(hasDeclaration(fieldDecl(isBitField())))));
68 auto InitializerListAsArgument = hasAnyArgument(
69 ignoringImplicit(cxxConstructExpr(isListInitialization())));
72 auto NewExprAsArgument = hasAnyArgument(ignoringImplicit(cxxNewExpr()));
74 auto ConstructingDerived =
75 hasParent(implicitCastExpr(hasCastKind(CastKind::CK_DerivedToBase)));
78 auto IsPrivateCtor = hasDeclaration(cxxConstructorDecl(isPrivate()));
80 auto HasInitList = anyOf(has(ignoringImplicit(initListExpr())),
81 has(cxxStdInitializerListExpr()));
85 auto SoughtConstructExpr =
87 unless(anyOf(IsCtorOfSmartPtr, HasInitList, BitFieldAsArgument,
88 InitializerListAsArgument, NewExprAsArgument,
89 ConstructingDerived, IsPrivateCtor)))
91 auto HasConstructExpr = has(ignoringImplicit(SoughtConstructExpr));
93 auto MakeTuple = ignoringImplicit(
95 callee(expr(ignoringImplicit(declRefExpr(
96 unless(hasExplicitTemplateArgs()),
97 to(functionDecl(hasAnyName(SmallVector<StringRef, 2>(
98 TupleMakeFunctions.begin(), TupleMakeFunctions.end())))))))))
103 auto MakeTupleCtor = ignoringImplicit(cxxConstructExpr(
104 has(materializeTemporaryExpr(MakeTuple)),
105 hasDeclaration(cxxConstructorDecl(ofClass(hasAnyName(
106 SmallVector<StringRef, 2>(TupleTypes.begin(), TupleTypes.end())))))));
108 auto SoughtParam = materializeTemporaryExpr(
109 anyOf(has(MakeTuple), has(MakeTupleCtor),
110 HasConstructExpr, has(cxxFunctionalCastExpr(HasConstructExpr))));
113 traverse(ast_type_traits::TK_AsIs,
114 cxxMemberCallExpr(CallPushBack, has(SoughtParam),
115 unless(isInTemplateInstantiation()))
121 const auto *Call = Result.Nodes.getNodeAs<CXXMemberCallExpr>(
"call");
122 const auto *CtorCall = Result.Nodes.getNodeAs<CXXConstructExpr>(
"ctor");
123 const auto *MakeCall = Result.Nodes.getNodeAs<CallExpr>(
"make");
124 assert((CtorCall || MakeCall) &&
"No push_back parameter matched");
126 if (IgnoreImplicitConstructors && CtorCall && CtorCall->getNumArgs() >= 1 &&
127 CtorCall->getArg(0)->getSourceRange() == CtorCall->getSourceRange())
130 const auto FunctionNameSourceRange = CharSourceRange::getCharRange(
131 Call->getExprLoc(), Call->getArg(0)->getExprLoc());
133 auto Diag =
diag(Call->getExprLoc(),
"use emplace_back instead of push_back");
135 if (FunctionNameSourceRange.getBegin().isMacroID())
138 const auto *EmplacePrefix = MakeCall ?
"emplace_back" :
"emplace_back(";
139 Diag << FixItHint::CreateReplacement(FunctionNameSourceRange, EmplacePrefix);
141 const SourceRange CallParensRange =
142 MakeCall ? SourceRange(MakeCall->getCallee()->getEndLoc(),
143 MakeCall->getRParenLoc())
144 : CtorCall->getParenOrBraceRange();
147 if (CallParensRange.getBegin().isInvalid())
150 const SourceLocation ExprBegin =
151 MakeCall ? MakeCall->getExprLoc() : CtorCall->getExprLoc();
154 const auto ParamCallSourceRange =
155 CharSourceRange::getTokenRange(ExprBegin, CallParensRange.getBegin());
157 Diag << FixItHint::CreateRemoval(ParamCallSourceRange)
158 << FixItHint::CreateRemoval(CharSourceRange::getTokenRange(
159 CallParensRange.getEnd(), CallParensRange.getEnd()));
163 Options.
store(Opts,
"IgnoreImplicitConstructors", IgnoreImplicitConstructors);