diff options
Diffstat (limited to 'clang-tools-extra/clang-tidy/modernize/UseEmplaceCheck.cpp')
| -rw-r--r-- | clang-tools-extra/clang-tidy/modernize/UseEmplaceCheck.cpp | 54 |
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) { |

