161 auto CallEmplacy = cxxMemberCallExpr(
163 functionDecl(hasAnyNameIgnoringTemplates(EmplacyFunctions))),
165 hasCanonicalType(hasDeclaration(has(typedefNameDecl(
166 hasName(
"value_type"),
167 hasType(hasCanonicalType(recordType().bind(
"value_type"))))))))));
173 auto IsCtorOfSmartPtr =
174 hasDeclaration(cxxConstructorDecl(ofClass(hasAnyName(SmartPointers))));
177 auto BitFieldAsArgument = hasAnyArgument(
178 ignoringImplicit(memberExpr(hasDeclaration(fieldDecl(isBitField())))));
181 auto InitializerListAsArgument = hasAnyArgument(
182 ignoringImplicit(allOf(cxxConstructExpr(isListInitialization()),
183 unless(cxxTemporaryObjectExpr()))));
186 auto NewExprAsArgument = hasAnyArgument(ignoringImplicit(cxxNewExpr()));
188 auto ConstructingDerived =
189 hasParent(implicitCastExpr(hasCastKind(CastKind::CK_DerivedToBase)));
192 auto IsPrivateOrProtectedCtor =
193 hasDeclaration(cxxConstructorDecl(anyOf(isPrivate(), isProtected())));
195 auto HasInitList = anyOf(has(ignoringImplicit(initListExpr())),
196 has(cxxStdInitializerListExpr()));
200 auto SoughtConstructExpr =
202 unless(anyOf(IsCtorOfSmartPtr, HasInitList, BitFieldAsArgument,
203 InitializerListAsArgument, NewExprAsArgument,
204 ConstructingDerived, IsPrivateOrProtectedCtor)))
206 auto HasConstructExpr = has(ignoringImplicit(SoughtConstructExpr));
209 auto HasConstructInitListExpr = has(initListExpr(
210 initCountLeq(1), anyOf(allOf(has(SoughtConstructExpr),
211 has(cxxConstructExpr(argumentCountIs(0)))),
212 has(cxxBindTemporaryExpr(
213 has(SoughtConstructExpr),
214 has(cxxConstructExpr(argumentCountIs(0))))))));
215 auto HasBracedInitListExpr =
216 anyOf(has(cxxBindTemporaryExpr(HasConstructInitListExpr)),
217 HasConstructInitListExpr);
219 auto MakeTuple = ignoringImplicit(
220 callExpr(callee(expr(ignoringImplicit(declRefExpr(
221 unless(hasExplicitTemplateArgs()),
222 to(functionDecl(hasAnyName(TupleMakeFunctions))))))))
227 auto MakeTupleCtor = ignoringImplicit(cxxConstructExpr(
228 has(materializeTemporaryExpr(MakeTuple)),
229 hasDeclaration(cxxConstructorDecl(ofClass(hasAnyName(TupleTypes))))));
232 materializeTemporaryExpr(
233 anyOf(has(MakeTuple), has(MakeTupleCtor), HasConstructExpr,
234 HasBracedInitListExpr,
235 has(cxxFunctionalCastExpr(HasConstructExpr)),
236 has(cxxFunctionalCastExpr(HasBracedInitListExpr))))
237 .bind(
"temporary_expr");
239 auto HasConstructExprWithValueTypeType =
240 has(ignoringImplicit(cxxConstructExpr(
242 hasType(hasCanonicalType(type(equalsBoundNode(
"value_type")))))));
244 auto HasBracedInitListWithValueTypeType = anyOf(
245 allOf(HasConstructInitListExpr,
246 has(initListExpr(hasType(
247 hasCanonicalType(type(equalsBoundNode(
"value_type"))))))),
248 has(cxxBindTemporaryExpr(HasConstructInitListExpr,
249 has(initListExpr(hasType(hasCanonicalType(
250 type(equalsBoundNode(
"value_type")))))))));
252 auto HasConstructExprWithValueTypeTypeAsLastArgument = hasLastArgument(
253 materializeTemporaryExpr(
254 anyOf(HasConstructExprWithValueTypeType,
255 HasBracedInitListWithValueTypeType,
256 has(cxxFunctionalCastExpr(HasConstructExprWithValueTypeType)),
257 has(cxxFunctionalCastExpr(HasBracedInitListWithValueTypeType))))
258 .bind(
"temporary_expr"));
261 traverse(TK_AsIs, cxxMemberCallExpr(CallPushBack, has(SoughtParam),
262 unless(isInTemplateInstantiation()))
263 .bind(
"push_back_call")),
267 traverse(TK_AsIs, cxxMemberCallExpr(CallPush, has(SoughtParam),
268 unless(isInTemplateInstantiation()))
273 traverse(TK_AsIs, cxxMemberCallExpr(CallPushFront, has(SoughtParam),
274 unless(isInTemplateInstantiation()))
275 .bind(
"push_front_call")),
281 CallEmplacy, HasConstructExprWithValueTypeTypeAsLastArgument,
282 hasSameNumArgsAsDeclNumParams(),
283 unless(isInTemplateInstantiation()))
284 .bind(
"emplacy_call")),
291 on(hasType(cxxRecordDecl(has(typedefNameDecl(
292 hasName(
"value_type"),
293 hasType(hasCanonicalType(recordType(hasDeclaration(
294 cxxRecordDecl(hasAnyName(SmallVector<StringRef, 2>(
295 TupleTypes.begin(), TupleTypes.end())))))))))))),
296 has(MakeTuple), hasSameNumArgsAsDeclNumParams(),
297 unless(isInTemplateInstantiation()))
298 .bind(
"emplacy_call")),
303 const auto *PushBackCall =
304 Result.Nodes.getNodeAs<CXXMemberCallExpr>(
"push_back_call");
305 const auto *PushCall = Result.Nodes.getNodeAs<CXXMemberCallExpr>(
"push_call");
306 const auto *PushFrontCall =
307 Result.Nodes.getNodeAs<CXXMemberCallExpr>(
"push_front_call");
308 const auto *EmplacyCall =
309 Result.Nodes.getNodeAs<CXXMemberCallExpr>(
"emplacy_call");
310 const auto *CtorCall = Result.Nodes.getNodeAs<CXXConstructExpr>(
"ctor");
311 const auto *MakeCall = Result.Nodes.getNodeAs<CallExpr>(
"make");
312 const auto *TemporaryExpr =
313 Result.Nodes.getNodeAs<MaterializeTemporaryExpr>(
"temporary_expr");
315 const CXXMemberCallExpr *Call = [&]() {
323 return PushFrontCall;
328 assert(Call &&
"No call matched");
329 assert((CtorCall || MakeCall) &&
"No push_back parameter matched");
331 if (IgnoreImplicitConstructors && CtorCall && CtorCall->getNumArgs() >= 1 &&
332 CtorCall->getArg(0)->getSourceRange() == CtorCall->getSourceRange())
335 const auto FunctionNameSourceRange = CharSourceRange::getCharRange(
336 Call->getExprLoc(), Call->getArg(0)->getExprLoc());
340 ? diag(TemporaryExpr ? TemporaryExpr->getBeginLoc()
341 : CtorCall ? CtorCall->getBeginLoc()
342 : MakeCall->getBeginLoc(),
343 "unnecessary temporary object created while calling %0")
344 : diag(Call->getExprLoc(),
"use emplace%select{|_back|_front}0 "
345 "instead of push%select{|_back|_front}0");
347 Diag << Call->getMethodDecl()->getName();
350 else if (PushBackCall)
355 if (FunctionNameSourceRange.getBegin().isMacroID())
359 const char *EmplacePrefix = MakeCall ?
"emplace_back" :
"emplace_back(";
360 Diag << FixItHint::CreateReplacement(FunctionNameSourceRange,
362 }
else if (PushCall) {
363 const char *EmplacePrefix = MakeCall ?
"emplace" :
"emplace(";
364 Diag << FixItHint::CreateReplacement(FunctionNameSourceRange,
366 }
else if (PushFrontCall) {
367 const char *EmplacePrefix = MakeCall ?
"emplace_front" :
"emplace_front(";
368 Diag << FixItHint::CreateReplacement(FunctionNameSourceRange,
372 const SourceRange CallParensRange =
373 MakeCall ? SourceRange(MakeCall->getCallee()->getEndLoc(),
374 MakeCall->getRParenLoc())
375 : CtorCall->getParenOrBraceRange();
378 if (CallParensRange.getBegin().isInvalid())
382 const SourceLocation ExprBegin = TemporaryExpr ? TemporaryExpr->getExprLoc()
383 : CtorCall ? CtorCall->getExprLoc()
384 : MakeCall->getExprLoc();
387 const auto ParamCallSourceRange =
388 CharSourceRange::getTokenRange(ExprBegin, CallParensRange.getBegin());
391 const auto EndCallSourceRange = CharSourceRange::getTokenRange(
392 CallParensRange.getEnd(),
393 TemporaryExpr ? TemporaryExpr->getEndLoc() : CallParensRange.getEnd());
395 Diag << FixItHint::CreateRemoval(ParamCallSourceRange)
396 << FixItHint::CreateRemoval(EndCallSourceRange);
398 if (MakeCall && EmplacyCall) {
400 Diag << FixItHint::CreateRemoval(
401 CharSourceRange::getCharRange(MakeCall->getCallee()->getEndLoc(),
402 MakeCall->getArg(0)->getBeginLoc()));