summaryrefslogtreecommitdiffstats
path: root/clang-tools-extra/clang-tidy/modernize/UseEmplaceCheck.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang-tools-extra/clang-tidy/modernize/UseEmplaceCheck.cpp')
-rw-r--r--clang-tools-extra/clang-tidy/modernize/UseEmplaceCheck.cpp54
1 files changed, 40 insertions, 14 deletions
diff --git a/clang-tools-extra/clang-tidy/modernize/UseEmplaceCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseEmplaceCheck.cpp
index 4084454ca0d..4c6991ccc16 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseEmplaceCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseEmplaceCheck.cpp
@@ -15,10 +15,16 @@ namespace clang {
namespace tidy {
namespace modernize {
-static const auto DefaultContainersWithPushBack =
+namespace {
+AST_MATCHER(DeclRefExpr, hasExplicitTemplateArgs) {
+ return Node.hasExplicitTemplateArgs();
+}
+
+const auto DefaultContainersWithPushBack =
"::std::vector; ::std::list; ::std::deque";
-static const auto DefaultSmartPointers =
+const auto DefaultSmartPointers =
"::std::shared_ptr; ::std::unique_ptr; ::std::auto_ptr; ::std::weak_ptr";
+} // namespace
UseEmplaceCheck::UseEmplaceCheck(StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context),
@@ -39,7 +45,6 @@ void UseEmplaceCheck::registerMatchers(MatchFinder *Finder) {
// because this requires special treatment (it could cause performance
// regression)
// + match for emplace calls that should be replaced with insertion
- // + match for make_pair calls.
auto callPushBack = cxxMemberCallExpr(
hasDeclaration(functionDecl(hasName("push_back"))),
on(hasType(cxxRecordDecl(hasAnyName(SmallVector<StringRef, 5>(
@@ -80,10 +85,23 @@ void UseEmplaceCheck::registerMatchers(MatchFinder *Finder) {
.bind("ctor");
auto hasConstructExpr = has(ignoringImplicit(soughtConstructExpr));
- auto ctorAsArgument = materializeTemporaryExpr(
- anyOf(hasConstructExpr, has(cxxFunctionalCastExpr(hasConstructExpr))));
+ auto makePair = ignoringImplicit(
+ callExpr(callee(expr(ignoringImplicit(
+ declRefExpr(unless(hasExplicitTemplateArgs()),
+ to(functionDecl(hasName("::std::make_pair"))))
+ )))).bind("make_pair"));
+
+ // make_pair can return type convertible to container's element type.
+ // Allow the conversion only on containers of pairs.
+ auto makePairCtor = ignoringImplicit(cxxConstructExpr(
+ has(materializeTemporaryExpr(makePair)),
+ hasDeclaration(cxxConstructorDecl(ofClass(hasName("::std::pair"))))));
- Finder->addMatcher(cxxMemberCallExpr(callPushBack, has(ctorAsArgument),
+ auto soughtParam = materializeTemporaryExpr(
+ anyOf(has(makePair), has(makePairCtor),
+ hasConstructExpr, has(cxxFunctionalCastExpr(hasConstructExpr))));
+
+ Finder->addMatcher(cxxMemberCallExpr(callPushBack, has(soughtParam),
unless(isInTemplateInstantiation()))
.bind("call"),
this);
@@ -92,8 +110,10 @@ void UseEmplaceCheck::registerMatchers(MatchFinder *Finder) {
void UseEmplaceCheck::check(const MatchFinder::MatchResult &Result) {
const auto *Call = Result.Nodes.getNodeAs<CXXMemberCallExpr>("call");
const auto *InnerCtorCall = Result.Nodes.getNodeAs<CXXConstructExpr>("ctor");
+ const auto *MakePairCall = Result.Nodes.getNodeAs<CallExpr>("make_pair");
+ assert((InnerCtorCall || MakePairCall) && "No push_back parameter matched");
- auto FunctionNameSourceRange = CharSourceRange::getCharRange(
+ const auto FunctionNameSourceRange = CharSourceRange::getCharRange(
Call->getExprLoc(), Call->getArg(0)->getExprLoc());
auto Diag = diag(Call->getExprLoc(), "use emplace_back instead of push_back");
@@ -101,22 +121,28 @@ void UseEmplaceCheck::check(const MatchFinder::MatchResult &Result) {
if (FunctionNameSourceRange.getBegin().isMacroID())
return;
- Diag << FixItHint::CreateReplacement(FunctionNameSourceRange,
- "emplace_back(");
+ const auto *EmplacePrefix = MakePairCall ? "emplace_back" : "emplace_back(";
+ Diag << FixItHint::CreateReplacement(FunctionNameSourceRange, EmplacePrefix);
- auto CallParensRange = InnerCtorCall->getParenOrBraceRange();
+ const SourceRange CallParensRange =
+ MakePairCall ? SourceRange(MakePairCall->getCallee()->getLocEnd(),
+ MakePairCall->getRParenLoc())
+ : InnerCtorCall->getParenOrBraceRange();
// Finish if there is no explicit constructor call.
if (CallParensRange.getBegin().isInvalid())
return;
+ const SourceLocation ExprBegin =
+ MakePairCall ? MakePairCall->getExprLoc() : InnerCtorCall->getExprLoc();
+
// Range for constructor name and opening brace.
- auto CtorCallSourceRange = CharSourceRange::getTokenRange(
- InnerCtorCall->getExprLoc(), CallParensRange.getBegin());
+ const auto ParamCallSourceRange =
+ CharSourceRange::getTokenRange(ExprBegin, CallParensRange.getBegin());
- Diag << FixItHint::CreateRemoval(CtorCallSourceRange)
+ Diag << FixItHint::CreateRemoval(ParamCallSourceRange)
<< FixItHint::CreateRemoval(CharSourceRange::getTokenRange(
- CallParensRange.getEnd(), CallParensRange.getEnd()));
+ CallParensRange.getEnd(), CallParensRange.getEnd()));
}
void UseEmplaceCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
OpenPOWER on IntegriCloud