aboutsummaryrefslogtreecommitdiff
path: root/clang-tidy/performance
diff options
context:
space:
mode:
authorAlexander Kornienko <alexfh@google.com>2017-11-28 16:41:03 +0000
committerAlexander Kornienko <alexfh@google.com>2017-11-28 16:41:03 +0000
commit0912716e425698bfec86d14af2d2ff30084160dd (patch)
treefdbfba081ed6e8c52b451d9526b137d39f3feb49 /clang-tidy/performance
parent690f486bb72ecc4f96dcc2e8f8a39c8a175c97d4 (diff)
[clang-tidy] Move more checks from misc- to performance-
Summary: rename_check.py misc-move-const-arg performance-move-const-arg rename_check.py misc-noexcept-move-constructor performance-noexcept-move-constructor Reviewers: hokein, xazax.hun Reviewed By: xazax.hun Subscribers: rnkovacs, klimek, mgorny, xazax.hun, cfe-commits Differential Revision: https://reviews.llvm.org/D40507 git-svn-id: https://llvm.org/svn/llvm-project/clang-tools-extra/trunk@319183 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'clang-tidy/performance')
-rw-r--r--clang-tidy/performance/CMakeLists.txt2
-rw-r--r--clang-tidy/performance/MoveConstArgCheck.cpp121
-rw-r--r--clang-tidy/performance/MoveConstArgCheck.h43
-rw-r--r--clang-tidy/performance/NoexceptMoveConstructorCheck.cpp77
-rw-r--r--clang-tidy/performance/NoexceptMoveConstructorCheck.h38
-rw-r--r--clang-tidy/performance/PerformanceTidyModule.cpp6
6 files changed, 287 insertions, 0 deletions
diff --git a/clang-tidy/performance/CMakeLists.txt b/clang-tidy/performance/CMakeLists.txt
index 67594332..ac417bcc 100644
--- a/clang-tidy/performance/CMakeLists.txt
+++ b/clang-tidy/performance/CMakeLists.txt
@@ -7,7 +7,9 @@ add_clang_library(clangTidyPerformanceModule
InefficientAlgorithmCheck.cpp
InefficientStringConcatenationCheck.cpp
InefficientVectorOperationCheck.cpp
+ MoveConstArgCheck.cpp
MoveConstructorInitCheck.cpp
+ NoexceptMoveConstructorCheck.cpp
PerformanceTidyModule.cpp
TypePromotionInMathFnCheck.cpp
UnnecessaryCopyInitialization.cpp
diff --git a/clang-tidy/performance/MoveConstArgCheck.cpp b/clang-tidy/performance/MoveConstArgCheck.cpp
new file mode 100644
index 00000000..8d494802
--- /dev/null
+++ b/clang-tidy/performance/MoveConstArgCheck.cpp
@@ -0,0 +1,121 @@
+//===--- MoveConstArgCheck.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 "MoveConstArgCheck.h"
+
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace performance {
+
+static void ReplaceCallWithArg(const CallExpr *Call, DiagnosticBuilder &Diag,
+ const SourceManager &SM,
+ const LangOptions &LangOpts) {
+ const Expr *Arg = Call->getArg(0);
+
+ CharSourceRange BeforeArgumentsRange = Lexer::makeFileCharRange(
+ CharSourceRange::getCharRange(Call->getLocStart(), Arg->getLocStart()),
+ SM, LangOpts);
+ CharSourceRange AfterArgumentsRange = Lexer::makeFileCharRange(
+ CharSourceRange::getCharRange(Call->getLocEnd(),
+ Call->getLocEnd().getLocWithOffset(1)),
+ SM, LangOpts);
+
+ if (BeforeArgumentsRange.isValid() && AfterArgumentsRange.isValid()) {
+ Diag << FixItHint::CreateRemoval(BeforeArgumentsRange)
+ << FixItHint::CreateRemoval(AfterArgumentsRange);
+ }
+}
+
+void MoveConstArgCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "CheckTriviallyCopyableMove", CheckTriviallyCopyableMove);
+}
+
+void MoveConstArgCheck::registerMatchers(MatchFinder *Finder) {
+ if (!getLangOpts().CPlusPlus)
+ return;
+
+ auto MoveCallMatcher =
+ callExpr(callee(functionDecl(hasName("::std::move"))), argumentCountIs(1),
+ unless(isInTemplateInstantiation()))
+ .bind("call-move");
+
+ Finder->addMatcher(MoveCallMatcher, this);
+
+ auto ConstParamMatcher = forEachArgumentWithParam(
+ MoveCallMatcher, parmVarDecl(hasType(references(isConstQualified()))));
+
+ Finder->addMatcher(callExpr(ConstParamMatcher).bind("receiving-expr"), this);
+ Finder->addMatcher(cxxConstructExpr(ConstParamMatcher).bind("receiving-expr"),
+ this);
+}
+
+void MoveConstArgCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *CallMove = Result.Nodes.getNodeAs<CallExpr>("call-move");
+ const auto *ReceivingExpr = Result.Nodes.getNodeAs<Expr>("receiving-expr");
+ const Expr *Arg = CallMove->getArg(0);
+ SourceManager &SM = Result.Context->getSourceManager();
+
+ CharSourceRange MoveRange =
+ CharSourceRange::getCharRange(CallMove->getSourceRange());
+ CharSourceRange FileMoveRange =
+ Lexer::makeFileCharRange(MoveRange, SM, getLangOpts());
+ if (!FileMoveRange.isValid())
+ return;
+
+ bool IsConstArg = Arg->getType().isConstQualified();
+ bool IsTriviallyCopyable =
+ Arg->getType().isTriviallyCopyableType(*Result.Context);
+
+ if (IsConstArg || IsTriviallyCopyable) {
+ if (const CXXRecordDecl *R = Arg->getType()->getAsCXXRecordDecl()) {
+ // According to [expr.prim.lambda]p3, "whether the closure type is
+ // trivially copyable" property can be changed by the implementation of
+ // the language, so we shouldn't rely on it when issuing diagnostics.
+ if (R->isLambda())
+ return;
+ // Don't warn when the type is not copyable.
+ for (const auto *Ctor : R->ctors()) {
+ if (Ctor->isCopyConstructor() && Ctor->isDeleted())
+ return;
+ }
+ }
+
+ if (!IsConstArg && IsTriviallyCopyable && !CheckTriviallyCopyableMove)
+ return;
+
+ bool IsVariable = isa<DeclRefExpr>(Arg);
+ const auto *Var =
+ IsVariable ? dyn_cast<DeclRefExpr>(Arg)->getDecl() : nullptr;
+ auto Diag = diag(FileMoveRange.getBegin(),
+ "std::move of the %select{|const }0"
+ "%select{expression|variable %4}1 "
+ "%select{|of the trivially-copyable type %5 }2"
+ "has no effect; remove std::move()"
+ "%select{| or make the variable non-const}3")
+ << IsConstArg << IsVariable << IsTriviallyCopyable
+ << (IsConstArg && IsVariable && !IsTriviallyCopyable) << Var
+ << Arg->getType();
+
+ ReplaceCallWithArg(CallMove, Diag, SM, getLangOpts());
+ } else if (ReceivingExpr) {
+ auto Diag = diag(FileMoveRange.getBegin(),
+ "passing result of std::move() as a const reference "
+ "argument; no move will actually happen");
+
+ ReplaceCallWithArg(CallMove, Diag, SM, getLangOpts());
+ }
+}
+
+} // namespace performance
+} // namespace tidy
+} // namespace clang
diff --git a/clang-tidy/performance/MoveConstArgCheck.h b/clang-tidy/performance/MoveConstArgCheck.h
new file mode 100644
index 00000000..13ed9aee
--- /dev/null
+++ b/clang-tidy/performance/MoveConstArgCheck.h
@@ -0,0 +1,43 @@
+//===--- MoveConstArgCheck.h - clang-tidy -------------------------===//
+//
+// 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_MISC_MOVECONSTANTARGUMENTCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_MOVECONSTANTARGUMENTCHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace performance {
+
+/// Find casts of calculation results to bigger type. Typically from int to
+///
+/// There is one option:
+///
+/// - `CheckTriviallyCopyableMove`: Whether to check for trivially-copyable
+// types as their objects are not moved but copied. Enabled by default.
+class MoveConstArgCheck : public ClangTidyCheck {
+public:
+ MoveConstArgCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ CheckTriviallyCopyableMove(
+ Options.get("CheckTriviallyCopyableMove", true)) {}
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+ const bool CheckTriviallyCopyableMove;
+};
+
+} // namespace performance
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_MOVECONSTANTARGUMENTCHECK_H
diff --git a/clang-tidy/performance/NoexceptMoveConstructorCheck.cpp b/clang-tidy/performance/NoexceptMoveConstructorCheck.cpp
new file mode 100644
index 00000000..86ef70ce
--- /dev/null
+++ b/clang-tidy/performance/NoexceptMoveConstructorCheck.cpp
@@ -0,0 +1,77 @@
+//===--- NoexceptMoveConstructorCheck.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 "NoexceptMoveConstructorCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace performance {
+
+void NoexceptMoveConstructorCheck::registerMatchers(MatchFinder *Finder) {
+ // Only register the matchers for C++11; the functionality currently does not
+ // provide any benefit to other languages, despite being benign.
+ if (!getLangOpts().CPlusPlus11)
+ return;
+
+ Finder->addMatcher(
+ cxxMethodDecl(anyOf(cxxConstructorDecl(), hasOverloadedOperatorName("=")),
+ unless(isImplicit()), unless(isDeleted()))
+ .bind("decl"),
+ this);
+}
+
+void NoexceptMoveConstructorCheck::check(
+ const MatchFinder::MatchResult &Result) {
+ if (const auto *Decl = Result.Nodes.getNodeAs<CXXMethodDecl>("decl")) {
+ StringRef MethodType = "assignment operator";
+ if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(Decl)) {
+ if (!Ctor->isMoveConstructor())
+ return;
+ MethodType = "constructor";
+ } else if (!Decl->isMoveAssignmentOperator()) {
+ return;
+ }
+
+ const auto *ProtoType = Decl->getType()->getAs<FunctionProtoType>();
+
+ if (isUnresolvedExceptionSpec(ProtoType->getExceptionSpecType()))
+ return;
+
+ switch (ProtoType->getNoexceptSpec(*Result.Context)) {
+ case FunctionProtoType::NR_NoNoexcept:
+ diag(Decl->getLocation(), "move %0s should be marked noexcept")
+ << MethodType;
+ // FIXME: Add a fixit.
+ break;
+ case FunctionProtoType::NR_Throw:
+ // Don't complain about nothrow(false), but complain on nothrow(expr)
+ // where expr evaluates to false.
+ if (const Expr *E = ProtoType->getNoexceptExpr()) {
+ if (isa<CXXBoolLiteralExpr>(E))
+ break;
+ diag(E->getExprLoc(),
+ "noexcept specifier on the move %0 evaluates to 'false'")
+ << MethodType;
+ }
+ break;
+ case FunctionProtoType::NR_Nothrow:
+ case FunctionProtoType::NR_Dependent:
+ case FunctionProtoType::NR_BadNoexcept:
+ break;
+ }
+ }
+}
+
+} // namespace performance
+} // namespace tidy
+} // namespace clang
diff --git a/clang-tidy/performance/NoexceptMoveConstructorCheck.h b/clang-tidy/performance/NoexceptMoveConstructorCheck.h
new file mode 100644
index 00000000..9687ab1f
--- /dev/null
+++ b/clang-tidy/performance/NoexceptMoveConstructorCheck.h
@@ -0,0 +1,38 @@
+//===--- NoexceptMoveConstructorCheck.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_PERFORMANCE_NOEXCEPTMOVECONSTRUCTORCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_NOEXCEPTMOVECONSTRUCTORCHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace performance {
+
+/// The check flags user-defined move constructors and assignment operators not
+/// marked with `noexcept` or marked with `noexcept(expr)` where `expr`
+/// evaluates to `false` (but is not a `false` literal itself).
+///
+/// Move constructors of all the types used with STL containers, for example,
+/// need to be declared `noexcept`. Otherwise STL will choose copy constructors
+/// instead. The same is valid for move assignment operations.
+class NoexceptMoveConstructorCheck : public ClangTidyCheck {
+public:
+ NoexceptMoveConstructorCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace performance
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_NOEXCEPTMOVECONSTRUCTORCHECK_H
diff --git a/clang-tidy/performance/PerformanceTidyModule.cpp b/clang-tidy/performance/PerformanceTidyModule.cpp
index 51a8728b..646c6595 100644
--- a/clang-tidy/performance/PerformanceTidyModule.cpp
+++ b/clang-tidy/performance/PerformanceTidyModule.cpp
@@ -16,7 +16,9 @@
#include "InefficientAlgorithmCheck.h"
#include "InefficientStringConcatenationCheck.h"
#include "InefficientVectorOperationCheck.h"
+#include "MoveConstArgCheck.h"
#include "MoveConstructorInitCheck.h"
+#include "NoexceptMoveConstructorCheck.h"
#include "TypePromotionInMathFnCheck.h"
#include "UnnecessaryCopyInitialization.h"
#include "UnnecessaryValueParamCheck.h"
@@ -40,8 +42,12 @@ public:
"performance-inefficient-string-concatenation");
CheckFactories.registerCheck<InefficientVectorOperationCheck>(
"performance-inefficient-vector-operation");
+ CheckFactories.registerCheck<MoveConstArgCheck>(
+ "performance-move-const-arg");
CheckFactories.registerCheck<MoveConstructorInitCheck>(
"performance-move-constructor-init");
+ CheckFactories.registerCheck<NoexceptMoveConstructorCheck>(
+ "performance-noexcept-move-constructor");
CheckFactories.registerCheck<TypePromotionInMathFnCheck>(
"performance-type-promotion-in-math-fn");
CheckFactories.registerCheck<UnnecessaryCopyInitialization>(