xref: /llvm-project/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/slicing.cpp (revision f1e2469edcfc160867e4ef73b2dcc259974c9d6a)
189a1d03eSRichard // RUN: %check_clang_tidy %s cppcoreguidelines-slicing %t
289a1d03eSRichard 
389a1d03eSRichard class Base {
489a1d03eSRichard   int i;
f()589a1d03eSRichard   void f() {}
g()689a1d03eSRichard   virtual void g() {}
789a1d03eSRichard };
889a1d03eSRichard 
989a1d03eSRichard class DerivedWithMemberVariables : public Base {
1089a1d03eSRichard   void f();
1189a1d03eSRichard   int j;
1289a1d03eSRichard };
1389a1d03eSRichard 
1489a1d03eSRichard class TwiceDerivedWithNoMemberVariables : public DerivedWithMemberVariables {
1589a1d03eSRichard   void f();
1689a1d03eSRichard };
1789a1d03eSRichard 
1889a1d03eSRichard class DerivedWithOverride : public Base {
1989a1d03eSRichard   void f();
g()2089a1d03eSRichard   void g() override {}
2189a1d03eSRichard };
2289a1d03eSRichard 
2389a1d03eSRichard class TwiceDerivedWithNoOverride : public DerivedWithOverride {
2489a1d03eSRichard   void f();
2589a1d03eSRichard };
2689a1d03eSRichard 
2789a1d03eSRichard void TakesBaseByValue(Base base);
2889a1d03eSRichard 
2989a1d03eSRichard DerivedWithMemberVariables ReturnsDerived();
3089a1d03eSRichard 
positivesWithMemberVariables()3189a1d03eSRichard void positivesWithMemberVariables() {
3289a1d03eSRichard   DerivedWithMemberVariables b;
3389a1d03eSRichard   Base a{b};
3489a1d03eSRichard   // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: slicing object from type 'DerivedWithMemberVariables' to 'Base' discards {{[0-9]*}} bytes of state [cppcoreguidelines-slicing]
3589a1d03eSRichard   a = b;
3689a1d03eSRichard   // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: slicing object from type 'DerivedWithMemberVariables' to 'Base' discards {{[0-9]*}} bytes of state
3789a1d03eSRichard   TakesBaseByValue(b);
3889a1d03eSRichard   // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: slicing object from type 'DerivedWithMemberVariables' to 'Base' discards {{[0-9]*}} bytes of state
3989a1d03eSRichard 
4089a1d03eSRichard   TwiceDerivedWithNoMemberVariables c;
4189a1d03eSRichard   a = c;
4289a1d03eSRichard   // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: slicing object from type 'TwiceDerivedWithNoMemberVariables' to 'Base' discards {{[0-9]*}} bytes of state
4389a1d03eSRichard 
4489a1d03eSRichard   a = ReturnsDerived();
4589a1d03eSRichard   // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: slicing object from type 'DerivedWithMemberVariables' to 'Base' discards {{[0-9]*}} bytes of state
4689a1d03eSRichard }
4789a1d03eSRichard 
positivesWithOverride()4889a1d03eSRichard void positivesWithOverride() {
4989a1d03eSRichard   DerivedWithOverride b;
5089a1d03eSRichard   Base a{b};
5189a1d03eSRichard   // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: slicing object from type 'DerivedWithOverride' to 'Base' discards override 'g'
5289a1d03eSRichard   a = b;
5389a1d03eSRichard   // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: slicing object from type 'DerivedWithOverride' to 'Base' discards override 'g'
5489a1d03eSRichard   TakesBaseByValue(b);
5589a1d03eSRichard   // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: slicing object from type 'DerivedWithOverride' to 'Base' discards override 'g'
5689a1d03eSRichard 
5789a1d03eSRichard   TwiceDerivedWithNoOverride c;
5889a1d03eSRichard   a = c;
5989a1d03eSRichard   // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: slicing object from type 'DerivedWithOverride' to 'Base' discards override 'g'
6089a1d03eSRichard }
6189a1d03eSRichard 
6289a1d03eSRichard void TakesBaseByReference(Base &base);
6389a1d03eSRichard 
6489a1d03eSRichard class DerivedThatAddsVirtualH : public Base {
6589a1d03eSRichard   virtual void h();
6689a1d03eSRichard };
6789a1d03eSRichard 
6889a1d03eSRichard class DerivedThatOverridesH : public DerivedThatAddsVirtualH {
6989a1d03eSRichard   void h() override;
7089a1d03eSRichard };
7189a1d03eSRichard 
negatives()7289a1d03eSRichard void negatives() {
7389a1d03eSRichard   // OK, simple copying from the same type.
7489a1d03eSRichard   Base a;
7589a1d03eSRichard   TakesBaseByValue(a);
7689a1d03eSRichard   DerivedWithMemberVariables b;
7789a1d03eSRichard   DerivedWithMemberVariables c{b};
7889a1d03eSRichard   b = c;
7989a1d03eSRichard 
8089a1d03eSRichard   // OK, derived type does not have extra state.
8189a1d03eSRichard   TwiceDerivedWithNoMemberVariables d;
8289a1d03eSRichard   DerivedWithMemberVariables e{d};
8389a1d03eSRichard   e = d;
8489a1d03eSRichard 
8589a1d03eSRichard   // OK, derived does not override any method.
8689a1d03eSRichard   TwiceDerivedWithNoOverride f;
8789a1d03eSRichard   DerivedWithOverride g{f};
8889a1d03eSRichard   g = f;
8989a1d03eSRichard 
9089a1d03eSRichard   // OK, no copying.
9189a1d03eSRichard   TakesBaseByReference(d);
9289a1d03eSRichard   TakesBaseByReference(f);
9389a1d03eSRichard 
9489a1d03eSRichard   // Derived type overrides methods, but these methods are not in the base type,
9589a1d03eSRichard   // so cannot be called accidentally. Right now this triggers, but we might
9689a1d03eSRichard   // want to allow it.
9789a1d03eSRichard   DerivedThatOverridesH h;
9889a1d03eSRichard   a = h;
9989a1d03eSRichard   // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: slicing object from type 'DerivedThatOverridesH' to 'Base' discards override 'h'
10089a1d03eSRichard }
101*f1e2469eSPiotr Zegar 
102*f1e2469eSPiotr Zegar namespace PR31187 {
103*f1e2469eSPiotr Zegar // Don't warn when calling constructor of base virtual class, from
104*f1e2469eSPiotr Zegar // initialization list of derived class constructor.
105*f1e2469eSPiotr Zegar 
106*f1e2469eSPiotr Zegar struct BaseA {
~BaseAPR31187::BaseA107*f1e2469eSPiotr Zegar virtual ~BaseA() {}
fooPR31187::BaseA108*f1e2469eSPiotr Zegar virtual void foo() {}
109*f1e2469eSPiotr Zegar 
110*f1e2469eSPiotr Zegar int i;
111*f1e2469eSPiotr Zegar };
112*f1e2469eSPiotr Zegar 
113*f1e2469eSPiotr Zegar struct BaseB : virtual BaseA {
fooPR31187::BaseB114*f1e2469eSPiotr Zegar virtual void foo() {}
115*f1e2469eSPiotr Zegar };
116*f1e2469eSPiotr Zegar 
117*f1e2469eSPiotr Zegar struct ClassWithVirtualBases : BaseB {
ClassWithVirtualBasesPR31187::ClassWithVirtualBases118*f1e2469eSPiotr Zegar   ClassWithVirtualBases(const BaseB& other) : BaseA(other), BaseB(other) {}
ClassWithVirtualBasesPR31187::ClassWithVirtualBases119*f1e2469eSPiotr Zegar   ClassWithVirtualBases(const ClassWithVirtualBases& other) : BaseA(other), BaseB(other) {}
120*f1e2469eSPiotr Zegar };
121*f1e2469eSPiotr Zegar 
122*f1e2469eSPiotr Zegar }
123