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