[clang-tools-extra] r251235 - [clang-tidy] Add check readability-implicit-bool-cast

Piotr Dziwinski via cfe-commits cfe-commits at lists.llvm.org
Sun Oct 25 08:31:26 PDT 2015


Author: piotrdz
Date: Sun Oct 25 10:31:25 2015
New Revision: 251235

URL: http://llvm.org/viewvc/llvm-project?rev=251235&view=rev
Log:
[clang-tidy] Add check readability-implicit-bool-cast

Summary:
This is another check that I ported to clang-tidy from colobot-lint tool.

As previously discussed on cfe-dev mailing list, this is one of those
checks that I think is general and useful enough for contribution to
clang-tidy.

This patch contains implementation of check taken from colobot-lint, but
it is extended a great deal, including FixIt hints for automated
refactoring, exhaustive testcases, and user documentation.

Reviewers: sbenza, aaron.ballman, alexfh

Subscribers: Eugene.Zelenko

Differential Revision: http://reviews.llvm.org/D13635

Added:
    clang-tools-extra/trunk/clang-tidy/readability/ImplicitBoolCastCheck.cpp
    clang-tools-extra/trunk/clang-tidy/readability/ImplicitBoolCastCheck.h
    clang-tools-extra/trunk/docs/clang-tidy/checks/readability-implicit-bool-cast.rst
    clang-tools-extra/trunk/test/clang-tidy/readability-implicit-bool-cast-allow-conditional-casts.cpp
    clang-tools-extra/trunk/test/clang-tidy/readability-implicit-bool-cast-cxx98.cpp
    clang-tools-extra/trunk/test/clang-tidy/readability-implicit-bool-cast.cpp
Modified:
    clang-tools-extra/trunk/clang-tidy/readability/CMakeLists.txt
    clang-tools-extra/trunk/clang-tidy/readability/ReadabilityTidyModule.cpp
    clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst

Modified: clang-tools-extra/trunk/clang-tidy/readability/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/readability/CMakeLists.txt?rev=251235&r1=251234&r2=251235&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/readability/CMakeLists.txt (original)
+++ clang-tools-extra/trunk/clang-tidy/readability/CMakeLists.txt Sun Oct 25 10:31:25 2015
@@ -6,6 +6,7 @@ add_clang_library(clangTidyReadabilityMo
   ElseAfterReturnCheck.cpp
   FunctionSizeCheck.cpp
   IdentifierNamingCheck.cpp
+  ImplicitBoolCastCheck.cpp
   InconsistentDeclarationParameterNameCheck.cpp
   NamedParameterCheck.cpp
   NamespaceCommentCheck.cpp

Added: clang-tools-extra/trunk/clang-tidy/readability/ImplicitBoolCastCheck.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/readability/ImplicitBoolCastCheck.cpp?rev=251235&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/readability/ImplicitBoolCastCheck.cpp (added)
+++ clang-tools-extra/trunk/clang-tidy/readability/ImplicitBoolCastCheck.cpp Sun Oct 25 10:31:25 2015
@@ -0,0 +1,425 @@
+//===--- ImplicitBoolCastCheck.cpp - clang-tidy----------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ImplicitBoolCastCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+
+namespace {
+
+const internal::VariadicDynCastAllOfMatcher<Stmt, ParenExpr> parenExpr;
+
+AST_MATCHER_P(CastExpr, hasCastKind, CastKind, Kind) {
+  return Node.getCastKind() == Kind;
+}
+
+AST_MATCHER(QualType, isBool) {
+  return !Node.isNull() && Node->isBooleanType();
+}
+
+AST_MATCHER(Stmt, isMacroExpansion) {
+  SourceManager &SM = Finder->getASTContext().getSourceManager();
+  SourceLocation Loc = Node.getLocStart();
+  return SM.isMacroBodyExpansion(Loc) || SM.isMacroArgExpansion(Loc);
+}
+
+bool isNULLMacroExpansion(const Stmt *Statement, ASTContext &Context) {
+  SourceManager &SM = Context.getSourceManager();
+  const LangOptions &LO = Context.getLangOpts();
+  SourceLocation Loc = Statement->getLocStart();
+  return SM.isMacroBodyExpansion(Loc) &&
+         clang::Lexer::getImmediateMacroName(Loc, SM, LO) == "NULL";
+}
+
+AST_MATCHER(Stmt, isNULLMacroExpansion) {
+  return isNULLMacroExpansion(&Node, Finder->getASTContext());
+}
+
+ast_matchers::internal::Matcher<Expr> createExceptionCasesMatcher() {
+  return expr(anyOf(hasParent(explicitCastExpr()),
+                    allOf(isMacroExpansion(), unless(isNULLMacroExpansion())),
+                    isInTemplateInstantiation(),
+                    hasAncestor(functionTemplateDecl())));
+}
+
+StatementMatcher createImplicitCastFromBoolMatcher() {
+  return implicitCastExpr(
+      unless(createExceptionCasesMatcher()),
+      anyOf(hasCastKind(CK_IntegralCast), hasCastKind(CK_IntegralToFloating),
+            // Prior to C++11 cast from bool literal to pointer was allowed.
+            allOf(anyOf(hasCastKind(CK_NullToPointer),
+                        hasCastKind(CK_NullToMemberPointer)),
+                  hasSourceExpression(cxxBoolLiteral()))),
+      hasSourceExpression(expr(hasType(qualType(isBool())))));
+}
+
+StringRef
+getZeroLiteralToCompareWithForGivenType(CastKind CastExpressionKind,
+                                        QualType CastSubExpressionType,
+                                        ASTContext &Context) {
+  switch (CastExpressionKind) {
+  case CK_IntegralToBoolean:
+    return CastSubExpressionType->isUnsignedIntegerType() ? "0u" : "0";
+
+  case CK_FloatingToBoolean:
+    return Context.hasSameType(CastSubExpressionType, Context.FloatTy) ? "0.0f"
+                                                                       : "0.0";
+
+  case CK_PointerToBoolean:
+  case CK_MemberPointerToBoolean: // Fall-through on purpose.
+    return Context.getLangOpts().CPlusPlus11 ? "nullptr" : "0";
+
+  default:
+    assert(false && "Unexpected cast kind");
+  }
+}
+
+bool isUnaryLogicalNotOperator(const Stmt *Statement) {
+  const auto *UnaryOperatorExpression =
+      llvm::dyn_cast<UnaryOperator>(Statement);
+  return UnaryOperatorExpression != nullptr &&
+         UnaryOperatorExpression->getOpcode() == UO_LNot;
+}
+
+bool areParensNeededForOverloadedOperator(OverloadedOperatorKind OperatorKind) {
+  switch (OperatorKind) {
+  case OO_New:
+  case OO_Delete: // Fall-through on purpose.
+  case OO_Array_New:
+  case OO_Array_Delete:
+  case OO_ArrowStar:
+  case OO_Arrow:
+  case OO_Call:
+  case OO_Subscript:
+    return false;
+
+  default:
+    return true;
+  }
+}
+
+bool areParensNeededForStatement(const Stmt *Statement) {
+  if (const CXXOperatorCallExpr *OverloadedOperatorCall =
+          llvm::dyn_cast<CXXOperatorCallExpr>(Statement)) {
+    return areParensNeededForOverloadedOperator(
+        OverloadedOperatorCall->getOperator());
+  }
+
+  return llvm::isa<BinaryOperator>(Statement) ||
+         llvm::isa<UnaryOperator>(Statement);
+}
+
+void addFixItHintsForGenericExpressionCastToBool(
+    DiagnosticBuilder &Diagnostic, const ImplicitCastExpr *CastExpression,
+    const Stmt *ParentStatement, ASTContext &Context) {
+  // In case of expressions like (! integer), we should remove the redundant not
+  // operator and use inverted comparison (integer == 0).
+  bool InvertComparison =
+      ParentStatement != nullptr && isUnaryLogicalNotOperator(ParentStatement);
+  if (InvertComparison) {
+    SourceLocation ParentStartLoc = ParentStatement->getLocStart();
+    SourceLocation ParentEndLoc =
+        llvm::cast<UnaryOperator>(ParentStatement)->getSubExpr()->getLocStart();
+    Diagnostic.AddFixItHint(FixItHint::CreateRemoval(
+        CharSourceRange::getCharRange(ParentStartLoc, ParentEndLoc)));
+
+    auto FurtherParents = Context.getParents(*ParentStatement);
+    ParentStatement = FurtherParents[0].get<Stmt>();
+  }
+
+  const Expr *SubExpression = CastExpression->getSubExpr();
+
+  bool NeedInnerParens = areParensNeededForStatement(SubExpression);
+  bool NeedOuterParens = ParentStatement != nullptr &&
+                         areParensNeededForStatement(ParentStatement);
+
+  std::string StartLocInsertion;
+
+  if (NeedOuterParens) {
+    StartLocInsertion += "(";
+  }
+  if (NeedInnerParens) {
+    StartLocInsertion += "(";
+  }
+
+  if (!StartLocInsertion.empty()) {
+    SourceLocation StartLoc = CastExpression->getLocStart();
+    Diagnostic.AddFixItHint(
+        FixItHint::CreateInsertion(StartLoc, StartLocInsertion));
+  }
+
+  std::string EndLocInsertion;
+
+  if (NeedInnerParens) {
+    EndLocInsertion += ")";
+  }
+
+  if (InvertComparison) {
+    EndLocInsertion += " == ";
+  } else {
+    EndLocInsertion += " != ";
+  }
+
+  EndLocInsertion += getZeroLiteralToCompareWithForGivenType(
+      CastExpression->getCastKind(), SubExpression->getType(), Context);
+
+  if (NeedOuterParens) {
+    EndLocInsertion += ")";
+  }
+
+  SourceLocation EndLoc = Lexer::getLocForEndOfToken(
+      CastExpression->getLocEnd(), 0, Context.getSourceManager(),
+      Context.getLangOpts());
+  Diagnostic.AddFixItHint(FixItHint::CreateInsertion(EndLoc, EndLocInsertion));
+}
+
+StringRef getEquivalentBoolLiteralForExpression(const Expr *Expression,
+                                                ASTContext &Context) {
+  if (isNULLMacroExpansion(Expression, Context)) {
+    return "false";
+  }
+
+  if (const auto *IntLit = llvm::dyn_cast<IntegerLiteral>(Expression)) {
+    return (IntLit->getValue() == 0) ? "false" : "true";
+  }
+
+  if (const auto *FloatLit = llvm::dyn_cast<FloatingLiteral>(Expression)) {
+    llvm::APFloat FloatLitAbsValue = FloatLit->getValue();
+    FloatLitAbsValue.clearSign();
+    return (FloatLitAbsValue.bitcastToAPInt() == 0) ? "false" : "true";
+  }
+
+  if (const auto *CharLit = llvm::dyn_cast<CharacterLiteral>(Expression)) {
+    return (CharLit->getValue() == 0) ? "false" : "true";
+  }
+
+  if (llvm::isa<StringLiteral>(Expression->IgnoreCasts())) {
+    return "true";
+  }
+
+  return StringRef();
+}
+
+void addFixItHintsForLiteralCastToBool(DiagnosticBuilder &Diagnostic,
+                                       const ImplicitCastExpr *CastExpression,
+                                       StringRef EquivalentLiteralExpression) {
+  SourceLocation StartLoc = CastExpression->getLocStart();
+  SourceLocation EndLoc = CastExpression->getLocEnd();
+
+  Diagnostic.AddFixItHint(FixItHint::CreateReplacement(
+      CharSourceRange::getTokenRange(StartLoc, EndLoc),
+      EquivalentLiteralExpression));
+}
+
+void addFixItHintsForGenericExpressionCastFromBool(
+    DiagnosticBuilder &Diagnostic, const ImplicitCastExpr *CastExpression,
+    ASTContext &Context, StringRef OtherType) {
+  const Expr *SubExpression = CastExpression->getSubExpr();
+  bool NeedParens = !llvm::isa<ParenExpr>(SubExpression);
+
+  std::string StartLocInsertion = "static_cast<";
+  StartLocInsertion += OtherType.str();
+  StartLocInsertion += ">";
+  if (NeedParens) {
+    StartLocInsertion += "(";
+  }
+
+  SourceLocation StartLoc = CastExpression->getLocStart();
+  Diagnostic.AddFixItHint(
+      FixItHint::CreateInsertion(StartLoc, StartLocInsertion));
+
+  if (NeedParens) {
+    SourceLocation EndLoc = Lexer::getLocForEndOfToken(
+        CastExpression->getLocEnd(), 0, Context.getSourceManager(),
+        Context.getLangOpts());
+
+    Diagnostic.AddFixItHint(FixItHint::CreateInsertion(EndLoc, ")"));
+  }
+}
+
+StringRef getEquivalentLiteralForBoolLiteral(
+    const CXXBoolLiteralExpr *BoolLiteralExpression, QualType DestinationType,
+    ASTContext &Context) {
+  // Prior to C++11, false literal could be implicitly converted to pointer.
+  if (!Context.getLangOpts().CPlusPlus11 &&
+      (DestinationType->isPointerType() ||
+       DestinationType->isMemberPointerType()) &&
+      BoolLiteralExpression->getValue() == false) {
+    return "0";
+  }
+
+  if (DestinationType->isFloatingType()) {
+    if (BoolLiteralExpression->getValue() == true) {
+      return Context.hasSameType(DestinationType, Context.FloatTy) ? "1.0f"
+                                                                   : "1.0";
+    }
+    return Context.hasSameType(DestinationType, Context.FloatTy) ? "0.0f"
+                                                                 : "0.0";
+  }
+
+  if (BoolLiteralExpression->getValue() == true) {
+    return DestinationType->isUnsignedIntegerType() ? "1u" : "1";
+  }
+  return DestinationType->isUnsignedIntegerType() ? "0u" : "0";
+}
+
+void addFixItHintsForLiteralCastFromBool(DiagnosticBuilder &Diagnostic,
+                                         const ImplicitCastExpr *CastExpression,
+                                         ASTContext &Context,
+                                         QualType DestinationType) {
+  SourceLocation StartLoc = CastExpression->getLocStart();
+  SourceLocation EndLoc = CastExpression->getLocEnd();
+  const auto *BoolLiteralExpression =
+      llvm::dyn_cast<CXXBoolLiteralExpr>(CastExpression->getSubExpr());
+
+  Diagnostic.AddFixItHint(FixItHint::CreateReplacement(
+      CharSourceRange::getTokenRange(StartLoc, EndLoc),
+      getEquivalentLiteralForBoolLiteral(BoolLiteralExpression, DestinationType,
+                                         Context)));
+}
+
+StatementMatcher createConditionalExpressionMatcher() {
+  return stmt(anyOf(ifStmt(), conditionalOperator(),
+                    parenExpr(hasParent(conditionalOperator()))));
+}
+
+bool isAllowedConditionalCast(const ImplicitCastExpr *CastExpression,
+                              ASTContext &Context) {
+  auto AllowedConditionalMatcher = stmt(hasParent(stmt(
+      anyOf(createConditionalExpressionMatcher(),
+            unaryOperator(hasOperatorName("!"),
+                          hasParent(createConditionalExpressionMatcher()))))));
+
+  auto MatchResult = match(AllowedConditionalMatcher, *CastExpression, Context);
+  return !MatchResult.empty();
+}
+
+} // anonymous namespace
+
+void ImplicitBoolCastCheck::registerMatchers(MatchFinder *Finder) {
+  // This check doesn't make much sense if we run it on language without
+  // built-in bool support.
+  if (!getLangOpts().Bool) {
+    return;
+  }
+
+  Finder->addMatcher(
+      implicitCastExpr(
+          // Exclude cases common to implicit cast to and from bool.
+          unless(createExceptionCasesMatcher()),
+          // 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())))),
+          anyOf(hasCastKind(CK_IntegralToBoolean),
+                hasCastKind(CK_FloatingToBoolean),
+                hasCastKind(CK_PointerToBoolean),
+                hasCastKind(CK_MemberPointerToBoolean)),
+          // Retrive also parent statement, to check if we need additional
+          // parens in replacement.
+          anyOf(hasParent(stmt().bind("parentStmt")), anything()))
+          .bind("implicitCastToBool"),
+      this);
+
+  Finder->addMatcher(
+      implicitCastExpr(
+          createImplicitCastFromBoolMatcher(),
+          // 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(hasOperatorName("=="), hasOperatorName("!=")),
+              hasLHS(createImplicitCastFromBoolMatcher()),
+              hasRHS(createImplicitCastFromBoolMatcher())))),
+          // Check also for nested casts, for example: bool -> int -> float.
+          anyOf(hasParent(implicitCastExpr().bind("furtherImplicitCast")),
+                anything()))
+          .bind("implicitCastFromBool"),
+      this);
+}
+
+void ImplicitBoolCastCheck::check(const MatchFinder::MatchResult &Result) {
+  if (const auto *CastToBool =
+          Result.Nodes.getNodeAs<ImplicitCastExpr>("implicitCastToBool")) {
+    const auto *ParentStatement = Result.Nodes.getNodeAs<Stmt>("parentStmt");
+    return handleCastToBool(CastToBool, ParentStatement, *Result.Context);
+  }
+
+  if (const auto *CastFromBool =
+          Result.Nodes.getNodeAs<ImplicitCastExpr>("implicitCastFromBool")) {
+    const auto *FurtherImplicitCastExpression =
+        Result.Nodes.getNodeAs<ImplicitCastExpr>("furtherImplicitCast");
+    return handleCastFromBool(CastFromBool, FurtherImplicitCastExpression,
+                              *Result.Context);
+  }
+}
+
+void ImplicitBoolCastCheck::handleCastToBool(
+    const ImplicitCastExpr *CastExpression, const Stmt *ParentStatement,
+    ASTContext &Context) {
+  if (AllowConditionalPointerCasts &&
+      (CastExpression->getCastKind() == CK_PointerToBoolean ||
+       CastExpression->getCastKind() == CK_MemberPointerToBoolean) &&
+      isAllowedConditionalCast(CastExpression, Context)) {
+    return;
+  }
+
+  if (AllowConditionalIntegerCasts &&
+      CastExpression->getCastKind() == CK_IntegralToBoolean &&
+      isAllowedConditionalCast(CastExpression, Context)) {
+    return;
+  }
+
+  std::string OtherType = CastExpression->getSubExpr()->getType().getAsString();
+  DiagnosticBuilder Diagnostic =
+      diag(CastExpression->getLocStart(), "implicit cast '%0' -> bool")
+      << OtherType;
+
+  StringRef EquivalentLiteralExpression = getEquivalentBoolLiteralForExpression(
+      CastExpression->getSubExpr(), Context);
+  if (!EquivalentLiteralExpression.empty()) {
+    addFixItHintsForLiteralCastToBool(Diagnostic, CastExpression,
+                                      EquivalentLiteralExpression);
+  } else {
+    addFixItHintsForGenericExpressionCastToBool(Diagnostic, CastExpression,
+                                                ParentStatement, Context);
+  }
+}
+
+void ImplicitBoolCastCheck::handleCastFromBool(
+    const ImplicitCastExpr *CastExpression,
+    const ImplicitCastExpr *FurtherImplicitCastExpression,
+    ASTContext &Context) {
+  QualType DestinationType = (FurtherImplicitCastExpression != nullptr)
+                                 ? FurtherImplicitCastExpression->getType()
+                                 : CastExpression->getType();
+  std::string DestinationTypeString = DestinationType.getAsString();
+  DiagnosticBuilder Diagnostic =
+      diag(CastExpression->getLocStart(), "implicit cast bool -> '%0'")
+      << DestinationTypeString;
+
+  if (llvm::isa<CXXBoolLiteralExpr>(CastExpression->getSubExpr())) {
+    addFixItHintsForLiteralCastFromBool(Diagnostic, CastExpression, Context,
+                                        DestinationType);
+  } else {
+    addFixItHintsForGenericExpressionCastFromBool(
+        Diagnostic, CastExpression, Context, DestinationTypeString);
+  }
+}
+
+} // namespace tidy
+} // namespace clang

Added: clang-tools-extra/trunk/clang-tidy/readability/ImplicitBoolCastCheck.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/readability/ImplicitBoolCastCheck.h?rev=251235&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/readability/ImplicitBoolCastCheck.h (added)
+++ clang-tools-extra/trunk/clang-tidy/readability/ImplicitBoolCastCheck.h Sun Oct 25 10:31:25 2015
@@ -0,0 +1,47 @@
+//===--- ImplicitBoolCastCheck.h - clang-tidy--------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_IMPLICIT_BOOL_CAST_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_IMPLICIT_BOOL_CAST_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+
+/// \brief Checks for use of implicit bool casts in expressions.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/readability-implicit-bool-cast.html
+class ImplicitBoolCastCheck : public ClangTidyCheck {
+public:
+  ImplicitBoolCastCheck(StringRef Name, ClangTidyContext *Context)
+      : ClangTidyCheck(Name, Context),
+        AllowConditionalIntegerCasts(
+            Options.get("AllowConditionalIntegerCasts", 0) != 0),
+        AllowConditionalPointerCasts(
+            Options.get("AllowConditionalPointerCasts", 0) != 0) {}
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+  void handleCastToBool(const ImplicitCastExpr *CastExpression,
+                        const Stmt *ParentStatement, ASTContext &Context);
+  void handleCastFromBool(const ImplicitCastExpr *CastExpression,
+                          const ImplicitCastExpr *FurtherImplicitCastExpression,
+                          ASTContext &Context);
+
+  bool AllowConditionalIntegerCasts;
+  bool AllowConditionalPointerCasts;
+};
+
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_IMPLICIT_BOOL_CAST_H

Modified: clang-tools-extra/trunk/clang-tidy/readability/ReadabilityTidyModule.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/readability/ReadabilityTidyModule.cpp?rev=251235&r1=251234&r2=251235&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/readability/ReadabilityTidyModule.cpp (original)
+++ clang-tools-extra/trunk/clang-tidy/readability/ReadabilityTidyModule.cpp Sun Oct 25 10:31:25 2015
@@ -15,6 +15,7 @@
 #include "ElseAfterReturnCheck.h"
 #include "FunctionSizeCheck.h"
 #include "IdentifierNamingCheck.h"
+#include "ImplicitBoolCastCheck.h"
 #include "InconsistentDeclarationParameterNameCheck.h"
 #include "NamedParameterCheck.h"
 #include "RedundantSmartptrGetCheck.h"
@@ -39,6 +40,8 @@ public:
         "readability-function-size");
     CheckFactories.registerCheck<IdentifierNamingCheck>(
         "readability-identifier-naming");
+    CheckFactories.registerCheck<ImplicitBoolCastCheck>(
+        "readability-implicit-bool-cast");
     CheckFactories.registerCheck<InconsistentDeclarationParameterNameCheck>(
         "readability-inconsistent-declaration-parameter-name");
     CheckFactories.registerCheck<UniqueptrDeleteReleaseCheck>(

Modified: clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst?rev=251235&r1=251234&r2=251235&view=diff
==============================================================================
--- clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst (original)
+++ clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst Sun Oct 25 10:31:25 2015
@@ -64,6 +64,7 @@ List of clang-tidy Checks
    readability-else-after-return
    readability-function-size
    readability-identifier-naming
+   readability-implicit-bool-cast
    readability-inconsistent-declaration-parameter-name
    readability-named-parameter
    readability-redundant-smartptr-get

Added: clang-tools-extra/trunk/docs/clang-tidy/checks/readability-implicit-bool-cast.rst
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/docs/clang-tidy/checks/readability-implicit-bool-cast.rst?rev=251235&view=auto
==============================================================================
--- clang-tools-extra/trunk/docs/clang-tidy/checks/readability-implicit-bool-cast.rst (added)
+++ clang-tools-extra/trunk/docs/clang-tidy/checks/readability-implicit-bool-cast.rst Sun Oct 25 10:31:25 2015
@@ -0,0 +1,97 @@
+readability-implicit-bool-cast
+==============================
+
+This check can be used to find implicit conversions between built-in types and
+booleans. Depending on use case, it may simply help with readability of the code,
+or in some cases, point to potential bugs which remain unnoticed due to implicit
+conversions.
+
+The following is a real-world example of bug which was hiding behind implicit
+bool cast:
+
+.. code:: c++
+
+  class Foo {
+    int m_foo;
+  public:
+    void setFoo(bool foo) { m_foo = foo; } // warning: implicit cast bool -> int
+    int getFoo() { return m_foo; }
+  };
+
+  void use(Foo& foo) {
+    bool value = foo.getFoo(); // warning: implicit cast int -> bool
+  }
+
+This code is the result of unsuccessful refactoring, where type of ``m_foo``
+changed from ``bool`` to ``int``. The programmer forgot to change all
+occurences of ``bool``, and the remaining code is no longer correct, yet it
+still compiles without any visible warnings.
+
+In addition to issuing warnings, FixIt hints are provided to help solve
+the reported issues. This can be used for improving readabilty of code, for example:
+
+.. code:: c++
+
+  void conversionsToBool() {
+    float floating;
+    bool boolean = floating;
+    // ^ propose replacement: bool boolean = floating != 0.0f;
+
+    int integer;
+    if (integer) {}
+    // ^ propose replacement: if (integer != 0) {}
+
+    int* pointer;
+    if (!pointer) {}
+    // ^ propose replacement: if (pointer == nullptr) {}
+
+    while (1) {}
+    // ^ propose replacement: while (true) {}
+  }
+
+  void functionTakingInt(int param);
+
+  void conversionsFromBool() {
+    bool boolean;
+    functionTakingInt(boolean);
+    // ^ propose replacement: functionTakingInt(static_cast<int>(boolean));
+
+    functionTakingInt(true);
+    // ^ propose replacement: functionTakingInt(1);
+  }
+
+In general, the following cast types are checked:
+ - integer expression/literal to boolean,
+ - floating expression/literal to boolean,
+ - pointer/pointer to member/``nullptr``/``NULL`` to boolean,
+ - boolean expression/literal to integer,
+ - boolean expression/literal to floating.
+
+The rules for generating FixIt hints are:
+ - in case of casts from other built-in type to bool, an explicit comparison
+   is proposed to make it clear what exaclty is being compared:
+
+   - ``bool boolean = floating;`` is changed to ``bool boolean = floating == 0.0f;``,
+   - for other types, appropriate literals are used (``0``, ``0u``, ``0.0f``, ``0.0``, ``nullptr``),
+ - in case of negated expressions cast to bool, the proposed replacement with
+   comparison is simplified:
+
+   - ``if (!pointer)`` is changed to ``if (pointer == nullptr)``,
+ - in case of casts from bool to other built-in types, an explicit ``static_cast``
+   is proposed to make it clear that a cast is taking place:
+
+   - ``int integer = boolean;`` is changed to ``int integer = static_cast<int>(boolean);``,
+ - if the cast is performed on type literals, an equivalent literal is proposed,
+   according to what type is actually expected, for example:
+
+   - ``functionTakingBool(0);`` is changed to ``functionTakingBool(false);``,
+   - ``functionTakingInt(true);`` is changed to ``functionTakingInt(1);``,
+   - for other types, appropriate literals are used (``false``, ``true``, ``0``, ``1``, ``0u``, ``1u``,
+     ``0.0f``, ``1.0f``, ``0.0``, ``1.0f``).
+
+Some additional accommodations are made for pre-C++11 dialects:
+ - ``false`` literal cast to pointer is detected,
+ - instead of ``nullptr`` literal, ``0`` is proposed as replacement.
+
+Occurences of implicit casts inside macros and template instantiations are
+deliberately ignored, as it is not clear how to deal with such cases.

Added: clang-tools-extra/trunk/test/clang-tidy/readability-implicit-bool-cast-allow-conditional-casts.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/readability-implicit-bool-cast-allow-conditional-casts.cpp?rev=251235&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/readability-implicit-bool-cast-allow-conditional-casts.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/readability-implicit-bool-cast-allow-conditional-casts.cpp Sun Oct 25 10:31:25 2015
@@ -0,0 +1,55 @@
+// RUN: %check_clang_tidy %s readability-implicit-bool-cast %t \
+// RUN: -config='{CheckOptions: \
+// RUN:  [{key: readability-implicit-bool-cast.AllowConditionalIntegerCasts, value: 1}, \
+// RUN:   {key: readability-implicit-bool-cast.AllowConditionalPointerCasts, value: 1}]}' \
+// RUN: -- -std=c++11
+
+template<typename T>
+void functionTaking(T);
+
+int functionReturningInt();
+int* functionReturningPointer();
+
+struct Struct {
+  int member;
+};
+
+
+void regularImplicitCastIntegerToBoolIsNotIgnored() {
+  int integer = 0;
+  functionTaking<bool>(integer);
+  // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit cast 'int' -> bool [readability-implicit-bool-cast]
+  // CHECK-FIXES: functionTaking<bool>(integer != 0);
+}
+
+void implicitCastIntegerToBoolInConditionalsIsAllowed() {
+  if (functionReturningInt()) {}
+  if (!functionReturningInt()) {}
+  int value1 = functionReturningInt() ? 1 : 2;
+  int value2 = ! functionReturningInt() ? 1 : 2;
+}
+
+void regularImplicitCastPointerToBoolIsNotIgnored() {
+  int* pointer = nullptr;
+  functionTaking<bool>(pointer);
+  // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit cast 'int *' -> bool
+  // CHECK-FIXES: functionTaking<bool>(pointer != nullptr);
+
+  int Struct::* memberPointer = &Struct::member;
+  functionTaking<bool>(memberPointer);
+  // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit cast 'int struct Struct::*' -> bool
+  // CHECK-FIXES: functionTaking<bool>(memberPointer != nullptr);
+}
+
+void implicitCastPointerToBoolInConditionalsIsAllowed() {
+  if (functionReturningPointer()) {}
+  if (not functionReturningPointer()) {}
+  int value1 = functionReturningPointer() ? 1 : 2;
+  int value2 = (not functionReturningPointer()) ? 1 : 2;
+
+  int Struct::* memberPointer = &Struct::member;
+  if (memberPointer) {}
+  if (memberPointer) {}
+  int value3 = memberPointer ? 1 : 2;
+  int value4 = (not memberPointer) ? 1 : 2;
+}

Added: clang-tools-extra/trunk/test/clang-tidy/readability-implicit-bool-cast-cxx98.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/readability-implicit-bool-cast-cxx98.cpp?rev=251235&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/readability-implicit-bool-cast-cxx98.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/readability-implicit-bool-cast-cxx98.cpp Sun Oct 25 10:31:25 2015
@@ -0,0 +1,42 @@
+// RUN: clang-tidy %s -checks=-*,readability-implicit-bool-cast -- -std=c++98
+
+#include <cstddef> // for NULL
+
+template<typename T>
+void functionTaking(T);
+
+struct Struct {
+  int member;
+};
+
+void useOldNullMacroInReplacements() {
+  int* pointer = NULL;
+  functionTaking<bool>(pointer);
+  // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit cast 'int *' -> bool [readability-implicit-bool-cast]
+  // CHECK-FIXES: functionTaking<bool>(pointer != 0);
+
+  int Struct::* memberPointer = NULL;
+  functionTaking<bool>(!memberPointer);
+  // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: implicit cast 'int struct Struct::*' -> bool
+  // CHECK-FIXES: functionTaking<bool>(memberPointer == 0);
+}
+
+void fixFalseLiteralConvertingToNullPointer() {
+  functionTaking<int*>(false);
+  // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit cast bool -> 'int *'
+  // CHECK-FIXES: functionTaking<int*>(0);
+
+  int* pointer = NULL;
+  if (pointer == false) {}
+  // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: implicit cast bool -> 'int *'
+  // CHECK-FIXES: if (pointer == 0) {}
+
+  functionTaking<int Struct::*>(false);
+  // CHECK-MESSAGES: :[[@LINE-1]]:33: warning: implicit cast bool -> 'int struct Struct::*'
+  // CHECK-FIXES: functionTaking<int Struct::*>(0);
+
+  int Struct::* memberPointer = NULL;
+  if (memberPointer != false) {}
+  // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit cast bool -> 'int struct Struct::*'
+  // CHECK-FIXES: if (memberPointer != 0) {}
+}

Added: clang-tools-extra/trunk/test/clang-tidy/readability-implicit-bool-cast.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/readability-implicit-bool-cast.cpp?rev=251235&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/readability-implicit-bool-cast.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/readability-implicit-bool-cast.cpp Sun Oct 25 10:31:25 2015
@@ -0,0 +1,430 @@
+// RUN: %check_clang_tidy %s readability-implicit-bool-cast %t
+
+#include <cstddef> // for NULL
+
+template<typename T>
+void functionTaking(T);
+
+struct Struct {
+  int member;
+};
+
+
+////////// Implicit cast from bool.
+
+void implicitCastFromBoolSimpleCases() {
+  bool boolean = true;
+
+  functionTaking<bool>(boolean);
+
+  functionTaking<int>(boolean);
+  // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: implicit cast bool -> 'int' [readability-implicit-bool-cast]
+  // CHECK-FIXES: functionTaking<int>(static_cast<int>(boolean));
+
+  functionTaking<unsigned long>(boolean);
+  // CHECK-MESSAGES: :[[@LINE-1]]:33: warning: implicit cast bool -> 'unsigned long'
+  // CHECK-FIXES: functionTaking<unsigned long>(static_cast<unsigned long>(boolean));
+
+  functionTaking<char>(boolean);
+  // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit cast bool -> 'char'
+  // CHECK-FIXES: functionTaking<char>(static_cast<char>(boolean));
+
+  functionTaking<float>(boolean);
+  // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: implicit cast bool -> 'float'
+  // CHECK-FIXES: functionTaking<float>(static_cast<float>(boolean));
+
+  functionTaking<double>(boolean);
+  // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: implicit cast bool -> 'double'
+  // CHECK-FIXES: functionTaking<double>(static_cast<double>(boolean));
+}
+
+float implicitCastFromBoolInReturnValue() {
+  bool boolean = false;
+  return boolean;
+  // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: implicit cast bool -> 'float'
+  // CHECK-FIXES: return static_cast<float>(boolean);
+}
+
+void implicitCastFromBoolInSingleBoolExpressions() {
+  bool boolean = true;
+
+  int integer = boolean - 3;
+  // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: implicit cast bool -> 'int'
+  // CHECK-FIXES: int integer = static_cast<int>(boolean) - 3;
+
+  float floating = boolean / 0.3f;
+  // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: implicit cast bool -> 'float'
+  // CHECK-FIXES: float floating = static_cast<float>(boolean) / 0.3f;
+
+  char character = boolean;
+  // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: implicit cast bool -> 'char'
+  // CHECK-FIXES: char character = static_cast<char>(boolean);
+}
+
+void implicitCastFromBoollInComplexBoolExpressions() {
+  bool boolean = true;
+  bool anotherBoolean = false;
+
+  int integer = boolean && anotherBoolean;
+  // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: implicit cast bool -> 'int'
+  // CHECK-FIXES: int integer = static_cast<int>(boolean && anotherBoolean);
+
+  unsigned long unsignedLong = (! boolean) + 4ul;
+  // CHECK-MESSAGES: :[[@LINE-1]]:32: warning: implicit cast bool -> 'unsigned long'
+  // CHECK-FIXES: unsigned long unsignedLong = static_cast<unsigned long>(! boolean) + 4ul;
+
+  float floating = (boolean || anotherBoolean) * 0.3f;
+  // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: implicit cast bool -> 'float'
+  // CHECK-FIXES: float floating = static_cast<float>(boolean || anotherBoolean) * 0.3f;
+
+  double doubleFloating = (boolean && (anotherBoolean || boolean)) * 0.3;
+  // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: implicit cast bool -> 'double'
+  // CHECK-FIXES: double doubleFloating = static_cast<double>(boolean && (anotherBoolean || boolean)) * 0.3;
+}
+
+void implicitCastFromBoolLiterals() {
+  functionTaking<int>(true);
+  // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: implicit cast bool -> 'int'
+  // CHECK-FIXES: functionTaking<int>(1);
+
+  functionTaking<unsigned long>(false);
+  // CHECK-MESSAGES: :[[@LINE-1]]:33: warning: implicit cast bool -> 'unsigned long'
+  // CHECK-FIXES: functionTaking<unsigned long>(0u);
+
+  functionTaking<char>(true);
+  // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit cast bool -> 'char'
+  // CHECK-FIXES: functionTaking<char>(1);
+
+  functionTaking<float>(false);
+  // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: implicit cast bool -> 'float'
+  // CHECK-FIXES: functionTaking<float>(0.0f);
+
+  functionTaking<double>(true);
+  // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: implicit cast bool -> 'double'
+  // CHECK-FIXES: functionTaking<double>(1.0);
+}
+
+void implicitCastFromBoolInComparisons() {
+  bool boolean = true;
+  int integer = 0;
+
+  functionTaking<bool>(boolean == integer);
+  // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit cast bool -> 'int'
+  // CHECK-FIXES: functionTaking<bool>(static_cast<int>(boolean) == integer);
+
+  functionTaking<bool>(integer != boolean);
+  // CHECK-MESSAGES: :[[@LINE-1]]:35: warning: implicit cast bool -> 'int'
+  // CHECK-FIXES: functionTaking<bool>(integer != static_cast<int>(boolean));
+}
+
+void ignoreBoolComparisons() {
+  bool boolean = true;
+  bool anotherBoolean = false;
+
+  functionTaking<bool>(boolean == anotherBoolean);
+  functionTaking<bool>(boolean != anotherBoolean);
+}
+
+void ignoreExplicitCastsFromBool() {
+  bool boolean = true;
+
+  int integer = static_cast<int>(boolean) + 3;
+  float floating = static_cast<float>(boolean) * 0.3f;
+  char character = static_cast<char>(boolean);
+}
+
+void ignoreImplicitCastFromBoolInMacroExpansions() {
+  bool boolean = true;
+
+  #define CAST_FROM_BOOL_IN_MACRO_BODY boolean + 3
+  int integerFromMacroBody = CAST_FROM_BOOL_IN_MACRO_BODY;
+
+  #define CAST_FROM_BOOL_IN_MACRO_ARGUMENT(x) x + 3
+  int integerFromMacroArgument = CAST_FROM_BOOL_IN_MACRO_ARGUMENT(boolean);
+}
+
+namespace ignoreImplicitCastFromBoolInTemplateInstantiations {
+
+template<typename T>
+void templateFunction() {
+  bool boolean = true;
+  T uknownType = boolean + 3;
+}
+
+void useOfTemplateFunction() {
+  templateFunction<int>();
+}
+
+} // namespace ignoreImplicitCastFromBoolInTemplateInstantiations
+
+////////// Implicit cast to bool.
+
+void implicitCastToBoolSimpleCases() {
+  int integer = 10;
+  functionTaking<bool>(integer);
+  // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit cast 'int' -> bool
+  // CHECK-FIXES: functionTaking<bool>(integer != 0);
+
+  unsigned long unsignedLong = 10;
+  functionTaking<bool>(unsignedLong);
+  // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit cast 'unsigned long' -> bool
+  // CHECK-FIXES: functionTaking<bool>(unsignedLong != 0u);
+
+  float floating = 0.0f;
+  functionTaking<bool>(floating);
+  // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit cast 'float' -> bool
+  // CHECK-FIXES: functionTaking<bool>(floating != 0.0f);
+
+  double doubleFloating = 1.0f;
+  functionTaking<bool>(doubleFloating);
+  // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit cast 'double' -> bool
+  // CHECK-FIXES: functionTaking<bool>(doubleFloating != 0.0);
+
+  char character = 'a';
+  functionTaking<bool>(character);
+  // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit cast 'char' -> bool
+  // CHECK-FIXES: functionTaking<bool>(character != 0);
+
+  int* pointer = nullptr;
+  functionTaking<bool>(pointer);
+  // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit cast 'int *' -> bool
+  // CHECK-FIXES: functionTaking<bool>(pointer != nullptr);
+
+  auto pointerToMember = &Struct::member;
+  functionTaking<bool>(pointerToMember);
+  // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit cast 'int struct Struct::*' -> bool
+  // CHECK-FIXES: functionTaking<bool>(pointerToMember != nullptr);
+}
+
+void implicitCastToBoolInSingleExpressions() {
+  int integer = 10;
+  bool boolComingFromInt = integer;
+  // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: implicit cast 'int' -> bool
+  // CHECK-FIXES: bool boolComingFromInt = integer != 0;
+
+  float floating = 10.0f;
+  bool boolComingFromFloat = floating;
+  // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: implicit cast 'float' -> bool
+  // CHECK-FIXES: bool boolComingFromFloat = floating != 0.0f;
+
+  char character = 'a';
+  bool boolComingFromChar = character;
+  // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: implicit cast 'char' -> bool
+  // CHECK-FIXES: bool boolComingFromChar = character != 0;
+
+  int* pointer = nullptr;
+  bool boolComingFromPointer = pointer;
+  // CHECK-MESSAGES: :[[@LINE-1]]:32: warning: implicit cast 'int *' -> bool
+  // CHECK-FIXES: bool boolComingFromPointer = pointer != nullptr;
+}
+
+void implicitCastToBoolInComplexExpressions() {
+  bool boolean = true;
+
+  int integer = 10;
+  int anotherInteger = 20;
+  bool boolComingFromInteger = integer + anotherInteger;
+  // CHECK-MESSAGES: :[[@LINE-1]]:32: warning: implicit cast 'int' -> bool
+  // CHECK-FIXES: bool boolComingFromInteger = (integer + anotherInteger) != 0;
+
+  float floating = 0.2f;
+  bool boolComingFromFloating = floating - 0.3f || boolean;
+  // CHECK-MESSAGES: :[[@LINE-1]]:33: warning: implicit cast 'float' -> bool
+  // CHECK-FIXES: bool boolComingFromFloating = ((floating - 0.3f) != 0.0f) || boolean;
+
+  double doubleFloating = 0.3;
+  bool boolComingFromDoubleFloating = (doubleFloating - 0.4) && boolean;
+  // CHECK-MESSAGES: :[[@LINE-1]]:39: warning: implicit cast 'double' -> bool
+  // CHECK-FIXES: bool boolComingFromDoubleFloating = ((doubleFloating - 0.4) != 0.0) && boolean;
+}
+
+void implicitCastInNegationExpressions() {
+  int integer = 10;
+  bool boolComingFromNegatedInt = !integer;
+  // CHECK-MESSAGES: :[[@LINE-1]]:36: warning: implicit cast 'int' -> bool
+  // CHECK-FIXES: bool boolComingFromNegatedInt = integer == 0;
+
+  float floating = 10.0f;
+  bool boolComingFromNegatedFloat = ! floating;
+  // CHECK-MESSAGES: :[[@LINE-1]]:39: warning: implicit cast 'float' -> bool
+  // CHECK-FIXES: bool boolComingFromNegatedFloat = floating == 0.0f;
+
+  char character = 'a';
+  bool boolComingFromNegatedChar = (! character);
+  // CHECK-MESSAGES: :[[@LINE-1]]:39: warning: implicit cast 'char' -> bool
+  // CHECK-FIXES: bool boolComingFromNegatedChar = (character == 0);
+
+  int* pointer = nullptr;
+  bool boolComingFromNegatedPointer = not pointer;
+  // CHECK-MESSAGES: :[[@LINE-1]]:43: warning: implicit cast 'int *' -> bool
+  // CHECK-FIXES: bool boolComingFromNegatedPointer = pointer == nullptr;
+}
+
+void implicitCastToBoolInControlStatements() {
+  int integer = 10;
+  if (integer) {}
+  // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: implicit cast 'int' -> bool
+  // CHECK-FIXES: if (integer != 0) {}
+
+  long int longInteger = 0.2f;
+  for (;longInteger;) {}
+  // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: implicit cast 'long' -> bool
+  // CHECK-FIXES: for (;longInteger != 0;) {}
+
+  float floating = 0.3f;
+  while (floating) {}
+  // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: implicit cast 'float' -> bool
+  // CHECK-FIXES: while (floating != 0.0f) {}
+
+  double doubleFloating = 0.4;
+  do {} while (doubleFloating);
+  // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: implicit cast 'double' -> bool
+  // CHECK-FIXES: do {} while (doubleFloating != 0.0);
+}
+
+bool implicitCastToBoolInReturnValue() {
+  float floating = 1.0f;
+  return floating;
+  // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: implicit cast 'float' -> bool
+  // CHECK-FIXES: return floating != 0.0f;
+}
+
+void implicitCastToBoolFromLiterals() {
+  functionTaking<bool>(0);
+  // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit cast 'int' -> bool
+  // CHECK-FIXES: functionTaking<bool>(false);
+
+  functionTaking<bool>(1);
+  // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit cast 'int' -> bool
+  // CHECK-FIXES: functionTaking<bool>(true);
+
+  functionTaking<bool>(2ul);
+  // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit cast 'unsigned long' -> bool
+  // CHECK-FIXES: functionTaking<bool>(true);
+
+
+  functionTaking<bool>(0.0f);
+  // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit cast 'float' -> bool
+  // CHECK-FIXES: functionTaking<bool>(false);
+
+  functionTaking<bool>(1.0f);
+  // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit cast 'float' -> bool
+  // CHECK-FIXES: functionTaking<bool>(true);
+
+  functionTaking<bool>(2.0);
+  // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit cast 'double' -> bool
+  // CHECK-FIXES: functionTaking<bool>(true);
+
+
+  functionTaking<bool>('\0');
+  // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit cast 'char' -> bool
+  // CHECK-FIXES: functionTaking<bool>(false);
+
+  functionTaking<bool>('a');
+  // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit cast 'char' -> bool
+  // CHECK-FIXES: functionTaking<bool>(true);
+
+
+  functionTaking<bool>("");
+  // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit cast 'const char *' -> bool
+  // CHECK-FIXES: functionTaking<bool>(true);
+
+  functionTaking<bool>("abc");
+  // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit cast 'const char *' -> bool
+  // CHECK-FIXES: functionTaking<bool>(true);
+
+  functionTaking<bool>(NULL);
+  // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit cast 'long' -> bool
+  // CHECK-FIXES: functionTaking<bool>(false);
+}
+
+void implicitCastToBoolFromUnaryMinusAndZeroLiterals() {
+  functionTaking<bool>(-0);
+  // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit cast 'int' -> bool
+  // CHECK-FIXES: functionTaking<bool>((-0) != 0);
+
+  functionTaking<bool>(-0.0f);
+  // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit cast 'float' -> bool
+  // CHECK-FIXES: functionTaking<bool>((-0.0f) != 0.0f);
+
+  functionTaking<bool>(-0.0);
+  // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit cast 'double' -> bool
+  // CHECK-FIXES: functionTaking<bool>((-0.0) != 0.0);
+}
+
+void implicitCastToBoolInWithOverloadedOperators() {
+  struct UserStruct {
+    int operator()(int x) { return x; }
+    int operator+(int y) { return y; }
+  };
+
+  UserStruct s;
+
+  functionTaking<bool>(s(0));
+  // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit cast 'int' -> bool
+  // CHECK-FIXES: functionTaking<bool>(s(0) != 0);
+
+  functionTaking<bool>(s + 2);
+  // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit cast 'int' -> bool
+  // CHECK-FIXES: functionTaking<bool>((s + 2) != 0);
+}
+
+int functionReturningInt();
+int* functionReturningPointer();
+
+void ignoreImplicitCastToBoolWhenDeclaringVariableInControlStatements() {
+  if (int integer = functionReturningInt()) {}
+
+  while (int* pointer = functionReturningPointer()) {}
+}
+
+void ignoreExplicitCastsToBool() {
+  int integer = 10;
+  bool boolComingFromInt = static_cast<bool>(integer);
+
+  float floating = 10.0f;
+  bool boolComingFromFloat = static_cast<bool>(floating);
+
+  char character = 'a';
+  bool boolComingFromChar = static_cast<bool>(character);
+
+  int* pointer = nullptr;
+  bool booleanComingFromPointer = static_cast<bool>(pointer);
+}
+
+void ignoreImplicitCastToBoolInMacroExpansions() {
+  int integer = 3;
+
+  #define CAST_TO_BOOL_IN_MACRO_BODY integer && false
+  bool boolFromMacroBody = CAST_TO_BOOL_IN_MACRO_BODY;
+
+  #define CAST_TO_BOOL_IN_MACRO_ARGUMENT(x) x || true
+  bool boolFromMacroArgument = CAST_TO_BOOL_IN_MACRO_ARGUMENT(integer);
+}
+
+namespace ignoreImplicitCastToBoolInTemplateInstantiations {
+
+template<typename T>
+void templateFunction() {
+  T unknownType = 0;
+  bool boolean = unknownType;
+}
+
+void useOfTemplateFunction() {
+  templateFunction<int>();
+}
+
+} // namespace ignoreImplicitCastToBoolInTemplateInstantiations
+
+namespace ignoreUserDefinedConversionOperator {
+
+struct StructWithUserConversion {
+  operator bool();
+};
+
+void useOfUserConversion() {
+  StructWithUserConversion structure;
+  functionTaking<bool>(structure);
+}
+
+} // namespace ignoreUserDefinedConversionOperator




More information about the cfe-commits mailing list