summaryrefslogtreecommitdiffstats
path: root/clang-tools-extra/clang-tidy
diff options
context:
space:
mode:
Diffstat (limited to 'clang-tools-extra/clang-tidy')
-rw-r--r--clang-tools-extra/clang-tidy/modernize/CMakeLists.txt1
-rw-r--r--clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp2
-rw-r--r--clang-tools-extra/clang-tidy/modernize/UseEmplaceCheck.cpp104
-rw-r--r--clang-tools-extra/clang-tidy/modernize/UseEmplaceCheck.h38
-rw-r--r--clang-tools-extra/clang-tidy/utils/Matchers.h2
5 files changed, 147 insertions, 0 deletions
diff --git a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
index d97600c13e0..e42e2a1a6b9 100644
--- a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
@@ -17,6 +17,7 @@ add_clang_library(clangTidyModernizeModule
UseAutoCheck.cpp
UseBoolLiteralsCheck.cpp
UseDefaultCheck.cpp
+ UseEmplaceCheck.cpp
UseNullptrCheck.cpp
UseOverrideCheck.cpp
diff --git a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
index da986a2afcc..5992adecd04 100644
--- a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
@@ -23,6 +23,7 @@
#include "UseAutoCheck.h"
#include "UseBoolLiteralsCheck.h"
#include "UseDefaultCheck.h"
+#include "UseEmplaceCheck.h"
#include "UseNullptrCheck.h"
#include "UseOverrideCheck.h"
@@ -54,6 +55,7 @@ public:
CheckFactories.registerCheck<UseBoolLiteralsCheck>(
"modernize-use-bool-literals");
CheckFactories.registerCheck<UseDefaultCheck>("modernize-use-default");
+ CheckFactories.registerCheck<UseEmplaceCheck>("modernize-use-emplace");
CheckFactories.registerCheck<UseNullptrCheck>("modernize-use-nullptr");
CheckFactories.registerCheck<UseOverrideCheck>("modernize-use-override");
}
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
diff --git a/clang-tools-extra/clang-tidy/modernize/UseEmplaceCheck.h b/clang-tools-extra/clang-tidy/modernize/UseEmplaceCheck.h
new file mode 100644
index 00000000000..298e1f280dc
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/UseEmplaceCheck.h
@@ -0,0 +1,38 @@
+//===--- UseEmplaceCheck.h - clang-tidy--------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_EMPLACE_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_EMPLACE_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+/// This check looks for cases when inserting new element into std::vector but
+/// the element is constructed temporarily.
+/// It replaces those calls for emplace_back of arguments passed to
+/// constructor of temporary object.
+///`
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/modernize-use-emplace.html
+class UseEmplaceCheck : public ClangTidyCheck {
+public:
+ UseEmplaceCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_EMPLACE_H
diff --git a/clang-tools-extra/clang-tidy/utils/Matchers.h b/clang-tools-extra/clang-tidy/utils/Matchers.h
index 1f3f6dfd57f..76673d4d209 100644
--- a/clang-tools-extra/clang-tidy/utils/Matchers.h
+++ b/clang-tools-extra/clang-tidy/utils/Matchers.h
@@ -45,6 +45,8 @@ AST_MATCHER(RecordDecl, isTriviallyDefaultConstructible) {
Node, Finder->getASTContext());
}
+AST_MATCHER(FieldDecl, isBitfield) { return Node.isBitField(); }
+
} // namespace matchers
} // namespace tidy
} // namespace clang
OpenPOWER on IntegriCloud