xref: /llvm-project/clang-tools-extra/test/clang-tidy/checkers/performance/move-constructor-init.cpp (revision e8a3ddafe063c970df9c23e803812369abde4c82)
189a1d03eSRichard // RUN: %check_clang_tidy %s performance-move-constructor-init,modernize-pass-by-value %t -- \
289a1d03eSRichard // RUN: -config='{CheckOptions: \
3*e8a3ddafSNathan James // RUN:  {modernize-pass-by-value.ValuesOnly: true}}' \
489a1d03eSRichard // RUN: -- -isystem %clang_tidy_headers
589a1d03eSRichard 
689a1d03eSRichard #include <s.h>
789a1d03eSRichard 
889a1d03eSRichard // CHECK-FIXES: #include <utility>
989a1d03eSRichard 
1089a1d03eSRichard template <class T> struct remove_reference      {typedef T type;};
1189a1d03eSRichard template <class T> struct remove_reference<T&>  {typedef T type;};
1289a1d03eSRichard template <class T> struct remove_reference<T&&> {typedef T type;};
1389a1d03eSRichard 
1489a1d03eSRichard template <typename T>
move(T && arg)1589a1d03eSRichard typename remove_reference<T>::type&& move(T&& arg) {
1689a1d03eSRichard   return static_cast<typename remove_reference<T>::type&&>(arg);
1789a1d03eSRichard }
1889a1d03eSRichard 
1989a1d03eSRichard struct C {
2089a1d03eSRichard   C() = default;
2189a1d03eSRichard   C(const C&) = default;
2289a1d03eSRichard };
2389a1d03eSRichard 
2489a1d03eSRichard struct B {
BB2589a1d03eSRichard   B() {}
BB2689a1d03eSRichard   B(const B&) {}
BB2789a1d03eSRichard   B(B &&) {}
2889a1d03eSRichard };
2989a1d03eSRichard 
3089a1d03eSRichard struct D : B {
DD3189a1d03eSRichard   D() : B() {}
DD3289a1d03eSRichard   D(const D &RHS) : B(RHS) {}
3389a1d03eSRichard   // CHECK-NOTES: :[[@LINE+3]]:16: warning: move constructor initializes base class by calling a copy constructor [performance-move-constructor-init]
3489a1d03eSRichard   // CHECK-NOTES: 26:3: note: copy constructor being called
3589a1d03eSRichard   // CHECK-NOTES: 27:3: note: candidate move constructor here
DD3689a1d03eSRichard   D(D &&RHS) : B(RHS) {}
3789a1d03eSRichard };
3889a1d03eSRichard 
3989a1d03eSRichard struct E : B {
EE4089a1d03eSRichard   E() : B() {}
EE4189a1d03eSRichard   E(const E &RHS) : B(RHS) {}
EE4289a1d03eSRichard   E(E &&RHS) : B(move(RHS)) {} // ok
4389a1d03eSRichard };
4489a1d03eSRichard 
4589a1d03eSRichard struct F {
4689a1d03eSRichard   C M;
4789a1d03eSRichard 
FF4889a1d03eSRichard   F(F &&) : M(C()) {} // ok
4989a1d03eSRichard };
5089a1d03eSRichard 
5189a1d03eSRichard struct G {
5289a1d03eSRichard   G() = default;
5389a1d03eSRichard   G(const G&) = default;
5489a1d03eSRichard   G(G&&) = delete;
5589a1d03eSRichard };
5689a1d03eSRichard 
5789a1d03eSRichard struct H : G {
5889a1d03eSRichard   H() = default;
5989a1d03eSRichard   H(const H&) = default;
HH6089a1d03eSRichard   H(H &&RHS) : G(RHS) {} // ok
6189a1d03eSRichard };
6289a1d03eSRichard 
6389a1d03eSRichard struct I {
6489a1d03eSRichard   I(const I &) = default; // suppresses move constructor creation
6589a1d03eSRichard };
6689a1d03eSRichard 
6789a1d03eSRichard struct J : I {
JJ6889a1d03eSRichard   J(J &&RHS) : I(RHS) {} // ok
6989a1d03eSRichard };
7089a1d03eSRichard 
7189a1d03eSRichard struct K {}; // Has implicit copy and move constructors, is trivially copyable
7289a1d03eSRichard struct L : K {
LL7389a1d03eSRichard   L(L &&RHS) : K(RHS) {} // ok
7489a1d03eSRichard };
7589a1d03eSRichard 
7689a1d03eSRichard struct M {
7789a1d03eSRichard   B Mem;
7889a1d03eSRichard   // CHECK-NOTES: :[[@LINE+1]]:16: warning: move constructor initializes class member by calling a copy constructor [performance-move-constructor-init]
MM7989a1d03eSRichard   M(M &&RHS) : Mem(RHS.Mem) {}
8089a1d03eSRichard   // CHECK-NOTES: 26:3: note: copy constructor being called
8189a1d03eSRichard   // CHECK-NOTES: 27:3: note: candidate move constructor here
8289a1d03eSRichard };
8389a1d03eSRichard 
8489a1d03eSRichard struct N {
8589a1d03eSRichard   B Mem;
NN8689a1d03eSRichard   N(N &&RHS) : Mem(move(RHS.Mem)) {}
8789a1d03eSRichard };
8889a1d03eSRichard 
8989a1d03eSRichard struct O {
OO9089a1d03eSRichard   O(O&& other) : b(other.b) {} // ok
9189a1d03eSRichard   const B b;
9289a1d03eSRichard };
9389a1d03eSRichard 
9489a1d03eSRichard struct P {
PP9589a1d03eSRichard   P(O&& other) : b(other.b) {} // ok
9689a1d03eSRichard   B b;
9789a1d03eSRichard };
9889a1d03eSRichard 
9989a1d03eSRichard struct Movable {
10089a1d03eSRichard   Movable(Movable &&) = default;
10189a1d03eSRichard   Movable(const Movable &) = default;
10289a1d03eSRichard   Movable &operator=(const Movable &) = default;
~MovableMovable10389a1d03eSRichard   ~Movable() {}
10489a1d03eSRichard };
10589a1d03eSRichard 
10689a1d03eSRichard struct TriviallyCopyable {
10789a1d03eSRichard   TriviallyCopyable() = default;
10889a1d03eSRichard   TriviallyCopyable(TriviallyCopyable &&) = default;
10989a1d03eSRichard   TriviallyCopyable(const TriviallyCopyable &) = default;
11089a1d03eSRichard };
11189a1d03eSRichard 
11289a1d03eSRichard struct Positive {
PositivePositive11389a1d03eSRichard   Positive(Movable M) : M_(M) {}
11489a1d03eSRichard   // CHECK-NOTES: [[@LINE-1]]:12: warning: pass by value and use std::move [modernize-pass-by-value]
11589a1d03eSRichard   // CHECK-FIXES: Positive(Movable M) : M_(std::move(M)) {}
11689a1d03eSRichard   Movable M_;
11789a1d03eSRichard };
11889a1d03eSRichard 
11989a1d03eSRichard struct NegativeMultipleInitializerReferences {
NegativeMultipleInitializerReferencesNegativeMultipleInitializerReferences12089a1d03eSRichard   NegativeMultipleInitializerReferences(Movable M) : M_(M), n_(M) {}
12189a1d03eSRichard   Movable M_;
12289a1d03eSRichard   Movable n_;
12389a1d03eSRichard };
12489a1d03eSRichard 
12589a1d03eSRichard struct NegativeReferencedInConstructorBody {
NegativeReferencedInConstructorBodyNegativeReferencedInConstructorBody12689a1d03eSRichard   NegativeReferencedInConstructorBody(Movable M) : M_(M) { M_ = M; }
12789a1d03eSRichard   Movable M_;
12889a1d03eSRichard };
12989a1d03eSRichard 
13089a1d03eSRichard struct NegativeParamTriviallyCopyable {
NegativeParamTriviallyCopyableNegativeParamTriviallyCopyable13189a1d03eSRichard   NegativeParamTriviallyCopyable(TriviallyCopyable T) : T_(T) {}
NegativeParamTriviallyCopyableNegativeParamTriviallyCopyable13289a1d03eSRichard   NegativeParamTriviallyCopyable(int I) : I_(I) {}
13389a1d03eSRichard 
13489a1d03eSRichard   TriviallyCopyable T_;
13589a1d03eSRichard   int I_;
13689a1d03eSRichard };
13789a1d03eSRichard 
13889a1d03eSRichard struct NegativeNotPassedByValue {
13989a1d03eSRichard   // This const ref constructor isn't warned about because the ValuesOnly option is set.
NegativeNotPassedByValueNegativeNotPassedByValue14089a1d03eSRichard   NegativeNotPassedByValue(const Movable &M) : M_(M) {}
NegativeNotPassedByValueNegativeNotPassedByValue14189a1d03eSRichard   NegativeNotPassedByValue(const Movable M) : M_(M) {}
NegativeNotPassedByValueNegativeNotPassedByValue14289a1d03eSRichard   NegativeNotPassedByValue(Movable &M) : M_(M) {}
NegativeNotPassedByValueNegativeNotPassedByValue14389a1d03eSRichard   NegativeNotPassedByValue(Movable *M) : M_(*M) {}
NegativeNotPassedByValueNegativeNotPassedByValue14489a1d03eSRichard   NegativeNotPassedByValue(const Movable *M) : M_(*M) {}
14589a1d03eSRichard   Movable M_;
14689a1d03eSRichard };
14789a1d03eSRichard 
14889a1d03eSRichard struct Immovable {
14989a1d03eSRichard   Immovable(const Immovable &) = default;
15089a1d03eSRichard   Immovable(Immovable &&) = delete;
15189a1d03eSRichard };
15289a1d03eSRichard 
15389a1d03eSRichard struct NegativeImmovableParameter {
NegativeImmovableParameterNegativeImmovableParameter15489a1d03eSRichard   NegativeImmovableParameter(Immovable I) : I_(I) {}
15589a1d03eSRichard   Immovable I_;
15689a1d03eSRichard };
157