Index: clang-tidy/misc/CMakeLists.txt =================================================================== --- clang-tidy/misc/CMakeLists.txt +++ clang-tidy/misc/CMakeLists.txt @@ -10,6 +10,7 @@ MacroParenthesesCheck.cpp MacroRepeatedSideEffectsCheck.cpp MiscTidyModule.cpp + MoveConstantArgumentCheck.cpp MoveConstructorInitCheck.cpp NewDeleteOverloadsCheck.cpp NoexceptMoveConstructorCheck.cpp Index: clang-tidy/misc/MiscTidyModule.cpp =================================================================== --- clang-tidy/misc/MiscTidyModule.cpp +++ clang-tidy/misc/MiscTidyModule.cpp @@ -18,6 +18,7 @@ #include "InefficientAlgorithmCheck.h" #include "MacroParenthesesCheck.h" #include "MacroRepeatedSideEffectsCheck.h" +#include "MoveConstantArgumentCheck.h" #include "MoveConstructorInitCheck.h" #include "NewDeleteOverloadsCheck.h" #include "NoexceptMoveConstructorCheck.h" @@ -54,6 +55,8 @@ "misc-macro-parentheses"); CheckFactories.registerCheck( "misc-macro-repeated-side-effects"); + CheckFactories.registerCheck( + "misc-move-const-arg"); CheckFactories.registerCheck( "misc-move-constructor-init"); CheckFactories.registerCheck( Index: clang-tidy/misc/MoveConstantArgumentCheck.h =================================================================== --- clang-tidy/misc/MoveConstantArgumentCheck.h +++ clang-tidy/misc/MoveConstantArgumentCheck.h @@ -0,0 +1,31 @@ +//===--- MoveConstandArgumentCheck.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_MOVECONTANTARGUMENTCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_MOVECONTANTARGUMENTCHECK_H + +#include "../ClangTidy.h" + +namespace clang { +namespace tidy { +namespace misc { + +class MoveConstantArgumentCheck : public ClangTidyCheck { +public: + MoveConstantArgumentCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; +}; + +} // namespace misc +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_MOVECONTANTARGUMENTCHECK_H Index: clang-tidy/misc/MoveConstantArgumentCheck.cpp =================================================================== --- clang-tidy/misc/MoveConstantArgumentCheck.cpp +++ clang-tidy/misc/MoveConstantArgumentCheck.cpp @@ -0,0 +1,52 @@ +//===--- MoveConstandArgumentCheck.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 "MoveConstantArgumentCheck.h" + +namespace clang { +namespace tidy { +namespace misc { + +using namespace ast_matchers; + +void MoveConstantArgumentCheck::registerMatchers(MatchFinder *Finder) { + Finder->addMatcher( + callExpr(callee(functionDecl(hasName("::std::move")))).bind("call-move"), + this); +} + +void MoveConstantArgumentCheck::check(const MatchFinder::MatchResult &Result) { + const auto *CallMove = Result.Nodes.getNodeAs("call-move"); + if (CallMove->getNumArgs() != 1) + return; + const Expr *Arg = CallMove->getArg(0); + auto *Context = Result.Context; + + bool IsTypeDependOnTemplateParameter = Arg->getType()->isDependentType(); + if (IsTypeDependOnTemplateParameter) + return; + bool IsConstArg = Arg->getType().isConstQualified(); + bool IsTriviallyCopyable = Arg->getType().isTriviallyCopyableType(*Context); + + if (IsConstArg || IsTriviallyCopyable) { + bool IsVariable = isa(Arg); + diag(CallMove->getLocStart(), "std::move of the %select{|const " + "}0%select{expression|variable}1 %select{|of " + "trivially-copyable type }2has no effect; " + "remove std::move()") + << IsConstArg << IsVariable << IsTriviallyCopyable + << FixItHint::CreateRemoval( + SourceRange(CallMove->getLocStart(), Arg->getLocStart())) + << FixItHint::CreateRemoval(CallMove->getLocEnd()); + } +} + +} // namespace misc +} // namespace tidy +} // namespace clang Index: test/clang-tidy/move-const-arg.cpp =================================================================== --- test/clang-tidy/move-const-arg.cpp +++ test/clang-tidy/move-const-arg.cpp @@ -0,0 +1,81 @@ +// RUN: %check_clang_tidy %s misc-move-const-arg %t -- -- -std=c++11 + +namespace std { +template +struct remove_reference; + +template + struct remove_reference + { typedef _Tp type; }; + +template + struct remove_reference<_Tp&> + { typedef _Tp type; }; + +template + struct remove_reference<_Tp&&> + { typedef _Tp type; }; + +template + constexpr typename std::remove_reference<_Tp>::type&& + move(_Tp&& __t); + +} // namespace std + +class A +{ + public: + A() {} + A(const A& rhs) {} + A(A&& rhs) {} +}; + +int f1() +{ + return std::move(42); + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: std::move of the expression of trivially-copyable type doesn't have effect. Remove std::move(). + // CHECK-FIXES: return 42; +} + +int f2(int x2) +{ + return std::move(x2); + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: std::move of the variable of trivially-copyable type doesn't have effect. Remove std::move(). + // CHECK-FIXES: return x2; +} + +int* f3(int* x3) +{ + return std::move(x3); + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: std::move of the expression of trivially-copyable type doesn't have effect. Remove std::move(). + // CHECK-FIXES: return x3; +} + +A f4(A x4) +{ + return std::move(x4); +} + +A f5(const A x5) +{ + return std::move(x5); + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: std::move of the const variable doesn't have effect. Remove std::move() or make the variable non-const. + // CHECK-FIXES: return x5; +} + +template +T f6(const T a) +{ + return std::move(a); +} + +void f7() +{ + int a = f6(10); +} + +void f8() +{ + A a = f6(A()); +} +