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:
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 
37 class Simple2 {
38   int n;
39   double x;
40 
41 public:
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 
59 class Simple3 {
60   int n;
61   double x;
62 
63 public:
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 
81 int something_int();
82 double something_double();
83 
84 class Simple4 {
85   int n;
86 
87 public:
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:
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:
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:
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:
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:
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:
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:
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:
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:
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:
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:
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:
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:
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:
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:
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:
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:
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:
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:
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 
410 class Complex20 {
411   int n;
412   int m;
413 
414 public:
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 
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 
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;
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 
509 struct 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 
520 struct 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 
529 struct 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 
537 struct 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 
557 struct 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 
567 struct PR52818  {
568     PR52818() : bar(5) {}
569     PR52818(int) : PR52818() { bar = 3; }
570 
571     int bar;
572 };
573 
574 struct RefReassignment {
575   RefReassignment(int &i) : m_i{i} {
576     m_i = 1;
577   }
578   int & m_i;
579 };
580 
581 struct ReassignmentAfterUnsafetyAssignment {
582   ReassignmentAfterUnsafetyAssignment() {
583     int a = 10;
584     m_i = a;
585     m_i = 1;
586   }
587   int m_i;
588 };
589 
590 namespace 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 
595 class Foo {
596 public:
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   }
609 private:
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 
620 namespace GH77684 {
621 struct 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 };
627 struct 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 };
633 struct T { int a; int b; int c; };
634 T v;
635 struct 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{1,2,3} { M = v; }
638 // CHECK-FIXES:  S3() : M{v} { }
639   T M;
640 };
641 }
642 
643 namespace GH82970 {
644 struct InitFromBindingDecl {
645   int m;
646   InitFromBindingDecl() {
647     struct { int i; } a;
648     auto [n] = a;
649     m = n;
650   }
651 };
652 } // namespace GH82970
653