[clang-tidy] 'implicit cast' -> 'implicit conversion'

Summary:
This patch renames checks, check options and changes messages to use correct
term "implicit conversion" instead of "implicit cast" (which has been in use in
Clang AST since ~10 years, but it's still technically incorrect w.r.t. C++
standard).

  * performance-implicit-cast-in-loop -> performance-implicit-conversion-in-loop
  * readability-implicit-bool-cast -> readability-implicit-bool-conversion
    - readability-implicit-bool-cast.AllowConditionalIntegerCasts ->
      readability-implicit-bool-conversion.AllowIntegerConditions
    - readability-implicit-bool-cast.AllowConditionalPointerCasts ->
      readability-implicit-bool-conversion.AllowPointerConditions

Reviewers: hokein, jdennett

Reviewed By: hokein

Subscribers: mgorny, JDevlieghere, xazax.hun, cfe-commits

Differential Revision: https://reviews.llvm.org/D36456

llvm-svn: 310366
This commit is contained in:
Alexander Kornienko 2017-08-08 14:53:52 +00:00
parent 64d31edef3
commit f1a6552a95
18 changed files with 355 additions and 319 deletions

View File

@ -3,7 +3,7 @@ set(LLVM_LINK_COMPONENTS support)
add_clang_library(clangTidyPerformanceModule add_clang_library(clangTidyPerformanceModule
FasterStringFindCheck.cpp FasterStringFindCheck.cpp
ForRangeCopyCheck.cpp ForRangeCopyCheck.cpp
ImplicitCastInLoopCheck.cpp ImplicitConversionInLoopCheck.cpp
InefficientStringConcatenationCheck.cpp InefficientStringConcatenationCheck.cpp
InefficientVectorOperationCheck.cpp InefficientVectorOperationCheck.cpp
PerformanceTidyModule.cpp PerformanceTidyModule.cpp

View File

@ -1,4 +1,4 @@
//===--- ImplicitCastInLoopCheck.cpp - clang-tidy--------------------------===// //===--- ImplicitConversionInLoopCheck.cpp - clang-tidy--------------------===//
// //
// The LLVM Compiler Infrastructure // The LLVM Compiler Infrastructure
// //
@ -7,7 +7,7 @@
// //
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
#include "ImplicitCastInLoopCheck.h" #include "ImplicitConversionInLoopCheck.h"
#include "clang/AST/ASTContext.h" #include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h" #include "clang/AST/Decl.h"
@ -21,30 +21,30 @@ namespace clang {
namespace tidy { namespace tidy {
namespace performance { namespace performance {
namespace {
// Checks if the stmt is a ImplicitCastExpr with a CastKind that is not a NoOp. // Checks if the stmt is a ImplicitCastExpr with a CastKind that is not a NoOp.
// The subtelty is that in some cases (user defined conversions), we can // The subtelty is that in some cases (user defined conversions), we can
// get to ImplicitCastExpr inside each other, with the outer one a NoOp. In this // get to ImplicitCastExpr inside each other, with the outer one a NoOp. In this
// case we skip the first cast expr. // case we skip the first cast expr.
bool IsNonTrivialImplicitCast(const Stmt *ST) { static bool IsNonTrivialImplicitCast(const Stmt *ST) {
if (const auto *ICE = dyn_cast<ImplicitCastExpr>(ST)) { if (const auto *ICE = dyn_cast<ImplicitCastExpr>(ST)) {
return (ICE->getCastKind() != CK_NoOp) || return (ICE->getCastKind() != CK_NoOp) ||
IsNonTrivialImplicitCast(ICE->getSubExpr()); IsNonTrivialImplicitCast(ICE->getSubExpr());
} }
return false; return false;
} }
} // namespace
void ImplicitCastInLoopCheck::registerMatchers(MatchFinder *Finder) { void ImplicitConversionInLoopCheck::registerMatchers(MatchFinder *Finder) {
// We look for const ref loop variables that (optionally inside an // We look for const ref loop variables that (optionally inside an
// ExprWithCleanup) materialize a temporary, and contain a implicit cast. The // ExprWithCleanup) materialize a temporary, and contain a implicit
// check on the implicit cast is done in check() because we can't access // conversion. The check on the implicit conversion is done in check() because
// implicit cast subnode via matchers: has() skips casts and materialize! // we can't access implicit conversion subnode via matchers: has() skips casts
// We also bind on the call to operator* to get the proper type in the // and materialize! We also bind on the call to operator* to get the proper
// diagnostic message. // type in the diagnostic message.
// Note that when the implicit cast is done through a user defined cast //
// operator, the node is a CXXMemberCallExpr, not a CXXOperatorCallExpr, so // Note that when the implicit conversion is done through a user defined
// it should not get caught by the cxxOperatorCallExpr() matcher. // conversion operator, the node is a CXXMemberCallExpr, not a
// CXXOperatorCallExpr, so it should not get caught by the
// cxxOperatorCallExpr() matcher.
Finder->addMatcher( Finder->addMatcher(
cxxForRangeStmt(hasLoopVariable( cxxForRangeStmt(hasLoopVariable(
varDecl(hasType(qualType(references(qualType(isConstQualified())))), varDecl(hasType(qualType(references(qualType(isConstQualified())))),
@ -55,7 +55,8 @@ void ImplicitCastInLoopCheck::registerMatchers(MatchFinder *Finder) {
this); this);
} }
void ImplicitCastInLoopCheck::check(const MatchFinder::MatchResult &Result) { void ImplicitConversionInLoopCheck::check(
const MatchFinder::MatchResult &Result) {
const auto *VD = Result.Nodes.getNodeAs<VarDecl>("faulty-var"); const auto *VD = Result.Nodes.getNodeAs<VarDecl>("faulty-var");
const auto *Init = Result.Nodes.getNodeAs<Expr>("init"); const auto *Init = Result.Nodes.getNodeAs<Expr>("init");
const auto *OperatorCall = const auto *OperatorCall =
@ -76,7 +77,7 @@ void ImplicitCastInLoopCheck::check(const MatchFinder::MatchResult &Result) {
ReportAndFix(Result.Context, VD, OperatorCall); ReportAndFix(Result.Context, VD, OperatorCall);
} }
void ImplicitCastInLoopCheck::ReportAndFix( void ImplicitConversionInLoopCheck::ReportAndFix(
const ASTContext *Context, const VarDecl *VD, const ASTContext *Context, const VarDecl *VD,
const CXXOperatorCallExpr *OperatorCall) { const CXXOperatorCallExpr *OperatorCall) {
// We only match on const ref, so we should print a const ref version of the // We only match on const ref, so we should print a const ref version of the
@ -85,8 +86,8 @@ void ImplicitCastInLoopCheck::ReportAndFix(
QualType ConstRefType = Context->getLValueReferenceType(ConstType); QualType ConstRefType = Context->getLValueReferenceType(ConstType);
const char Message[] = const char Message[] =
"the type of the loop variable %0 is different from the one returned " "the type of the loop variable %0 is different from the one returned "
"by the iterator and generates an implicit cast; you can either " "by the iterator and generates an implicit conversion; you can either "
"change the type to the correct one (%1 but 'const auto&' is always a " "change the type to the matching one (%1 but 'const auto&' is always a "
"valid option) or remove the reference to make it explicit that you are " "valid option) or remove the reference to make it explicit that you are "
"creating a new value"; "creating a new value";
diag(VD->getLocStart(), Message) << VD << ConstRefType; diag(VD->getLocStart(), Message) << VD << ConstRefType;

View File

@ -1,4 +1,4 @@
//===--- ImplicitCastInLoopCheck.h - clang-tidy------------------*- C++ -*-===// //===--- ImplicitConversionInLoopCheck.h - clang-tidy------------*- C++ -*-===//
// //
// The LLVM Compiler Infrastructure // The LLVM Compiler Infrastructure
// //
@ -7,8 +7,8 @@
// //
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_IMPLICIT_CAST_IN_LOOP_CHECK_H_ #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_IMPLICIT_CONVERSION_IN_LOOP_CHECK_H_
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_IMPLICIT_CAST_IN_LOOP_CHECK_H_ #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_IMPLICIT_CONVERSION_IN_LOOP_CHECK_H_
#include "../ClangTidy.h" #include "../ClangTidy.h"
@ -19,9 +19,9 @@ namespace performance {
// Checks that in a for range loop, if the provided type is a reference, then // Checks that in a for range loop, if the provided type is a reference, then
// the underlying type is the one returned by the iterator (i.e. that there // the underlying type is the one returned by the iterator (i.e. that there
// isn't any implicit conversion). // isn't any implicit conversion).
class ImplicitCastInLoopCheck : public ClangTidyCheck { class ImplicitConversionInLoopCheck : public ClangTidyCheck {
public: public:
ImplicitCastInLoopCheck(StringRef Name, ClangTidyContext *Context) ImplicitConversionInLoopCheck(StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context) {} : ClangTidyCheck(Name, Context) {}
void registerMatchers(ast_matchers::MatchFinder *Finder) override; void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override; void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
@ -35,4 +35,4 @@ private:
} // namespace tidy } // namespace tidy
} // namespace clang } // namespace clang
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_IMPLICIT_CAST_IN_LOOP_CHECK_H_ #endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_IMPLICIT_CONVERSION_IN_LOOP_CHECK_H_

View File

@ -12,7 +12,7 @@
#include "../ClangTidyModuleRegistry.h" #include "../ClangTidyModuleRegistry.h"
#include "FasterStringFindCheck.h" #include "FasterStringFindCheck.h"
#include "ForRangeCopyCheck.h" #include "ForRangeCopyCheck.h"
#include "ImplicitCastInLoopCheck.h" #include "ImplicitConversionInLoopCheck.h"
#include "InefficientStringConcatenationCheck.h" #include "InefficientStringConcatenationCheck.h"
#include "InefficientVectorOperationCheck.h" #include "InefficientVectorOperationCheck.h"
#include "TypePromotionInMathFnCheck.h" #include "TypePromotionInMathFnCheck.h"
@ -30,8 +30,8 @@ public:
"performance-faster-string-find"); "performance-faster-string-find");
CheckFactories.registerCheck<ForRangeCopyCheck>( CheckFactories.registerCheck<ForRangeCopyCheck>(
"performance-for-range-copy"); "performance-for-range-copy");
CheckFactories.registerCheck<ImplicitCastInLoopCheck>( CheckFactories.registerCheck<ImplicitConversionInLoopCheck>(
"performance-implicit-cast-in-loop"); "performance-implicit-conversion-in-loop");
CheckFactories.registerCheck<InefficientStringConcatenationCheck>( CheckFactories.registerCheck<InefficientStringConcatenationCheck>(
"performance-inefficient-string-concatenation"); "performance-inefficient-string-concatenation");
CheckFactories.registerCheck<InefficientVectorOperationCheck>( CheckFactories.registerCheck<InefficientVectorOperationCheck>(

View File

@ -9,7 +9,7 @@ add_clang_library(clangTidyReadabilityModule
ElseAfterReturnCheck.cpp ElseAfterReturnCheck.cpp
FunctionSizeCheck.cpp FunctionSizeCheck.cpp
IdentifierNamingCheck.cpp IdentifierNamingCheck.cpp
ImplicitBoolCastCheck.cpp ImplicitBoolConversionCheck.cpp
InconsistentDeclarationParameterNameCheck.cpp InconsistentDeclarationParameterNameCheck.cpp
MisleadingIndentationCheck.cpp MisleadingIndentationCheck.cpp
MisplacedArrayIndexCheck.cpp MisplacedArrayIndexCheck.cpp

View File

@ -1,4 +1,4 @@
//===--- ImplicitBoolCastCheck.cpp - clang-tidy----------------------------===// //===--- ImplicitBoolConversionCheck.cpp - clang-tidy----------------------===//
// //
// The LLVM Compiler Infrastructure // The LLVM Compiler Infrastructure
// //
@ -7,7 +7,7 @@
// //
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
#include "ImplicitBoolCastCheck.h" #include "ImplicitBoolConversionCheck.h"
#include "clang/AST/ASTContext.h" #include "clang/AST/ASTContext.h"
#include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Lex/Lexer.h" #include "clang/Lex/Lexer.h"
@ -218,7 +218,7 @@ StringRef getEquivalentForBoolLiteral(const CXXBoolLiteralExpr *BoolLiteral,
return BoolLiteral->getValue() ? "1" : "0"; return BoolLiteral->getValue() ? "1" : "0";
} }
bool isAllowedConditionalCast(const ImplicitCastExpr *Cast, bool isCastAllowedInCondition(const ImplicitCastExpr *Cast,
ASTContext &Context) { ASTContext &Context) {
std::queue<const Stmt *> Q; std::queue<const Stmt *> Q;
Q.push(Cast); Q.push(Cast);
@ -245,22 +245,19 @@ bool isAllowedConditionalCast(const ImplicitCastExpr *Cast,
} // anonymous namespace } // anonymous namespace
ImplicitBoolCastCheck::ImplicitBoolCastCheck(StringRef Name, ImplicitBoolConversionCheck::ImplicitBoolConversionCheck(
ClangTidyContext *Context) StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context), : ClangTidyCheck(Name, Context),
AllowConditionalIntegerCasts( AllowIntegerConditions(Options.get("AllowIntegerConditions", false)),
Options.get("AllowConditionalIntegerCasts", false)), AllowPointerConditions(Options.get("AllowPointerConditions", false)) {}
AllowConditionalPointerCasts(
Options.get("AllowConditionalPointerCasts", false)) {}
void ImplicitBoolCastCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { void ImplicitBoolConversionCheck::storeOptions(
Options.store(Opts, "AllowConditionalIntegerCasts", ClangTidyOptions::OptionMap &Opts) {
AllowConditionalIntegerCasts); Options.store(Opts, "AllowIntegerConditions", AllowIntegerConditions);
Options.store(Opts, "AllowConditionalPointerCasts", Options.store(Opts, "AllowPointerConditions", AllowPointerConditions);
AllowConditionalPointerCasts);
} }
void ImplicitBoolCastCheck::registerMatchers(MatchFinder *Finder) { void ImplicitBoolConversionCheck::registerMatchers(MatchFinder *Finder) {
// This check doesn't make much sense if we run it on language without // This check doesn't make much sense if we run it on language without
// built-in bool support. // built-in bool support.
if (!getLangOpts().Bool) { if (!getLangOpts().Bool) {
@ -326,7 +323,8 @@ void ImplicitBoolCastCheck::registerMatchers(MatchFinder *Finder) {
this); this);
} }
void ImplicitBoolCastCheck::check(const MatchFinder::MatchResult &Result) { void ImplicitBoolConversionCheck::check(
const MatchFinder::MatchResult &Result) {
if (const auto *CastToBool = if (const auto *CastToBool =
Result.Nodes.getNodeAs<ImplicitCastExpr>("implicitCastToBool")) { Result.Nodes.getNodeAs<ImplicitCastExpr>("implicitCastToBool")) {
const auto *Parent = Result.Nodes.getNodeAs<Stmt>("parentStmt"); const auto *Parent = Result.Nodes.getNodeAs<Stmt>("parentStmt");
@ -341,23 +339,22 @@ void ImplicitBoolCastCheck::check(const MatchFinder::MatchResult &Result) {
} }
} }
void ImplicitBoolCastCheck::handleCastToBool(const ImplicitCastExpr *Cast, void ImplicitBoolConversionCheck::handleCastToBool(const ImplicitCastExpr *Cast,
const Stmt *Parent, const Stmt *Parent,
ASTContext &Context) { ASTContext &Context) {
if (AllowConditionalPointerCasts && if (AllowPointerConditions &&
(Cast->getCastKind() == CK_PointerToBoolean || (Cast->getCastKind() == CK_PointerToBoolean ||
Cast->getCastKind() == CK_MemberPointerToBoolean) && Cast->getCastKind() == CK_MemberPointerToBoolean) &&
isAllowedConditionalCast(Cast, Context)) { isCastAllowedInCondition(Cast, Context)) {
return; return;
} }
if (AllowConditionalIntegerCasts && if (AllowIntegerConditions && Cast->getCastKind() == CK_IntegralToBoolean &&
Cast->getCastKind() == CK_IntegralToBoolean && isCastAllowedInCondition(Cast, Context)) {
isAllowedConditionalCast(Cast, Context)) {
return; return;
} }
auto Diag = diag(Cast->getLocStart(), "implicit cast %0 -> bool") auto Diag = diag(Cast->getLocStart(), "implicit conversion %0 -> bool")
<< Cast->getSubExpr()->getType(); << Cast->getSubExpr()->getType();
StringRef EquivalentLiteral = StringRef EquivalentLiteral =
@ -369,12 +366,13 @@ void ImplicitBoolCastCheck::handleCastToBool(const ImplicitCastExpr *Cast,
} }
} }
void ImplicitBoolCastCheck::handleCastFromBool( void ImplicitBoolConversionCheck::handleCastFromBool(
const ImplicitCastExpr *Cast, const ImplicitCastExpr *NextImplicitCast, const ImplicitCastExpr *Cast, const ImplicitCastExpr *NextImplicitCast,
ASTContext &Context) { ASTContext &Context) {
QualType DestType = QualType DestType =
NextImplicitCast ? NextImplicitCast->getType() : Cast->getType(); NextImplicitCast ? NextImplicitCast->getType() : Cast->getType();
auto Diag = diag(Cast->getLocStart(), "implicit cast bool -> %0") << DestType; auto Diag = diag(Cast->getLocStart(), "implicit conversion bool -> %0")
<< DestType;
if (const auto *BoolLiteral = if (const auto *BoolLiteral =
dyn_cast<CXXBoolLiteralExpr>(Cast->getSubExpr())) { dyn_cast<CXXBoolLiteralExpr>(Cast->getSubExpr())) {

View File

@ -1,4 +1,4 @@
//===--- ImplicitBoolCastCheck.h - clang-tidy--------------------*- C++ -*-===// //===--- ImplicitBoolConversionCheck.h - clang-tidy--------------*- C++ -*-===//
// //
// The LLVM Compiler Infrastructure // The LLVM Compiler Infrastructure
// //
@ -7,8 +7,8 @@
// //
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_IMPLICIT_BOOL_CAST_H #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_IMPLICIT_BOOL_CONVERSION_H
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_IMPLICIT_BOOL_CAST_H #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_IMPLICIT_BOOL_CONVERSION_H
#include "../ClangTidy.h" #include "../ClangTidy.h"
@ -16,13 +16,13 @@ namespace clang {
namespace tidy { namespace tidy {
namespace readability { namespace readability {
/// \brief Checks for use of implicit bool casts in expressions. /// \brief Checks for use of implicit bool conversions in expressions.
/// ///
/// For the user-facing documentation see: /// For the user-facing documentation see:
/// http://clang.llvm.org/extra/clang-tidy/checks/readability-implicit-bool-cast.html /// http://clang.llvm.org/extra/clang-tidy/checks/readability-implicit-bool-conversion.html
class ImplicitBoolCastCheck : public ClangTidyCheck { class ImplicitBoolConversionCheck : public ClangTidyCheck {
public: public:
ImplicitBoolCastCheck(StringRef Name, ClangTidyContext *Context); ImplicitBoolConversionCheck(StringRef Name, ClangTidyContext *Context);
void storeOptions(ClangTidyOptions::OptionMap &Opts) override; void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
void registerMatchers(ast_matchers::MatchFinder *Finder) override; void registerMatchers(ast_matchers::MatchFinder *Finder) override;
@ -35,12 +35,12 @@ private:
const ImplicitCastExpr *FurtherImplicitCastExpression, const ImplicitCastExpr *FurtherImplicitCastExpression,
ASTContext &Context); ASTContext &Context);
bool AllowConditionalIntegerCasts; const bool AllowIntegerConditions;
bool AllowConditionalPointerCasts; const bool AllowPointerConditions;
}; };
} // namespace readability } // namespace readability
} // namespace tidy } // namespace tidy
} // namespace clang } // namespace clang
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_IMPLICIT_BOOL_CAST_H #endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_IMPLICIT_BOOL_CONVERSION_H

View File

@ -18,7 +18,7 @@
#include "ElseAfterReturnCheck.h" #include "ElseAfterReturnCheck.h"
#include "FunctionSizeCheck.h" #include "FunctionSizeCheck.h"
#include "IdentifierNamingCheck.h" #include "IdentifierNamingCheck.h"
#include "ImplicitBoolCastCheck.h" #include "ImplicitBoolConversionCheck.h"
#include "InconsistentDeclarationParameterNameCheck.h" #include "InconsistentDeclarationParameterNameCheck.h"
#include "MisleadingIndentationCheck.h" #include "MisleadingIndentationCheck.h"
#include "MisplacedArrayIndexCheck.h" #include "MisplacedArrayIndexCheck.h"
@ -58,8 +58,8 @@ public:
"readability-function-size"); "readability-function-size");
CheckFactories.registerCheck<IdentifierNamingCheck>( CheckFactories.registerCheck<IdentifierNamingCheck>(
"readability-identifier-naming"); "readability-identifier-naming");
CheckFactories.registerCheck<ImplicitBoolCastCheck>( CheckFactories.registerCheck<ImplicitBoolConversionCheck>(
"readability-implicit-bool-cast"); "readability-implicit-bool-conversion");
CheckFactories.registerCheck<InconsistentDeclarationParameterNameCheck>( CheckFactories.registerCheck<InconsistentDeclarationParameterNameCheck>(
"readability-inconsistent-declaration-parameter-name"); "readability-inconsistent-declaration-parameter-name");
CheckFactories.registerCheck<MisleadingIndentationCheck>( CheckFactories.registerCheck<MisleadingIndentationCheck>(

View File

@ -57,7 +57,19 @@ The improvements are...
Improvements to clang-tidy Improvements to clang-tidy
-------------------------- --------------------------
The improvements are... * Renamed checks to use correct term "implicit conversion" instead of "implicit
cast" and modified messages and option names accordingly:
- **performance-implicit-cast-in-loop** was renamed to
`performance-implicit-conversion-in-loop
<http://clang.llvm.org/extra/clang-tidy/checks/performance-implicit-conversion-in-loop.html>`_
- **readability-implicit-bool-cast** was renamed to
`readability-implicit-bool-conversion
<http://clang.llvm.org/extra/clang-tidy/checks/readability-implicit-bool-conversion.html>`_;
the check's options were renamed as follows:
``AllowConditionalIntegerCasts`` -> ``AllowIntegerConditions``,
``AllowConditionalPointerCasts`` -> ``AllowPointerConditions``.
Improvements to include-fixer Improvements to include-fixer
----------------------------- -----------------------------

View File

@ -150,7 +150,7 @@ Clang-Tidy Checks
mpi-type-mismatch mpi-type-mismatch
performance-faster-string-find performance-faster-string-find
performance-for-range-copy performance-for-range-copy
performance-implicit-cast-in-loop performance-implicit-conversion-in-loop
performance-inefficient-string-concatenation performance-inefficient-string-concatenation
performance-inefficient-vector-operation performance-inefficient-vector-operation
performance-type-promotion-in-math-fn performance-type-promotion-in-math-fn
@ -164,7 +164,7 @@ Clang-Tidy Checks
readability-else-after-return readability-else-after-return
readability-function-size readability-function-size
readability-identifier-naming readability-identifier-naming
readability-implicit-bool-cast readability-implicit-bool-conversion
readability-inconsistent-declaration-parameter-name readability-inconsistent-declaration-parameter-name
readability-misleading-indentation readability-misleading-indentation
readability-misplaced-array-index readability-misplaced-array-index

View File

@ -1,21 +1,12 @@
:orphan:
.. title:: clang-tidy - performance-implicit-cast-in-loop .. title:: clang-tidy - performance-implicit-cast-in-loop
.. meta::
:http-equiv=refresh: 5;URL=performance-implicit-conversion-in-loop.html
performance-implicit-cast-in-loop performance-implicit-cast-in-loop
================================= =================================
This warning appears in a range-based loop with a loop variable of const ref This check has been renamed to `performance-implicit-conversion-in-loop
type where the type of the variable does not match the one returned by the <performance-implicit-conversion-in-loop.html>`_.
iterator. This means that an implicit cast has been added, which can for example
result in expensive deep copies.
Example:
.. code-block:: c++
map<int, vector<string>> my_map;
for (const pair<int, vector<string>>& p : my_map) {}
// The iterator type is in fact pair<const int, vector<string>>, which means
// that the compiler added a cast, resulting in a copy of the vectors.
The easiest solution is usually to use ``const auto&`` instead of writing the type
manually.

View File

@ -0,0 +1,21 @@
.. title:: clang-tidy - performance-implicit-conversion-in-loop
performance-implicit-conversion-in-loop
=======================================
This warning appears in a range-based loop with a loop variable of const ref
type where the type of the variable does not match the one returned by the
iterator. This means that an implicit conversion happens, which can for example
result in expensive deep copies.
Example:
.. code-block:: c++
map<int, vector<string>> my_map;
for (const pair<int, vector<string>>& p : my_map) {}
// The iterator type is in fact pair<const int, vector<string>>, which means
// that the compiler added a conversion, resulting in a copy of the vectors.
The easiest solution is usually to use ``const auto&`` instead of writing the
type manually.

View File

@ -1,130 +1,11 @@
:orphan:
.. title:: clang-tidy - readability-implicit-bool-cast .. title:: clang-tidy - readability-implicit-bool-cast
.. meta::
:http-equiv=refresh: 5;URL=readability-implicit-bool-conversion.html
readability-implicit-bool-cast readability-implicit-bool-cast
============================== ==============================
This check can be used to find implicit conversions between built-in types and This check has been renamed to `readability-implicit-bool-conversion
booleans. Depending on use case, it may simply help with readability of the code, <readability-implicit-bool-conversion.html>`_.
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-block:: 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
occurrences of ``bool``, and the remaining code is no longer correct, yet it
still compiles without any visible warnings.
In addition to issuing warnings, fix-it hints are provided to help solve the
reported issues. This can be used for improving readability of code, for
example:
.. code-block:: 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 fix-it 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.
Occurrences of implicit casts inside macros and template instantiations are
deliberately ignored, as it is not clear how to deal with such cases.
Options
-------
.. option:: AllowConditionalIntegerCasts
When non-zero, the check will allow conditional integer casts. Default is
`0`.
.. option:: AllowConditionalPointerCasts
When non-zero, the check will allow conditional pointer casts. Default is `0`.

View File

@ -0,0 +1,132 @@
.. title:: clang-tidy - readability-implicit-bool-conversion
readability-implicit-bool-conversion
====================================
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`` conversion:
.. code-block:: c++
class Foo {
int m_foo;
public:
void setFoo(bool foo) { m_foo = foo; } // warning: implicit conversion bool -> int
int getFoo() { return m_foo; }
};
void use(Foo& foo) {
bool value = foo.getFoo(); // warning: implicit conversion 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
occurrences of ``bool``, and the remaining code is no longer correct, yet it
still compiles without any visible warnings.
In addition to issuing warnings, fix-it hints are provided to help solve the
reported issues. This can be used for improving readability of code, for
example:
.. code-block:: 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 conversion 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 fix-it hints are:
- in case of conversions 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 conversion to bool, the proposed replacement
with comparison is simplified:
- ``if (!pointer)`` is changed to ``if (pointer == nullptr)``,
- in case of conversions from bool to other built-in types, an explicit
``static_cast`` is proposed to make it clear that a conversion is taking
place:
- ``int integer = boolean;`` is changed to
``int integer = static_cast<int>(boolean);``,
- if the conversion 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 conversion to pointer is detected,
- instead of ``nullptr`` literal, ``0`` is proposed as replacement.
Occurrences of implicit conversions inside macros and template instantiations
are deliberately ignored, as it is not clear how to deal with such cases.
Options
-------
.. option:: AllowIntegerConditions
When non-zero, the check will allow conditional integer conversions. Default
is `0`.
.. option:: AllowPointerConditions
When non-zero, the check will allow conditional pointer conversions. Default
is `0`.

View File

@ -1,4 +1,4 @@
// RUN: %check_clang_tidy %s performance-implicit-cast-in-loop %t // RUN: %check_clang_tidy %s performance-implicit-conversion-in-loop %t
// ---------- Classes used in the tests ---------- // ---------- Classes used in the tests ----------
@ -26,8 +26,8 @@ struct View {
T end(); T end();
}; };
// With this class, the implicit cast is a call to the (implicit) constructor of // With this class, the implicit conversion is a call to the (implicit)
// the class. // constructor of the class.
template <typename T> template <typename T>
class ImplicitWrapper { class ImplicitWrapper {
public: public:
@ -35,8 +35,8 @@ class ImplicitWrapper {
ImplicitWrapper(const T& t); ImplicitWrapper(const T& t);
}; };
// With this class, the implicit cast is a call to the conversion operators of // With this class, the implicit conversion is a call to the conversion
// SimpleClass and ComplexClass. // operators of SimpleClass and ComplexClass.
template <typename T> template <typename T>
class OperatorWrapper { class OperatorWrapper {
public: public:
@ -98,7 +98,7 @@ void ComplexClassRefIterator() {
void ImplicitSimpleClassIterator() { void ImplicitSimpleClassIterator() {
for (const ImplicitWrapper<SimpleClass>& foo : SimpleView()) {} for (const ImplicitWrapper<SimpleClass>& foo : SimpleView()) {}
// CHECK-MESSAGES: [[@LINE-1]]:{{[0-9]*}}: warning: the type of the loop variable 'foo' is different from the one returned by the iterator and generates an implicit cast; you can either change the type to the correct one ('const SimpleClass &' but 'const auto&' is always a valid option) or remove the reference to make it explicit that you are creating a new value [performance-implicit-cast-in-loop] // CHECK-MESSAGES: [[@LINE-1]]:{{[0-9]*}}: warning: the type of the loop variable 'foo' is different from the one returned by the iterator and generates an implicit conversion; you can either change the type to the matching one ('const SimpleClass &' but 'const auto&' is always a valid option) or remove the reference to make it explicit that you are creating a new value [performance-implicit-conversion-in-loop]
// for (ImplicitWrapper<SimpleClass>& foo : SimpleView()) {} // for (ImplicitWrapper<SimpleClass>& foo : SimpleView()) {}
for (const ImplicitWrapper<SimpleClass> foo : SimpleView()) {} for (const ImplicitWrapper<SimpleClass> foo : SimpleView()) {}
for (ImplicitWrapper<SimpleClass>foo : SimpleView()) {} for (ImplicitWrapper<SimpleClass>foo : SimpleView()) {}

View File

@ -1,7 +1,7 @@
// RUN: %check_clang_tidy %s readability-implicit-bool-cast %t \ // RUN: %check_clang_tidy %s readability-implicit-bool-conversion %t \
// RUN: -config='{CheckOptions: \ // RUN: -config='{CheckOptions: \
// RUN: [{key: readability-implicit-bool-cast.AllowConditionalIntegerCasts, value: 1}, \ // RUN: [{key: readability-implicit-bool-conversion.AllowIntegerConditions, value: 1}, \
// RUN: {key: readability-implicit-bool-cast.AllowConditionalPointerCasts, value: 1}]}' \ // RUN: {key: readability-implicit-bool-conversion.AllowPointerConditions, value: 1}]}' \
// RUN: -- -std=c++11 // RUN: -- -std=c++11
template<typename T> template<typename T>
@ -15,14 +15,14 @@ struct Struct {
}; };
void regularImplicitCastIntegerToBoolIsNotIgnored() { void regularImplicitConversionIntegerToBoolIsNotIgnored() {
int integer = 0; int integer = 0;
functionTaking<bool>(integer); functionTaking<bool>(integer);
// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit cast 'int' -> bool [readability-implicit-bool-cast] // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'int' -> bool [readability-implicit-bool-conversion]
// CHECK-FIXES: functionTaking<bool>(integer != 0); // CHECK-FIXES: functionTaking<bool>(integer != 0);
} }
void implicitCastIntegerToBoolInConditionalsIsAllowed() { void implicitConversionIntegerToBoolInConditionalsIsAllowed() {
if (functionReturningInt()) {} if (functionReturningInt()) {}
if (!functionReturningInt()) {} if (!functionReturningInt()) {}
if (functionReturningInt() && functionReturningPointer()) {} if (functionReturningInt() && functionReturningPointer()) {}
@ -40,19 +40,19 @@ void implicitCastIntegerToBoolInConditionalsIsAllowed() {
int *p1 = functionReturningPointer() ?: &value3; int *p1 = functionReturningPointer() ?: &value3;
} }
void regularImplicitCastPointerToBoolIsNotIgnored() { void regularImplicitConversionPointerToBoolIsNotIgnored() {
int* pointer = nullptr; int* pointer = nullptr;
functionTaking<bool>(pointer); functionTaking<bool>(pointer);
// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit cast 'int *' -> bool // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'int *' -> bool
// CHECK-FIXES: functionTaking<bool>(pointer != nullptr); // CHECK-FIXES: functionTaking<bool>(pointer != nullptr);
int Struct::* memberPointer = &Struct::member; int Struct::* memberPointer = &Struct::member;
functionTaking<bool>(memberPointer); functionTaking<bool>(memberPointer);
// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit cast 'int Struct::*' -> bool // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'int Struct::*' -> bool
// CHECK-FIXES: functionTaking<bool>(memberPointer != nullptr); // CHECK-FIXES: functionTaking<bool>(memberPointer != nullptr);
} }
void implicitCastPointerToBoolInConditionalsIsAllowed() { void implicitConversionPointerToBoolInConditionalsIsAllowed() {
if (functionReturningPointer()) {} if (functionReturningPointer()) {}
if (not functionReturningPointer()) {} if (not functionReturningPointer()) {}
int value1 = functionReturningPointer() ? 1 : 2; int value1 = functionReturningPointer() ? 1 : 2;

View File

@ -1,4 +1,4 @@
// RUN: %check_clang_tidy %s readability-implicit-bool-cast %t -- -- -std=c++98 // RUN: %check_clang_tidy %s readability-implicit-bool-conversion %t -- -- -std=c++98
// We need NULL macro, but some buildbots don't like including <cstddef> header // We need NULL macro, but some buildbots don't like including <cstddef> header
// This is a portable way of getting it to work // This is a portable way of getting it to work
@ -15,31 +15,31 @@ struct Struct {
void useOldNullMacroInReplacements() { void useOldNullMacroInReplacements() {
int* pointer = NULL; int* pointer = NULL;
functionTaking<bool>(pointer); functionTaking<bool>(pointer);
// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit cast 'int *' -> bool [readability-implicit-bool-cast] // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'int *' -> bool [readability-implicit-bool-conversion]
// CHECK-FIXES: functionTaking<bool>(pointer != 0); // CHECK-FIXES: functionTaking<bool>(pointer != 0);
int Struct::* memberPointer = NULL; int Struct::* memberPointer = NULL;
functionTaking<bool>(!memberPointer); functionTaking<bool>(!memberPointer);
// CHECK-MESSAGES: :[[@LINE-1]]:25: warning: implicit cast 'int Struct::*' -> bool // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: implicit conversion 'int Struct::*' -> bool
// CHECK-FIXES: functionTaking<bool>(memberPointer == 0); // CHECK-FIXES: functionTaking<bool>(memberPointer == 0);
} }
void fixFalseLiteralConvertingToNullPointer() { void fixFalseLiteralConvertingToNullPointer() {
functionTaking<int*>(false); functionTaking<int*>(false);
// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit cast bool -> 'int *' // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion bool -> 'int *'
// CHECK-FIXES: functionTaking<int*>(0); // CHECK-FIXES: functionTaking<int*>(0);
int* pointer = NULL; int* pointer = NULL;
if (pointer == false) {} if (pointer == false) {}
// CHECK-MESSAGES: :[[@LINE-1]]:18: warning: implicit cast bool -> 'int *' // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: implicit conversion bool -> 'int *'
// CHECK-FIXES: if (pointer == 0) {} // CHECK-FIXES: if (pointer == 0) {}
functionTaking<int Struct::*>(false); functionTaking<int Struct::*>(false);
// CHECK-MESSAGES: :[[@LINE-1]]:33: warning: implicit cast bool -> 'int Struct::*' // CHECK-MESSAGES: :[[@LINE-1]]:33: warning: implicit conversion bool -> 'int Struct::*'
// CHECK-FIXES: functionTaking<int Struct::*>(0); // CHECK-FIXES: functionTaking<int Struct::*>(0);
int Struct::* memberPointer = NULL; int Struct::* memberPointer = NULL;
if (memberPointer != false) {} if (memberPointer != false) {}
// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit cast bool -> 'int Struct::*' // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion bool -> 'int Struct::*'
// CHECK-FIXES: if (memberPointer != 0) {} // CHECK-FIXES: if (memberPointer != 0) {}
} }

View File

@ -1,4 +1,4 @@
// RUN: %check_clang_tidy %s readability-implicit-bool-cast %t // RUN: %check_clang_tidy %s readability-implicit-bool-conversion %t
// We need NULL macro, but some buildbots don't like including <cstddef> header // We need NULL macro, but some buildbots don't like including <cstddef> header
// This is a portable way of getting it to work // This is a portable way of getting it to work
@ -13,42 +13,42 @@ struct Struct {
}; };
////////// Implicit cast from bool. ////////// Implicit conversion from bool.
void implicitCastFromBoolSimpleCases() { void implicitConversionFromBoolSimpleCases() {
bool boolean = true; bool boolean = true;
functionTaking<bool>(boolean); functionTaking<bool>(boolean);
functionTaking<int>(boolean); functionTaking<int>(boolean);
// CHECK-MESSAGES: :[[@LINE-1]]:23: warning: implicit cast bool -> 'int' [readability-implicit-bool-cast] // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: implicit conversion bool -> 'int' [readability-implicit-bool-conversion]
// CHECK-FIXES: functionTaking<int>(static_cast<int>(boolean)); // CHECK-FIXES: functionTaking<int>(static_cast<int>(boolean));
functionTaking<unsigned long>(boolean); functionTaking<unsigned long>(boolean);
// CHECK-MESSAGES: :[[@LINE-1]]:33: warning: implicit cast bool -> 'unsigned long' // CHECK-MESSAGES: :[[@LINE-1]]:33: warning: implicit conversion bool -> 'unsigned long'
// CHECK-FIXES: functionTaking<unsigned long>(static_cast<unsigned long>(boolean)); // CHECK-FIXES: functionTaking<unsigned long>(static_cast<unsigned long>(boolean));
functionTaking<char>(boolean); functionTaking<char>(boolean);
// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit cast bool -> 'char' // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion bool -> 'char'
// CHECK-FIXES: functionTaking<char>(static_cast<char>(boolean)); // CHECK-FIXES: functionTaking<char>(static_cast<char>(boolean));
functionTaking<float>(boolean); functionTaking<float>(boolean);
// CHECK-MESSAGES: :[[@LINE-1]]:25: warning: implicit cast bool -> 'float' // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: implicit conversion bool -> 'float'
// CHECK-FIXES: functionTaking<float>(static_cast<float>(boolean)); // CHECK-FIXES: functionTaking<float>(static_cast<float>(boolean));
functionTaking<double>(boolean); functionTaking<double>(boolean);
// CHECK-MESSAGES: :[[@LINE-1]]:26: warning: implicit cast bool -> 'double' // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: implicit conversion bool -> 'double'
// CHECK-FIXES: functionTaking<double>(static_cast<double>(boolean)); // CHECK-FIXES: functionTaking<double>(static_cast<double>(boolean));
} }
float implicitCastFromBoolInReturnValue() { float implicitConversionFromBoolInReturnValue() {
bool boolean = false; bool boolean = false;
return boolean; return boolean;
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: implicit cast bool -> 'float' // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: implicit conversion bool -> 'float'
// CHECK-FIXES: return static_cast<float>(boolean); // CHECK-FIXES: return static_cast<float>(boolean);
} }
void implicitCastFromBoolInSingleBoolExpressions(bool b1, bool b2) { void implicitConversionFromBoolInSingleBoolExpressions(bool b1, bool b2) {
bool boolean = true; bool boolean = true;
boolean = b1 ^ b2; boolean = b1 ^ b2;
boolean = b1 && b2; boolean = b1 && b2;
@ -58,71 +58,71 @@ void implicitCastFromBoolInSingleBoolExpressions(bool b1, bool b2) {
boolean = b2 != false; boolean = b2 != false;
int integer = boolean - 3; int integer = boolean - 3;
// CHECK-MESSAGES: :[[@LINE-1]]:17: warning: implicit cast bool -> 'int' // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: implicit conversion bool -> 'int'
// CHECK-FIXES: int integer = static_cast<int>(boolean) - 3; // CHECK-FIXES: int integer = static_cast<int>(boolean) - 3;
float floating = boolean / 0.3f; float floating = boolean / 0.3f;
// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: implicit cast bool -> 'float' // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: implicit conversion bool -> 'float'
// CHECK-FIXES: float floating = static_cast<float>(boolean) / 0.3f; // CHECK-FIXES: float floating = static_cast<float>(boolean) / 0.3f;
char character = boolean; char character = boolean;
// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: implicit cast bool -> 'char' // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: implicit conversion bool -> 'char'
// CHECK-FIXES: char character = static_cast<char>(boolean); // CHECK-FIXES: char character = static_cast<char>(boolean);
} }
void implicitCastFromBoollInComplexBoolExpressions() { void implicitConversionFromBoollInComplexBoolExpressions() {
bool boolean = true; bool boolean = true;
bool anotherBoolean = false; bool anotherBoolean = false;
int integer = boolean && anotherBoolean; int integer = boolean && anotherBoolean;
// CHECK-MESSAGES: :[[@LINE-1]]:17: warning: implicit cast bool -> 'int' // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: implicit conversion bool -> 'int'
// CHECK-FIXES: int integer = static_cast<int>(boolean && anotherBoolean); // CHECK-FIXES: int integer = static_cast<int>(boolean && anotherBoolean);
unsigned long unsignedLong = (! boolean) + 4ul; unsigned long unsignedLong = (! boolean) + 4ul;
// CHECK-MESSAGES: :[[@LINE-1]]:32: warning: implicit cast bool -> 'unsigned long' // CHECK-MESSAGES: :[[@LINE-1]]:32: warning: implicit conversion bool -> 'unsigned long'
// CHECK-FIXES: unsigned long unsignedLong = static_cast<unsigned long>(! boolean) + 4ul; // CHECK-FIXES: unsigned long unsignedLong = static_cast<unsigned long>(! boolean) + 4ul;
float floating = (boolean || anotherBoolean) * 0.3f; float floating = (boolean || anotherBoolean) * 0.3f;
// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: implicit cast bool -> 'float' // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: implicit conversion bool -> 'float'
// CHECK-FIXES: float floating = static_cast<float>(boolean || anotherBoolean) * 0.3f; // CHECK-FIXES: float floating = static_cast<float>(boolean || anotherBoolean) * 0.3f;
double doubleFloating = (boolean && (anotherBoolean || boolean)) * 0.3; double doubleFloating = (boolean && (anotherBoolean || boolean)) * 0.3;
// CHECK-MESSAGES: :[[@LINE-1]]:27: warning: implicit cast bool -> 'double' // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: implicit conversion bool -> 'double'
// CHECK-FIXES: double doubleFloating = static_cast<double>(boolean && (anotherBoolean || boolean)) * 0.3; // CHECK-FIXES: double doubleFloating = static_cast<double>(boolean && (anotherBoolean || boolean)) * 0.3;
} }
void implicitCastFromBoolLiterals() { void implicitConversionFromBoolLiterals() {
functionTaking<int>(true); functionTaking<int>(true);
// CHECK-MESSAGES: :[[@LINE-1]]:23: warning: implicit cast bool -> 'int' // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: implicit conversion bool -> 'int'
// CHECK-FIXES: functionTaking<int>(1); // CHECK-FIXES: functionTaking<int>(1);
functionTaking<unsigned long>(false); functionTaking<unsigned long>(false);
// CHECK-MESSAGES: :[[@LINE-1]]:33: warning: implicit cast bool -> 'unsigned long' // CHECK-MESSAGES: :[[@LINE-1]]:33: warning: implicit conversion bool -> 'unsigned long'
// CHECK-FIXES: functionTaking<unsigned long>(0u); // CHECK-FIXES: functionTaking<unsigned long>(0u);
functionTaking<signed char>(true); functionTaking<signed char>(true);
// CHECK-MESSAGES: :[[@LINE-1]]:31: warning: implicit cast bool -> 'signed char' // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: implicit conversion bool -> 'signed char'
// CHECK-FIXES: functionTaking<signed char>(1); // CHECK-FIXES: functionTaking<signed char>(1);
functionTaking<float>(false); functionTaking<float>(false);
// CHECK-MESSAGES: :[[@LINE-1]]:25: warning: implicit cast bool -> 'float' // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: implicit conversion bool -> 'float'
// CHECK-FIXES: functionTaking<float>(0.0f); // CHECK-FIXES: functionTaking<float>(0.0f);
functionTaking<double>(true); functionTaking<double>(true);
// CHECK-MESSAGES: :[[@LINE-1]]:26: warning: implicit cast bool -> 'double' // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: implicit conversion bool -> 'double'
// CHECK-FIXES: functionTaking<double>(1.0); // CHECK-FIXES: functionTaking<double>(1.0);
} }
void implicitCastFromBoolInComparisons() { void implicitConversionFromBoolInComparisons() {
bool boolean = true; bool boolean = true;
int integer = 0; int integer = 0;
functionTaking<bool>(boolean == integer); functionTaking<bool>(boolean == integer);
// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit cast bool -> 'int' // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion bool -> 'int'
// CHECK-FIXES: functionTaking<bool>(static_cast<int>(boolean) == integer); // CHECK-FIXES: functionTaking<bool>(static_cast<int>(boolean) == integer);
functionTaking<bool>(integer != boolean); functionTaking<bool>(integer != boolean);
// CHECK-MESSAGES: :[[@LINE-1]]:35: warning: implicit cast bool -> 'int' // CHECK-MESSAGES: :[[@LINE-1]]:35: warning: implicit conversion bool -> 'int'
// CHECK-FIXES: functionTaking<bool>(integer != static_cast<int>(boolean)); // CHECK-FIXES: functionTaking<bool>(integer != static_cast<int>(boolean));
} }
@ -142,7 +142,7 @@ void ignoreExplicitCastsFromBool() {
char character = static_cast<char>(boolean); char character = static_cast<char>(boolean);
} }
void ignoreImplicitCastFromBoolInMacroExpansions() { void ignoreImplicitConversionFromBoolInMacroExpansions() {
bool boolean = true; bool boolean = true;
#define CAST_FROM_BOOL_IN_MACRO_BODY boolean + 3 #define CAST_FROM_BOOL_IN_MACRO_BODY boolean + 3
@ -152,7 +152,7 @@ void ignoreImplicitCastFromBoolInMacroExpansions() {
int integerFromMacroArgument = CAST_FROM_BOOL_IN_MACRO_ARGUMENT(boolean); int integerFromMacroArgument = CAST_FROM_BOOL_IN_MACRO_ARGUMENT(boolean);
} }
namespace ignoreImplicitCastFromBoolInTemplateInstantiations { namespace ignoreImplicitConversionFromBoolInTemplateInstantiations {
template<typename T> template<typename T>
void templateFunction() { void templateFunction() {
@ -164,204 +164,204 @@ void useOfTemplateFunction() {
templateFunction<int>(); templateFunction<int>();
} }
} // namespace ignoreImplicitCastFromBoolInTemplateInstantiations } // namespace ignoreImplicitConversionFromBoolInTemplateInstantiations
////////// Implicit cast to bool. ////////// Implicit conversions to bool.
void implicitCastToBoolSimpleCases() { void implicitConversionToBoolSimpleCases() {
int integer = 10; int integer = 10;
functionTaking<bool>(integer); functionTaking<bool>(integer);
// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit cast 'int' -> bool // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'int' -> bool
// CHECK-FIXES: functionTaking<bool>(integer != 0); // CHECK-FIXES: functionTaking<bool>(integer != 0);
unsigned long unsignedLong = 10; unsigned long unsignedLong = 10;
functionTaking<bool>(unsignedLong); functionTaking<bool>(unsignedLong);
// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit cast 'unsigned long' -> bool // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'unsigned long' -> bool
// CHECK-FIXES: functionTaking<bool>(unsignedLong != 0u); // CHECK-FIXES: functionTaking<bool>(unsignedLong != 0u);
float floating = 0.0f; float floating = 0.0f;
functionTaking<bool>(floating); functionTaking<bool>(floating);
// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit cast 'float' -> bool // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'float' -> bool
// CHECK-FIXES: functionTaking<bool>(floating != 0.0f); // CHECK-FIXES: functionTaking<bool>(floating != 0.0f);
double doubleFloating = 1.0f; double doubleFloating = 1.0f;
functionTaking<bool>(doubleFloating); functionTaking<bool>(doubleFloating);
// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit cast 'double' -> bool // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'double' -> bool
// CHECK-FIXES: functionTaking<bool>(doubleFloating != 0.0); // CHECK-FIXES: functionTaking<bool>(doubleFloating != 0.0);
signed char character = 'a'; signed char character = 'a';
functionTaking<bool>(character); functionTaking<bool>(character);
// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit cast 'signed char' -> bool // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'signed char' -> bool
// CHECK-FIXES: functionTaking<bool>(character != 0); // CHECK-FIXES: functionTaking<bool>(character != 0);
int* pointer = nullptr; int* pointer = nullptr;
functionTaking<bool>(pointer); functionTaking<bool>(pointer);
// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit cast 'int *' -> bool // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'int *' -> bool
// CHECK-FIXES: functionTaking<bool>(pointer != nullptr); // CHECK-FIXES: functionTaking<bool>(pointer != nullptr);
auto pointerToMember = &Struct::member; auto pointerToMember = &Struct::member;
functionTaking<bool>(pointerToMember); functionTaking<bool>(pointerToMember);
// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit cast 'int Struct::*' -> bool // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'int Struct::*' -> bool
// CHECK-FIXES: functionTaking<bool>(pointerToMember != nullptr); // CHECK-FIXES: functionTaking<bool>(pointerToMember != nullptr);
} }
void implicitCastToBoolInSingleExpressions() { void implicitConversionToBoolInSingleExpressions() {
int integer = 10; int integer = 10;
bool boolComingFromInt = integer; bool boolComingFromInt = integer;
// CHECK-MESSAGES: :[[@LINE-1]]:28: warning: implicit cast 'int' -> bool // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: implicit conversion 'int' -> bool
// CHECK-FIXES: bool boolComingFromInt = integer != 0; // CHECK-FIXES: bool boolComingFromInt = integer != 0;
float floating = 10.0f; float floating = 10.0f;
bool boolComingFromFloat = floating; bool boolComingFromFloat = floating;
// CHECK-MESSAGES: :[[@LINE-1]]:30: warning: implicit cast 'float' -> bool // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: implicit conversion 'float' -> bool
// CHECK-FIXES: bool boolComingFromFloat = floating != 0.0f; // CHECK-FIXES: bool boolComingFromFloat = floating != 0.0f;
signed char character = 'a'; signed char character = 'a';
bool boolComingFromChar = character; bool boolComingFromChar = character;
// CHECK-MESSAGES: :[[@LINE-1]]:29: warning: implicit cast 'signed char' -> bool // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: implicit conversion 'signed char' -> bool
// CHECK-FIXES: bool boolComingFromChar = character != 0; // CHECK-FIXES: bool boolComingFromChar = character != 0;
int* pointer = nullptr; int* pointer = nullptr;
bool boolComingFromPointer = pointer; bool boolComingFromPointer = pointer;
// CHECK-MESSAGES: :[[@LINE-1]]:32: warning: implicit cast 'int *' -> bool // CHECK-MESSAGES: :[[@LINE-1]]:32: warning: implicit conversion 'int *' -> bool
// CHECK-FIXES: bool boolComingFromPointer = pointer != nullptr; // CHECK-FIXES: bool boolComingFromPointer = pointer != nullptr;
} }
void implicitCastToBoolInComplexExpressions() { void implicitConversionToBoolInComplexExpressions() {
bool boolean = true; bool boolean = true;
int integer = 10; int integer = 10;
int anotherInteger = 20; int anotherInteger = 20;
bool boolComingFromInteger = integer + anotherInteger; bool boolComingFromInteger = integer + anotherInteger;
// CHECK-MESSAGES: :[[@LINE-1]]:32: warning: implicit cast 'int' -> bool // CHECK-MESSAGES: :[[@LINE-1]]:32: warning: implicit conversion 'int' -> bool
// CHECK-FIXES: bool boolComingFromInteger = (integer + anotherInteger) != 0; // CHECK-FIXES: bool boolComingFromInteger = (integer + anotherInteger) != 0;
float floating = 0.2f; float floating = 0.2f;
bool boolComingFromFloating = floating - 0.3f || boolean; bool boolComingFromFloating = floating - 0.3f || boolean;
// CHECK-MESSAGES: :[[@LINE-1]]:33: warning: implicit cast 'float' -> bool // CHECK-MESSAGES: :[[@LINE-1]]:33: warning: implicit conversion 'float' -> bool
// CHECK-FIXES: bool boolComingFromFloating = ((floating - 0.3f) != 0.0f) || boolean; // CHECK-FIXES: bool boolComingFromFloating = ((floating - 0.3f) != 0.0f) || boolean;
double doubleFloating = 0.3; double doubleFloating = 0.3;
bool boolComingFromDoubleFloating = (doubleFloating - 0.4) && boolean; bool boolComingFromDoubleFloating = (doubleFloating - 0.4) && boolean;
// CHECK-MESSAGES: :[[@LINE-1]]:39: warning: implicit cast 'double' -> bool // CHECK-MESSAGES: :[[@LINE-1]]:39: warning: implicit conversion 'double' -> bool
// CHECK-FIXES: bool boolComingFromDoubleFloating = ((doubleFloating - 0.4) != 0.0) && boolean; // CHECK-FIXES: bool boolComingFromDoubleFloating = ((doubleFloating - 0.4) != 0.0) && boolean;
} }
void implicitCastInNegationExpressions() { void implicitConversionInNegationExpressions() {
int integer = 10; int integer = 10;
bool boolComingFromNegatedInt = !integer; bool boolComingFromNegatedInt = !integer;
// CHECK-MESSAGES: :[[@LINE-1]]:36: warning: implicit cast 'int' -> bool // CHECK-MESSAGES: :[[@LINE-1]]:36: warning: implicit conversion 'int' -> bool
// CHECK-FIXES: bool boolComingFromNegatedInt = integer == 0; // CHECK-FIXES: bool boolComingFromNegatedInt = integer == 0;
float floating = 10.0f; float floating = 10.0f;
bool boolComingFromNegatedFloat = ! floating; bool boolComingFromNegatedFloat = ! floating;
// CHECK-MESSAGES: :[[@LINE-1]]:39: warning: implicit cast 'float' -> bool // CHECK-MESSAGES: :[[@LINE-1]]:39: warning: implicit conversion 'float' -> bool
// CHECK-FIXES: bool boolComingFromNegatedFloat = floating == 0.0f; // CHECK-FIXES: bool boolComingFromNegatedFloat = floating == 0.0f;
signed char character = 'a'; signed char character = 'a';
bool boolComingFromNegatedChar = (! character); bool boolComingFromNegatedChar = (! character);
// CHECK-MESSAGES: :[[@LINE-1]]:39: warning: implicit cast 'signed char' -> bool // CHECK-MESSAGES: :[[@LINE-1]]:39: warning: implicit conversion 'signed char' -> bool
// CHECK-FIXES: bool boolComingFromNegatedChar = (character == 0); // CHECK-FIXES: bool boolComingFromNegatedChar = (character == 0);
int* pointer = nullptr; int* pointer = nullptr;
bool boolComingFromNegatedPointer = not pointer; bool boolComingFromNegatedPointer = not pointer;
// CHECK-MESSAGES: :[[@LINE-1]]:43: warning: implicit cast 'int *' -> bool // CHECK-MESSAGES: :[[@LINE-1]]:43: warning: implicit conversion 'int *' -> bool
// CHECK-FIXES: bool boolComingFromNegatedPointer = pointer == nullptr; // CHECK-FIXES: bool boolComingFromNegatedPointer = pointer == nullptr;
} }
void implicitCastToBoolInControlStatements() { void implicitConversionToBoolInControlStatements() {
int integer = 10; int integer = 10;
if (integer) {} if (integer) {}
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: implicit cast 'int' -> bool // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: implicit conversion 'int' -> bool
// CHECK-FIXES: if (integer != 0) {} // CHECK-FIXES: if (integer != 0) {}
long int longInteger = 0.2f; long int longInteger = 0.2f;
for (;longInteger;) {} for (;longInteger;) {}
// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: implicit cast 'long' -> bool // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: implicit conversion 'long' -> bool
// CHECK-FIXES: for (;longInteger != 0;) {} // CHECK-FIXES: for (;longInteger != 0;) {}
float floating = 0.3f; float floating = 0.3f;
while (floating) {} while (floating) {}
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: implicit cast 'float' -> bool // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: implicit conversion 'float' -> bool
// CHECK-FIXES: while (floating != 0.0f) {} // CHECK-FIXES: while (floating != 0.0f) {}
double doubleFloating = 0.4; double doubleFloating = 0.4;
do {} while (doubleFloating); do {} while (doubleFloating);
// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: implicit cast 'double' -> bool // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: implicit conversion 'double' -> bool
// CHECK-FIXES: do {} while (doubleFloating != 0.0); // CHECK-FIXES: do {} while (doubleFloating != 0.0);
} }
bool implicitCastToBoolInReturnValue() { bool implicitConversionToBoolInReturnValue() {
float floating = 1.0f; float floating = 1.0f;
return floating; return floating;
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: implicit cast 'float' -> bool // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: implicit conversion 'float' -> bool
// CHECK-FIXES: return floating != 0.0f; // CHECK-FIXES: return floating != 0.0f;
} }
void implicitCastToBoolFromLiterals() { void implicitConversionToBoolFromLiterals() {
functionTaking<bool>(0); functionTaking<bool>(0);
// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit cast 'int' -> bool // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'int' -> bool
// CHECK-FIXES: functionTaking<bool>(false); // CHECK-FIXES: functionTaking<bool>(false);
functionTaking<bool>(1); functionTaking<bool>(1);
// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit cast 'int' -> bool // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'int' -> bool
// CHECK-FIXES: functionTaking<bool>(true); // CHECK-FIXES: functionTaking<bool>(true);
functionTaking<bool>(2ul); functionTaking<bool>(2ul);
// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit cast 'unsigned long' -> bool // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'unsigned long' -> bool
// CHECK-FIXES: functionTaking<bool>(true); // CHECK-FIXES: functionTaking<bool>(true);
functionTaking<bool>(0.0f); functionTaking<bool>(0.0f);
// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit cast 'float' -> bool // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'float' -> bool
// CHECK-FIXES: functionTaking<bool>(false); // CHECK-FIXES: functionTaking<bool>(false);
functionTaking<bool>(1.0f); functionTaking<bool>(1.0f);
// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit cast 'float' -> bool // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'float' -> bool
// CHECK-FIXES: functionTaking<bool>(true); // CHECK-FIXES: functionTaking<bool>(true);
functionTaking<bool>(2.0); functionTaking<bool>(2.0);
// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit cast 'double' -> bool // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'double' -> bool
// CHECK-FIXES: functionTaking<bool>(true); // CHECK-FIXES: functionTaking<bool>(true);
functionTaking<bool>('\0'); functionTaking<bool>('\0');
// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit cast 'char' -> bool // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'char' -> bool
// CHECK-FIXES: functionTaking<bool>(false); // CHECK-FIXES: functionTaking<bool>(false);
functionTaking<bool>('a'); functionTaking<bool>('a');
// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit cast 'char' -> bool // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'char' -> bool
// CHECK-FIXES: functionTaking<bool>(true); // CHECK-FIXES: functionTaking<bool>(true);
functionTaking<bool>(""); functionTaking<bool>("");
// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit cast 'const char *' -> bool // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'const char *' -> bool
// CHECK-FIXES: functionTaking<bool>(true); // CHECK-FIXES: functionTaking<bool>(true);
functionTaking<bool>("abc"); functionTaking<bool>("abc");
// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit cast 'const char *' -> bool // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'const char *' -> bool
// CHECK-FIXES: functionTaking<bool>(true); // CHECK-FIXES: functionTaking<bool>(true);
functionTaking<bool>(NULL); functionTaking<bool>(NULL);
// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit cast 'long' -> bool // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'long' -> bool
// CHECK-FIXES: functionTaking<bool>(false); // CHECK-FIXES: functionTaking<bool>(false);
} }
void implicitCastToBoolFromUnaryMinusAndZeroLiterals() { void implicitConversionToBoolFromUnaryMinusAndZeroLiterals() {
functionTaking<bool>(-0); functionTaking<bool>(-0);
// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit cast 'int' -> bool // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'int' -> bool
// CHECK-FIXES: functionTaking<bool>((-0) != 0); // CHECK-FIXES: functionTaking<bool>((-0) != 0);
functionTaking<bool>(-0.0f); functionTaking<bool>(-0.0f);
// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit cast 'float' -> bool // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'float' -> bool
// CHECK-FIXES: functionTaking<bool>((-0.0f) != 0.0f); // CHECK-FIXES: functionTaking<bool>((-0.0f) != 0.0f);
functionTaking<bool>(-0.0); functionTaking<bool>(-0.0);
// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit cast 'double' -> bool // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'double' -> bool
// CHECK-FIXES: functionTaking<bool>((-0.0) != 0.0); // CHECK-FIXES: functionTaking<bool>((-0.0) != 0.0);
} }
void implicitCastToBoolInWithOverloadedOperators() { void implicitConversionToBoolInWithOverloadedOperators() {
struct UserStruct { struct UserStruct {
int operator()(int x) { return x; } int operator()(int x) { return x; }
int operator+(int y) { return y; } int operator+(int y) { return y; }
@ -370,18 +370,18 @@ void implicitCastToBoolInWithOverloadedOperators() {
UserStruct s; UserStruct s;
functionTaking<bool>(s(0)); functionTaking<bool>(s(0));
// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit cast 'int' -> bool // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'int' -> bool
// CHECK-FIXES: functionTaking<bool>(s(0) != 0); // CHECK-FIXES: functionTaking<bool>(s(0) != 0);
functionTaking<bool>(s + 2); functionTaking<bool>(s + 2);
// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit cast 'int' -> bool // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'int' -> bool
// CHECK-FIXES: functionTaking<bool>((s + 2) != 0); // CHECK-FIXES: functionTaking<bool>((s + 2) != 0);
} }
int functionReturningInt(); int functionReturningInt();
int* functionReturningPointer(); int* functionReturningPointer();
void ignoreImplicitCastToBoolWhenDeclaringVariableInControlStatements() { void ignoreImplicitConversionToBoolWhenDeclaringVariableInControlStatements() {
if (int integer = functionReturningInt()) {} if (int integer = functionReturningInt()) {}
while (int* pointer = functionReturningPointer()) {} while (int* pointer = functionReturningPointer()) {}
@ -401,7 +401,7 @@ void ignoreExplicitCastsToBool() {
bool booleanComingFromPointer = static_cast<bool>(pointer); bool booleanComingFromPointer = static_cast<bool>(pointer);
} }
void ignoreImplicitCastToBoolInMacroExpansions() { void ignoreImplicitConversionToBoolInMacroExpansions() {
int integer = 3; int integer = 3;
#define CAST_TO_BOOL_IN_MACRO_BODY integer && false #define CAST_TO_BOOL_IN_MACRO_BODY integer && false
@ -411,7 +411,7 @@ void ignoreImplicitCastToBoolInMacroExpansions() {
bool boolFromMacroArgument = CAST_TO_BOOL_IN_MACRO_ARGUMENT(integer); bool boolFromMacroArgument = CAST_TO_BOOL_IN_MACRO_ARGUMENT(integer);
} }
namespace ignoreImplicitCastToBoolInTemplateInstantiations { namespace ignoreImplicitConversionToBoolInTemplateInstantiations {
template<typename T> template<typename T>
void templateFunction() { void templateFunction() {
@ -423,7 +423,7 @@ void useOfTemplateFunction() {
templateFunction<int>(); templateFunction<int>();
} }
} // namespace ignoreImplicitCastToBoolInTemplateInstantiations } // namespace ignoreImplicitConversionToBoolInTemplateInstantiations
namespace ignoreUserDefinedConversionOperator { namespace ignoreUserDefinedConversionOperator {