diff options
author | Piotr Padlewski <piotr.padlewski@gmail.com> | 2016-06-21 15:23:27 +0000 |
---|---|---|
committer | Piotr Padlewski <piotr.padlewski@gmail.com> | 2016-06-21 15:23:27 +0000 |
commit | 552d44948221d6b219ec142fd8460f4bdf108a21 (patch) | |
tree | 199cd686cc2407da3bd4b4ce983516adf158c754 /clang-tools-extra/clang-tidy/modernize/UseEmplaceCheck.cpp | |
parent | 715ec09dcfc143326e76bd3818ecd3ca8eb5263d (diff) | |
download | bcm5719-llvm-552d44948221d6b219ec142fd8460f4bdf108a21.tar.gz bcm5719-llvm-552d44948221d6b219ec142fd8460f4bdf108a21.zip |
[clang-tidy] Add modernize-use-emplace
Summary: Add check that replaces call of push_back to emplace_back
Reviewers: hokein
Differential Revision: http://reviews.llvm.org/D20964
llvm-svn: 273275
Diffstat (limited to 'clang-tools-extra/clang-tidy/modernize/UseEmplaceCheck.cpp')
-rw-r--r-- | clang-tools-extra/clang-tidy/modernize/UseEmplaceCheck.cpp | 104 |
1 files changed, 104 insertions, 0 deletions
diff --git a/clang-tools-extra/clang-tidy/modernize/UseEmplaceCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseEmplaceCheck.cpp new file mode 100644 index 00000000000..3536373a722 --- /dev/null +++ b/clang-tools-extra/clang-tidy/modernize/UseEmplaceCheck.cpp @@ -0,0 +1,104 @@ +//===--- UseEmplaceCheck.cpp - clang-tidy----------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "UseEmplaceCheck.h" +#include "../utils/Matchers.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace modernize { + +void UseEmplaceCheck::registerMatchers(MatchFinder *Finder) { + if (!getLangOpts().CPlusPlus11) + return; + + // FIXME: Bunch of functionality that could be easily added: + // + add handling of `push_front` for std::forward_list, std::list + // and std::deque. + // + add handling of `push` for std::stack, std::queue, std::priority_queue + // + add handling of `insert` for stl associative container, but be careful + // 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("std::vector", "llvm::SmallVector", + "std::list", "std::deque"))))); + + // We can't replace push_backs of smart pointer because + // if emplacement fails (f.e. bad_alloc in vector) we will have leak of + // passed pointer because smart pointer won't be constructed + // (and destructed) as in push_back case. + auto isCtorOfSmartPtr = hasDeclaration(cxxConstructorDecl( + ofClass(hasAnyName("std::shared_ptr", "std::unique_ptr", "std::auto_ptr", + "std::weak_ptr")))); + + // Bitfields binds only to consts and emplace_back take it by universal ref. + auto bitFieldAsArgument = hasAnyArgument(ignoringParenImpCasts( + memberExpr(hasDeclaration(fieldDecl(matchers::isBitfield()))))); + + // We could have leak of resource. + auto newExprAsArgument = hasAnyArgument(ignoringParenImpCasts(cxxNewExpr())); + auto constructingDerived = + hasParent(implicitCastExpr(hasCastKind(CastKind::CK_DerivedToBase))); + + auto hasInitList = has(ignoringParenImpCasts(initListExpr())); + auto soughtConstructExpr = + cxxConstructExpr( + unless(anyOf(isCtorOfSmartPtr, hasInitList, bitFieldAsArgument, + newExprAsArgument, constructingDerived, + has(materializeTemporaryExpr(hasInitList))))) + .bind("ctor"); + auto hasConstructExpr = has(ignoringParenImpCasts(soughtConstructExpr)); + + auto ctorAsArgument = materializeTemporaryExpr( + anyOf(hasConstructExpr, has(cxxFunctionalCastExpr(hasConstructExpr)))); + + Finder->addMatcher( + cxxMemberCallExpr(callPushBack, has(ctorAsArgument)).bind("call"), this); +} + +void UseEmplaceCheck::check(const MatchFinder::MatchResult &Result) { + const auto *Call = Result.Nodes.getNodeAs<CXXMemberCallExpr>("call"); + const auto *InnerCtorCall = Result.Nodes.getNodeAs<CXXConstructExpr>("ctor"); + + auto FunctionNameSourceRange = CharSourceRange::getCharRange( + Call->getExprLoc(), Call->getArg(0)->getExprLoc()); + + auto Diag = diag(Call->getExprLoc(), "use emplace_back instead of push_back"); + + if (FunctionNameSourceRange.getBegin().isMacroID()) + return; + + Diag << FixItHint::CreateReplacement(FunctionNameSourceRange, + "emplace_back("); + + auto CallParensRange = InnerCtorCall->getParenOrBraceRange(); + + // Finish if there is no explicit constructor call. + if (CallParensRange.getBegin().isInvalid()) + return; + + // Range for constructor name and opening brace. + auto CtorCallSourceRange = CharSourceRange::getCharRange( + InnerCtorCall->getExprLoc(), + CallParensRange.getBegin().getLocWithOffset(1)); + + Diag << FixItHint::CreateRemoval(CtorCallSourceRange) + << FixItHint::CreateRemoval(CharSourceRange::getCharRange( + CallParensRange.getEnd(), + CallParensRange.getEnd().getLocWithOffset(1))); +} + +} // namespace modernize +} // namespace tidy +} // namespace clang |