1 // RUN: %check_clang_tidy %s cppcoreguidelines-avoid-const-or-ref-data-members %t
2 namespace std {
3 template <typename T>
4 struct unique_ptr {};
5 
6 template <typename T>
7 struct shared_ptr {};
8 } // namespace std
9 
10 namespace gsl {
11 template <typename T>
12 struct not_null {};
13 } // namespace gsl
14 
15 struct Ok {
16   int i;
17   int *p;
18   const int *pc;
19   std::unique_ptr<int> up;
20   std::shared_ptr<int> sp;
21   gsl::not_null<int*> n;
22 };
23 
24 struct ConstMember {
25   const int c;
26   // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: member 'c' of type 'const int' is const qualified [cppcoreguidelines-avoid-const-or-ref-data-members]
27 };
28 
29 struct LvalueRefMember {
30   int &lr;
31   // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: member 'lr' of type 'int &' is a reference
32 };
33 
34 struct ConstRefMember {
35   const int &cr;
36   // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: member 'cr' of type 'const int &' is a reference
37 };
38 
39 struct RvalueRefMember {
40   int &&rr;
41   // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: member 'rr' of type 'int &&' is a reference
42 };
43 
44 struct ConstAndRefMembers {
45   const int c;
46   // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: member 'c' of type 'const int' is const qualified
47   int &lr;
48   // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: member 'lr' of type 'int &' is a reference
49   const int &cr;
50   // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: member 'cr' of type 'const int &' is a reference
51   int &&rr;
52   // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: member 'rr' of type 'int &&' is a reference
53 };
54 
55 struct Foo {};
56 
57 struct Ok2 {
58   Foo i;
59   Foo *p;
60   const Foo *pc;
61   std::unique_ptr<Foo> up;
62   std::shared_ptr<Foo> sp;
63   gsl::not_null<Foo*> n;
64 };
65 
66 struct ConstMember2 {
67   const Foo c;
68   // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: member 'c' of type 'const Foo' is const qualified
69 };
70 
71 struct LvalueRefMember2 {
72   Foo &lr;
73   // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: member 'lr' of type 'Foo &' is a reference
74 };
75 
76 struct ConstRefMember2 {
77   const Foo &cr;
78   // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: member 'cr' of type 'const Foo &' is a reference
79 };
80 
81 struct RvalueRefMember2 {
82   Foo &&rr;
83   // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: member 'rr' of type 'Foo &&' is a reference
84 };
85 
86 struct ConstAndRefMembers2 {
87   const Foo c;
88   // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: member 'c' of type 'const Foo' is const qualified
89   Foo &lr;
90   // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: member 'lr' of type 'Foo &' is a reference
91   const Foo &cr;
92   // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: member 'cr' of type 'const Foo &' is a reference
93   Foo &&rr;
94   // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: member 'rr' of type 'Foo &&' is a reference
95 };
96 
97 using ConstType = const int;
98 using RefType = int &;
99 using ConstRefType = const int &;
100 using RefRefType = int &&;
101 
102 struct WithAlias {
103   ConstType c;
104   // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: member 'c' of type 'ConstType' (aka 'const int') is const qualified
105   RefType lr;
106   // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: member 'lr' of type 'RefType' (aka 'int &') is a reference
107   ConstRefType cr;
108   // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: member 'cr' of type 'ConstRefType' (aka 'const int &') is a reference
109   RefRefType rr;
110   // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: member 'rr' of type 'RefRefType' (aka 'int &&') is a reference
111 };
112 
113 template <int N>
114 using Array = int[N];
115 
116 struct ConstArrayMember {
117   const Array<1> c;
118   // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: member 'c' of type 'const Array<1>' (aka 'const int[1]') is const qualified
119 };
120 
121 struct LvalueRefArrayMember {
122   Array<2> &lr;
123   // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: member 'lr' of type 'Array<2> &' (aka 'int (&)[2]') is a reference
124 };
125 
126 struct ConstLvalueRefArrayMember {
127   const Array<3> &cr;
128   // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: member 'cr' of type 'const Array<3> &' (aka 'const int (&)[3]') is a reference
129 };
130 
131 struct RvalueRefArrayMember {
132   Array<4> &&rr;
133   // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: member 'rr' of type 'Array<4> &&' (aka 'int (&&)[4]') is a reference
134 };
135 
136 template <typename T>
137 struct TemplatedOk {
138   T t;
139 };
140 
141 template <typename T>
142 struct TemplatedConst {
143   T t;
144   // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: member 't' of type 'const int' is const qualified
145 };
146 
147 template <typename T>
148 struct TemplatedConstRef {
149   T t;
150   // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: member 't' of type 'const int &' is a reference
151 };
152 
153 template <typename T>
154 struct TemplatedRefRef {
155   T t;
156   // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: member 't' of type 'int &&' is a reference
157 };
158 
159 template <typename T>
160 struct TemplatedRef {
161   T t;
162   // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: member 't' of type 'int &' is a reference
163 };
164 
165 TemplatedOk<int> t1{};
166 TemplatedConst<const int> t2{123};
167 TemplatedConstRef<const int &> t3{123};
168 TemplatedRefRef<int &&> t4{123};
169 TemplatedRef<int &> t5{t1.t};
170 
171 // Lambdas capturing const or ref members should not trigger warnings
172 void lambdas()
173 {
174   int x1{123};
175   const int x2{123};
176   const int& x3{123};
177   int&& x4{123};
178   int& x5{x1};
179 
180   auto v1 = [x1]{};
181   auto v2 = [x2]{};
182   auto v3 = [x3]{};
183   auto v4 = [x4]{};
184   auto v5 = [x5]{};
185 
186   auto r1 = [&x1]{};
187   auto r2 = [&x2]{};
188   auto r3 = [&x3]{};
189   auto r4 = [&x4]{};
190   auto r5 = [&x5]{};
191 
192   auto iv = [=]{
193     auto c1 = x1;
194     auto c2 = x2;
195     auto c3 = x3;
196     auto c4 = x4;
197     auto c5 = x5;
198   };
199 
200   auto ir = [&]{
201     auto c1 = x1;
202     auto c2 = x2;
203     auto c3 = x3;
204     auto c4 = x4;
205     auto c5 = x5;
206   };
207 }
208 
209 struct NonCopyableWithRef
210 {
211   NonCopyableWithRef(NonCopyableWithRef const&) = delete;
212   NonCopyableWithRef& operator=(NonCopyableWithRef const&) = delete;
213   NonCopyableWithRef(NonCopyableWithRef&&) = default;
214   NonCopyableWithRef& operator=(NonCopyableWithRef&&) = default;
215 
216   int& x;
217   // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: member 'x' of type 'int &' is a reference
218 };
219 
220 struct NonMovableWithRef
221 {
222   NonMovableWithRef(NonMovableWithRef const&) = default;
223   NonMovableWithRef& operator=(NonMovableWithRef const&) = default;
224   NonMovableWithRef(NonMovableWithRef&&) = delete;
225   NonMovableWithRef& operator=(NonMovableWithRef&&) = delete;
226 
227   int& x;
228   // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: member 'x' of type 'int &' is a reference
229 };
230 
231 struct NonCopyableNonMovableWithRef
232 {
233   NonCopyableNonMovableWithRef(NonCopyableNonMovableWithRef const&) = delete;
234   NonCopyableNonMovableWithRef(NonCopyableNonMovableWithRef&&) = delete;
235   NonCopyableNonMovableWithRef& operator=(NonCopyableNonMovableWithRef const&) = delete;
236   NonCopyableNonMovableWithRef& operator=(NonCopyableNonMovableWithRef&&) = delete;
237 
238   int& x; // OK, non copyable nor movable
239 };
240 
241 struct NonCopyable
242 {
243   NonCopyable(NonCopyable const&) = delete;
244   NonCopyable& operator=(NonCopyable const&) = delete;
245   NonCopyable(NonCopyable&&) = default;
246   NonCopyable& operator=(NonCopyable&&) = default;
247 };
248 
249 struct NonMovable
250 {
251   NonMovable(NonMovable const&) = default;
252   NonMovable& operator=(NonMovable const&) = default;
253   NonMovable(NonMovable&&) = delete;
254   NonMovable& operator=(NonMovable&&) = delete;
255 };
256 
257 struct NonCopyableNonMovable
258 {
259   NonCopyableNonMovable(NonCopyableNonMovable const&) = delete;
260   NonCopyableNonMovable(NonCopyableNonMovable&&) = delete;
261   NonCopyableNonMovable& operator=(NonCopyableNonMovable const&) = delete;
262   NonCopyableNonMovable& operator=(NonCopyableNonMovable&&) = delete;
263 };
264 
265 // Test inheritance
266 struct InheritFromNonCopyable : NonCopyable
267 {
268   int& x;
269   // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: member 'x' of type 'int &' is a reference
270 };
271 
272 struct InheritFromNonMovable : NonMovable
273 {
274   int& x;
275   // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: member 'x' of type 'int &' is a reference
276 };
277 
278 struct InheritFromNonCopyableNonMovable : NonCopyableNonMovable
279 {
280   int& x;  // OK, non copyable nor movable
281 };
282 
283 struct InheritBothFromNonCopyableAndNonMovable : NonCopyable, NonMovable
284 {
285   int& x;  // OK, non copyable nor movable
286 };
287 
288 template<class T> struct TemplateInheritFromNonCopyable : NonCopyable
289 {
290   int& x;
291   // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: member 'x' of type 'int &' is a reference
292 };
293 
294 template<class T> struct TemplateInheritFromNonMovable : NonMovable
295 {
296   int& x;
297   // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: member 'x' of type 'int &' is a reference
298 };
299 
300 template<class T> struct TemplateInheritFromNonCopyableNonMovable : NonCopyableNonMovable
301 {
302   int& x;  // OK, non copyable nor movable
303 };
304 
305 template<class T> struct TemplateInheritBothFromNonCopyableAndNonMovable : NonCopyable, NonMovable
306 {
307   int& x;  // OK, non copyable nor movable
308 };
309 
310 // Test composition
311 struct ContainsNonCopyable
312 {
313   NonCopyable x;
314   int& y;
315   // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: member 'y' of type 'int &' is a reference
316 };
317 
318 struct ContainsNonMovable
319 {
320   NonMovable x;
321   int& y;
322   // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: member 'y' of type 'int &' is a reference
323 };
324 
325 struct ContainsNonCopyableNonMovable
326 {
327   NonCopyableNonMovable x;
328   int& y;  // OK, non copyable nor movable
329 };
330 
331 struct ContainsBothNonCopyableAndNonMovable
332 {
333   NonCopyable x;
334   NonMovable y;
335   int& z;  // OK, non copyable nor movable
336 };
337 
338 // If copies are deleted and moves are not declared, moves are not implicitly declared,
339 // so the class is also not movable and we should not warn
340 struct NonCopyableMovesNotDeclared
341 {
342   NonCopyableMovesNotDeclared(NonCopyableMovesNotDeclared const&) = delete;
343   NonCopyableMovesNotDeclared& operator=(NonCopyableMovesNotDeclared const&) = delete;
344 
345   int& x;  // OK, non copyable nor movable
346 };
347 
348 // If moves are deleted but copies are not declared, copies are implicitly deleted,
349 // so the class is also not copyable and we should not warn
350 struct NonMovableCopiesNotDeclared
351 {
352   NonMovableCopiesNotDeclared(NonMovableCopiesNotDeclared&&) = delete;
353   NonMovableCopiesNotDeclared& operator=(NonMovableCopiesNotDeclared&&) = delete;
354 
355   int& x;  // OK, non copyable nor movable
356 };
357