[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