1// RUN: %check_clang_tidy %s cppcoreguidelines-prefer-member-initializer %t -- -- -fcxx-exceptions
2
3extern 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
9class Simple1 {
10 int n;
11 double x;
12
13public:
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
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
37class Simple2 {
38 int n;
39 double x;
40
41public:
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
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
59class Simple3 {
60 int n;
61 double x;
62
63public:
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
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
81int something_int();
82double something_double();
83
84class Simple4 {
85 int n;
86
87public:
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
98static bool dice();
99
100class Complex1 {
101 int n;
102 int m;
103
104public:
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
114class Complex2 {
115 int n;
116 int m;
117
118public:
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
129class Complex3 {
130 int n;
131 int m;
132
133public:
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
143class Complex4 {
144 int n;
145 int m;
146
147public:
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
158class Complex5 {
159 int n;
160 int m;
161
162public:
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
173class Complex6 {
174 int n;
175 int m;
176
177public:
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
189class Complex7 {
190 int n;
191 int m;
192
193public:
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
204class Complex8 {
205 int n;
206 int m;
207
208public:
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
220class Complex9 {
221 int n;
222 int m;
223
224public:
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
239class Complex10 {
240 int n;
241 int m;
242
243public:
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
259class E {};
260int risky(); // may throw
261
262class Complex11 {
263 int n;
264 int m;
265
266public:
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
280class Complex12 {
281 int n;
282 int m;
283
284public:
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
298class Complex13 {
299 int n;
300 int m;
301
302public:
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
312class Complex14 {
313 int n;
314 int m;
315
316public:
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
328void returning();
329
330class Complex15 {
331 int n;
332 int m;
333
334public:
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
348class Complex16 {
349 int n;
350 int m;
351
352public:
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
362class Complex17 {
363 int n;
364 int m;
365
366public:
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
376class Complex18 {
377 int n;
378
379public:
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
390class Complex19 {
391 int n;
392public:
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
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
410class Complex20 {
411 int n;
412 int m;
413
414public:
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
424class VeryComplex1 {
425 int n1, n2, n3;
426 double x1, x2, x3;
427 int n4, n5, n6;
428 double x4, x5, x6;
429
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
476struct Outside {
477 int n;
478 double x;
479 Outside();
480};
481
482Outside::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
492struct SafeDependancy {
493 int m;
494 int n;
495 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.
502 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
509struct BadDependancy {
510 int m;
511 int n;
512 BadDependancy(int N) : n(N) {
513 m = n;
514 }
515 BadDependancy(short N) : n(N) {
516 m = n + 1;
517 }
518};
519
520struct InitFromVarDecl {
521 int m;
522 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
529struct HasInClassInit {
530 int m = 4;
531 HasInClassInit() {
532 m = 3;
533 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'm' should be initialized in a member initializer of the constructor
534 }
535};
536
537struct HasInitListInit {
538 int M;
539 // CHECK-MESSAGES: :[[@LINE+5]]:5: warning: 'M' should be initialized in a member initializer of the constructor
540 // CHECK-FIXES: HasInitListInit(const HasInitListInit &Other) : M(Other.M) {
541 // CHECK-FIXES-NEXT: {{^ $}}
542 // CHECK-FIXES-NEXT: }
543 HasInitListInit(const HasInitListInit &Other) : M(4) {
544 M = Other.M;
545 }
546 // CHECK-MESSAGES: :[[@LINE+5]]:5: warning: 'M' should be initialized in a member initializer of the constructor
547 // CHECK-FIXES: HasInitListInit(HasInitListInit &&Other) : M(Other.M) {
548 // CHECK-FIXES-NEXT: {{^ $}}
549 // CHECK-FIXES-NEXT: }
550 HasInitListInit(HasInitListInit &&Other) : M() {
551 M = Other.M;
552 }
553};
554
555#define ASSIGN_IN_MACRO(FIELD, VALUE) FIELD = (VALUE);
556
557struct MacroCantFix {
558 int n; // NoFix
559 // CHECK-FIXES: int n; // NoFix
560 MacroCantFix() {
561 ASSIGN_IN_MACRO(n, 0)
562 // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: 'n' should be initialized in a member initializer of the constructor
563 // CHECK-FIXES: ASSIGN_IN_MACRO(n, 0)
564 }
565};
566
567struct PR52818 {
568 PR52818() : bar(5) {}
569 PR52818(int) : PR52818() { bar = 3; }
570
571 int bar;
572};
573
574struct RefReassignment {
575 RefReassignment(int &i) : m_i{i} {
576 m_i = 1;
577 }
578 int & m_i;
579};
580
581struct ReassignmentAfterUnsafetyAssignment {
582 ReassignmentAfterUnsafetyAssignment() {
583 int a = 10;
584 m_i = a;
585 m_i = 1;
586 }
587 int m_i;
588};
589
590namespace PR70189 {
591#define RGB(r,g,b) ((unsigned long)(((unsigned char)(r)|((unsigned short)((unsigned char)(g))<<8))|(((unsigned long)(unsigned char)(b))<<16)))
592#define INVALID_HANDLE_VALUE ((void*)(unsigned long long)-1)
593#define SIMPLE 12
594
595class Foo {
596public:
597 Foo() {
598// CHECK-FIXES: Foo() : m_color(RGB(255, 128, 0)), m_handle(INVALID_HANDLE_VALUE), m_myval(SIMPLE) {
599 m_color = RGB(255, 128, 0);
600// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'm_color' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
601// CHECK-FIXES: {{^\ *$}}
602 m_handle = INVALID_HANDLE_VALUE;
603// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'm_handle' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
604// CHECK-FIXES: {{^\ *$}}
605 m_myval = SIMPLE;
606// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'm_myval' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
607// CHECK-FIXES: {{^\ *$}}
608 }
609private:
610 unsigned long m_color;
611 void* m_handle;
612 int m_myval;
613};
614
615#undef SIMPLE
616#undef INVALID_HANDLE_VALUE
617#undef RGB
618}
619
620namespace GH77684 {
621struct S1 {
622// CHECK-MESSAGES: :[[@LINE+1]]:16: warning: 'M' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
623 S1() : M{} { M = 0; }
624// CHECK-FIXES: S1() : M{0} { }
625 int M;
626};
627struct S2 {
628// CHECK-MESSAGES: :[[@LINE+1]]:17: warning: 'M' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
629 S2() : M{2} { M = 1; }
630// CHECK-FIXES: S2() : M{1} { }
631 int M;
632};
633struct T { int a; int b; int c; };
634T v;
635struct S3 {
636// CHECK-MESSAGES: :[[@LINE+1]]:21: warning: 'M' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
637 S3() : M{.a: 1,.b: 2,.c: 3} { M = v; }
638// CHECK-FIXES: S3() : M{v} { }
639 T M;
640};
641}
642

source code of clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/prefer-member-initializer.cpp