diff options
Diffstat (limited to 'clang-tools-extra/test/clang-tidy/performance-move-const-arg.cpp')
| -rw-r--r-- | clang-tools-extra/test/clang-tidy/performance-move-const-arg.cpp | 248 |
1 files changed, 248 insertions, 0 deletions
diff --git a/clang-tools-extra/test/clang-tidy/performance-move-const-arg.cpp b/clang-tools-extra/test/clang-tidy/performance-move-const-arg.cpp new file mode 100644 index 00000000000..06ed6e0b56b --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/performance-move-const-arg.cpp @@ -0,0 +1,248 @@ +// RUN: %check_clang_tidy %s performance-move-const-arg %t + +namespace std { +template <typename> +struct remove_reference; + +template <typename _Tp> +struct remove_reference { + typedef _Tp type; +}; + +template <typename _Tp> +struct remove_reference<_Tp &> { + typedef _Tp type; +}; + +template <typename _Tp> +struct remove_reference<_Tp &&> { + typedef _Tp type; +}; + +template <typename _Tp> +constexpr typename std::remove_reference<_Tp>::type &&move(_Tp &&__t) { + return static_cast<typename std::remove_reference<_Tp>::type &&>(__t); +} + +template <typename _Tp> +constexpr _Tp && +forward(typename remove_reference<_Tp>::type &__t) noexcept { + return static_cast<_Tp &&>(__t); +} + +} // namespace std + +class A { +public: + A() {} + A(const A &rhs) {} + A(A &&rhs) {} +}; + +struct TriviallyCopyable { + int i; +}; + +void f(TriviallyCopyable) {} + +void g() { + TriviallyCopyable obj; + f(std::move(obj)); + // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: std::move of the variable 'obj' of the trivially-copyable type 'TriviallyCopyable' has no effect; remove std::move() [performance-move-const-arg] + // CHECK-FIXES: f(obj); +} + +int f1() { + return std::move(42); + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: std::move of the expression of the trivially-copyable type 'int' has no effect; remove std::move() [performance-move-const-arg] + // CHECK-FIXES: return 42; +} + +int f2(int x2) { + return std::move(x2); + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: std::move of the variable 'x2' of the trivially-copyable type 'int' + // CHECK-FIXES: return x2; +} + +int *f3(int *x3) { + return std::move(x3); + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: std::move of the variable 'x3' of the trivially-copyable type 'int *' + // 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 'x5' has no effect; remove std::move() or make the variable non-const [performance-move-const-arg] + // CHECK-FIXES: return x5; +} + +template <typename T> +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 'a' has no effect; remove std::move() or make the variable non-const + // CHECK-FIXES: M1(A b = a;) +} + +#define M2(x) std::move(x) +int f9() { return M2(1); } + +template <typename T> +T f10(const int x10) { + return std::move(x10); + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: std::move of the const variable 'x10' of the trivially-copyable type 'const int' has no effect; remove std::move() [performance-move-const-arg] + // CHECK-FIXES: return x10; +} +void f11() { + f10<int>(1); + f10<double>(1); +} + +class NoMoveSemantics { +public: + NoMoveSemantics(); + NoMoveSemantics(const NoMoveSemantics &); + + NoMoveSemantics &operator=(const NoMoveSemantics &); +}; + +void callByConstRef(const NoMoveSemantics &); +void callByConstRef(int i, const NoMoveSemantics &); + +void moveToConstReferencePositives() { + NoMoveSemantics obj; + + // Basic case. + callByConstRef(std::move(obj)); + // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: passing result of std::move() as + // CHECK-FIXES: callByConstRef(obj); + + // Also works for second argument. + callByConstRef(1, std::move(obj)); + // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: passing result of std::move() as + // CHECK-FIXES: callByConstRef(1, obj); + + // Works if std::move() applied to a temporary. + callByConstRef(std::move(NoMoveSemantics())); + // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: passing result of std::move() as + // CHECK-FIXES: callByConstRef(NoMoveSemantics()); + + // Works if calling a copy constructor. + NoMoveSemantics other(std::move(obj)); + // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: passing result of std::move() as + // CHECK-FIXES: NoMoveSemantics other(obj); + + // Works if calling assignment operator. + other = std::move(obj); + // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: passing result of std::move() as + // CHECK-FIXES: other = obj; +} + +class MoveSemantics { +public: + MoveSemantics(); + MoveSemantics(MoveSemantics &&); + + MoveSemantics &operator=(MoveSemantics &&); +}; + +void callByValue(MoveSemantics); + +void callByRValueRef(MoveSemantics &&); + +template <class T> +void templateFunction(T obj) { + T other = std::move(obj); +} + +#define M3(T, obj) \ + do { \ + T other = std::move(obj); \ + } while (true) + +#define CALL(func) (func)() + +void moveToConstReferenceNegatives() { + // No warning when actual move takes place. + MoveSemantics move_semantics; + callByValue(std::move(move_semantics)); + callByRValueRef(std::move(move_semantics)); + MoveSemantics other(std::move(move_semantics)); + other = std::move(move_semantics); + + // No warning if std::move() not used. + NoMoveSemantics no_move_semantics; + callByConstRef(no_move_semantics); + + // No warning if instantiating a template. + templateFunction(no_move_semantics); + + // No warning inside of macro expansions. + M3(NoMoveSemantics, no_move_semantics); + + // No warning inside of macro expansion, even if the macro expansion is inside + // a lambda that is, in turn, an argument to a macro. + CALL([no_move_semantics] { M3(NoMoveSemantics, no_move_semantics); }); + + auto lambda = [] {}; + auto lambda2 = std::move(lambda); +} + +class MoveOnly { +public: + MoveOnly(const MoveOnly &other) = delete; + MoveOnly &operator=(const MoveOnly &other) = delete; + MoveOnly(MoveOnly &&other) = default; + MoveOnly &operator=(MoveOnly &&other) = default; +}; +template <class T> +void Q(T); +void moveOnlyNegatives(MoveOnly val) { + Q(std::move(val)); +} + +void fmovable(MoveSemantics); + +void lambda1() { + auto f = [](MoveSemantics m) { + fmovable(std::move(m)); + }; + f(MoveSemantics()); +} + +template<class T> struct function {}; + +template<typename Result, typename... Args> +class function<Result(Args...)> { +public: + function() = default; + void operator()(Args... args) const { + fmovable(std::forward<Args>(args)...); + } +}; + +void functionInvocation() { + function<void(MoveSemantics)> callback; + MoveSemantics m; + callback(std::move(m)); +} + +void lambda2() { + function<void(MoveSemantics)> callback; + + auto f = [callback = std::move(callback)](MoveSemantics m) mutable { + // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: std::move of the variable 'callback' of the trivially-copyable type 'function<void (MoveSemantics)>' has no effect; remove std::move() + // CHECK-FIXES: auto f = [callback = callback](MoveSemantics m) mutable { + callback(std::move(m)); + }; + f(MoveSemantics()); +} |

