1 // RUN: %check_clang_tidy %s cppcoreguidelines-prefer-member-initializer %t -- -- -fcxx-exceptions
2
3 extern void __assert_fail (__const char *__assertion, __const char *__file,
4 unsigned int __line, __const char *__function)
5 __attribute__ ((__noreturn__));
6 #define assert(expr) \
7 ((expr) ? (void)(0) : __assert_fail (#expr, __FILE__, __LINE__, __func__))
8
9 class Simple1 {
10 int n;
11 double x;
12
13 public:
Simple1()14 Simple1() {
15 // CHECK-FIXES: Simple1() : n(0), x(0.0) {
16 n = 0;
17 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'n' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
18 // CHECK-FIXES: {{^\ *$}}
19 x = 0.0;
20 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'x' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
21 // CHECK-FIXES: {{^\ *$}}
22 }
23
Simple1(int nn,double xx)24 Simple1(int nn, double xx) {
25 // CHECK-FIXES: Simple1(int nn, double xx) : n(nn), x(xx) {
26 n = nn;
27 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'n' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
28 // CHECK-FIXES: {{^\ *$}}
29 x = xx;
30 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'x' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
31 // CHECK-FIXES: {{^\ *$}}
32 }
33
34 ~Simple1() = default;
35 };
36
37 class Simple2 {
38 int n;
39 double x;
40
41 public:
Simple2()42 Simple2() : n(0) {
43 // CHECK-FIXES: Simple2() : n(0), x(0.0) {
44 x = 0.0;
45 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'x' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
46 // CHECK-FIXES: {{^\ *$}}
47 }
48
Simple2(int nn,double xx)49 Simple2(int nn, double xx) : n(nn) {
50 // CHECK-FIXES: Simple2(int nn, double xx) : n(nn), x(xx) {
51 x = xx;
52 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'x' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
53 // CHECK-FIXES: {{^\ *$}}
54 }
55
56 ~Simple2() = default;
57 };
58
59 class Simple3 {
60 int n;
61 double x;
62
63 public:
Simple3()64 Simple3() : x(0.0) {
65 // CHECK-FIXES: Simple3() : n(0), x(0.0) {
66 n = 0;
67 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'n' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
68 // CHECK-FIXES: {{^\ *$}}
69 }
70
Simple3(int nn,double xx)71 Simple3(int nn, double xx) : x(xx) {
72 // CHECK-FIXES: Simple3(int nn, double xx) : n(nn), x(xx) {
73 n = nn;
74 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'n' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
75 // CHECK-FIXES: {{^\ *$}}
76 }
77
78 ~Simple3() = default;
79 };
80
81 int something_int();
82 double something_double();
83
84 class Simple4 {
85 int n;
86
87 public:
Simple4()88 Simple4() {
89 // CHECK-FIXES: Simple4() : n(something_int()) {
90 n = something_int();
91 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'n' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
92 // CHECK-FIXES: {{^\ *$}}
93 }
94
95 ~Simple4() = default;
96 };
97
98 static bool dice();
99
100 class Complex1 {
101 int n;
102 int m;
103
104 public:
Complex1()105 Complex1() : n(0) {
106 if (dice())
107 m = 1;
108 // NO-MESSAGES: initialization of 'm' is nested in a conditional expression
109 }
110
111 ~Complex1() = default;
112 };
113
114 class Complex2 {
115 int n;
116 int m;
117
118 public:
Complex2()119 Complex2() : n(0) {
120 if (!dice())
121 return;
122 m = 1;
123 // NO-MESSAGES: initialization of 'm' follows a conditional expression
124 }
125
126 ~Complex2() = default;
127 };
128
129 class Complex3 {
130 int n;
131 int m;
132
133 public:
Complex3()134 Complex3() : n(0) {
135 while (dice())
136 m = 1;
137 // NO-MESSAGES: initialization of 'm' is nested in a conditional loop
138 }
139
140 ~Complex3() = default;
141 };
142
143 class Complex4 {
144 int n;
145 int m;
146
147 public:
Complex4()148 Complex4() : n(0) {
149 while (!dice())
150 return;
151 m = 1;
152 // NO-MESSAGES: initialization of 'm' follows a conditional loop
153 }
154
155 ~Complex4() = default;
156 };
157
158 class Complex5 {
159 int n;
160 int m;
161
162 public:
Complex5()163 Complex5() : n(0) {
164 do {
165 m = 1;
166 // NO-MESSAGES: initialization of 'm' is nested in a conditional loop
167 } while (dice());
168 }
169
170 ~Complex5() = default;
171 };
172
173 class Complex6 {
174 int n;
175 int m;
176
177 public:
Complex6()178 Complex6() : n(0) {
179 do {
180 return;
181 } while (!dice());
182 m = 1;
183 // NO-MESSAGES: initialization of 'm' follows a conditional loop
184 }
185
186 ~Complex6() = default;
187 };
188
189 class Complex7 {
190 int n;
191 int m;
192
193 public:
Complex7()194 Complex7() : n(0) {
195 for (int i = 2; i < 1; ++i) {
196 m = 1;
197 }
198 // NO-MESSAGES: initialization of 'm' is nested into a conditional loop
199 }
200
201 ~Complex7() = default;
202 };
203
204 class Complex8 {
205 int n;
206 int m;
207
208 public:
Complex8()209 Complex8() : n(0) {
210 for (int i = 0; i < 2; ++i) {
211 return;
212 }
213 m = 1;
214 // NO-MESSAGES: initialization of 'm' follows a conditional loop
215 }
216
217 ~Complex8() = default;
218 };
219
220 class Complex9 {
221 int n;
222 int m;
223
224 public:
Complex9()225 Complex9() : n(0) {
226 switch (dice()) {
227 case 1:
228 m = 1;
229 // NO-MESSAGES: initialization of 'm' is nested in a conditional expression
230 break;
231 default:
232 break;
233 }
234 }
235
236 ~Complex9() = default;
237 };
238
239 class Complex10 {
240 int n;
241 int m;
242
243 public:
Complex10()244 Complex10() : n(0) {
245 switch (dice()) {
246 case 1:
247 return;
248 break;
249 default:
250 break;
251 }
252 m = 1;
253 // NO-MESSAGES: initialization of 'm' follows a conditional expression
254 }
255
256 ~Complex10() = default;
257 };
258
259 class E {};
260 int risky(); // may throw
261
262 class Complex11 {
263 int n;
264 int m;
265
266 public:
Complex11()267 Complex11() : n(0) {
268 try {
269 risky();
270 m = 1;
271 // NO-MESSAGES: initialization of 'm' follows is nested in a try-block
272 } catch (const E& e) {
273 return;
274 }
275 }
276
277 ~Complex11() = default;
278 };
279
280 class Complex12 {
281 int n;
282 int m;
283
284 public:
Complex12()285 Complex12() : n(0) {
286 try {
287 risky();
288 } catch (const E& e) {
289 return;
290 }
291 m = 1;
292 // NO-MESSAGES: initialization of 'm' follows a try-block
293 }
294
295 ~Complex12() = default;
296 };
297
298 class Complex13 {
299 int n;
300 int m;
301
302 public:
Complex13()303 Complex13() : n(0) {
304 return;
305 m = 1;
306 // NO-MESSAGES: initialization of 'm' follows a return statement
307 }
308
309 ~Complex13() = default;
310 };
311
312 class Complex14 {
313 int n;
314 int m;
315
316 public:
Complex14()317 Complex14() : n(0) {
318 goto X;
319 m = 1;
320 // NO-MESSAGES: initialization of 'm' follows a goto statement
321 X:
322 ;
323 }
324
325 ~Complex14() = default;
326 };
327
328 void returning();
329
330 class Complex15 {
331 int n;
332 int m;
333
334 public:
Complex15()335 Complex15() : n(0) {
336 // CHECK-FIXES: Complex15() : n(0), m(1) {
337 returning();
338 m = 1;
339 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'm' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
340 // CHECK-FIXES: {{^\ *$}}
341 }
342
343 ~Complex15() = default;
344 };
345
346 [[noreturn]] void not_returning();
347
348 class Complex16 {
349 int n;
350 int m;
351
352 public:
Complex16()353 Complex16() : n(0) {
354 not_returning();
355 m = 1;
356 // NO-MESSAGES: initialization of 'm' follows a non-returning function call
357 }
358
359 ~Complex16() = default;
360 };
361
362 class Complex17 {
363 int n;
364 int m;
365
366 public:
Complex17()367 Complex17() : n(0) {
368 throw 1;
369 m = 1;
370 // NO-MESSAGES: initialization of 'm' follows a 'throw' statement;
371 }
372
373 ~Complex17() = default;
374 };
375
376 class Complex18 {
377 int n;
378
379 public:
Complex18()380 Complex18() try {
381 n = risky();
382 // NO-MESSAGES: initialization of 'n' in a 'try' body;
383 } catch (const E& e) {
384 n = 0;
385 }
386
387 ~Complex18() = default;
388 };
389
390 class Complex19 {
391 int n;
392 public:
Complex19()393 Complex19() {
394 // CHECK-FIXES: Complex19() : n(0) {
395 n = 0;
396 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'n' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
397 // CHECK-FIXES: {{^\ *$}}
398 }
399
Complex19(int)400 explicit Complex19(int) {
401 // CHECK-FIXES: Complex19(int) : n(12) {
402 n = 12;
403 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'n' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
404 // CHECK-FIXES: {{^\ *$}}
405 }
406
407 ~Complex19() = default;
408 };
409
410 class Complex20 {
411 int n;
412 int m;
413
414 public:
Complex20(int k)415 Complex20(int k) : n(0) {
416 assert(k > 0);
417 m = 1;
418 // NO-MESSAGES: initialization of 'm' follows an assertion
419 }
420
421 ~Complex20() = default;
422 };
423
424 class VeryComplex1 {
425 int n1, n2, n3;
426 double x1, x2, x3;
427 int n4, n5, n6;
428 double x4, x5, x6;
429
VeryComplex1()430 VeryComplex1() : n3(something_int()), x3(something_double()),
431 n5(something_int()), x4(something_double()),
432 x5(something_double()) {
433 // CHECK-FIXES: VeryComplex1() : n2(something_int()), n1(something_int()), n3(something_int()), x2(something_double()), x1(something_double()), x3(something_double()),
434 // CHECK-FIXES: n4(something_int()), n5(something_int()), n6(something_int()), x4(something_double()),
435 // CHECK-FIXES: x5(something_double()), x6(something_double()) {
436
437 // FIXME: Order of elements on the constructor initializer list should match
438 // the order of the declaration of the fields. Thus the correct fixes
439 // should look like these:
440 //
441 // C ECK-FIXES: VeryComplex1() : n2(something_int()), n1(something_int()), n3(something_int()), x2(something_double()), x1(something_double()), x3(something_double()),
442 // C ECK-FIXES: n4(something_int()), n5(something_int()), n6(something_int()), x4(something_double()),
443 // C ECK-FIXES: x5(something_double()), x6(something_double()) {
444 //
445 // However, the Diagnostics Engine processes fixes in the order of the
446 // diagnostics and insertions to the same position are handled in left to
447 // right order thus in the case two adjacent fields are initialized
448 // inside the constructor in reverse order the provided fix is a
449 // constructor initializer list that does not match the order of the
450 // declaration of the fields.
451
452 x2 = something_double();
453 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'x2' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
454 // CHECK-FIXES: {{^\ *$}}
455 n2 = something_int();
456 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'n2' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
457 // CHECK-FIXES: {{^\ *$}}
458 x6 = something_double();
459 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'x6' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
460 // CHECK-FIXES: {{^\ *$}}
461 x1 = something_double();
462 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'x1' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
463 // CHECK-FIXES: {{^\ *$}}
464 n6 = something_int();
465 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'n6' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
466 // CHECK-FIXES: {{^\ *$}}
467 n1 = something_int();
468 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'n1' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
469 // CHECK-FIXES: {{^\ *$}}
470 n4 = something_int();
471 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'n4' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
472 // CHECK-FIXES: {{^\ *$}}
473 }
474 };
475
476 struct Outside {
477 int n;
478 double x;
479 Outside();
480 };
481
Outside()482 Outside::Outside() {
483 // CHECK-FIXES: Outside::Outside() : n(1), x(1.0) {
484 n = 1;
485 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'n' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
486 // CHECK-FIXES: {{^\ *$}}
487 x = 1.0;
488 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'x' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
489 // CHECK-FIXES: {{^\ *$}}
490 }
491
492 struct SafeDependancy {
493 int m;
494 int n;
SafeDependancySafeDependancy495 SafeDependancy(int M) : m(M) {
496 // CHECK-FIXES: SafeDependancy(int M) : m(M), n(m) {
497 n = m;
498 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'n' should be initialized in a member initializer of the constructor
499 }
500 // We match against direct field dependancy as well as descendant field
501 // dependancy, ensure both are accounted for.
SafeDependancySafeDependancy502 SafeDependancy(short M) : m(M) {
503 // CHECK-FIXES: SafeDependancy(short M) : m(M), n(m + 1) {
504 n = m + 1;
505 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'n' should be initialized in a member initializer of the constructor
506 }
507 };
508
509 struct BadDependancy {
510 int m;
511 int n;
BadDependancyBadDependancy512 BadDependancy(int N) : n(N) {
513 m = n;
514 }
BadDependancyBadDependancy515 BadDependancy(short N) : n(N) {
516 m = n + 1;
517 }
518 };
519
520 struct InitFromVarDecl {
521 int m;
InitFromVarDeclInitFromVarDecl522 InitFromVarDecl() {
523 // Can't apply this fix as n is declared in the body of the constructor.
524 int n = 3;
525 m = n;
526 }
527 };
528
529 struct AlreadyHasInit {
530 int m = 4;
AlreadyHasInitAlreadyHasInit531 AlreadyHasInit() {
532 m = 3;
533 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'm' should be initialized in a member initializer of the constructor
534 }
535 };
536
537 #define ASSIGN_IN_MACRO(FIELD, VALUE) FIELD = (VALUE);
538
539 struct MacroCantFix {
540 int n; // NoFix
541 // CHECK-FIXES: int n; // NoFix
MacroCantFixMacroCantFix542 MacroCantFix() {
543 ASSIGN_IN_MACRO(n, 0)
544 // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: 'n' should be initialized in a member initializer of the constructor
545 // CHECK-FIXES: ASSIGN_IN_MACRO(n, 0)
546 }
547 };
548