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()))));
185 auto NewExprAsArgument = hasAnyArgument(ignoringImplicit(cxxNewExpr()));
187 auto ConstructingDerived =
188 hasParent(implicitCastExpr(hasCastKind(CastKind::CK_DerivedToBase)));
191 auto IsPrivateOrProtectedCtor =
192 hasDeclaration(cxxConstructorDecl(anyOf(isPrivate(), isProtected())));
194 auto HasInitList = anyOf(has(ignoringImplicit(initListExpr())),
195 has(cxxStdInitializerListExpr()));
199 const auto SoughtConstructExpr =
201 unless(anyOf(IsCtorOfSmartPtr, HasInitList, BitFieldAsArgument,
202 InitializerListAsArgument, NewExprAsArgument,
203 ConstructingDerived, IsPrivateOrProtectedCtor)))
205 auto HasConstructExpr = has(ignoringImplicit(SoughtConstructExpr));
208 auto HasConstructInitListExpr = has(initListExpr(
209 initCountLeq(1), anyOf(allOf(has(SoughtConstructExpr),
210 has(cxxConstructExpr(argumentCountIs(0)))),
211 has(cxxBindTemporaryExpr(
212 has(SoughtConstructExpr),
213 has(cxxConstructExpr(argumentCountIs(0))))))));
214 auto HasBracedInitListExpr =
215 anyOf(has(cxxBindTemporaryExpr(HasConstructInitListExpr)),
216 HasConstructInitListExpr);
218 const auto MakeTuple = ignoringImplicit(
219 callExpr(callee(expr(ignoringImplicit(declRefExpr(
220 unless(hasExplicitTemplateArgs()),
221 to(functionDecl(hasAnyName(TupleMakeFunctions))))))))
226 const auto MakeTupleCtor = ignoringImplicit(cxxConstructExpr(
227 has(materializeTemporaryExpr(MakeTuple)),
228 hasDeclaration(cxxConstructorDecl(ofClass(hasAnyName(TupleTypes))))));
230 const auto SoughtParam =
231 materializeTemporaryExpr(
232 anyOf(has(MakeTuple), has(MakeTupleCtor), HasConstructExpr,
233 HasBracedInitListExpr,
234 has(cxxFunctionalCastExpr(HasConstructExpr)),
235 has(cxxFunctionalCastExpr(HasBracedInitListExpr))))
236 .bind(
"temporary_expr");
238 auto HasConstructExprWithValueTypeType =
239 has(ignoringImplicit(cxxConstructExpr(
241 hasType(hasCanonicalType(type(equalsBoundNode(
"value_type")))))));
243 auto HasBracedInitListWithValueTypeType = anyOf(
244 allOf(HasConstructInitListExpr,
245 has(initListExpr(hasType(
246 hasCanonicalType(type(equalsBoundNode(
"value_type"))))))),
247 has(cxxBindTemporaryExpr(HasConstructInitListExpr,
248 has(initListExpr(hasType(hasCanonicalType(
249 type(equalsBoundNode(
"value_type")))))))));
251 const auto HasConstructExprWithValueTypeTypeAsLastArgument = hasLastArgument(
252 materializeTemporaryExpr(
253 anyOf(HasConstructExprWithValueTypeType,
254 HasBracedInitListWithValueTypeType,
255 has(cxxFunctionalCastExpr(HasConstructExprWithValueTypeType)),
256 has(cxxFunctionalCastExpr(HasBracedInitListWithValueTypeType))))
257 .bind(
"temporary_expr"));
260 traverse(TK_AsIs, cxxMemberCallExpr(CallPushBack, has(SoughtParam),
261 unless(isInTemplateInstantiation()))
262 .bind(
"push_back_call")),
266 traverse(TK_AsIs, cxxMemberCallExpr(CallPush, has(SoughtParam),
267 unless(isInTemplateInstantiation()))
272 traverse(TK_AsIs, cxxMemberCallExpr(CallPushFront, has(SoughtParam),
273 unless(isInTemplateInstantiation()))
274 .bind(
"push_front_call")),
280 CallEmplacy, HasConstructExprWithValueTypeTypeAsLastArgument,
281 hasSameNumArgsAsDeclNumParams(),
282 unless(isInTemplateInstantiation()))
283 .bind(
"emplacy_call")),
290 on(hasType(cxxRecordDecl(has(typedefNameDecl(
291 hasName(
"value_type"),
292 hasType(hasCanonicalType(recordType(hasDeclaration(
294 TupleTypes.begin(), TupleTypes.end())))))))))))),
295 has(MakeTuple), hasSameNumArgsAsDeclNumParams(),
296 unless(isInTemplateInstantiation()))
297 .bind(
"emplacy_call")),
302 const auto *PushBackCall =
303 Result.Nodes.getNodeAs<CXXMemberCallExpr>(
"push_back_call");
304 const auto *PushCall = Result.Nodes.getNodeAs<CXXMemberCallExpr>(
"push_call");
305 const auto *PushFrontCall =
306 Result.Nodes.getNodeAs<CXXMemberCallExpr>(
"push_front_call");
307 const auto *EmplacyCall =
308 Result.Nodes.getNodeAs<CXXMemberCallExpr>(
"emplacy_call");
309 const auto *CtorCall = Result.Nodes.getNodeAs<CXXConstructExpr>(
"ctor");
310 const auto *MakeCall = Result.Nodes.getNodeAs<CallExpr>(
"make");
311 const auto *TemporaryExpr =
312 Result.Nodes.getNodeAs<MaterializeTemporaryExpr>(
"temporary_expr");
314 const CXXMemberCallExpr *Call = [&]() {
320 return PushFrontCall;
324 assert(Call &&
"No call matched");
325 assert((CtorCall || MakeCall) &&
"No push_back parameter matched");
327 if (IgnoreImplicitConstructors && CtorCall && CtorCall->getNumArgs() >= 1 &&
328 CtorCall->getArg(0)->getSourceRange() == CtorCall->getSourceRange())
331 const auto FunctionNameSourceRange = CharSourceRange::getCharRange(
332 Call->getExprLoc(), Call->getArg(0)->getExprLoc());
336 ? diag(TemporaryExpr ? TemporaryExpr->getBeginLoc()
337 : CtorCall ? CtorCall->getBeginLoc()
338 : MakeCall->getBeginLoc(),
339 "unnecessary temporary object created while calling %0")
340 : diag(Call->getExprLoc(),
"use emplace%select{|_back|_front}0 "
341 "instead of push%select{|_back|_front}0");
343 Diag << Call->getMethodDecl()->getName();
346 else if (PushBackCall)
351 if (FunctionNameSourceRange.getBegin().isMacroID())
355 const char *EmplacePrefix = MakeCall ?
"emplace_back" :
"emplace_back(";
356 Diag << FixItHint::CreateReplacement(FunctionNameSourceRange,
358 }
else if (PushCall) {
359 const char *EmplacePrefix = MakeCall ?
"emplace" :
"emplace(";
360 Diag << FixItHint::CreateReplacement(FunctionNameSourceRange,
362 }
else if (PushFrontCall) {
363 const char *EmplacePrefix = MakeCall ?
"emplace_front" :
"emplace_front(";
364 Diag << FixItHint::CreateReplacement(FunctionNameSourceRange,
368 const SourceRange CallParensRange =
369 MakeCall ? SourceRange(MakeCall->getCallee()->getEndLoc(),
370 MakeCall->getRParenLoc())
371 : CtorCall->getParenOrBraceRange();
374 if (CallParensRange.getBegin().isInvalid())
378 const SourceLocation ExprBegin = TemporaryExpr ? TemporaryExpr->getExprLoc()
379 : CtorCall ? CtorCall->getExprLoc()
380 : MakeCall->getExprLoc();
383 const auto ParamCallSourceRange =
384 CharSourceRange::getTokenRange(ExprBegin, CallParensRange.getBegin());
387 const auto EndCallSourceRange = CharSourceRange::getTokenRange(
388 CallParensRange.getEnd(),
389 TemporaryExpr ? TemporaryExpr->getEndLoc() : CallParensRange.getEnd());
391 Diag << FixItHint::CreateRemoval(ParamCallSourceRange)
392 << FixItHint::CreateRemoval(EndCallSourceRange);
394 if (MakeCall && EmplacyCall) {
396 Diag << FixItHint::CreateRemoval(
397 CharSourceRange::getCharRange(MakeCall->getCallee()->getEndLoc(),
398 MakeCall->getArg(0)->getBeginLoc()));