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,70 @@ +//===--- 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" + +#include + +namespace clang { +namespace tidy { +namespace misc { + +using namespace ast_matchers; + +void MoveConstantArgumentCheck::registerMatchers(MatchFinder *Finder) { + if (!getLangOpts().CPlusPlus) + return; + Finder->addMatcher(callExpr(unless(isInTemplateInstantiation()), + 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 IsConstArg = Arg->getType().isConstQualified(); + bool IsTriviallyCopyable = Arg->getType().isTriviallyCopyableType(*Context); + + if (IsConstArg || IsTriviallyCopyable) { + auto MoveRange = CharSourceRange::getCharRange(CallMove->getLocStart(), + CallMove->getLocEnd()); + auto FileMoveRange = Lexer::makeFileCharRange( + MoveRange, Context->getSourceManager(), getLangOpts()); + if (!FileMoveRange.isValid()) { + // Do nothing if this move call is in a macro expansion. + return; + } + bool IsVariable = isa(Arg); + + diag(FileMoveRange.getBegin(), + "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(Lexer::makeFileCharRange( + CharSourceRange::getCharRange(CallMove->getLocStart(), + Arg->getLocStart()), + Context->getSourceManager(), getLangOpts())) + << FixItHint::CreateRemoval(Lexer::makeFileCharRange( + CharSourceRange::getCharRange( + CallMove->getLocEnd(), + CallMove->getLocEnd().getLocWithOffset(1)), + Context->getSourceManager(), getLangOpts())); + } +} + +} // 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,68 @@ +// 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 has no 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 has no 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 variable of + // trivially-copyable type has no 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 + // has no effect; remove std::move(). + // CHECK-FIXES: return x5; +} + +template T f6(const T x6) { return std::move(x6); } + +void f7() { int a = f6(10); } + +#define M1(x) x +void f8() { + const A a; + M1(A b = std::move(a);) + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: std::move of the const variable + // has no effect; remove std::move(). + // CHECK-FIXES: M1(A b = a;) +} + +#define M2(x) std::move(x) +int f9() { return M2(1); }