[clang-tools-extra] 5bec2b7 - Added options to readability-implicit-bool-conversion (#120087)

via cfe-commits cfe-commits at lists.llvm.org
Fri Dec 27 23:35:33 PST 2024


Author: 4m4n-x-B4w4ne
Date: 2024-12-28T15:35:30+08:00
New Revision: 5bec2b71b44ddff44aa4d8534b58a5561389bb1d

URL: https://github.com/llvm/llvm-project/commit/5bec2b71b44ddff44aa4d8534b58a5561389bb1d
DIFF: https://github.com/llvm/llvm-project/commit/5bec2b71b44ddff44aa4d8534b58a5561389bb1d.diff

LOG: Added options to readability-implicit-bool-conversion  (#120087)

As given in the issue #36323 , I added two new options in the
clang-tools-extra/clan-tidy/readibility/ImplicitBoolConversionCheck.cpp
and header file.
I have also written new test cases to test these new options in
test/readibility directory.

Added: 
    clang-tools-extra/test/clang-tidy/checkers/readability/implicit-bool-conversion-check.cpp

Modified: 
    clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp
    clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.h
    clang-tools-extra/docs/ReleaseNotes.rst
    clang-tools-extra/docs/clang-tidy/checks/readability/implicit-bool-conversion.rst

Removed: 
    


################################################################################
diff  --git a/clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp b/clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp
index f9fd1d903e231e..48851da143068f 100644
--- a/clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp
@@ -259,13 +259,17 @@ ImplicitBoolConversionCheck::ImplicitBoolConversionCheck(
       AllowIntegerConditions(Options.get("AllowIntegerConditions", false)),
       AllowPointerConditions(Options.get("AllowPointerConditions", false)),
       UseUpperCaseLiteralSuffix(
-          Options.get("UseUpperCaseLiteralSuffix", false)) {}
+          Options.get("UseUpperCaseLiteralSuffix", false)),
+      CheckConversionsToBool(Options.get("CheckConversionsToBool", true)),
+      CheckConversionsFromBool(Options.get("CheckConversionsFromBool", true)) {}
 
 void ImplicitBoolConversionCheck::storeOptions(
     ClangTidyOptions::OptionMap &Opts) {
   Options.store(Opts, "AllowIntegerConditions", AllowIntegerConditions);
   Options.store(Opts, "AllowPointerConditions", AllowPointerConditions);
   Options.store(Opts, "UseUpperCaseLiteralSuffix", UseUpperCaseLiteralSuffix);
+  Options.store(Opts, "CheckConversionsToBool", CheckConversionsToBool);
+  Options.store(Opts, "CheckConversionsFromBool", CheckConversionsFromBool);
 }
 
 void ImplicitBoolConversionCheck::registerMatchers(MatchFinder *Finder) {
@@ -277,6 +281,7 @@ void ImplicitBoolConversionCheck::registerMatchers(MatchFinder *Finder) {
                  expr(hasType(qualType().bind("type")),
                       hasParent(initListExpr(hasParent(explicitCastExpr(
                           hasType(qualType(equalsBoundNode("type"))))))))));
+
   auto ImplicitCastFromBool = implicitCastExpr(
       anyOf(hasCastKind(CK_IntegralCast), hasCastKind(CK_IntegralToFloating),
             // Prior to C++11 cast from bool literal to pointer was allowed.
@@ -287,72 +292,84 @@ void ImplicitBoolConversionCheck::registerMatchers(MatchFinder *Finder) {
   auto BoolXor =
       binaryOperator(hasOperatorName("^"), hasLHS(ImplicitCastFromBool),
                      hasRHS(ImplicitCastFromBool));
-  auto ComparisonInCall = allOf(
-      hasParent(callExpr()),
-      hasSourceExpression(binaryOperator(hasAnyOperatorName("==", "!="))));
-
   auto IsInCompilerGeneratedFunction = hasAncestor(namedDecl(anyOf(
       isImplicit(), functionDecl(isDefaulted()), functionTemplateDecl())));
 
-  Finder->addMatcher(
-      traverse(TK_AsIs,
-               implicitCastExpr(
-                   anyOf(hasCastKind(CK_IntegralToBoolean),
-                         hasCastKind(CK_FloatingToBoolean),
-                         hasCastKind(CK_PointerToBoolean),
-                         hasCastKind(CK_MemberPointerToBoolean)),
-                   // Exclude cases of C23 comparison result.
-                   unless(allOf(isC23(),
-                                hasSourceExpression(ignoringParens(
-                                    binaryOperator(hasAnyOperatorName(
-                                        ">", ">=", "==", "!=", "<", "<=")))))),
-                   // Exclude case of using if or while statements with variable
-                   // declaration, e.g.:
-                   //   if (int var = functionCall()) {}
-                   unless(hasParent(
-                       stmt(anyOf(ifStmt(), whileStmt()), has(declStmt())))),
-                   // Exclude cases common to implicit cast to and from bool.
-                   unless(ExceptionCases), unless(has(BoolXor)),
-                   // Exclude C23 cases common to implicit cast to bool.
-                   unless(ComparisonInCall),
-                   // Retrieve also parent statement, to check if we need
-                   // additional parens in replacement.
-                   optionally(hasParent(stmt().bind("parentStmt"))),
-                   unless(isInTemplateInstantiation()),
-                   unless(IsInCompilerGeneratedFunction))
-                   .bind("implicitCastToBool")),
-      this);
-
-  auto BoolComparison = binaryOperator(hasAnyOperatorName("==", "!="),
-                                       hasLHS(ImplicitCastFromBool),
-                                       hasRHS(ImplicitCastFromBool));
-  auto BoolOpAssignment = binaryOperator(hasAnyOperatorName("|=", "&="),
-                                         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(
-      traverse(
-          TK_AsIs,
-          implicitCastExpr(
-              ImplicitCastFromBool, unless(ExceptionCases),
-              // Exclude comparisons of bools, as they are always cast to
-              // integers in such context:
-              //   bool_expr_a == bool_expr_b
-              //   bool_expr_a != bool_expr_b
-              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(IsInCompilerGeneratedFunction))),
-      this);
+  if (CheckConversionsToBool) {
+    auto ComparisonInCall = allOf(
+        hasParent(callExpr()),
+        hasSourceExpression(binaryOperator(hasAnyOperatorName("==", "!="))));
+
+    Finder->addMatcher(
+        traverse(
+            TK_AsIs,
+            implicitCastExpr(
+                anyOf(hasCastKind(CK_IntegralToBoolean),
+                      hasCastKind(CK_FloatingToBoolean),
+                      hasCastKind(CK_PointerToBoolean),
+                      hasCastKind(CK_MemberPointerToBoolean)),
+                // Exclude cases of C23 comparison result.
+                unless(allOf(isC23(),
+                             hasSourceExpression(ignoringParens(
+                                 binaryOperator(hasAnyOperatorName(
+                                     ">", ">=", "==", "!=", "<", "<=")))))),
+                // Exclude case of using if or while statements with variable
+                // declaration, e.g.:
+                //   if (int var = functionCall()) {}
+                unless(hasParent(
+                    stmt(anyOf(ifStmt(), whileStmt()), has(declStmt())))),
+                // Exclude cases common to implicit cast to and from bool.
+                unless(ExceptionCases), unless(has(BoolXor)),
+                // Exclude C23 cases common to implicit cast to bool.
+                unless(ComparisonInCall),
+                // Retrieve also parent statement, to check if we need
+                // additional parens in replacement.
+                optionally(hasParent(stmt().bind("parentStmt"))),
+                unless(isInTemplateInstantiation()),
+                unless(IsInCompilerGeneratedFunction))
+                .bind("implicitCastToBool")),
+        this);
+  }
+
+  if (CheckConversionsFromBool) {
+
+    auto BoolComparison = binaryOperator(hasAnyOperatorName("==", "!="),
+                                         hasLHS(ImplicitCastFromBool),
+                                         hasRHS(ImplicitCastFromBool));
+
+    auto BoolOpAssignment = binaryOperator(
+        hasAnyOperatorName("|=", "&="), 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(
+        traverse(
+            TK_AsIs,
+            implicitCastExpr(
+                ImplicitCastFromBool, unless(ExceptionCases),
+                // Exclude comparisons of bools, as they are
+                // always cast to integers in such context:
+                //   bool_expr_a == bool_expr_b
+                //   bool_expr_a != bool_expr_b
+                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(IsInCompilerGeneratedFunction))),
+        this);
+  }
 }
 
 void ImplicitBoolConversionCheck::check(

diff  --git a/clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.h b/clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.h
index 5947f7316e67cc..b0c3c2943e649c 100644
--- a/clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.h
+++ b/clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.h
@@ -37,6 +37,8 @@ class ImplicitBoolConversionCheck : public ClangTidyCheck {
   const bool AllowIntegerConditions;
   const bool AllowPointerConditions;
   const bool UseUpperCaseLiteralSuffix;
+  const bool CheckConversionsToBool;
+  const bool CheckConversionsFromBool;
 };
 
 } // namespace clang::tidy::readability

diff  --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index fabd0cc78ac645..8c360222ce43da 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -342,10 +342,11 @@ Changes in existing checks
   diagnostic.
 
 - Improved :doc:`readability-implicit-bool-conversion
-  <clang-tidy/checks/readability/implicit-bool-conversion>` check
-  by adding the option `UseUpperCaseLiteralSuffix` to select the
-  case of the literal suffix in fixes and fixing false positive for implicit
-  conversion of comparison result in C23.
+  <clang-tidy/checks/readability/implicit-bool-conversion>` check by adding the
+  option `UseUpperCaseLiteralSuffix` to select the case of the literal suffix in 
+  fixes and fixing false positive for implicit conversion of comparison result in 
+  C23, and by adding the option `CheckConversionsToBool` or 
+  `CheckConversionsFromBool` to configure checks for conversions involving ``bool``.
 
 - Improved :doc:`readability-redundant-smartptr-get
   <clang-tidy/checks/readability/redundant-smartptr-get>` check to

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 88cff387f4c165..f7c15ffa2da51b 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
@@ -147,3 +147,41 @@ Options
       if (foo) {}
       // ^ propose replacement default: if (foo != 0u) {}
       // ^ propose replacement with option `UseUpperCaseLiteralSuffix`: if (foo != 0U) {}
+
+.. option:: CheckConversionsToBool
+
+   When `true`, the check diagnoses implicit conversions to ``bool``.
+   Default is `true`.
+
+   Example
+
+   .. code-block:: c++
+
+      int x = 42;
+      if (x) {}
+      // ^ propose replacement: if (x != 0) {}
+
+      float f = 3.14;
+      if (f) {}
+      // ^ propose replacement: if (f != 0.0f) {}
+
+.. option:: CheckConversionsFromBool
+
+   When `true`, the check diagnoses implicit conversions from ``bool``.
+   Default is `true`.
+
+   Example
+
+   .. code-block:: c++
+
+      bool b = true;
+
+      int x = b;
+      // ^ propose replacement: int x = b ? 1 : 0;
+
+      float f = b;
+      // ^ propose replacement: float f = b ? 1.0f : 0.0f;
+
+      int* p = b;
+      // ^ propose replacement: int* p = b ? some_ptr : nullptr;
+

diff  --git a/clang-tools-extra/test/clang-tidy/checkers/readability/implicit-bool-conversion-check.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/implicit-bool-conversion-check.cpp
new file mode 100644
index 00000000000000..8ba4635de1704f
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/implicit-bool-conversion-check.cpp
@@ -0,0 +1,57 @@
+// RUN: %check_clang_tidy -check-suffix=FROM %s readability-implicit-bool-conversion %t -- \
+// RUN:     -config='{CheckOptions: { \
+// RUN:         readability-implicit-bool-conversion.CheckConversionsToBool: false, \
+// RUN:         readability-implicit-bool-conversion.CheckConversionsFromBool: true \
+// RUN:     }}' -- -std=c23
+// RUN: %check_clang_tidy -check-suffix=TO %s readability-implicit-bool-conversion %t -- \
+// RUN:     -config='{CheckOptions: { \
+// RUN:         readability-implicit-bool-conversion.CheckConversionsToBool: true, \
+// RUN:         readability-implicit-bool-conversion.CheckConversionsFromBool: false \
+// RUN:     }}' -- -std=c23
+// RUN: %check_clang_tidy -check-suffix=NORMAL %s readability-implicit-bool-conversion %t -- \
+// RUN:     -config='{CheckOptions: { \
+// RUN:         readability-implicit-bool-conversion.CheckConversionsToBool: false, \
+// RUN:         readability-implicit-bool-conversion.CheckConversionsFromBool: false \
+// RUN:     }}' -- -std=c23
+// RUN: %check_clang_tidy -check-suffix=TO,FROM %s readability-implicit-bool-conversion %t -- \
+// RUN:     -config='{CheckOptions: { \
+// RUN:         readability-implicit-bool-conversion.CheckConversionsToBool: true, \
+// RUN:         readability-implicit-bool-conversion.CheckConversionsFromBool: true \
+// RUN:     }}' -- -std=c23
+
+// Test various implicit bool conversions in 
diff erent contexts
+void TestImplicitBoolConversion() {
+    // Basic type conversions to bool
+    int intValue = 42;
+    if (intValue) // CHECK-MESSAGES-TO: :[[@LINE]]:9: warning: implicit conversion 'int' -> 'bool' [readability-implicit-bool-conversion]
+                  // CHECK-FIXES-TO: if (intValue != 0)
+        (void)0;
+
+    float floatValue = 3.14f;
+    while (floatValue) // CHECK-MESSAGES-TO: :[[@LINE]]:12: warning: implicit conversion 'float' -> 'bool' [readability-implicit-bool-conversion]
+                       // CHECK-FIXES-TO: while (floatValue != 0.0f)
+        break;
+
+    char charValue = 'a';
+    do {
+        break;
+    } while (charValue); // CHECK-MESSAGES-TO: :[[@LINE]]:14: warning: implicit conversion 'char' -> 'bool' [readability-implicit-bool-conversion]
+                         // CHECK-FIXES-TO: } while (charValue != 0);
+
+    // Pointer conversions to bool
+    int* ptrValue = &intValue;
+    if (ptrValue) // CHECK-MESSAGES-TO: :[[@LINE]]:9: warning: implicit conversion 'int *' -> 'bool' [readability-implicit-bool-conversion]
+                  // CHECK-FIXES-TO: if (ptrValue != nullptr)
+        (void)0;
+
+    // Conversions from bool to other types
+    bool boolValue = true;
+    int intFromBool = boolValue; // CHECK-MESSAGES-FROM: :[[@LINE]]:23: warning: implicit conversion 'bool' -> 'int' [readability-implicit-bool-conversion]
+                                 // CHECK-FIXES-FROM: int intFromBool = static_cast<int>(boolValue);
+                                 
+    float floatFromBool = boolValue; // CHECK-MESSAGES-FROM: :[[@LINE]]:27: warning: implicit conversion 'bool' -> 'float' [readability-implicit-bool-conversion]
+                                     // CHECK-FIXES-FROM: float floatFromBool = static_cast<float>(boolValue);
+
+    char charFromBool = boolValue; // CHECK-MESSAGES-FROM: :[[@LINE]]:25: warning: implicit conversion 'bool' -> 'char' [readability-implicit-bool-conversion]
+                                   // CHECK-FIXES-FROM: char charFromBool = static_cast<char>(boolValue);
+}


        


More information about the cfe-commits mailing list