1 // RUN: %check_clang_tidy %s performance-move-constructor-init,modernize-pass-by-value %t -- \ 2 // RUN: -config='{CheckOptions: \ 3 // RUN: [{key: modernize-pass-by-value.ValuesOnly, value: 1}]}' \ 4 // RUN: -- -isystem %S/Inputs/Headers 5 6 #include <s.h> 7 8 // CHECK-FIXES: #include <utility> 9 10 template <class T> struct remove_reference {typedef T type;}; 11 template <class T> struct remove_reference<T&> {typedef T type;}; 12 template <class T> struct remove_reference<T&&> {typedef T type;}; 13 14 template <typename T> move(T && arg)15typename remove_reference<T>::type&& move(T&& arg) { 16 return static_cast<typename remove_reference<T>::type&&>(arg); 17 } 18 19 struct C { 20 C() = default; 21 C(const C&) = default; 22 }; 23 24 struct B { BB25 B() {} BB26 B(const B&) {} BB27 B(B &&) {} 28 }; 29 30 struct D : B { DD31 D() : B() {} DD32 D(const D &RHS) : B(RHS) {} 33 // CHECK-NOTES: :[[@LINE+3]]:16: warning: move constructor initializes base class by calling a copy constructor [performance-move-constructor-init] 34 // CHECK-NOTES: 26:3: note: copy constructor being called 35 // CHECK-NOTES: 27:3: note: candidate move constructor here DD36 D(D &&RHS) : B(RHS) {} 37 }; 38 39 struct E : B { EE40 E() : B() {} EE41 E(const E &RHS) : B(RHS) {} EE42 E(E &&RHS) : B(move(RHS)) {} // ok 43 }; 44 45 struct F { 46 C M; 47 FF48 F(F &&) : M(C()) {} // ok 49 }; 50 51 struct G { 52 G() = default; 53 G(const G&) = default; 54 G(G&&) = delete; 55 }; 56 57 struct H : G { 58 H() = default; 59 H(const H&) = default; HH60 H(H &&RHS) : G(RHS) {} // ok 61 }; 62 63 struct I { 64 I(const I &) = default; // suppresses move constructor creation 65 }; 66 67 struct J : I { JJ68 J(J &&RHS) : I(RHS) {} // ok 69 }; 70 71 struct K {}; // Has implicit copy and move constructors, is trivially copyable 72 struct L : K { LL73 L(L &&RHS) : K(RHS) {} // ok 74 }; 75 76 struct M { 77 B Mem; 78 // CHECK-NOTES: :[[@LINE+1]]:16: warning: move constructor initializes class member by calling a copy constructor [performance-move-constructor-init] MM79 M(M &&RHS) : Mem(RHS.Mem) {} 80 // CHECK-NOTES: 26:3: note: copy constructor being called 81 // CHECK-NOTES: 27:3: note: candidate move constructor here 82 }; 83 84 struct N { 85 B Mem; NN86 N(N &&RHS) : Mem(move(RHS.Mem)) {} 87 }; 88 89 struct O { OO90 O(O&& other) : b(other.b) {} // ok 91 const B b; 92 }; 93 94 struct P { PP95 P(O&& other) : b(other.b) {} // ok 96 B b; 97 }; 98 99 struct Movable { 100 Movable(Movable &&) = default; 101 Movable(const Movable &) = default; 102 Movable &operator=(const Movable &) = default; ~MovableMovable103 ~Movable() {} 104 }; 105 106 struct TriviallyCopyable { 107 TriviallyCopyable() = default; 108 TriviallyCopyable(TriviallyCopyable &&) = default; 109 TriviallyCopyable(const TriviallyCopyable &) = default; 110 }; 111 112 struct Positive { PositivePositive113 Positive(Movable M) : M_(M) {} 114 // CHECK-NOTES: [[@LINE-1]]:12: warning: pass by value and use std::move [modernize-pass-by-value] 115 // CHECK-FIXES: Positive(Movable M) : M_(std::move(M)) {} 116 Movable M_; 117 }; 118 119 struct NegativeMultipleInitializerReferences { NegativeMultipleInitializerReferencesNegativeMultipleInitializerReferences120 NegativeMultipleInitializerReferences(Movable M) : M_(M), n_(M) {} 121 Movable M_; 122 Movable n_; 123 }; 124 125 struct NegativeReferencedInConstructorBody { NegativeReferencedInConstructorBodyNegativeReferencedInConstructorBody126 NegativeReferencedInConstructorBody(Movable M) : M_(M) { M_ = M; } 127 Movable M_; 128 }; 129 130 struct NegativeParamTriviallyCopyable { NegativeParamTriviallyCopyableNegativeParamTriviallyCopyable131 NegativeParamTriviallyCopyable(TriviallyCopyable T) : T_(T) {} NegativeParamTriviallyCopyableNegativeParamTriviallyCopyable132 NegativeParamTriviallyCopyable(int I) : I_(I) {} 133 134 TriviallyCopyable T_; 135 int I_; 136 }; 137 138 struct NegativeNotPassedByValue { 139 // This const ref constructor isn't warned about because the ValuesOnly option is set. NegativeNotPassedByValueNegativeNotPassedByValue140 NegativeNotPassedByValue(const Movable &M) : M_(M) {} NegativeNotPassedByValueNegativeNotPassedByValue141 NegativeNotPassedByValue(const Movable M) : M_(M) {} NegativeNotPassedByValueNegativeNotPassedByValue142 NegativeNotPassedByValue(Movable &M) : M_(M) {} NegativeNotPassedByValueNegativeNotPassedByValue143 NegativeNotPassedByValue(Movable *M) : M_(*M) {} NegativeNotPassedByValueNegativeNotPassedByValue144 NegativeNotPassedByValue(const Movable *M) : M_(*M) {} 145 Movable M_; 146 }; 147 148 struct Immovable { 149 Immovable(const Immovable &) = default; 150 Immovable(Immovable &&) = delete; 151 }; 152 153 struct NegativeImmovableParameter { NegativeImmovableParameterNegativeImmovableParameter154 NegativeImmovableParameter(Immovable I) : I_(I) {} 155 Immovable I_; 156 }; 157