159 auto CallEmplacy = cxxMemberCallExpr(
161 functionDecl(hasAnyNameIgnoringTemplates(EmplacyFunctions))),
163 hasCanonicalType(hasDeclaration(has(typedefNameDecl(
164 hasName(
"value_type"),
165 hasType(hasCanonicalType(recordType().bind(
"value_type"))))))))));
171 auto IsCtorOfSmartPtr =
172 hasDeclaration(cxxConstructorDecl(ofClass(hasAnyName(SmartPointers))));
175 auto BitFieldAsArgument = hasAnyArgument(
176 ignoringImplicit(memberExpr(hasDeclaration(fieldDecl(isBitField())))));
179 auto InitializerListAsArgument = hasAnyArgument(
180 ignoringImplicit(allOf(cxxConstructExpr(isListInitialization()),
181 unless(cxxTemporaryObjectExpr()))));
184 auto NewExprAsArgument = hasAnyArgument(ignoringImplicit(cxxNewExpr()));
186 auto ConstructingDerived =
187 hasParent(implicitCastExpr(hasCastKind(CastKind::CK_DerivedToBase)));
190 auto IsPrivateOrProtectedCtor =
191 hasDeclaration(cxxConstructorDecl(anyOf(isPrivate(), isProtected())));
193 auto HasInitList = anyOf(has(ignoringImplicit(initListExpr())),
194 has(cxxStdInitializerListExpr()));
198 auto SoughtConstructExpr =
200 unless(anyOf(IsCtorOfSmartPtr, HasInitList, BitFieldAsArgument,
201 InitializerListAsArgument, NewExprAsArgument,
202 ConstructingDerived, IsPrivateOrProtectedCtor)))
204 auto HasConstructExpr = has(ignoringImplicit(SoughtConstructExpr));
207 auto HasConstructInitListExpr = has(initListExpr(
208 initCountLeq(1), anyOf(allOf(has(SoughtConstructExpr),
209 has(cxxConstructExpr(argumentCountIs(0)))),
210 has(cxxBindTemporaryExpr(
211 has(SoughtConstructExpr),
212 has(cxxConstructExpr(argumentCountIs(0))))))));
213 auto HasBracedInitListExpr =
214 anyOf(has(cxxBindTemporaryExpr(HasConstructInitListExpr)),
215 HasConstructInitListExpr);
217 auto MakeTuple = ignoringImplicit(
218 callExpr(callee(expr(ignoringImplicit(declRefExpr(
219 unless(hasExplicitTemplateArgs()),
220 to(functionDecl(hasAnyName(TupleMakeFunctions))))))))
225 auto MakeTupleCtor = ignoringImplicit(cxxConstructExpr(
226 has(materializeTemporaryExpr(MakeTuple)),
227 hasDeclaration(cxxConstructorDecl(ofClass(hasAnyName(TupleTypes))))));
230 materializeTemporaryExpr(
231 anyOf(has(MakeTuple), has(MakeTupleCtor), HasConstructExpr,
232 HasBracedInitListExpr,
233 has(cxxFunctionalCastExpr(HasConstructExpr)),
234 has(cxxFunctionalCastExpr(HasBracedInitListExpr))))
235 .bind(
"temporary_expr");
237 auto HasConstructExprWithValueTypeType =
238 has(ignoringImplicit(cxxConstructExpr(
240 hasType(hasCanonicalType(type(equalsBoundNode(
"value_type")))))));
242 auto HasBracedInitListWithValueTypeType = anyOf(
243 allOf(HasConstructInitListExpr,
244 has(initListExpr(hasType(
245 hasCanonicalType(type(equalsBoundNode(
"value_type"))))))),
246 has(cxxBindTemporaryExpr(HasConstructInitListExpr,
247 has(initListExpr(hasType(hasCanonicalType(
248 type(equalsBoundNode(
"value_type")))))))));
250 auto HasConstructExprWithValueTypeTypeAsLastArgument = hasLastArgument(
251 materializeTemporaryExpr(
252 anyOf(HasConstructExprWithValueTypeType,
253 HasBracedInitListWithValueTypeType,
254 has(cxxFunctionalCastExpr(HasConstructExprWithValueTypeType)),
255 has(cxxFunctionalCastExpr(HasBracedInitListWithValueTypeType))))
256 .bind(
"temporary_expr"));
259 traverse(TK_AsIs, cxxMemberCallExpr(CallPushBack, has(SoughtParam),
260 unless(isInTemplateInstantiation()))
261 .bind(
"push_back_call")),
265 traverse(TK_AsIs, cxxMemberCallExpr(CallPush, has(SoughtParam),
266 unless(isInTemplateInstantiation()))
271 traverse(TK_AsIs, cxxMemberCallExpr(CallPushFront, has(SoughtParam),
272 unless(isInTemplateInstantiation()))
273 .bind(
"push_front_call")),
279 CallEmplacy, HasConstructExprWithValueTypeTypeAsLastArgument,
280 hasSameNumArgsAsDeclNumParams(),
281 unless(isInTemplateInstantiation()))
282 .bind(
"emplacy_call")),
289 on(hasType(cxxRecordDecl(has(typedefNameDecl(
290 hasName(
"value_type"),
291 hasType(hasCanonicalType(recordType(hasDeclaration(
292 cxxRecordDecl(hasAnyName(SmallVector<StringRef, 2>(
293 TupleTypes.begin(), TupleTypes.end())))))))))))),
294 has(MakeTuple), hasSameNumArgsAsDeclNumParams(),
295 unless(isInTemplateInstantiation()))
296 .bind(
"emplacy_call")),
301 const auto *PushBackCall =
302 Result.Nodes.getNodeAs<CXXMemberCallExpr>(
"push_back_call");
303 const auto *PushCall = Result.Nodes.getNodeAs<CXXMemberCallExpr>(
"push_call");
304 const auto *PushFrontCall =
305 Result.Nodes.getNodeAs<CXXMemberCallExpr>(
"push_front_call");
306 const auto *EmplacyCall =
307 Result.Nodes.getNodeAs<CXXMemberCallExpr>(
"emplacy_call");
308 const auto *CtorCall = Result.Nodes.getNodeAs<CXXConstructExpr>(
"ctor");
309 const auto *MakeCall = Result.Nodes.getNodeAs<CallExpr>(
"make");
310 const auto *TemporaryExpr =
311 Result.Nodes.getNodeAs<MaterializeTemporaryExpr>(
"temporary_expr");
313 const CXXMemberCallExpr *Call = [&]() {
319 return PushFrontCall;
323 assert(Call &&
"No call matched");
324 assert((CtorCall || MakeCall) &&
"No push_back parameter matched");
326 if (IgnoreImplicitConstructors && CtorCall && CtorCall->getNumArgs() >= 1 &&
327 CtorCall->getArg(0)->getSourceRange() == CtorCall->getSourceRange())
330 const auto FunctionNameSourceRange = CharSourceRange::getCharRange(
331 Call->getExprLoc(), Call->getArg(0)->getExprLoc());
335 ? diag(TemporaryExpr ? TemporaryExpr->getBeginLoc()
336 : CtorCall ? CtorCall->getBeginLoc()
337 : MakeCall->getBeginLoc(),
338 "unnecessary temporary object created while calling %0")
339 : diag(Call->getExprLoc(),
"use emplace%select{|_back|_front}0 "
340 "instead of push%select{|_back|_front}0");
342 Diag << Call->getMethodDecl()->getName();
345 else if (PushBackCall)
350 if (FunctionNameSourceRange.getBegin().isMacroID())
354 const char *EmplacePrefix = MakeCall ?
"emplace_back" :
"emplace_back(";
355 Diag << FixItHint::CreateReplacement(FunctionNameSourceRange,
357 }
else if (PushCall) {
358 const char *EmplacePrefix = MakeCall ?
"emplace" :
"emplace(";
359 Diag << FixItHint::CreateReplacement(FunctionNameSourceRange,
361 }
else if (PushFrontCall) {
362 const char *EmplacePrefix = MakeCall ?
"emplace_front" :
"emplace_front(";
363 Diag << FixItHint::CreateReplacement(FunctionNameSourceRange,
367 const SourceRange CallParensRange =
368 MakeCall ? SourceRange(MakeCall->getCallee()->getEndLoc(),
369 MakeCall->getRParenLoc())
370 : CtorCall->getParenOrBraceRange();
373 if (CallParensRange.getBegin().isInvalid())
377 const SourceLocation ExprBegin = TemporaryExpr ? TemporaryExpr->getExprLoc()
378 : CtorCall ? CtorCall->getExprLoc()
379 : MakeCall->getExprLoc();
382 const auto ParamCallSourceRange =
383 CharSourceRange::getTokenRange(ExprBegin, CallParensRange.getBegin());
386 const auto EndCallSourceRange = CharSourceRange::getTokenRange(
387 CallParensRange.getEnd(),
388 TemporaryExpr ? TemporaryExpr->getEndLoc() : CallParensRange.getEnd());
390 Diag << FixItHint::CreateRemoval(ParamCallSourceRange)
391 << FixItHint::CreateRemoval(EndCallSourceRange);
393 if (MakeCall && EmplacyCall) {
395 Diag << FixItHint::CreateRemoval(
396 CharSourceRange::getCharRange(MakeCall->getCallee()->getEndLoc(),
397 MakeCall->getArg(0)->getBeginLoc()));