1 // RUN: %check_clang_tidy %s readability-implicit-bool-conversion %t
2 
3 // We need NULL macro, but some buildbots don't like including <cstddef> header
4 // This is a portable way of getting it to work
5 #undef NULL
6 #define NULL 0L
7 
8 template<typename T>
9 void functionTaking(T);
10 
11 struct Struct {
12   int member;
13 };
14 
15 
16 ////////// Implicit conversion from bool.
17 
implicitConversionFromBoolSimpleCases()18 void implicitConversionFromBoolSimpleCases() {
19   bool boolean = true;
20 
21   functionTaking<bool>(boolean);
22 
23   functionTaking<int>(boolean);
24   // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: implicit conversion bool -> 'int' [readability-implicit-bool-conversion]
25   // CHECK-FIXES: functionTaking<int>(static_cast<int>(boolean));
26 
27   functionTaking<unsigned long>(boolean);
28   // CHECK-MESSAGES: :[[@LINE-1]]:33: warning: implicit conversion bool -> 'unsigned long'
29   // CHECK-FIXES: functionTaking<unsigned long>(static_cast<unsigned long>(boolean));
30 
31   functionTaking<char>(boolean);
32   // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion bool -> 'char'
33   // CHECK-FIXES: functionTaking<char>(static_cast<char>(boolean));
34 
35   functionTaking<float>(boolean);
36   // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: implicit conversion bool -> 'float'
37   // CHECK-FIXES: functionTaking<float>(static_cast<float>(boolean));
38 
39   functionTaking<double>(boolean);
40   // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: implicit conversion bool -> 'double'
41   // CHECK-FIXES: functionTaking<double>(static_cast<double>(boolean));
42 }
43 
implicitConversionFromBoolInReturnValue()44 float implicitConversionFromBoolInReturnValue() {
45   bool boolean = false;
46   return boolean;
47   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: implicit conversion bool -> 'float'
48   // CHECK-FIXES: return static_cast<float>(boolean);
49 }
50 
implicitConversionFromBoolInSingleBoolExpressions(bool b1,bool b2)51 void implicitConversionFromBoolInSingleBoolExpressions(bool b1, bool b2) {
52   bool boolean = true;
53   boolean = b1 ^ b2;
54   boolean = b1 && b2;
55   boolean |= !b1 || !b2;
56   boolean &= b1;
57   boolean = b1 == true;
58   boolean = b2 != false;
59 
60   int integer = boolean - 3;
61   // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: implicit conversion bool -> 'int'
62   // CHECK-FIXES: int integer = static_cast<int>(boolean) - 3;
63 
64   float floating = boolean / 0.3f;
65   // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: implicit conversion bool -> 'float'
66   // CHECK-FIXES: float floating = static_cast<float>(boolean) / 0.3f;
67 
68   char character = boolean;
69   // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: implicit conversion bool -> 'char'
70   // CHECK-FIXES: char character = static_cast<char>(boolean);
71 }
72 
implicitConversionFromBoollInComplexBoolExpressions()73 void implicitConversionFromBoollInComplexBoolExpressions() {
74   bool boolean = true;
75   bool anotherBoolean = false;
76 
77   int integer = boolean && anotherBoolean;
78   // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: implicit conversion bool -> 'int'
79   // CHECK-FIXES: int integer = static_cast<int>(boolean && anotherBoolean);
80 
81   unsigned long unsignedLong = (! boolean) + 4ul;
82   // CHECK-MESSAGES: :[[@LINE-1]]:32: warning: implicit conversion bool -> 'unsigned long'
83   // CHECK-FIXES: unsigned long unsignedLong = static_cast<unsigned long>(! boolean) + 4ul;
84 
85   float floating = (boolean || anotherBoolean) * 0.3f;
86   // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: implicit conversion bool -> 'float'
87   // CHECK-FIXES: float floating = static_cast<float>(boolean || anotherBoolean) * 0.3f;
88 
89   double doubleFloating = (boolean && (anotherBoolean || boolean)) * 0.3;
90   // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: implicit conversion bool -> 'double'
91   // CHECK-FIXES: double doubleFloating = static_cast<double>(boolean && (anotherBoolean || boolean)) * 0.3;
92 }
93 
implicitConversionFromBoolLiterals()94 void implicitConversionFromBoolLiterals() {
95   functionTaking<int>(true);
96   // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: implicit conversion bool -> 'int'
97   // CHECK-FIXES: functionTaking<int>(1);
98 
99   functionTaking<unsigned long>(false);
100   // CHECK-MESSAGES: :[[@LINE-1]]:33: warning: implicit conversion bool -> 'unsigned long'
101   // CHECK-FIXES: functionTaking<unsigned long>(0u);
102 
103   functionTaking<signed char>(true);
104   // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: implicit conversion bool -> 'signed char'
105   // CHECK-FIXES: functionTaking<signed char>(1);
106 
107   functionTaking<float>(false);
108   // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: implicit conversion bool -> 'float'
109   // CHECK-FIXES: functionTaking<float>(0.0f);
110 
111   functionTaking<double>(true);
112   // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: implicit conversion bool -> 'double'
113   // CHECK-FIXES: functionTaking<double>(1.0);
114 }
115 
implicitConversionFromBoolInComparisons()116 void implicitConversionFromBoolInComparisons() {
117   bool boolean = true;
118   int integer = 0;
119 
120   functionTaking<bool>(boolean == integer);
121   // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion bool -> 'int'
122   // CHECK-FIXES: functionTaking<bool>(static_cast<int>(boolean) == integer);
123 
124   functionTaking<bool>(integer != boolean);
125   // CHECK-MESSAGES: :[[@LINE-1]]:35: warning: implicit conversion bool -> 'int'
126   // CHECK-FIXES: functionTaking<bool>(integer != static_cast<int>(boolean));
127 }
128 
ignoreBoolComparisons()129 void ignoreBoolComparisons() {
130   bool boolean = true;
131   bool anotherBoolean = false;
132 
133   functionTaking<bool>(boolean == anotherBoolean);
134   functionTaking<bool>(boolean != anotherBoolean);
135 }
136 
ignoreExplicitCastsFromBool()137 void ignoreExplicitCastsFromBool() {
138   bool boolean = true;
139 
140   int integer = static_cast<int>(boolean) + 3;
141   float floating = static_cast<float>(boolean) * 0.3f;
142   char character = static_cast<char>(boolean);
143 }
144 
ignoreImplicitConversionFromBoolInMacroExpansions()145 void ignoreImplicitConversionFromBoolInMacroExpansions() {
146   bool boolean = true;
147 
148   #define CAST_FROM_BOOL_IN_MACRO_BODY boolean + 3
149   int integerFromMacroBody = CAST_FROM_BOOL_IN_MACRO_BODY;
150 
151   #define CAST_FROM_BOOL_IN_MACRO_ARGUMENT(x) x + 3
152   int integerFromMacroArgument = CAST_FROM_BOOL_IN_MACRO_ARGUMENT(boolean);
153 }
154 
155 namespace ignoreImplicitConversionFromBoolInTemplateInstantiations {
156 
157 template<typename T>
templateFunction()158 void templateFunction() {
159   bool boolean = true;
160   T uknownType = boolean + 3;
161 }
162 
useOfTemplateFunction()163 void useOfTemplateFunction() {
164   templateFunction<int>();
165 }
166 
167 } // namespace ignoreImplicitConversionFromBoolInTemplateInstantiations
168 
169 ////////// Implicit conversions to bool.
170 
implicitConversionToBoolSimpleCases()171 void implicitConversionToBoolSimpleCases() {
172   int integer = 10;
173   functionTaking<bool>(integer);
174   // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'int' -> bool
175   // CHECK-FIXES: functionTaking<bool>(integer != 0);
176 
177   unsigned long unsignedLong = 10;
178   functionTaking<bool>(unsignedLong);
179   // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'unsigned long' -> bool
180   // CHECK-FIXES: functionTaking<bool>(unsignedLong != 0u);
181 
182   float floating = 0.0f;
183   functionTaking<bool>(floating);
184   // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'float' -> bool
185   // CHECK-FIXES: functionTaking<bool>(floating != 0.0f);
186 
187   double doubleFloating = 1.0f;
188   functionTaking<bool>(doubleFloating);
189   // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'double' -> bool
190   // CHECK-FIXES: functionTaking<bool>(doubleFloating != 0.0);
191 
192   signed char character = 'a';
193   functionTaking<bool>(character);
194   // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'signed char' -> bool
195   // CHECK-FIXES: functionTaking<bool>(character != 0);
196 
197   int* pointer = nullptr;
198   functionTaking<bool>(pointer);
199   // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'int *' -> bool
200   // CHECK-FIXES: functionTaking<bool>(pointer != nullptr);
201 
202   auto pointerToMember = &Struct::member;
203   functionTaking<bool>(pointerToMember);
204   // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'int Struct::*' -> bool
205   // CHECK-FIXES: functionTaking<bool>(pointerToMember != nullptr);
206 }
207 
implicitConversionToBoolInSingleExpressions()208 void implicitConversionToBoolInSingleExpressions() {
209   int integer = 10;
210   bool boolComingFromInt = integer;
211   // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: implicit conversion 'int' -> bool
212   // CHECK-FIXES: bool boolComingFromInt = integer != 0;
213 
214   float floating = 10.0f;
215   bool boolComingFromFloat = floating;
216   // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: implicit conversion 'float' -> bool
217   // CHECK-FIXES: bool boolComingFromFloat = floating != 0.0f;
218 
219   signed char character = 'a';
220   bool boolComingFromChar = character;
221   // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: implicit conversion 'signed char' -> bool
222   // CHECK-FIXES: bool boolComingFromChar = character != 0;
223 
224   int* pointer = nullptr;
225   bool boolComingFromPointer = pointer;
226   // CHECK-MESSAGES: :[[@LINE-1]]:32: warning: implicit conversion 'int *' -> bool
227   // CHECK-FIXES: bool boolComingFromPointer = pointer != nullptr;
228 }
229 
implicitConversionToBoolInComplexExpressions()230 void implicitConversionToBoolInComplexExpressions() {
231   bool boolean = true;
232 
233   int integer = 10;
234   int anotherInteger = 20;
235   bool boolComingFromInteger = integer + anotherInteger;
236   // CHECK-MESSAGES: :[[@LINE-1]]:32: warning: implicit conversion 'int' -> bool
237   // CHECK-FIXES: bool boolComingFromInteger = (integer + anotherInteger) != 0;
238 
239   float floating = 0.2f;
240   bool boolComingFromFloating = floating - 0.3f || boolean;
241   // CHECK-MESSAGES: :[[@LINE-1]]:33: warning: implicit conversion 'float' -> bool
242   // CHECK-FIXES: bool boolComingFromFloating = ((floating - 0.3f) != 0.0f) || boolean;
243 
244   double doubleFloating = 0.3;
245   bool boolComingFromDoubleFloating = (doubleFloating - 0.4) && boolean;
246   // CHECK-MESSAGES: :[[@LINE-1]]:39: warning: implicit conversion 'double' -> bool
247   // CHECK-FIXES: bool boolComingFromDoubleFloating = ((doubleFloating - 0.4) != 0.0) && boolean;
248 }
249 
implicitConversionInNegationExpressions()250 void implicitConversionInNegationExpressions() {
251   int integer = 10;
252   bool boolComingFromNegatedInt = !integer;
253   // CHECK-MESSAGES: :[[@LINE-1]]:36: warning: implicit conversion 'int' -> bool
254   // CHECK-FIXES: bool boolComingFromNegatedInt = integer == 0;
255 
256   float floating = 10.0f;
257   bool boolComingFromNegatedFloat = ! floating;
258   // CHECK-MESSAGES: :[[@LINE-1]]:39: warning: implicit conversion 'float' -> bool
259   // CHECK-FIXES: bool boolComingFromNegatedFloat = floating == 0.0f;
260 
261   signed char character = 'a';
262   bool boolComingFromNegatedChar = (! character);
263   // CHECK-MESSAGES: :[[@LINE-1]]:39: warning: implicit conversion 'signed char' -> bool
264   // CHECK-FIXES: bool boolComingFromNegatedChar = (character == 0);
265 
266   int* pointer = nullptr;
267   bool boolComingFromNegatedPointer = not pointer;
268   // CHECK-MESSAGES: :[[@LINE-1]]:43: warning: implicit conversion 'int *' -> bool
269   // CHECK-FIXES: bool boolComingFromNegatedPointer = pointer == nullptr;
270 }
271 
implicitConversionToBoolInControlStatements()272 void implicitConversionToBoolInControlStatements() {
273   int integer = 10;
274   if (integer) {}
275   // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: implicit conversion 'int' -> bool
276   // CHECK-FIXES: if (integer != 0) {}
277 
278   long int longInteger = 0.2f;
279   for (;longInteger;) {}
280   // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: implicit conversion 'long' -> bool
281   // CHECK-FIXES: for (;longInteger != 0;) {}
282 
283   float floating = 0.3f;
284   while (floating) {}
285   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: implicit conversion 'float' -> bool
286   // CHECK-FIXES: while (floating != 0.0f) {}
287 
288   double doubleFloating = 0.4;
289   do {} while (doubleFloating);
290   // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: implicit conversion 'double' -> bool
291   // CHECK-FIXES: do {} while (doubleFloating != 0.0);
292 }
293 
implicitConversionToBoolInReturnValue()294 bool implicitConversionToBoolInReturnValue() {
295   float floating = 1.0f;
296   return floating;
297   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: implicit conversion 'float' -> bool
298   // CHECK-FIXES: return floating != 0.0f;
299 }
300 
implicitConversionToBoolFromLiterals()301 void implicitConversionToBoolFromLiterals() {
302   functionTaking<bool>(0);
303   // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'int' -> bool
304   // CHECK-FIXES: functionTaking<bool>(false);
305 
306   functionTaking<bool>(1);
307   // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'int' -> bool
308   // CHECK-FIXES: functionTaking<bool>(true);
309 
310   functionTaking<bool>(2ul);
311   // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'unsigned long' -> bool
312   // CHECK-FIXES: functionTaking<bool>(true);
313 
314 
315   functionTaking<bool>(0.0f);
316   // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'float' -> bool
317   // CHECK-FIXES: functionTaking<bool>(false);
318 
319   functionTaking<bool>(1.0f);
320   // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'float' -> bool
321   // CHECK-FIXES: functionTaking<bool>(true);
322 
323   functionTaking<bool>(2.0);
324   // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'double' -> bool
325   // CHECK-FIXES: functionTaking<bool>(true);
326 
327 
328   functionTaking<bool>('\0');
329   // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'char' -> bool
330   // CHECK-FIXES: functionTaking<bool>(false);
331 
332   functionTaking<bool>('a');
333   // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'char' -> bool
334   // CHECK-FIXES: functionTaking<bool>(true);
335 
336 
337   functionTaking<bool>("");
338   // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'const char *' -> bool
339   // CHECK-FIXES: functionTaking<bool>(true);
340 
341   functionTaking<bool>("abc");
342   // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'const char *' -> bool
343   // CHECK-FIXES: functionTaking<bool>(true);
344 
345   functionTaking<bool>(NULL);
346   // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'long' -> bool
347   // CHECK-FIXES: functionTaking<bool>(false);
348 }
349 
implicitConversionToBoolFromUnaryMinusAndZeroLiterals()350 void implicitConversionToBoolFromUnaryMinusAndZeroLiterals() {
351   functionTaking<bool>(-0);
352   // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'int' -> bool
353   // CHECK-FIXES: functionTaking<bool>((-0) != 0);
354 
355   functionTaking<bool>(-0.0f);
356   // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'float' -> bool
357   // CHECK-FIXES: functionTaking<bool>((-0.0f) != 0.0f);
358 
359   functionTaking<bool>(-0.0);
360   // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'double' -> bool
361   // CHECK-FIXES: functionTaking<bool>((-0.0) != 0.0);
362 }
363 
implicitConversionToBoolInWithOverloadedOperators()364 void implicitConversionToBoolInWithOverloadedOperators() {
365   struct UserStruct {
366     int operator()(int x) { return x; }
367     int operator+(int y) { return y; }
368   };
369 
370   UserStruct s;
371 
372   functionTaking<bool>(s(0));
373   // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'int' -> bool
374   // CHECK-FIXES: functionTaking<bool>(s(0) != 0);
375 
376   functionTaking<bool>(s + 2);
377   // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'int' -> bool
378   // CHECK-FIXES: functionTaking<bool>((s + 2) != 0);
379 }
380 
381 int functionReturningInt();
382 int* functionReturningPointer();
383 
ignoreImplicitConversionToBoolWhenDeclaringVariableInControlStatements()384 void ignoreImplicitConversionToBoolWhenDeclaringVariableInControlStatements() {
385   if (int integer = functionReturningInt()) {}
386 
387   while (int* pointer = functionReturningPointer()) {}
388 }
389 
ignoreExplicitCastsToBool()390 void ignoreExplicitCastsToBool() {
391   int integer = 10;
392   bool boolComingFromInt = static_cast<bool>(integer);
393 
394   float floating = 10.0f;
395   bool boolComingFromFloat = static_cast<bool>(floating);
396 
397   char character = 'a';
398   bool boolComingFromChar = static_cast<bool>(character);
399 
400   int* pointer = nullptr;
401   bool booleanComingFromPointer = static_cast<bool>(pointer);
402 }
403 
ignoreImplicitConversionToBoolInMacroExpansions()404 void ignoreImplicitConversionToBoolInMacroExpansions() {
405   int integer = 3;
406 
407   #define CAST_TO_BOOL_IN_MACRO_BODY integer && false
408   bool boolFromMacroBody = CAST_TO_BOOL_IN_MACRO_BODY;
409 
410   #define CAST_TO_BOOL_IN_MACRO_ARGUMENT(x) x || true
411   bool boolFromMacroArgument = CAST_TO_BOOL_IN_MACRO_ARGUMENT(integer);
412 }
413 
414 namespace ignoreImplicitConversionToBoolInTemplateInstantiations {
415 
416 template<typename T>
templateFunction()417 void templateFunction() {
418   T unknownType = 0;
419   bool boolean = unknownType;
420 }
421 
useOfTemplateFunction()422 void useOfTemplateFunction() {
423   templateFunction<int>();
424 }
425 
426 } // namespace ignoreImplicitConversionToBoolInTemplateInstantiations
427 
428 namespace ignoreUserDefinedConversionOperator {
429 
430 struct StructWithUserConversion {
431   operator bool();
432 };
433 
useOfUserConversion()434 void useOfUserConversion() {
435   StructWithUserConversion structure;
436   functionTaking<bool>(structure);
437 }
438 
439 } // namespace ignoreUserDefinedConversionOperator
440 
441 namespace ignore_1bit_bitfields {
442 
443 struct S {
444   int a;
445   int b : 1;
446   int c : 2;
447 
Signore_1bit_bitfields::S448   S(bool a, bool b, bool c) : a(a), b(b), c(c) {}
449   // CHECK-MESSAGES: :[[@LINE-1]]:33: warning: implicit conversion bool -> 'int'
450   // CHECK-MESSAGES: :[[@LINE-2]]:45: warning: implicit conversion bool -> 'int'
451   // CHECK-FIXES: S(bool a, bool b, bool c) : a(static_cast<int>(a)), b(b), c(static_cast<int>(c)) {}
452 };
453 
f(S & s)454 bool f(S& s) {
455   functionTaking<bool>(s.a);
456   // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'int' -> bool
457   // CHECK-FIXES: functionTaking<bool>(s.a != 0);
458   functionTaking<bool>(s.b);
459   // CHECK-FIXES: functionTaking<bool>(s.b);
460   s.a = true;
461   // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: implicit conversion bool -> 'int'
462   // CHECK-FIXES: s.a = 1;
463   s.b = true;
464   // CHECK-FIXES: s.b = true;
465   s.c = true;
466   // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: implicit conversion bool -> 'int'
467   // CHECK-FIXES: s.c = 1;
468   functionTaking<bool>(s.c);
469   // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'int' -> bool
470   // CHECK-FIXES: functionTaking<bool>(s.c != 0);
471 }
472 
473 } // namespace ignore_1bit_bitfields
474