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,63 @@ +//===--- 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 { + +/// Checks, if integer \p Literal is preprocessor dependent +static bool isPreprocessorIndependent(const CXXBoolLiteralExpr *Literal, + const MatchFinder::MatchResult &Result) { + const LangOptions &Opts = Result.Context->getLangOpts(); + auto LiteralSource = Lexer::getSourceText( + CharSourceRange::getTokenRange(Literal->getSourceRange()), + *Result.SourceManager, Opts); + + // If it's not 'true' of 'false', that means that it must be inside macro. + return LiteralSource == "true" || LiteralSource == "false"; +} + +void BoolToIntegerConversionCheck::registerMatchers(MatchFinder *Finder) { + if (!getLangOpts().CPlusPlus) + return; + Finder->addMatcher( + implicitCastExpr(has(cxxBoolLiteral().bind("bool_literal"))).bind("cast"), + this); +} + +void BoolToIntegerConversionCheck::check( + const MatchFinder::MatchResult &Result) { + const auto *BoolLiteral = + Result.Nodes.getNodeAs("bool_literal"); + const auto *Cast = Result.Nodes.getNodeAs("cast"); + const auto Type = Cast->getType().getLocalUnqualifiedType(); + if (isPreprocessorIndependent(BoolLiteral, Result)) { + diag(BoolLiteral->getLocation(), "implicitly converting bool literal to " + "%0. Use integer literal instead") + << Type + << FixItHint::CreateReplacement(BoolLiteral->getSourceRange(), + BoolLiteral->getValue() ? "1" : "0"); + } else { + diag(BoolLiteral->getLocation(), "implicitly converting bool literal to " + "%0 inside macro. Use integer " + "literal instead") + << Type; + } +} + +} // 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 implicit cast from bool literals to integers with int 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,16 @@ +.. 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,58 @@ +// 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 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;