314 lines · cpp
1// RUN: %check_clang_tidy %s modernize-pass-by-value %t -- -- -fno-delayed-template-parsing2 3namespace {4// POD types are trivially move constructible.5struct POD {6 int a, b, c;7};8 9struct Movable {10 int a, b, c;11 Movable() = default;12 Movable(const Movable &) {}13 Movable(Movable &&) {}14};15 16struct NotMovable {17 NotMovable() = default;18 NotMovable(const NotMovable &) = default;19 NotMovable(NotMovable &&) = delete;20 int a, b, c;21};22}23 24struct A {25 A(const Movable &M) : M(M) {}26 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: pass by value and use std::move [modernize-pass-by-value]27 // CHECK-FIXES: A(Movable M) : M(std::move(M)) {}28 Movable M;29};30 31// Test that we aren't modifying other things than a parameter.32Movable GlobalObj;33struct B {34 B(const Movable &M) : M(GlobalObj) {}35 Movable M;36};37 38// Test that a parameter with more than one reference to it won't be changed.39struct C {40 // Tests extra-reference in body.41 C(const Movable &M) : M(M) { this->i = M.a; }42 43 // Tests extra-reference in init-list.44 C(const Movable &M, int) : M(M), i(M.a) {}45 Movable M;46 int i;47};48 49// Test that both declaration and definition are updated.50struct D {51 D(const Movable &M);52 // CHECK-FIXES: D(Movable M);53 Movable M;54};55D::D(const Movable &M) : M(M) {}56// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: pass by value and use std::move57// CHECK-FIXES: D::D(Movable M) : M(std::move(M)) {}58 59// Test with default parameter.60struct E {61 E(const Movable &M = Movable()) : M(M) {}62 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: pass by value and use std::move63 // CHECK-FIXES: E(Movable M = Movable()) : M(std::move(M)) {}64 Movable M;65};66 67// Test with object that can't be moved.68struct F {69 F(const NotMovable &NM) : NM(NM) {}70 NotMovable NM;71};72 73// Test unnamed parameter in declaration.74struct G {75 G(const Movable &);76 // CHECK-FIXES: G(Movable );77 Movable M;78};79G::G(const Movable &M) : M(M) {}80// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: pass by value and use std::move81// CHECK-FIXES: G::G(Movable M) : M(std::move(M)) {}82 83// Test parameter with and without qualifier.84namespace ns_H {85typedef ::Movable HMovable;86}87struct H {88 H(const ns_H::HMovable &M);89 // CHECK-FIXES: H(ns_H::HMovable M);90 ns_H::HMovable M;91};92using namespace ns_H;93H::H(const HMovable &M) : M(M) {}94// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: pass by value and use std::move95// CHECK-FIXES: H::H(HMovable M) : M(std::move(M)) {}96 97// Try messing up with macros.98#define MOVABLE_PARAM(Name) const Movable & Name99// CHECK-FIXES: #define MOVABLE_PARAM(Name) const Movable & Name100struct I {101 I(MOVABLE_PARAM(M)) : M(M) {}102 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: pass by value and use std::move103 // CHECK-FIXES: I(MOVABLE_PARAM(M)) : M(M) {}104 Movable M;105};106#undef MOVABLE_PARAM107 108// Test that templates aren't modified.109template <typename T> struct J {110 J(const T &M) : M(M) {}111 T M;112};113J<Movable> j1(Movable());114J<NotMovable> j2(NotMovable());115 116template<class T>117struct MovableTemplateT118{119 MovableTemplateT() {}120 MovableTemplateT(const MovableTemplateT& o) { }121 MovableTemplateT(MovableTemplateT&& o) { }122};123 124template <class T>125struct J2 {126 J2(const MovableTemplateT<T>& A);127 MovableTemplateT<T> M;128};129 130template <class T>131J2<T>::J2(const MovableTemplateT<T>& A) : M(A) {}132J2<int> j3(MovableTemplateT<int>{});133 134struct K_Movable {135 K_Movable() = default;136 K_Movable(const K_Movable &) = default;137 K_Movable(K_Movable &&o) { dummy = o.dummy; }138 int dummy;139};140 141// Test with movable type with an user defined move constructor.142struct K {143 K(const K_Movable &M) : M(M) {}144 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: pass by value and use std::move145 // CHECK-FIXES: K(K_Movable M) : M(std::move(M)) {}146 K_Movable M;147};148 149template <typename T> struct L {150 L(const Movable &M) : M(M) {}151 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: pass by value and use std::move152 // CHECK-FIXES: L(Movable M) : M(std::move(M)) {}153 Movable M;154};155L<int> l(Movable());156 157// Test with a non-instantiated template class.158template <typename T> struct N {159 N(const Movable &M) : M(M) {}160 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: pass by value and use std::move161 // CHECK-FIXES: N(Movable M) : M(std::move(M)) {}162 163 Movable M;164 T A;165};166 167// Test with value parameter.168struct O {169 O(Movable M) : M(M) {}170 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: pass by value and use std::move171 // CHECK-FIXES: O(Movable M) : M(std::move(M)) {}172 Movable M;173};174 175// Test with a const-value parameter.176struct P {177 P(const Movable M) : M(M) {}178 Movable M;179};180 181// Test with multiples parameters where some need to be changed and some don't.182// need to.183struct Q {184 Q(const Movable &A, const Movable &B, const Movable &C, double D)185 : A(A), B(B), C(C), D(D) {}186 // CHECK-MESSAGES: :[[@LINE-2]]:23: warning: pass by value and use std::move187 // CHECK-MESSAGES: :[[@LINE-3]]:41: warning: pass by value and use std::move188 // CHECK-FIXES: Q(const Movable &A, Movable B, Movable C, double D)189 // CHECK-FIXES: : A(A), B(std::move(B)), C(std::move(C)), D(D) {}190 const Movable &A;191 Movable B;192 Movable C;193 double D;194};195 196// Test that value-parameters with a nested name specifier are left as-is.197namespace ns_R {198typedef ::Movable RMovable;199}200struct R {201 R(ns_R::RMovable M) : M(M) {}202 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: pass by value and use std::move203 // CHECK-FIXES: R(ns_R::RMovable M) : M(std::move(M)) {}204 ns_R::RMovable M;205};206 207// Test with rvalue parameter.208struct S {209 S(Movable &&M) : M(M) {}210 Movable M;211};212 213template <typename T, int N> struct array { T A[N]; };214 215// Test that types that are trivially copyable will not use std::move. This will216// cause problems with performance-move-const-arg, as it will revert it.217struct T {218 T(array<int, 10> a) : a_(a) {}219 array<int, 10> a_;220};221 222struct U {223 U(const POD &M) : M(M) {}224 POD M;225};226 227// The rewrite can't look through `typedefs` and `using`.228// Test that we don't partially rewrite one decl without rewriting the other.229using MovableConstRef = const Movable &;230struct V {231 V(MovableConstRef M);232 // CHECK-FIXES: V(MovableConstRef M);233 Movable M;234};235V::V(const Movable &M) : M(M) {}236// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: pass by value and use std::move237// CHECK-FIXES: V::V(const Movable &M) : M(M) {}238 239// Test with paired lvalue/rvalue overloads.240struct W1 {241 W1(const Movable &M) : M(M) {}242 W1(Movable &&M);243 Movable M;244};245struct W2 {246 W2(const Movable &M, int) : M(M) {}247 W2(Movable &&M, int);248 Movable M;249};250struct W3 {251 W3(const W1 &, const Movable &M) : M(M) {}252 W3(W1 &&, Movable &&M);253 Movable M;254};255 256struct ProtectedMovable {257 ProtectedMovable() = default;258 ProtectedMovable(const ProtectedMovable &) {}259protected:260 ProtectedMovable(ProtectedMovable &&) {}261};262 263struct PrivateMovable {264 PrivateMovable() = default;265 PrivateMovable(const PrivateMovable &) {}266private:267 PrivateMovable(PrivateMovable &&) {}268 269 friend struct X5;270};271 272struct InheritedProtectedMovable : ProtectedMovable {273 InheritedProtectedMovable() = default;274 InheritedProtectedMovable(const InheritedProtectedMovable &) {}275 InheritedProtectedMovable(InheritedProtectedMovable &&) {}276};277 278struct InheritedPrivateMovable : PrivateMovable {279 InheritedPrivateMovable() = default;280 InheritedPrivateMovable(const InheritedPrivateMovable &) {}281 InheritedPrivateMovable(InheritedPrivateMovable &&) {}282};283 284struct X1 {285 X1(const ProtectedMovable &M) : M(M) {}286 ProtectedMovable M;287};288 289struct X2 {290 X2(const PrivateMovable &M) : M(M) {}291 PrivateMovable M;292};293 294struct X3 {295 X3(const InheritedProtectedMovable &M) : M(M) {}296 // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: pass by value and use std::move297 // CHECK-FIXES: X3(InheritedProtectedMovable M) : M(std::move(M)) {}298 InheritedProtectedMovable M;299};300 301struct X4 {302 X4(const InheritedPrivateMovable &M) : M(M) {}303 // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: pass by value and use std::move304 // CHECK-FIXES: X4(InheritedPrivateMovable M) : M(std::move(M)) {}305 InheritedPrivateMovable M;306};307 308struct X5 {309 X5(const PrivateMovable &M) : M(M) {}310 // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: pass by value and use std::move311 // CHECK-FIXES: X5(PrivateMovable M) : M(std::move(M)) {}312 PrivateMovable M;313};314