Index: clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.h =================================================================== --- clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.h +++ clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.h @@ -36,6 +36,7 @@ const bool AllowIntegerConditions; const bool AllowPointerConditions; + const bool UseUppercaseLiteralSuffix; }; } // namespace readability Index: clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp =================================================================== --- clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp +++ clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp @@ -41,13 +41,14 @@ StringRef getZeroLiteralToCompareWithForType(CastKind CastExprKind, QualType Type, - ASTContext &Context) { + ASTContext &Context, + bool UppercaseSuffix) { switch (CastExprKind) { case CK_IntegralToBoolean: - return Type->isUnsignedIntegerType() ? "0u" : "0"; + return Type->isUnsignedIntegerType() ? (UppercaseSuffix ? "0U" : "0u") : "0"; case CK_FloatingToBoolean: - return Context.hasSameType(Type, Context.FloatTy) ? "0.0f" : "0.0"; + return Context.hasSameType(Type, Context.FloatTy) ? (UppercaseSuffix ? "0.0F" : "0.0f") : "0.0"; case CK_PointerToBoolean: case CK_MemberPointerToBoolean: // Fall-through on purpose. @@ -90,7 +91,7 @@ void fixGenericExprCastToBool(DiagnosticBuilder &Diag, const ImplicitCastExpr *Cast, const Stmt *Parent, - ASTContext &Context) { + ASTContext &Context, bool UppercaseSuffix) { // In case of expressions like (! integer), we should remove the redundant not // operator and use inverted comparison (integer == 0). bool InvertComparison = @@ -137,7 +138,7 @@ } EndLocInsertion += getZeroLiteralToCompareWithForType( - Cast->getCastKind(), SubExpr->getType(), Context); + Cast->getCastKind(), SubExpr->getType(), Context, UppercaseSuffix); if (NeedOuterParens) { EndLocInsertion += ")"; @@ -196,7 +197,8 @@ } StringRef getEquivalentForBoolLiteral(const CXXBoolLiteralExpr *BoolLiteral, - QualType DestType, ASTContext &Context) { + QualType DestType, ASTContext &Context, + bool UppercaseSuffix) { // Prior to C++11, false literal could be implicitly converted to pointer. if (!Context.getLangOpts().CPlusPlus11 && (DestType->isPointerType() || DestType->isMemberPointerType()) && @@ -206,12 +208,16 @@ if (DestType->isFloatingType()) { if (Context.hasSameType(DestType, Context.FloatTy)) { + if (UppercaseSuffix) + return BoolLiteral->getValue() ? "1.0F" : "0.0F"; return BoolLiteral->getValue() ? "1.0f" : "0.0f"; } return BoolLiteral->getValue() ? "1.0" : "0.0"; } if (DestType->isUnsignedIntegerType()) { + if (UppercaseSuffix) + return BoolLiteral->getValue() ? "1U" : "0U"; return BoolLiteral->getValue() ? "1u" : "0u"; } return BoolLiteral->getValue() ? "1" : "0"; @@ -248,7 +254,8 @@ StringRef Name, ClangTidyContext *Context) : ClangTidyCheck(Name, Context), AllowIntegerConditions(Options.get("AllowIntegerConditions", false)), - AllowPointerConditions(Options.get("AllowPointerConditions", false)) {} + AllowPointerConditions(Options.get("AllowPointerConditions", false)), + UseUppercaseLiteralSuffix(Context->isCheckEnabled("readability-uppercase-literal-suffix")) {} void ImplicitBoolConversionCheck::storeOptions( ClangTidyOptions::OptionMap &Opts) { @@ -368,7 +375,7 @@ if (!EquivalentLiteral.empty()) { Diag << tooling::fixit::createReplacement(*Cast, EquivalentLiteral); } else { - fixGenericExprCastToBool(Diag, Cast, Parent, Context); + fixGenericExprCastToBool(Diag, Cast, Parent, Context, UseUppercaseLiteralSuffix); } } @@ -383,7 +390,8 @@ if (const auto *BoolLiteral = dyn_cast(Cast->getSubExpr())) { Diag << tooling::fixit::createReplacement( - *Cast, getEquivalentForBoolLiteral(BoolLiteral, DestType, Context)); + *Cast, getEquivalentForBoolLiteral(BoolLiteral, DestType, Context, + UseUppercaseLiteralSuffix)); } else { fixGenericExprCastFromBool(Diag, Cast, Context, DestType.getAsString()); } Index: clang-tools-extra/test/clang-tidy/readability-implicit-bool-conversion.cpp =================================================================== --- clang-tools-extra/test/clang-tidy/readability-implicit-bool-conversion.cpp +++ clang-tools-extra/test/clang-tidy/readability-implicit-bool-conversion.cpp @@ -70,7 +70,7 @@ // CHECK-FIXES: char character = static_cast(boolean); } -void implicitConversionFromBoollInComplexBoolExpressions() { +void implicitConversionFromBoolInComplexBoolExpressions() { bool boolean = true; bool anotherBoolean = false; Index: clang-tools-extra/test/clang-tidy/readability-uppercase-literal-suffix-implicit-bool-conversion.cpp =================================================================== --- /dev/null +++ clang-tools-extra/test/clang-tidy/readability-uppercase-literal-suffix-implicit-bool-conversion.cpp @@ -0,0 +1,124 @@ +// RUN: %check_clang_tidy %s readability-uppercase-literal-suffix,readability-implicit-bool-conversion %t + +template +void functionTaking(T); + + +////////// Implicit conversion to bool with enforced uppercase suffix. + +void implicitConversionToBoolSimpleCases() { + unsigned int unsignedInteger = 10u; + // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: integer literal has suffix 'u', which is not uppercase + // CHECK-MESSAGES-NEXT: unsigned int unsignedInteger = 10u; + // CHECK-MESSAGES-NEXT: ^ ~ + // CHECK-MESSAGES-NEXT: {{^ *}}U{{$}} + // CHECK-FIXES: unsigned int unsignedInteger = 10U; + + functionTaking(unsignedInteger); + // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'unsigned int' -> bool [readability-implicit-bool-conversion] + // CHECK-FIXES: functionTaking(unsignedInteger != 0U); + + unsigned long unsignedLong = 10ul; + // CHECK-MESSAGES: :[[@LINE-1]]:32: warning: integer literal has suffix 'ul', which is not uppercase [readability-uppercase-literal-suffix] + // CHECK-MESSAGES-NEXT: unsigned long unsignedLong = 10ul; + // CHECK-MESSAGES-NEXT: ^ ~~ + // CHECK-MESSAGES-NEXT: {{^ *}}UL{{$}} + // CHECK-FIXES: unsigned long unsignedLong = 10UL; + + functionTaking(unsignedLong); + // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'unsigned long' -> bool [readability-implicit-bool-conversion] + // CHECK-FIXES: functionTaking(unsignedLong != 0U); + + float floating = 10.0f; + // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: floating point literal has suffix 'f', which is not uppercase [readability-uppercase-literal-suffix] + // CHECK-MESSAGES-NEXT: float floating = 10.0f; + // CHECK-MESSAGES-NEXT: ^ ~ + // CHECK-MESSAGES-NEXT: {{^ *}}F{{$}} + // CHECK-FIXES: float floating = 10.0F; + + functionTaking(floating); + // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'float' -> bool [readability-implicit-bool-conversion] + // CHECK-FIXES: functionTaking(floating != 0.0F); + + double doubleFloating = 10.0; + functionTaking(doubleFloating); + // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'double' -> bool [readability-implicit-bool-conversion] + // CHECK-FIXES: functionTaking(doubleFloating != 0.0); +} + +void implicitConversionToBoolInComplexExpressions() { + bool boolean = true; + + unsigned int integer = 10U; + unsigned int anotherInteger = 20U; + bool boolComingFromUnsignedInteger = integer + anotherInteger; + // CHECK-MESSAGES: :[[@LINE-1]]:40: warning: implicit conversion 'unsigned int' -> bool + // CHECK-FIXES: bool boolComingFromUnsignedInteger = (integer + anotherInteger) != 0U; + + float floating = 0.2F; + // combination of two errors on the same line + bool boolComingFromFloating = floating - 0.3f || boolean; + // CHECK-MESSAGES: :[[@LINE-1]]:33: warning: implicit conversion 'float' -> bool + // CHECK-MESSAGES: :[[@LINE-2]]:44: warning: floating point literal has suffix 'f', which is not uppercase [readability-uppercase-literal-suffix] + // CHECK-FIXES: bool boolComingFromFloating = ((floating - 0.3F) != 0.0F) || boolean; +} + +void implicitConversionInNegationExpressions() { + // ensure that in negation the replaced suffix is also capitalized + float floating = 10.0F; + bool boolComingFromNegatedFloat = ! floating; + // CHECK-MESSAGES: :[[@LINE-1]]:39: warning: implicit conversion 'float' -> bool + // CHECK-FIXES: bool boolComingFromNegatedFloat = floating == 0.0F; +} + +void implicitConversionToBoolInControlStatements() { + unsigned long longInteger = 2U; + for (;longInteger;) {} + // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: implicit conversion 'unsigned long' -> bool + // CHECK-FIXES: for (;longInteger != 0U;) {} + + float floating = 0.3F; + while (floating) {} + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: implicit conversion 'float' -> bool + // CHECK-FIXES: while (floating != 0.0F) {} +} + +void implicitConversionToBoolFromUnaryOperatorLiterals() { + functionTaking(-0); + // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'int' -> bool + // CHECK-FIXES: functionTaking((-0) != 0); + + functionTaking(-0.0F); + // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'float' -> bool + // CHECK-FIXES: functionTaking((-0.0F) != 0.0F); + + functionTaking(-0.0); + // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'double' -> bool + // CHECK-FIXES: functionTaking((-0.0) != 0.0); +} + +bool implicitConversionToBoolFromUnsignedInReturnValue() { + unsigned integer = 1u; + // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: integer literal has suffix 'u', which is not uppercase + // CHECK-MESSAGES-NEXT: unsigned integer = 1u; + // CHECK-MESSAGES-NEXT: ^~ + // CHECK-MESSAGES-NEXT: {{^ *}}U{{$}} + // CHECK-FIXES: unsigned integer = 1U; + + return integer; + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: implicit conversion 'unsigned int' -> bool [readability-implicit-bool-conversion] + // CHECK-FIXES: return integer != 0U; +} + +bool implicitConversionToBoolFromFloatInReturnValue() { + float floating = 1.0f; + // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: floating point literal has suffix 'f', which is not uppercase [readability-uppercase-literal-suffix] + // CHECK-MESSAGES-NEXT: float floating = 1.0f; + // CHECK-MESSAGES-NEXT: ^ ~ + // CHECK-MESSAGES-NEXT: {{^ *}}F{{$}} + // CHECK-FIXES: float floating = 1.0F; + + return floating; + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: implicit conversion 'float' -> bool [readability-implicit-bool-conversion] + // CHECK-FIXES: return floating != 0.0F; +}