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{.t: 123}; |
167 | TemplatedConstRef<const int &> t3{.t: 123}; |
168 | TemplatedRefRef<int &&> t4{.t: 123}; |
169 | TemplatedRef<int &> t5{.t: 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 | // Test composition |
289 | struct ContainsNonCopyable |
290 | { |
291 | NonCopyable x; |
292 | int& y; |
293 | // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: member 'y' of type 'int &' is a reference |
294 | }; |
295 | |
296 | struct ContainsNonMovable |
297 | { |
298 | NonMovable x; |
299 | int& y; |
300 | // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: member 'y' of type 'int &' is a reference |
301 | }; |
302 | |
303 | struct ContainsNonCopyableNonMovable |
304 | { |
305 | NonCopyableNonMovable x; |
306 | int& y; // OK, non copyable nor movable |
307 | }; |
308 | |
309 | struct ContainsBothNonCopyableAndNonMovable |
310 | { |
311 | NonCopyable x; |
312 | NonMovable y; |
313 | int& z; // OK, non copyable nor movable |
314 | }; |
315 | |
316 | // If copies are deleted and moves are not declared, moves are not implicitly declared, |
317 | // so the class is also not movable and we should not warn |
318 | struct NonCopyableMovesNotDeclared |
319 | { |
320 | NonCopyableMovesNotDeclared(NonCopyableMovesNotDeclared const&) = delete; |
321 | NonCopyableMovesNotDeclared& operator=(NonCopyableMovesNotDeclared const&) = delete; |
322 | |
323 | int& x; // OK, non copyable nor movable |
324 | }; |
325 | |
326 | // If moves are deleted but copies are not declared, copies are implicitly deleted, |
327 | // so the class is also not copyable and we should not warn |
328 | struct NonMovableCopiesNotDeclared |
329 | { |
330 | NonMovableCopiesNotDeclared(NonMovableCopiesNotDeclared&&) = delete; |
331 | NonMovableCopiesNotDeclared& operator=(NonMovableCopiesNotDeclared&&) = delete; |
332 | |
333 | int& x; // OK, non copyable nor movable |
334 | }; |
335 | |