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