166 auto CallEmplacy = cxxMemberCallExpr(
168 functionDecl(hasAnyNameIgnoringTemplates(EmplacyFunctions))),
170 hasCanonicalType(hasDeclaration(has(typedefNameDecl(
171 hasName(
"value_type"),
172 hasType(hasCanonicalType(recordType().bind(
"value_type"))))))))));
178 auto IsCtorOfSmartPtr =
179 hasDeclaration(cxxConstructorDecl(ofClass(hasAnyName(SmartPointers))));
182 auto BitFieldAsArgument = hasAnyArgument(
183 ignoringImplicit(memberExpr(hasDeclaration(fieldDecl(isBitField())))));
186 auto InitializerListAsArgument = hasAnyArgument(
187 ignoringImplicit(allOf(cxxConstructExpr(isListInitialization()),
188 unless(cxxTemporaryObjectExpr()))));
191 auto NewExprAsArgument = hasAnyArgument(ignoringImplicit(cxxNewExpr()));
193 auto ConstructingDerived =
194 hasParent(implicitCastExpr(hasCastKind(CastKind::CK_DerivedToBase)));
197 auto IsPrivateOrProtectedCtor =
198 hasDeclaration(cxxConstructorDecl(anyOf(isPrivate(), isProtected())));
200 auto HasInitList = anyOf(has(ignoringImplicit(initListExpr())),
201 has(cxxStdInitializerListExpr()));
205 auto SoughtConstructExpr =
207 unless(anyOf(IsCtorOfSmartPtr, HasInitList, BitFieldAsArgument,
208 InitializerListAsArgument, NewExprAsArgument,
209 ConstructingDerived, IsPrivateOrProtectedCtor)))
211 auto HasConstructExpr = has(ignoringImplicit(SoughtConstructExpr));
214 auto HasConstructInitListExpr = has(initListExpr(
215 initCountLeq(1), anyOf(allOf(has(SoughtConstructExpr),
216 has(cxxConstructExpr(argumentCountIs(0)))),
217 has(cxxBindTemporaryExpr(
218 has(SoughtConstructExpr),
219 has(cxxConstructExpr(argumentCountIs(0))))))));
220 auto HasBracedInitListExpr =
221 anyOf(has(cxxBindTemporaryExpr(HasConstructInitListExpr)),
222 HasConstructInitListExpr);
224 auto MakeTuple = ignoringImplicit(
225 callExpr(callee(expr(ignoringImplicit(declRefExpr(
226 unless(hasExplicitTemplateArgs()),
227 to(functionDecl(hasAnyName(TupleMakeFunctions))))))))
232 auto MakeTupleCtor = ignoringImplicit(cxxConstructExpr(
233 has(materializeTemporaryExpr(MakeTuple)),
234 hasDeclaration(cxxConstructorDecl(ofClass(hasAnyName(TupleTypes))))));
237 materializeTemporaryExpr(
238 anyOf(has(MakeTuple), has(MakeTupleCtor), HasConstructExpr,
239 HasBracedInitListExpr,
240 has(cxxFunctionalCastExpr(HasConstructExpr)),
241 has(cxxFunctionalCastExpr(HasBracedInitListExpr))))
242 .bind(
"temporary_expr");
244 auto HasConstructExprWithValueTypeType =
245 has(ignoringImplicit(cxxConstructExpr(
247 hasType(hasCanonicalType(type(equalsBoundNode(
"value_type")))))));
249 auto HasBracedInitListWithValueTypeType = anyOf(
250 allOf(HasConstructInitListExpr,
251 has(initListExpr(hasType(
252 hasCanonicalType(type(equalsBoundNode(
"value_type"))))))),
253 has(cxxBindTemporaryExpr(HasConstructInitListExpr,
254 has(initListExpr(hasType(hasCanonicalType(
255 type(equalsBoundNode(
"value_type")))))))));
257 auto HasConstructExprWithValueTypeTypeAsLastArgument = hasLastArgument(
258 materializeTemporaryExpr(
259 anyOf(HasConstructExprWithValueTypeType,
260 HasBracedInitListWithValueTypeType,
261 has(cxxFunctionalCastExpr(HasConstructExprWithValueTypeType)),
262 has(cxxFunctionalCastExpr(HasBracedInitListWithValueTypeType))))
263 .bind(
"temporary_expr"));
266 traverse(TK_AsIs, cxxMemberCallExpr(CallPushBack, has(SoughtParam),
267 unless(isInTemplateInstantiation()))
268 .bind(
"push_back_call")),
272 traverse(TK_AsIs, cxxMemberCallExpr(CallPush, has(SoughtParam),
273 unless(isInTemplateInstantiation()))
278 traverse(TK_AsIs, cxxMemberCallExpr(CallPushFront, has(SoughtParam),
279 unless(isInTemplateInstantiation()))
280 .bind(
"push_front_call")),
286 CallEmplacy, HasConstructExprWithValueTypeTypeAsLastArgument,
287 hasSameNumArgsAsDeclNumParams(),
288 unless(isInTemplateInstantiation()))
289 .bind(
"emplacy_call")),
296 on(hasType(cxxRecordDecl(has(typedefNameDecl(
297 hasName(
"value_type"),
298 hasType(hasCanonicalType(recordType(hasDeclaration(
299 cxxRecordDecl(hasAnyName(SmallVector<StringRef, 2>(
300 TupleTypes.begin(), TupleTypes.end())))))))))))),
301 has(MakeTuple), hasSameNumArgsAsDeclNumParams(),
302 unless(isInTemplateInstantiation()))
303 .bind(
"emplacy_call")),
308 const auto *PushBackCall =
309 Result.Nodes.getNodeAs<CXXMemberCallExpr>(
"push_back_call");
310 const auto *PushCall = Result.Nodes.getNodeAs<CXXMemberCallExpr>(
"push_call");
311 const auto *PushFrontCall =
312 Result.Nodes.getNodeAs<CXXMemberCallExpr>(
"push_front_call");
313 const auto *EmplacyCall =
314 Result.Nodes.getNodeAs<CXXMemberCallExpr>(
"emplacy_call");
315 const auto *CtorCall = Result.Nodes.getNodeAs<CXXConstructExpr>(
"ctor");
316 const auto *MakeCall = Result.Nodes.getNodeAs<CallExpr>(
"make");
317 const auto *TemporaryExpr =
318 Result.Nodes.getNodeAs<MaterializeTemporaryExpr>(
"temporary_expr");
320 const CXXMemberCallExpr *Call = [&]() {
328 return PushFrontCall;
333 assert(Call &&
"No call matched");
334 assert((CtorCall || MakeCall) &&
"No push_back parameter matched");
336 if (IgnoreImplicitConstructors && CtorCall && CtorCall->getNumArgs() >= 1 &&
337 CtorCall->getArg(0)->getSourceRange() == CtorCall->getSourceRange())
340 const auto FunctionNameSourceRange = CharSourceRange::getCharRange(
341 Call->getExprLoc(), Call->getArg(0)->getExprLoc());
345 ? diag(TemporaryExpr ? TemporaryExpr->getBeginLoc()
346 : CtorCall ? CtorCall->getBeginLoc()
347 : MakeCall->getBeginLoc(),
348 "unnecessary temporary object created while calling %0")
349 : diag(Call->getExprLoc(),
"use emplace%select{|_back|_front}0 "
350 "instead of push%select{|_back|_front}0");
352 Diag << Call->getMethodDecl()->getName();
355 else if (PushBackCall)
360 if (FunctionNameSourceRange.getBegin().isMacroID())
364 const char *EmplacePrefix = MakeCall ?
"emplace_back" :
"emplace_back(";
365 Diag << FixItHint::CreateReplacement(FunctionNameSourceRange,
367 }
else if (PushCall) {
368 const char *EmplacePrefix = MakeCall ?
"emplace" :
"emplace(";
369 Diag << FixItHint::CreateReplacement(FunctionNameSourceRange,
371 }
else if (PushFrontCall) {
372 const char *EmplacePrefix = MakeCall ?
"emplace_front" :
"emplace_front(";
373 Diag << FixItHint::CreateReplacement(FunctionNameSourceRange,
377 const SourceRange CallParensRange =
378 MakeCall ? SourceRange(MakeCall->getCallee()->getEndLoc(),
379 MakeCall->getRParenLoc())
380 : CtorCall->getParenOrBraceRange();
383 if (CallParensRange.getBegin().isInvalid())
387 const SourceLocation ExprBegin = TemporaryExpr ? TemporaryExpr->getExprLoc()
388 : CtorCall ? CtorCall->getExprLoc()
389 : MakeCall->getExprLoc();
392 const auto ParamCallSourceRange =
393 CharSourceRange::getTokenRange(ExprBegin, CallParensRange.getBegin());
396 const auto EndCallSourceRange = CharSourceRange::getTokenRange(
397 CallParensRange.getEnd(),
398 TemporaryExpr ? TemporaryExpr->getEndLoc() : CallParensRange.getEnd());
400 Diag << FixItHint::CreateRemoval(ParamCallSourceRange)
401 << FixItHint::CreateRemoval(EndCallSourceRange);
403 if (MakeCall && EmplacyCall) {
405 Diag << FixItHint::CreateRemoval(
406 CharSourceRange::getCharRange(MakeCall->getCallee()->getEndLoc(),
407 MakeCall->getArg(0)->getBeginLoc()));