1 | // RUN: %check_clang_tidy %s performance-move-constructor-init,modernize-pass-by-value %t -- \ |
2 | // RUN: -config='{CheckOptions: \ |
3 | // RUN: {modernize-pass-by-value.ValuesOnly: true}}' \ |
4 | // RUN: -- -isystem %clang_tidy_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> |
15 | typename 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 { |
25 | B() {} |
26 | B(const B&) {} |
27 | B(B &&) {} |
28 | }; |
29 | |
30 | struct D : B { |
31 | D() : B() {} |
32 | 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 |
36 | D(D &&RHS) : B(RHS) {} |
37 | }; |
38 | |
39 | struct E : B { |
40 | E() : B() {} |
41 | E(const E &RHS) : B(RHS) {} |
42 | E(E &&RHS) : B(move(arg&: RHS)) {} // ok |
43 | }; |
44 | |
45 | struct F { |
46 | C M; |
47 | |
48 | 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; |
60 | 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 { |
68 | J(J &&RHS) : I(RHS) {} // ok |
69 | }; |
70 | |
71 | struct K {}; // Has implicit copy and move constructors, is trivially copyable |
72 | struct L : K { |
73 | 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] |
79 | 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; |
86 | N(N &&RHS) : Mem(move(arg&: RHS.Mem)) {} |
87 | }; |
88 | |
89 | struct O { |
90 | O(O&& other) : b(other.b) {} // ok |
91 | const B b; |
92 | }; |
93 | |
94 | struct P { |
95 | 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; |
103 | ~Movable() {} |
104 | }; |
105 | |
106 | struct TriviallyCopyable { |
107 | TriviallyCopyable() = default; |
108 | TriviallyCopyable(TriviallyCopyable &&) = default; |
109 | TriviallyCopyable(const TriviallyCopyable &) = default; |
110 | }; |
111 | |
112 | struct Positive { |
113 | 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 { |
120 | NegativeMultipleInitializerReferences(Movable M) : M_(M), n_(M) {} |
121 | Movable M_; |
122 | Movable n_; |
123 | }; |
124 | |
125 | struct NegativeReferencedInConstructorBody { |
126 | NegativeReferencedInConstructorBody(Movable M) : M_(M) { M_ = M; } |
127 | Movable M_; |
128 | }; |
129 | |
130 | struct NegativeParamTriviallyCopyable { |
131 | NegativeParamTriviallyCopyable(TriviallyCopyable T) : T_(T) {} |
132 | 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. |
140 | NegativeNotPassedByValue(const Movable &M) : M_(M) {} |
141 | NegativeNotPassedByValue(const Movable M) : M_(M) {} |
142 | NegativeNotPassedByValue(Movable &M) : M_(M) {} |
143 | NegativeNotPassedByValue(Movable *M) : M_(*M) {} |
144 | 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 { |
154 | NegativeImmovableParameter(Immovable I) : I_(I) {} |
155 | Immovable I_; |
156 | }; |
157 | |