diff options
author | Alexander Kornienko <alexfh@google.com> | 2017-11-28 16:41:03 +0000 |
---|---|---|
committer | Alexander Kornienko <alexfh@google.com> | 2017-11-28 16:41:03 +0000 |
commit | 0912716e425698bfec86d14af2d2ff30084160dd (patch) | |
tree | fdbfba081ed6e8c52b451d9526b137d39f3feb49 /clang-tidy/performance | |
parent | 690f486bb72ecc4f96dcc2e8f8a39c8a175c97d4 (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.txt | 2 | ||||
-rw-r--r-- | clang-tidy/performance/MoveConstArgCheck.cpp | 121 | ||||
-rw-r--r-- | clang-tidy/performance/MoveConstArgCheck.h | 43 | ||||
-rw-r--r-- | clang-tidy/performance/NoexceptMoveConstructorCheck.cpp | 77 | ||||
-rw-r--r-- | clang-tidy/performance/NoexceptMoveConstructorCheck.h | 38 | ||||
-rw-r--r-- | clang-tidy/performance/PerformanceTidyModule.cpp | 6 |
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>( |