@@ -259,13 +259,17 @@ ImplicitBoolConversionCheck::ImplicitBoolConversionCheck(
259259 AllowIntegerConditions (Options.get(" AllowIntegerConditions" , false )),
260260 AllowPointerConditions(Options.get(" AllowPointerConditions" , false )),
261261 UseUpperCaseLiteralSuffix(
262- Options.get(" UseUpperCaseLiteralSuffix" , false )) {}
262+ Options.get(" UseUpperCaseLiteralSuffix" , false )),
263+ CheckConversionsToBool(Options.get(" CheckConversionsToBool" , true )),
264+ CheckConversionsFromBool(Options.get(" CheckConversionsFromBool" , true )) {}
263265
264266void ImplicitBoolConversionCheck::storeOptions (
265267 ClangTidyOptions::OptionMap &Opts) {
266268 Options.store (Opts, " AllowIntegerConditions" , AllowIntegerConditions);
267269 Options.store (Opts, " AllowPointerConditions" , AllowPointerConditions);
268270 Options.store (Opts, " UseUpperCaseLiteralSuffix" , UseUpperCaseLiteralSuffix);
271+ Options.store (Opts, " CheckConversionsToBool" , CheckConversionsToBool);
272+ Options.store (Opts, " CheckConversionsFromBool" , CheckConversionsFromBool);
269273}
270274
271275void ImplicitBoolConversionCheck::registerMatchers (MatchFinder *Finder) {
@@ -277,6 +281,7 @@ void ImplicitBoolConversionCheck::registerMatchers(MatchFinder *Finder) {
277281 expr (hasType (qualType ().bind (" type" )),
278282 hasParent (initListExpr (hasParent (explicitCastExpr (
279283 hasType (qualType (equalsBoundNode (" type" ))))))))));
284+
280285 auto ImplicitCastFromBool = implicitCastExpr (
281286 anyOf (hasCastKind (CK_IntegralCast), hasCastKind (CK_IntegralToFloating),
282287 // Prior to C++11 cast from bool literal to pointer was allowed.
@@ -287,72 +292,84 @@ void ImplicitBoolConversionCheck::registerMatchers(MatchFinder *Finder) {
287292 auto BoolXor =
288293 binaryOperator (hasOperatorName (" ^" ), hasLHS (ImplicitCastFromBool),
289294 hasRHS (ImplicitCastFromBool));
290- auto ComparisonInCall = allOf (
291- hasParent (callExpr ()),
292- hasSourceExpression (binaryOperator (hasAnyOperatorName (" ==" , " !=" ))));
293-
294295 auto IsInCompilerGeneratedFunction = hasAncestor (namedDecl (anyOf (
295296 isImplicit (), functionDecl (isDefaulted ()), functionTemplateDecl ())));
296297
297- Finder->addMatcher (
298- traverse (TK_AsIs,
299- implicitCastExpr (
300- anyOf (hasCastKind (CK_IntegralToBoolean),
301- hasCastKind (CK_FloatingToBoolean),
302- hasCastKind (CK_PointerToBoolean),
303- hasCastKind (CK_MemberPointerToBoolean)),
304- // Exclude cases of C23 comparison result.
305- unless (allOf (isC23 (),
306- hasSourceExpression (ignoringParens (
307- binaryOperator (hasAnyOperatorName (
308- " >" , " >=" , " ==" , " !=" , " <" , " <=" )))))),
309- // Exclude case of using if or while statements with variable
310- // declaration, e.g.:
311- // if (int var = functionCall()) {}
312- unless (hasParent (
313- stmt (anyOf (ifStmt (), whileStmt ()), has (declStmt ())))),
314- // Exclude cases common to implicit cast to and from bool.
315- unless (ExceptionCases), unless (has (BoolXor)),
316- // Exclude C23 cases common to implicit cast to bool.
317- unless (ComparisonInCall),
318- // Retrieve also parent statement, to check if we need
319- // additional parens in replacement.
320- optionally (hasParent (stmt ().bind (" parentStmt" ))),
321- unless (isInTemplateInstantiation ()),
322- unless (IsInCompilerGeneratedFunction))
323- .bind (" implicitCastToBool" )),
324- this );
325-
326- auto BoolComparison = binaryOperator (hasAnyOperatorName (" ==" , " !=" ),
327- hasLHS (ImplicitCastFromBool),
328- hasRHS (ImplicitCastFromBool));
329- auto BoolOpAssignment = binaryOperator (hasAnyOperatorName (" |=" , " &=" ),
330- hasLHS (expr (hasType (booleanType ()))));
331- auto BitfieldAssignment = binaryOperator (
332- hasLHS (memberExpr (hasDeclaration (fieldDecl (hasBitWidth (1 ))))));
333- auto BitfieldConstruct = cxxConstructorDecl (hasDescendant (cxxCtorInitializer (
334- withInitializer (equalsBoundNode (" implicitCastFromBool" )),
335- forField (hasBitWidth (1 )))));
336- Finder->addMatcher (
337- traverse (
338- TK_AsIs,
339- implicitCastExpr (
340- ImplicitCastFromBool, unless (ExceptionCases),
341- // Exclude comparisons of bools, as they are always cast to
342- // integers in such context:
343- // bool_expr_a == bool_expr_b
344- // bool_expr_a != bool_expr_b
345- unless (hasParent (
346- binaryOperator (anyOf (BoolComparison, BoolXor,
347- BoolOpAssignment, BitfieldAssignment)))),
348- implicitCastExpr ().bind (" implicitCastFromBool" ),
349- unless (hasParent (BitfieldConstruct)),
350- // Check also for nested casts, for example: bool -> int -> float.
351- anyOf (hasParent (implicitCastExpr ().bind (" furtherImplicitCast" )),
352- anything ()),
353- unless (isInTemplateInstantiation ()),
354- unless (IsInCompilerGeneratedFunction))),
355- this );
298+ if (CheckConversionsToBool) {
299+ auto ComparisonInCall = allOf (
300+ hasParent (callExpr ()),
301+ hasSourceExpression (binaryOperator (hasAnyOperatorName (" ==" , " !=" ))));
302+
303+ Finder->addMatcher (
304+ traverse (
305+ TK_AsIs,
306+ implicitCastExpr (
307+ anyOf (hasCastKind (CK_IntegralToBoolean),
308+ hasCastKind (CK_FloatingToBoolean),
309+ hasCastKind (CK_PointerToBoolean),
310+ hasCastKind (CK_MemberPointerToBoolean)),
311+ // Exclude cases of C23 comparison result.
312+ unless (allOf (isC23 (),
313+ hasSourceExpression (ignoringParens (
314+ binaryOperator (hasAnyOperatorName (
315+ " >" , " >=" , " ==" , " !=" , " <" , " <=" )))))),
316+ // Exclude case of using if or while statements with variable
317+ // declaration, e.g.:
318+ // if (int var = functionCall()) {}
319+ unless (hasParent (
320+ stmt (anyOf (ifStmt (), whileStmt ()), has (declStmt ())))),
321+ // Exclude cases common to implicit cast to and from bool.
322+ unless (ExceptionCases), unless (has (BoolXor)),
323+ // Exclude C23 cases common to implicit cast to bool.
324+ unless (ComparisonInCall),
325+ // Retrieve also parent statement, to check if we need
326+ // additional parens in replacement.
327+ optionally (hasParent (stmt ().bind (" parentStmt" ))),
328+ unless (isInTemplateInstantiation ()),
329+ unless (IsInCompilerGeneratedFunction))
330+ .bind (" implicitCastToBool" )),
331+ this );
332+ }
333+
334+ if (CheckConversionsFromBool) {
335+
336+ auto BoolComparison = binaryOperator (hasAnyOperatorName (" ==" , " !=" ),
337+ hasLHS (ImplicitCastFromBool),
338+ hasRHS (ImplicitCastFromBool));
339+
340+ auto BoolOpAssignment = binaryOperator (
341+ hasAnyOperatorName (" |=" , " &=" ), hasLHS (expr (hasType (booleanType ()))));
342+
343+ auto BitfieldAssignment = binaryOperator (
344+ hasLHS (memberExpr (hasDeclaration (fieldDecl (hasBitWidth (1 ))))));
345+
346+ auto BitfieldConstruct =
347+ cxxConstructorDecl (hasDescendant (cxxCtorInitializer (
348+ withInitializer (equalsBoundNode (" implicitCastFromBool" )),
349+ forField (hasBitWidth (1 )))));
350+
351+ Finder->addMatcher (
352+ traverse (
353+ TK_AsIs,
354+ implicitCastExpr (
355+ ImplicitCastFromBool, unless (ExceptionCases),
356+ // Exclude comparisons of bools, as they are
357+ // always cast to integers in such context:
358+ // bool_expr_a == bool_expr_b
359+ // bool_expr_a != bool_expr_b
360+ unless (hasParent (binaryOperator (anyOf (BoolComparison, BoolXor,
361+ BoolOpAssignment,
362+ BitfieldAssignment)))),
363+ implicitCastExpr ().bind (" implicitCastFromBool" ),
364+ unless (hasParent (BitfieldConstruct)),
365+ // Check also for nested casts, for example:
366+ // bool -> int -> float.
367+ anyOf (hasParent (implicitCastExpr ().bind (" furtherImplicitCast" )),
368+ anything ()),
369+ unless (isInTemplateInstantiation ()),
370+ unless (IsInCompilerGeneratedFunction))),
371+ this );
372+ }
356373}
357374
358375void ImplicitBoolConversionCheck::check (
0 commit comments