1 | // RUN: %check_clang_tidy %s cppcoreguidelines-slicing %t |
2 | |
3 | class Base { |
4 | int i; |
5 | void f() {} |
6 | virtual void g() {} |
7 | }; |
8 | |
9 | class DerivedWithMemberVariables : public Base { |
10 | void f(); |
11 | int j; |
12 | }; |
13 | |
14 | class TwiceDerivedWithNoMemberVariables : public DerivedWithMemberVariables { |
15 | void f(); |
16 | }; |
17 | |
18 | class DerivedWithOverride : public Base { |
19 | void f(); |
20 | void g() override {} |
21 | }; |
22 | |
23 | class TwiceDerivedWithNoOverride : public DerivedWithOverride { |
24 | void f(); |
25 | }; |
26 | |
27 | void TakesBaseByValue(Base base); |
28 | |
29 | DerivedWithMemberVariables ReturnsDerived(); |
30 | |
31 | void positivesWithMemberVariables() { |
32 | DerivedWithMemberVariables b; |
33 | Base a{b}; |
34 | // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: slicing object from type 'DerivedWithMemberVariables' to 'Base' discards {{[0-9]*}} bytes of state [cppcoreguidelines-slicing] |
35 | a = b; |
36 | // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: slicing object from type 'DerivedWithMemberVariables' to 'Base' discards {{[0-9]*}} bytes of state |
37 | TakesBaseByValue(base: b); |
38 | // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: slicing object from type 'DerivedWithMemberVariables' to 'Base' discards {{[0-9]*}} bytes of state |
39 | |
40 | TwiceDerivedWithNoMemberVariables c; |
41 | a = c; |
42 | // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: slicing object from type 'TwiceDerivedWithNoMemberVariables' to 'Base' discards {{[0-9]*}} bytes of state |
43 | |
44 | a = ReturnsDerived(); |
45 | // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: slicing object from type 'DerivedWithMemberVariables' to 'Base' discards {{[0-9]*}} bytes of state |
46 | } |
47 | |
48 | void positivesWithOverride() { |
49 | DerivedWithOverride b; |
50 | Base a{b}; |
51 | // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: slicing object from type 'DerivedWithOverride' to 'Base' discards override 'g' |
52 | a = b; |
53 | // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: slicing object from type 'DerivedWithOverride' to 'Base' discards override 'g' |
54 | TakesBaseByValue(base: b); |
55 | // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: slicing object from type 'DerivedWithOverride' to 'Base' discards override 'g' |
56 | |
57 | TwiceDerivedWithNoOverride c; |
58 | a = c; |
59 | // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: slicing object from type 'DerivedWithOverride' to 'Base' discards override 'g' |
60 | } |
61 | |
62 | void TakesBaseByReference(Base &base); |
63 | |
64 | class DerivedThatAddsVirtualH : public Base { |
65 | virtual void h(); |
66 | }; |
67 | |
68 | class DerivedThatOverridesH : public DerivedThatAddsVirtualH { |
69 | void h() override; |
70 | }; |
71 | |
72 | void negatives() { |
73 | // OK, simple copying from the same type. |
74 | Base a; |
75 | TakesBaseByValue(base: a); |
76 | DerivedWithMemberVariables b; |
77 | DerivedWithMemberVariables c{b}; |
78 | b = c; |
79 | |
80 | // OK, derived type does not have extra state. |
81 | TwiceDerivedWithNoMemberVariables d; |
82 | DerivedWithMemberVariables e{d}; |
83 | e = d; |
84 | |
85 | // OK, derived does not override any method. |
86 | TwiceDerivedWithNoOverride f; |
87 | DerivedWithOverride g{f}; |
88 | g = f; |
89 | |
90 | // OK, no copying. |
91 | TakesBaseByReference(base&: d); |
92 | TakesBaseByReference(base&: f); |
93 | |
94 | // Derived type overrides methods, but these methods are not in the base type, |
95 | // so cannot be called accidentally. Right now this triggers, but we might |
96 | // want to allow it. |
97 | DerivedThatOverridesH h; |
98 | a = h; |
99 | // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: slicing object from type 'DerivedThatOverridesH' to 'Base' discards override 'h' |
100 | } |
101 | |
102 | namespace PR31187 { |
103 | // Don't warn when calling constructor of base virtual class, from |
104 | // initialization list of derived class constructor. |
105 | |
106 | struct BaseA { |
107 | virtual ~BaseA() {} |
108 | virtual void foo() {} |
109 | |
110 | int i; |
111 | }; |
112 | |
113 | struct BaseB : virtual BaseA { |
114 | virtual void foo() {} |
115 | }; |
116 | |
117 | struct ClassWithVirtualBases : BaseB { |
118 | ClassWithVirtualBases(const BaseB& other) : BaseA(other), BaseB(other) {} |
119 | ClassWithVirtualBases(const ClassWithVirtualBases& other) : BaseA(other), BaseB(other) {} |
120 | }; |
121 | |
122 | } |
123 | |