diff options
3 files changed, 26 insertions, 6 deletions
diff --git a/clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp b/clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp index 1cf1d03e825..b8ae224be59 100644 --- a/clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp @@ -306,6 +306,11 @@ void ImplicitBoolConversionCheck::registerMatchers(MatchFinder *Finder) { auto boolOpAssignment = binaryOperator(anyOf(hasOperatorName("|="), hasOperatorName("&=")), hasLHS(expr(hasType(booleanType())))); + auto bitfieldAssignment = binaryOperator( + hasLHS(memberExpr(hasDeclaration(fieldDecl(hasBitWidth(1)))))); + auto bitfieldConstruct = cxxConstructorDecl(hasDescendant(cxxCtorInitializer( + withInitializer(equalsBoundNode("implicitCastFromBool")), + forField(hasBitWidth(1))))); Finder->addMatcher( implicitCastExpr( implicitCastFromBool, @@ -313,14 +318,15 @@ void ImplicitBoolConversionCheck::registerMatchers(MatchFinder *Finder) { // in such context: // bool_expr_a == bool_expr_b // bool_expr_a != bool_expr_b - unless(hasParent(binaryOperator( - anyOf(boolComparison, boolXor, boolOpAssignment)))), + unless(hasParent(binaryOperator(anyOf( + boolComparison, boolXor, boolOpAssignment, bitfieldAssignment)))), + implicitCastExpr().bind("implicitCastFromBool"), + unless(hasParent(bitfieldConstruct)), // Check also for nested casts, for example: bool -> int -> float. anyOf(hasParent(implicitCastExpr().bind("furtherImplicitCast")), anything()), unless(isInTemplateInstantiation()), - unless(hasAncestor(functionTemplateDecl()))) - .bind("implicitCastFromBool"), + unless(hasAncestor(functionTemplateDecl()))), this); } diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability-implicit-bool-conversion.rst b/clang-tools-extra/docs/clang-tidy/checks/readability-implicit-bool-conversion.rst index a093680842d..9c3aad8ebc6 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/readability-implicit-bool-conversion.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/readability-implicit-bool-conversion.rst @@ -74,7 +74,8 @@ In general, the following conversion types are checked: - pointer/pointer to member/``nullptr``/``NULL`` to boolean, -- boolean expression/literal to integer, +- boolean expression/literal to integer (conversion from boolean to a single + bit bitfield is explicitly allowed), - boolean expression/literal to floating. diff --git a/clang-tools-extra/test/clang-tidy/readability-implicit-bool-conversion.cpp b/clang-tools-extra/test/clang-tidy/readability-implicit-bool-conversion.cpp index 1cc0f4f51e8..d5e9bee4294 100644 --- a/clang-tools-extra/test/clang-tidy/readability-implicit-bool-conversion.cpp +++ b/clang-tools-extra/test/clang-tidy/readability-implicit-bool-conversion.cpp @@ -444,14 +444,27 @@ struct S { int a; int b : 1; int c : 2; + + S(bool a, bool b, bool c) : a(a), b(b), c(c) {} + // CHECK-MESSAGES: :[[@LINE-1]]:33: warning: implicit conversion bool -> 'int' + // CHECK-MESSAGES: :[[@LINE-2]]:45: warning: implicit conversion bool -> 'int' + // CHECK-FIXES: S(bool a, bool b, bool c) : a(static_cast<int>(a)), b(b), c(static_cast<int>(c)) {} }; -bool f(const S& s) { +bool f(S& s) { functionTaking<bool>(s.a); // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'int' -> bool // CHECK-FIXES: functionTaking<bool>(s.a != 0); functionTaking<bool>(s.b); // CHECK-FIXES: functionTaking<bool>(s.b); + s.a = true; + // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: implicit conversion bool -> 'int' + // CHECK-FIXES: s.a = 1; + s.b = true; + // CHECK-FIXES: s.b = true; + s.c = true; + // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: implicit conversion bool -> 'int' + // CHECK-FIXES: s.c = 1; functionTaking<bool>(s.c); // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'int' -> bool // CHECK-FIXES: functionTaking<bool>(s.c != 0); |