xref: /llvm-project/clang-tools-extra/test/clang-tidy/checkers/readability/implicit-bool-conversion.c (revision a1d31caa8c53082d12f580122dcf2b2ff8285e78)
1 // RUN: %check_clang_tidy %s readability-implicit-bool-conversion %t -- -- -std=c23
2 // RUN: %check_clang_tidy -check-suffix=UPPER-CASE %s readability-implicit-bool-conversion %t -- \
3 // RUN:     -config='{CheckOptions: { \
4 // RUN:         readability-implicit-bool-conversion.UseUpperCaseLiteralSuffix: true \
5 // RUN:     }}' -- -std=c23
6 
7 #undef NULL
8 #define NULL 0L
9 
10 void functionTakingBool(bool);
11 void functionTakingInt(int);
12 void functionTakingUnsignedLong(unsigned long);
13 void functionTakingChar(char);
14 void functionTakingFloat(float);
15 void functionTakingDouble(double);
16 void functionTakingSignedChar(signed char);
17 
18 
19 ////////// Implicit conversion from bool.
20 
21 void implicitConversionFromBoolSimpleCases() {
22   bool boolean = true;
23 
24   functionTakingBool(boolean);
25 
26   functionTakingInt(boolean);
27   // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: implicit conversion 'bool' -> 'int' [readability-implicit-bool-conversion]
28   // CHECK-FIXES: functionTakingInt((int)boolean);
29 
30   functionTakingUnsignedLong(boolean);
31   // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: implicit conversion 'bool' -> 'unsigned long'
32   // CHECK-FIXES: functionTakingUnsignedLong((unsigned long)boolean);
33 
34   functionTakingChar(boolean);
35   // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: implicit conversion 'bool' -> 'char'
36   // CHECK-FIXES: functionTakingChar((char)boolean);
37 
38   functionTakingFloat(boolean);
39   // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: implicit conversion 'bool' -> 'float'
40   // CHECK-FIXES: functionTakingFloat((float)boolean);
41 
42   functionTakingDouble(boolean);
43   // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'bool' -> 'double'
44   // CHECK-FIXES: functionTakingDouble((double)boolean);
45 }
46 
47 float implicitConversionFromBoolInReturnValue() {
48   bool boolean = false;
49   return boolean;
50   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: implicit conversion 'bool' -> 'float'
51   // CHECK-FIXES: return (float)boolean;
52 }
53 
54 void implicitConversionFromBoolInSingleBoolExpressions(bool b1, bool b2) {
55   bool boolean = true;
56   boolean = b1 ^ b2;
57   boolean |= !b1 || !b2;
58   boolean &= b1;
59 
60   int integer = boolean - 3;
61   // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: implicit conversion 'bool' -> 'int'
62   // CHECK-FIXES: int integer = (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 = (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 = (char)boolean;
71 }
72 
73 void implicitConversionFromBoolInComplexBoolExpressions() {
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-MESSAGES: :[[@LINE-2]]:28: warning: implicit conversion 'bool' -> 'int'
80   // CHECK-FIXES: int integer = (int)boolean && (int)anotherBoolean;
81 
82   float floating = (boolean || anotherBoolean) * 0.3f;
83   // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: implicit conversion 'bool' -> 'int'
84   // CHECK-MESSAGES: :[[@LINE-2]]:32: warning: implicit conversion 'bool' -> 'int'
85   // CHECK-FIXES: float floating = ((int)boolean || (int)anotherBoolean) * 0.3f;
86 
87   double doubleFloating = (boolean && (anotherBoolean || boolean)) * 0.3;
88   // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: implicit conversion 'bool' -> 'int'
89   // CHECK-MESSAGES: :[[@LINE-2]]:40: warning: implicit conversion 'bool' -> 'int'
90   // CHECK-MESSAGES: :[[@LINE-3]]:58: warning: implicit conversion 'bool' -> 'int'
91   // CHECK-FIXES: double doubleFloating = ((int)boolean && ((int)anotherBoolean || (int)boolean)) * 0.3;
92 }
93 
94 void implicitConversionFromBoolLiterals() {
95   functionTakingInt(true);
96   // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: implicit conversion 'bool' -> 'int'
97   // CHECK-FIXES: functionTakingInt(1);
98 
99   functionTakingUnsignedLong(false);
100   // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: implicit conversion 'bool' -> 'unsigned long'
101   // CHECK-FIXES: functionTakingUnsignedLong(0u);
102   // CHECK-FIXES-UPPER-CASE: functionTakingUnsignedLong(0U);
103 
104   functionTakingSignedChar(true);
105   // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: implicit conversion 'bool' -> 'signed char'
106   // CHECK-FIXES: functionTakingSignedChar(1);
107 
108   functionTakingFloat(false);
109   // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: implicit conversion 'bool' -> 'float'
110   // CHECK-FIXES: functionTakingFloat(0.0f);
111   // CHECK-FIXES-UPPER-CASE: functionTakingFloat(0.0F);
112 
113   functionTakingDouble(true);
114   // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'bool' -> 'double'
115   // CHECK-FIXES: functionTakingDouble(1.0);
116 }
117 
118 void implicitConversionFromBoolInComparisons() {
119   bool boolean = true;
120   int integer = 0;
121 
122   functionTakingBool(boolean == integer);
123   // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: implicit conversion 'bool' -> 'int'
124   // CHECK-FIXES: functionTakingBool((int)boolean == integer);
125 
126   functionTakingBool(integer != boolean);
127   // CHECK-MESSAGES: :[[@LINE-1]]:33: warning: implicit conversion 'bool' -> 'int'
128   // CHECK-FIXES: functionTakingBool(integer != (int)boolean);
129 }
130 
131 void ignoreBoolComparisons() {
132   bool boolean = true;
133   bool anotherBoolean = false;
134 
135   functionTakingBool(boolean == anotherBoolean);
136   functionTakingBool(boolean != anotherBoolean);
137 }
138 
139 void ignoreExplicitCastsFromBool() {
140   bool boolean = true;
141 
142   int integer = (int)boolean + 3;
143   float floating = (float)boolean * 0.3f;
144   char character = (char)boolean;
145 }
146 
147 void ignoreImplicitConversionFromBoolInMacroExpansions() {
148   bool boolean = true;
149 
150   #define CAST_FROM_BOOL_IN_MACRO_BODY boolean + 3
151   int integerFromMacroBody = CAST_FROM_BOOL_IN_MACRO_BODY;
152 
153   #define CAST_FROM_BOOL_IN_MACRO_ARGUMENT(x) x + 3
154   int integerFromMacroArgument = CAST_FROM_BOOL_IN_MACRO_ARGUMENT(boolean);
155 }
156 
157 ////////// Implicit conversions to bool.
158 
159 void implicitConversionToBoolSimpleCases() {
160   int integer = 10;
161   functionTakingBool(integer);
162   // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: implicit conversion 'int' -> 'bool'
163   // CHECK-FIXES: functionTakingBool(integer != 0);
164 
165   unsigned long unsignedLong = 10;
166   functionTakingBool(unsignedLong);
167   // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: implicit conversion 'unsigned long' -> 'bool'
168   // CHECK-FIXES: functionTakingBool(unsignedLong != 0u);
169   // CHECK-FIXES-UPPER-CASE: functionTakingBool(unsignedLong != 0U);
170 
171   float floating = 0.0f;
172   functionTakingBool(floating);
173   // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: implicit conversion 'float' -> 'bool'
174   // CHECK-FIXES: functionTakingBool(floating != 0.0f);
175   // CHECK-FIXES-UPPER-CASE: functionTakingBool(floating != 0.0F);
176 
177   double doubleFloating = 1.0f;
178   functionTakingBool(doubleFloating);
179   // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: implicit conversion 'double' -> 'bool'
180   // CHECK-FIXES: functionTakingBool(doubleFloating != 0.0);
181 
182   signed char character = 'a';
183   functionTakingBool(character);
184   // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: implicit conversion 'signed char' -> 'bool'
185   // CHECK-FIXES: functionTakingBool(character != 0);
186 
187   int* pointer = nullptr;
188   functionTakingBool(pointer);
189   // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: implicit conversion 'int *' -> 'bool'
190   // CHECK-FIXES: functionTakingBool(pointer != nullptr);
191 }
192 
193 void implicitConversionToBoolInSingleExpressions() {
194   int integer = 10;
195   bool boolComingFromInt;
196   boolComingFromInt = integer;
197   // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: implicit conversion 'int' -> 'bool'
198   // CHECK-FIXES: boolComingFromInt = (integer != 0);
199 
200   float floating = 10.0f;
201   bool boolComingFromFloat;
202   boolComingFromFloat = floating;
203   // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: implicit conversion 'float' -> 'bool'
204   // CHECK-FIXES: boolComingFromFloat = (floating != 0.0f);
205   // CHECK-FIXES-UPPER-CASE: boolComingFromFloat = (floating != 0.0F);
206 
207   signed char character = 'a';
208   bool boolComingFromChar;
209   boolComingFromChar = character;
210   // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'signed char' -> 'bool'
211   // CHECK-FIXES: boolComingFromChar = (character != 0);
212 
213   int* pointer = nullptr;
214   bool boolComingFromPointer;
215   boolComingFromPointer = pointer;
216   // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: implicit conversion 'int *' -> 'bool'
217   // CHECK-FIXES: boolComingFromPointer = (pointer != nullptr);
218 }
219 
220 void implicitConversionToBoolInComplexExpressions() {
221   bool boolean = true;
222 
223   int integer = 10;
224   int anotherInteger = 20;
225   bool boolComingFromInteger;
226   boolComingFromInteger = integer + anotherInteger;
227   // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: implicit conversion 'int' -> 'bool'
228   // CHECK-FIXES: boolComingFromInteger = ((integer + anotherInteger) != 0);
229 }
230 
231 void implicitConversionInNegationExpressions() {
232   int integer = 10;
233   bool boolComingFromNegatedInt;
234   boolComingFromNegatedInt = !integer;
235   // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: implicit conversion 'int' -> 'bool'
236   // CHECK-FIXES: boolComingFromNegatedInt = ((!integer) != 0);
237 }
238 
239 bool implicitConversionToBoolInReturnValue() {
240   float floating = 1.0f;
241   return floating;
242   // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: implicit conversion 'float' -> 'bool'
243   // CHECK-FIXES: return floating != 0.0f;
244 }
245 
246 void implicitConversionToBoolFromLiterals() {
247   functionTakingBool(0);
248   // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: implicit conversion 'int' -> 'bool'
249   // CHECK-FIXES: functionTakingBool(false);
250 
251   functionTakingBool(1);
252   // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: implicit conversion 'int' -> 'bool'
253   // CHECK-FIXES: functionTakingBool(true);
254 
255   functionTakingBool(2ul);
256   // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: implicit conversion 'unsigned long' -> 'bool'
257   // CHECK-FIXES: functionTakingBool(true);
258 
259   functionTakingBool(0.0f);
260   // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: implicit conversion 'float' -> 'bool'
261   // CHECK-FIXES: functionTakingBool(false);
262 
263   functionTakingBool(1.0f);
264   // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: implicit conversion 'float' -> 'bool'
265   // CHECK-FIXES: functionTakingBool(true);
266 
267   functionTakingBool(2.0);
268   // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: implicit conversion 'double' -> 'bool'
269   // CHECK-FIXES: functionTakingBool(true);
270 
271   functionTakingBool('\0');
272   // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: implicit conversion 'int' -> 'bool'
273   // CHECK-FIXES: functionTakingBool(false);
274 
275   functionTakingBool('a');
276   // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: implicit conversion 'int' -> 'bool'
277   // CHECK-FIXES: functionTakingBool(true);
278 
279   functionTakingBool("");
280   // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: implicit conversion 'char *' -> 'bool'
281   // CHECK-FIXES: functionTakingBool(true);
282 
283   functionTakingBool("abc");
284   // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: implicit conversion 'char *' -> 'bool'
285   // CHECK-FIXES: functionTakingBool(true);
286 
287   functionTakingBool(NULL);
288   // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: implicit conversion 'long' -> 'bool'
289   // CHECK-FIXES: functionTakingBool(false);
290 }
291 
292 void implicitConversionToBoolFromUnaryMinusAndZeroLiterals() {
293   functionTakingBool(-0);
294   // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: implicit conversion 'int' -> 'bool'
295   // CHECK-FIXES: functionTakingBool((-0) != 0);
296 
297   functionTakingBool(-0.0f);
298   // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: implicit conversion 'float' -> 'bool'
299   // CHECK-FIXES: functionTakingBool((-0.0f) != 0.0f);
300   // CHECK-FIXES-UPPER-CASE: functionTakingBool((-0.0f) != 0.0F);
301 
302   functionTakingBool(-0.0);
303   // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: implicit conversion 'double' -> 'bool'
304   // CHECK-FIXES: functionTakingBool((-0.0) != 0.0);
305 }
306 
307 void ignoreImplicitCastToBoolForComparisonResult() {
308   bool boolFromComparison0 = 1 != 0;
309   bool boolFromComparison1 = 1 == 0;
310   bool boolFromComparison2 = 1 > 0;
311   bool boolFromComparison3 = 1 >= 0;
312   bool boolFromComparison4 = 1 < 0;
313   bool boolFromComparison5 = 1 <= 0;
314 }
315 
316 void ignoreExplicitCastsToBool() {
317   int integer = 10;
318   bool boolComingFromInt = (bool)integer;
319 
320   float floating = 10.0f;
321   bool boolComingFromFloat = (bool)floating;
322 
323   char character = 'a';
324   bool boolComingFromChar = (bool)character;
325 
326   int* pointer = nullptr;
327   bool booleanComingFromPointer = (bool)pointer;
328 }
329 
330 void ignoreImplicitConversionToBoolInMacroExpansions() {
331   int integer = 3;
332 
333   #define CAST_TO_BOOL_IN_MACRO_BODY integer && false
334   bool boolFromMacroBody = CAST_TO_BOOL_IN_MACRO_BODY;
335 
336   #define CAST_TO_BOOL_IN_MACRO_ARGUMENT(x) x || true
337   bool boolFromMacroArgument = CAST_TO_BOOL_IN_MACRO_ARGUMENT(integer);
338 }
339 
340 int implicitConversionReturnInt()
341 {
342     return true;
343     // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: implicit conversion 'bool' -> 'int'
344     // CHECK-FIXES: return 1
345 }
346 
347 int implicitConversionReturnIntWithParens()
348 {
349     return (true);
350     // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: implicit conversion 'bool' -> 'int'
351     // CHECK-FIXES: return 1
352 }
353 
354 bool implicitConversionReturnBool()
355 {
356     return 1;
357     // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: implicit conversion 'int' -> 'bool'
358     // CHECK-FIXES: return true
359 }
360 
361 bool implicitConversionReturnBoolWithParens()
362 {
363     return (1);
364     // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: implicit conversion 'int' -> 'bool'
365     // CHECK-FIXES: return true
366 }
367 
368 int keepCompactReturnInC_PR71848() {
369   bool foo = false;
370   return( foo );
371 // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: implicit conversion 'bool' -> 'int' [readability-implicit-bool-conversion]
372 // CHECK-FIXES: return(int)( foo );
373 }
374