Index: clang-tidy/modernize/BoolToIntegerConversionCheck.h =================================================================== --- /dev/null +++ clang-tidy/modernize/BoolToIntegerConversionCheck.h @@ -0,0 +1,36 @@ +//===--- BoolToIntegerConversionCheck.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_MODERNIZE_BOOL_TO_INTEGER_CONVERSION_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_BOOL_TO_INTEGER_CONVERSION_H + +#include "../ClangTidy.h" + +namespace clang { +namespace tidy { +namespace modernize { + +/// Finds implicit casts of bool literal to integer types like int a = true, +/// and replaces it with integer literals like int a = 1 +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/modernize-bool-to-integer-conversion.html +class BoolToIntegerConversionCheck : public ClangTidyCheck { +public: + BoolToIntegerConversionCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; +}; + +} // namespace modernize +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_BOOL_TO_INTEGER_CONVERSION_H Index: clang-tidy/modernize/BoolToIntegerConversionCheck.cpp =================================================================== --- /dev/null +++ clang-tidy/modernize/BoolToIntegerConversionCheck.cpp @@ -0,0 +1,69 @@ +//===--- BoolToIntegerConversionCheck.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 "BoolToIntegerConversionCheck.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 modernize { + +AST_MATCHER(FieldDecl, isOneBitBitField) { + return Node.isBitField() && + Node.getBitWidthValue(Finder->getASTContext()) == 1; +} + +void BoolToIntegerConversionCheck::registerMatchers(MatchFinder *Finder) { + if (!getLangOpts().CPlusPlus) + return; + + auto convertingToOneBitBitfield = hasParent(binaryOperator(hasLHS(memberExpr( + hasDeclaration(fieldDecl(isOneBitBitField()).bind("bitfield")))))); + + Finder->addMatcher( + implicitCastExpr(has(cxxBoolLiteral().bind("bool_literal")), + unless(convertingToOneBitBitfield)) + .bind("cast"), + this); +} + +void BoolToIntegerConversionCheck::check( + const MatchFinder::MatchResult &Result) { + + const auto *Bitfield = Result.Nodes.getNodeAs("bitfield"); + + if (Bitfield && Bitfield->getBitWidthValue(*Result.Context) == 1) + return; + + const auto *BoolLiteral = + Result.Nodes.getNodeAs("bool_literal"); + const auto *Cast = Result.Nodes.getNodeAs("cast"); + const auto Type = Cast->getType().getLocalUnqualifiedType(); + auto Location = BoolLiteral->getLocation(); + + auto Diag = diag(Location, + "implicitly converting bool literal to %0%select{| inside a " + "macro}1; use integer literal instead") + << Type; + + if (Location.isMacroID()) + Diag << 1; + else + Diag << 0 + << FixItHint::CreateReplacement(BoolLiteral->getSourceRange(), + BoolLiteral->getValue() ? "1" : "0"); +} + +} // namespace modernize +} // namespace tidy +} // namespace clang Index: clang-tidy/modernize/CMakeLists.txt =================================================================== --- clang-tidy/modernize/CMakeLists.txt +++ clang-tidy/modernize/CMakeLists.txt @@ -1,6 +1,7 @@ set(LLVM_LINK_COMPONENTS support) add_clang_library(clangTidyModernizeModule + BoolToIntegerConversionCheck.cpp DeprecatedHeadersCheck.cpp LoopConvertCheck.cpp LoopConvertUtils.cpp Index: clang-tidy/modernize/ModernizeTidyModule.cpp =================================================================== --- clang-tidy/modernize/ModernizeTidyModule.cpp +++ clang-tidy/modernize/ModernizeTidyModule.cpp @@ -10,6 +10,7 @@ #include "../ClangTidy.h" #include "../ClangTidyModule.h" #include "../ClangTidyModuleRegistry.h" +#include "BoolToIntegerConversionCheck.h" #include "DeprecatedHeadersCheck.h" #include "LoopConvertCheck.h" #include "MakeUniqueCheck.h" @@ -32,6 +33,8 @@ class ModernizeModule : public ClangTidyModule { public: void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override { + CheckFactories.registerCheck( + "modernize-bool-to-integer-conversion"); CheckFactories.registerCheck( "modernize-deprecated-headers"); CheckFactories.registerCheck("modernize-loop-convert"); Index: docs/ReleaseNotes.rst =================================================================== --- docs/ReleaseNotes.rst +++ docs/ReleaseNotes.rst @@ -113,6 +113,11 @@ Replaces C standard library headers with their C++ alternatives. +- New `modernize-bool-to-integer-conversion + `_ check + + Replaces bool literals which are being implicitly cast to integers with integer literals. + - New `modernize-raw-string-literal `_ check Index: docs/clang-tidy/checks/list.rst =================================================================== --- docs/clang-tidy/checks/list.rst +++ docs/clang-tidy/checks/list.rst @@ -31,9 +31,9 @@ google-build-using-namespace google-explicit-constructor google-global-names-in-headers - google-readability-braces-around-statements (redirects to readability-braces-around-statements) + google-readability-braces-around-statements (redirects to readability-braces-around-statements) google-readability-casting - google-readability-function-size (redirects to readability-function-size) + google-readability-function-size (redirects to readability-function-size) google-readability-namespace-comments google-readability-redundant-smartptr-get google-readability-todo @@ -76,6 +76,7 @@ misc-unused-parameters misc-unused-raii misc-virtual-near-miss + modernize-bool-to-integer-conversion modernize-deprecated-headers modernize-loop-convert modernize-make-unique Index: docs/clang-tidy/checks/modernize-bool-to-integer-conversion.rst =================================================================== --- /dev/null +++ docs/clang-tidy/checks/modernize-bool-to-integer-conversion.rst @@ -0,0 +1,17 @@ +.. title:: clang-tidy - modernize-bool-to-integer-conversion + +modernize-bool-to-integer-conversion +==================================== + +This check looks for implicit conversion from bool literals to integer types + +.. code-block:: C++ + + int a = false; + vector v(true); // Makes vector of one element + + // Changes it to + int a = 0; + vector v(1); // Makes vector of one element + + Index: test/clang-tidy/modernize-bool-to-integer-conversion.cpp =================================================================== --- /dev/null +++ test/clang-tidy/modernize-bool-to-integer-conversion.cpp @@ -0,0 +1,78 @@ +// RUN: %check_clang_tidy %s modernize-bool-to-integer-conversion %t + +const int is42Answer = true; +// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicitly converting bool literal to 'int'; use integer literal instead [modernize-bool-to-integer-conversion] +// CHECK-FIXES: const int is42Answer = 1;{{$}} + +volatile int noItsNot = false; +// CHECK-MESSAGES: :[[@LINE-1]]:25: warning: implicitly converting bool literal to 'int'; {{..}} +// CHECK-FIXES: volatile int noItsNot = 0;{{$}} +int a = 42; +int az = a; + +long long ll = true; +// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: implicitly converting bool literal to 'long long';{{..}} +// CHECK-FIXES: long long ll = 1;{{$}} + +void fun(int) {} +#define ONE true + +// No fixup for macros. +int one = ONE; +// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: implicitly converting bool literal to 'int' inside a macro; use integer literal instead [modernize-bool-to-integer-conversion] + +void test() { + fun(ONE); +// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: implicitly converting bool{{..}} + + fun(42); + fun(true); +// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: implicitly {{..}} +// CHECK-FIXES: fun(1);{{$}} +} + +char c = true; +// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: implicitly {{..}} +// CHECK-FIXES: char c = 1; + +float f = false; +// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: implicitly converting bool literal to 'float';{{..}} +// CHECK-FIXES: float f = 0; + +struct Blah { + Blah(int blah) { } +}; + +const int &ref = false; +// CHECK-MESSAGES: :[[@LINE-1]]:18: warning: implicitly converting bool literal to 'int'{{..}} +// CHECK-FIXES: const int &ref = 0; + +Blah bla = true; +// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: implicitly converting bool literal to 'int'{{..}} +// CHECK-FIXES: Blah bla = 1; + +Blah bla2 = 1; + +char c2 = 1; +char c3 = '0'; +bool b = true; + +struct BitFields { + unsigned a : 3; + unsigned flag : 1; +}; + +void testBitFields() { + BitFields b; + + b.a = true; +// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: implicitly converting +// CHECK-FIXES: b.a = 1; + + // Don't warn of bitfields of size 1. Unfortunately we can't just + // change type of flag to bool, because some compilers like MSVC doesn't + // pack bitfields of different types. + b.flag = true; + + +}