153 const auto CallPushBack =
155 const auto CallPush =
157 const auto CallPushFront =
160 const auto CallEmplacy = cxxMemberCallExpr(
162 functionDecl(hasAnyNameIgnoringTemplates(EmplacyFunctions))),
164 hasCanonicalType(hasDeclaration(has(typedefNameDecl(
165 hasName(
"value_type"),
166 hasType(hasCanonicalType(recordType().bind(
"value_type"))))))))));
172 auto IsCtorOfSmartPtr =
173 hasDeclaration(cxxConstructorDecl(ofClass(hasAnyName(SmartPointers))));
176 auto BitFieldAsArgument = hasAnyArgument(
177 ignoringImplicit(memberExpr(hasDeclaration(fieldDecl(isBitField())))));
180 auto InitializerListAsArgument = hasAnyArgument(
181 ignoringImplicit(allOf(cxxConstructExpr(isListInitialization()),
182 unless(cxxTemporaryObjectExpr()))));
186 auto NullPointerConstantAsArgument = hasAnyArgument(
187 expr(hasType(hasCanonicalType(anyOf(pointerType(), memberPointerType()))),
189 ignoringParenImpCasts(anyOf(integerLiteral(), gnuNullExpr())))));
192 auto NewExprAsArgument = hasAnyArgument(ignoringImplicit(cxxNewExpr()));
194 auto ConstructingDerived =
195 hasParent(implicitCastExpr(hasCastKind(CastKind::CK_DerivedToBase)));
198 auto IsPrivateOrProtectedCtor =
199 hasDeclaration(cxxConstructorDecl(anyOf(isPrivate(), isProtected())));
201 auto HasInitList = anyOf(has(ignoringImplicit(initListExpr())),
202 has(cxxStdInitializerListExpr()));
206 const auto SoughtConstructExpr =
208 unless(anyOf(IsCtorOfSmartPtr, HasInitList, BitFieldAsArgument,
209 NullPointerConstantAsArgument, InitializerListAsArgument,
210 NewExprAsArgument, ConstructingDerived,
211 IsPrivateOrProtectedCtor)))
213 auto HasConstructExpr = has(ignoringImplicit(SoughtConstructExpr));
216 auto HasConstructInitListExpr = has(initListExpr(
217 initCountLeq(1), anyOf(allOf(has(SoughtConstructExpr),
218 has(cxxConstructExpr(argumentCountIs(0)))),
219 has(cxxBindTemporaryExpr(
220 has(SoughtConstructExpr),
221 has(cxxConstructExpr(argumentCountIs(0))))))));
222 auto HasBracedInitListExpr =
223 anyOf(has(cxxBindTemporaryExpr(HasConstructInitListExpr)),
224 HasConstructInitListExpr);
226 const auto MakeTuple = ignoringImplicit(
227 callExpr(callee(expr(ignoringImplicit(declRefExpr(
228 unless(hasExplicitTemplateArgs()),
229 to(functionDecl(hasAnyName(TupleMakeFunctions))))))))
234 const auto MakeTupleCtor = ignoringImplicit(cxxConstructExpr(
235 has(materializeTemporaryExpr(MakeTuple)),
236 hasDeclaration(cxxConstructorDecl(ofClass(hasAnyName(TupleTypes))))));
238 const auto SoughtParam =
239 materializeTemporaryExpr(
240 anyOf(has(MakeTuple), has(MakeTupleCtor), HasConstructExpr,
241 HasBracedInitListExpr,
242 has(cxxFunctionalCastExpr(HasConstructExpr)),
243 has(cxxFunctionalCastExpr(HasBracedInitListExpr))))
244 .bind(
"temporary_expr");
246 auto HasConstructExprWithValueTypeType =
247 has(ignoringImplicit(cxxConstructExpr(
249 hasType(hasCanonicalType(type(equalsBoundNode(
"value_type")))))));
251 auto HasBracedInitListWithValueTypeType = anyOf(
252 allOf(HasConstructInitListExpr,
253 has(initListExpr(hasType(
254 hasCanonicalType(type(equalsBoundNode(
"value_type"))))))),
255 has(cxxBindTemporaryExpr(HasConstructInitListExpr,
256 has(initListExpr(hasType(hasCanonicalType(
257 type(equalsBoundNode(
"value_type")))))))));
259 const auto HasConstructExprWithValueTypeTypeAsLastArgument = hasLastArgument(
260 materializeTemporaryExpr(
261 anyOf(HasConstructExprWithValueTypeType,
262 HasBracedInitListWithValueTypeType,
263 has(cxxFunctionalCastExpr(HasConstructExprWithValueTypeType)),
264 has(cxxFunctionalCastExpr(HasBracedInitListWithValueTypeType))))
265 .bind(
"temporary_expr"));
268 traverse(TK_AsIs, cxxMemberCallExpr(CallPushBack, has(SoughtParam),
269 unless(isInTemplateInstantiation()))
270 .bind(
"push_back_call")),
274 traverse(TK_AsIs, cxxMemberCallExpr(CallPush, has(SoughtParam),
275 unless(isInTemplateInstantiation()))
280 traverse(TK_AsIs, cxxMemberCallExpr(CallPushFront, has(SoughtParam),
281 unless(isInTemplateInstantiation()))
282 .bind(
"push_front_call")),
288 CallEmplacy, HasConstructExprWithValueTypeTypeAsLastArgument,
289 hasSameNumArgsAsDeclNumParams(),
290 unless(isInTemplateInstantiation()))
291 .bind(
"emplacy_call")),
298 on(hasType(cxxRecordDecl(has(typedefNameDecl(
299 hasName(
"value_type"),
300 hasType(hasCanonicalType(recordType(hasDeclaration(
302 TupleTypes.begin(), TupleTypes.end())))))))))))),
303 has(MakeTuple), hasSameNumArgsAsDeclNumParams(),
304 unless(isInTemplateInstantiation()))
305 .bind(
"emplacy_call")),
310 const auto *PushBackCall =
311 Result.Nodes.getNodeAs<CXXMemberCallExpr>(
"push_back_call");
312 const auto *PushCall = Result.Nodes.getNodeAs<CXXMemberCallExpr>(
"push_call");
313 const auto *PushFrontCall =
314 Result.Nodes.getNodeAs<CXXMemberCallExpr>(
"push_front_call");
315 const auto *EmplacyCall =
316 Result.Nodes.getNodeAs<CXXMemberCallExpr>(
"emplacy_call");
317 const auto *CtorCall = Result.Nodes.getNodeAs<CXXConstructExpr>(
"ctor");
318 const auto *MakeCall = Result.Nodes.getNodeAs<CallExpr>(
"make");
319 const auto *TemporaryExpr =
320 Result.Nodes.getNodeAs<MaterializeTemporaryExpr>(
"temporary_expr");
322 const CXXMemberCallExpr *Call = [&]() {
328 return PushFrontCall;
332 assert(Call &&
"No call matched");
333 assert((CtorCall || MakeCall) &&
"No push_back parameter matched");
335 if (IgnoreImplicitConstructors && CtorCall && CtorCall->getNumArgs() >= 1 &&
336 CtorCall->getArg(0)->getSourceRange() == CtorCall->getSourceRange())
339 const auto FunctionNameSourceRange = CharSourceRange::getCharRange(
340 Call->getExprLoc(), Call->getArg(0)->getExprLoc());
344 ? diag(TemporaryExpr ? TemporaryExpr->getBeginLoc()
345 : CtorCall ? CtorCall->getBeginLoc()
346 : MakeCall->getBeginLoc(),
347 "unnecessary temporary object created while calling %0")
348 : diag(Call->getExprLoc(),
"use emplace%select{|_back|_front}0 "
349 "instead of push%select{|_back|_front}0");
351 Diag << Call->getMethodDecl()->getName();
354 else if (PushBackCall)
359 if (FunctionNameSourceRange.getBegin().isMacroID())
363 const char *EmplacePrefix = MakeCall ?
"emplace_back" :
"emplace_back(";
364 Diag << FixItHint::CreateReplacement(FunctionNameSourceRange,
366 }
else if (PushCall) {
367 const char *EmplacePrefix = MakeCall ?
"emplace" :
"emplace(";
368 Diag << FixItHint::CreateReplacement(FunctionNameSourceRange,
370 }
else if (PushFrontCall) {
371 const char *EmplacePrefix = MakeCall ?
"emplace_front" :
"emplace_front(";
372 Diag << FixItHint::CreateReplacement(FunctionNameSourceRange,
376 const SourceRange CallParensRange =
377 MakeCall ? SourceRange(MakeCall->getCallee()->getEndLoc(),
378 MakeCall->getRParenLoc())
379 : CtorCall->getParenOrBraceRange();
382 if (CallParensRange.getBegin().isInvalid())
386 const SourceLocation ExprBegin = TemporaryExpr ? TemporaryExpr->getExprLoc()
387 : CtorCall ? CtorCall->getExprLoc()
388 : MakeCall->getExprLoc();
391 const auto ParamCallSourceRange =
392 CharSourceRange::getTokenRange(ExprBegin, CallParensRange.getBegin());
395 const auto EndCallSourceRange = CharSourceRange::getTokenRange(
396 CallParensRange.getEnd(),
397 TemporaryExpr ? TemporaryExpr->getEndLoc() : CallParensRange.getEnd());
399 Diag << FixItHint::CreateRemoval(ParamCallSourceRange)
400 << FixItHint::CreateRemoval(EndCallSourceRange);
402 if (MakeCall && EmplacyCall) {
404 Diag << FixItHint::CreateRemoval(
405 CharSourceRange::getCharRange(MakeCall->getCallee()->getEndLoc(),
406 MakeCall->getArg(0)->getBeginLoc()));