Index: clang-tidy/readability/CMakeLists.txt =================================================================== --- clang-tidy/readability/CMakeLists.txt +++ clang-tidy/readability/CMakeLists.txt @@ -17,6 +17,7 @@ NamedParameterCheck.cpp NamespaceCommentCheck.cpp NonConstParameterCheck.cpp + NumericalCostantsToMaxIntCheck.cpp ReadabilityTidyModule.cpp RedundantControlFlowCheck.cpp RedundantDeclarationCheck.cpp Index: clang-tidy/readability/NumericalCostantsToMaxIntCheck.h =================================================================== --- /dev/null +++ clang-tidy/readability/NumericalCostantsToMaxIntCheck.h @@ -0,0 +1,42 @@ +//===--- NumericalCostantsToMaxIntCheck.h - clang-tidy ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_NUMERICALCOSTANTSTOMAXINTCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_NUMERICALCOSTANTSTOMAXINTCHECK_H + +#include "../ClangTidy.h" +#include "../utils/IncludeInserter.h" + +namespace clang { +namespace tidy { +namespace readability { + +/// \brief This check looks for numerical unsigned constants that are equal to +/// -1 or ~0 and substitutes them with std::numeric_limits::max(). +/// +/// If necessary adds the header file 'limits' of the standard library. +/// +class NumericalCostantsToMaxIntCheck : public ClangTidyCheck { +public: + NumericalCostantsToMaxIntCheck(StringRef Name, ClangTidyContext *Context); + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; + void registerPPCallbacks(CompilerInstance &Compiler) override; + void storeOptions(ClangTidyOptions::OptionMap &Opts) override; + +private: + const utils::IncludeSorter::IncludeStyle IncludeStyle; + std::unique_ptr Inserter; +}; + +} // namespace readability +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_NUMERICALCOSTANTSTOMAXINTCHECK_H Index: clang-tidy/readability/NumericalCostantsToMaxIntCheck.cpp =================================================================== --- /dev/null +++ clang-tidy/readability/NumericalCostantsToMaxIntCheck.cpp @@ -0,0 +1,88 @@ +//===--- NumericalcostantstomaxintCheck.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 "NumericalCostantsToMaxIntCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/Frontend/CompilerInstance.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace readability { + +void NumericalCostantsToMaxIntCheck::storeOptions( + ClangTidyOptions::OptionMap &Opts) { + Options.store(Opts, "IncludeStyle", IncludeStyle); +} + +NumericalCostantsToMaxIntCheck::NumericalCostantsToMaxIntCheck( + StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context), + IncludeStyle(utils::IncludeSorter::parseIncludeStyle( + Options.getLocalOrGlobal("IncludeStyle", "llvm"))) {} + +void NumericalCostantsToMaxIntCheck::registerPPCallbacks( + CompilerInstance &Compiler) { + if (!getLangOpts().CPlusPlus) + return; + + Inserter.reset(new utils::IncludeInserter( + Compiler.getSourceManager(), Compiler.getLangOpts(), IncludeStyle)); + Compiler.getPreprocessor().addPPCallbacks(Inserter->CreatePPCallbacks()); +} + +void NumericalCostantsToMaxIntCheck::registerMatchers(MatchFinder *Finder) { + if (!getLangOpts().CPlusPlus) + return; + Finder->addMatcher( + varDecl(hasType(qualType(allOf(isUnsignedInteger(), isConstQualified()))), + anyOf(hasInitializer(ignoringImpCasts(unaryOperator( + hasOperatorName("-"), + hasUnaryOperand( + integerLiteral(equals(1)).bind("Literal"))))), + hasInitializer(ignoringImpCasts(unaryOperator( + hasOperatorName("~"), + hasUnaryOperand( + integerLiteral(equals(0)).bind("Literal"))))))) + .bind("VarDecl"), + this); +} + +void NumericalCostantsToMaxIntCheck::check( + const MatchFinder::MatchResult &Result) { + const auto *Decl = Result.Nodes.getNodeAs("VarDecl"); + const auto *Lit = Result.Nodes.getNodeAs("Literal"); + assert(Decl != nullptr); + std::string InsteadOf = "-1"; + std::string Replacement = + (Twine("std::numeric_limits<") + + Decl->getType().getAtomicUnqualifiedType().getAsString() + ">::max()") + .str(); + if (Lit->getValue() == 0) + InsteadOf = "~0"; + const SourceManager *SM = Result.SourceManager; + SourceRange LitSR = + SourceRange(SM->getSpellingLoc(Lit->getBeginLoc().getLocWithOffset(-1)), + SM->getSpellingLoc(Lit->getEndLoc())); + auto Diag = diag(Lit->getLocation(), + "use '%0' instead of '%1' for unsigned constant int") + << Replacement << InsteadOf + << FixItHint::CreateReplacement(LitSR, Replacement); + + Optional Insertion = Inserter->CreateIncludeInsertion( + Result.SourceManager->getMainFileID(), "limits", true); + if (Insertion) + Diag << Insertion.getValue(); +} + +} // namespace readability +} // namespace tidy +} // namespace clang Index: clang-tidy/readability/ReadabilityTidyModule.cpp =================================================================== --- clang-tidy/readability/ReadabilityTidyModule.cpp +++ clang-tidy/readability/ReadabilityTidyModule.cpp @@ -25,6 +25,7 @@ #include "MisplacedArrayIndexCheck.h" #include "NamedParameterCheck.h" #include "NonConstParameterCheck.h" +#include "NumericalCostantsToMaxIntCheck.h" #include "RedundantControlFlowCheck.h" #include "RedundantDeclarationCheck.h" #include "RedundantFunctionPtrDereferenceCheck.h" @@ -72,6 +73,8 @@ "readability-misleading-indentation"); CheckFactories.registerCheck( "readability-misplaced-array-index"); + CheckFactories.registerCheck( + "readability-numerical-costants-to-max-int"); CheckFactories.registerCheck( "readability-redundant-function-ptr-dereference"); CheckFactories.registerCheck( Index: docs/ReleaseNotes.rst =================================================================== --- docs/ReleaseNotes.rst +++ docs/ReleaseNotes.rst @@ -111,6 +111,12 @@ Detects usage of magic numbers, numbers that are used as literals instead of introduced via constants or symbols. + +- New :doc:`readability-numerical-costants-to-max-int + ` check. + + Checks for numerical unsigned constants that are equal to '-1' or '~0' + and substitutes them with 'std::numeric_limits::max()'. Improvements to include-fixer ----------------------------- Index: docs/clang-tidy/checks/list.rst =================================================================== --- docs/clang-tidy/checks/list.rst +++ docs/clang-tidy/checks/list.rst @@ -232,6 +232,7 @@ readability-misplaced-array-index readability-named-parameter readability-non-const-parameter + readability-numerical-costants-to-max-int readability-redundant-control-flow readability-redundant-declaration readability-redundant-function-ptr-dereference Index: docs/clang-tidy/checks/readability-numerical-costants-to-max-int.rst =================================================================== --- /dev/null +++ docs/clang-tidy/checks/readability-numerical-costants-to-max-int.rst @@ -0,0 +1,44 @@ +.. title:: clang-tidy - readability-numerical-costants-to-max-int + +readability-numerical-costants-to-max-int +========================================= + + +Checks for numerical unsigned constants that are equal to '-1' or '~0' +and substitutes them with 'std::numeric_limits::max()'. + +If necessary adds the header file 'limits' of the standard library. + +Examples: + +.. code-block:: c++ + + unsigned const long int x = -1; + +becomes + +.. code-block:: c++ + + unsigned const long int x = std::numeric_limits::max(); + +or + +.. code-block:: c++ + + unsigned const short x = ~0; + + +becomes + +.. code-block:: c++ + + unsigned const short x = std::numeric_limits::max(); + + +Options +------- + +.. option:: IncludeStyle + + A string specifying which include-style is used, `llvm` or `google`. Default + is `llvm`. \ No newline at end of file Index: test/clang-tidy/readability-numerical-costants-to-max-int.cpp =================================================================== --- /dev/null +++ test/clang-tidy/readability-numerical-costants-to-max-int.cpp @@ -0,0 +1,120 @@ +// RUN: %check_clang_tidy %s readability-numerical-costants-to-max-int %t +unsigned const int Uval1 = -1; +// CHECK-MESSAGES: :[[@LINE-1]]:29: warning: use 'std::numeric_limits::max()' instead of '-1' for unsigned constant int [readability-numerical-costants-to-max-int] +// CHECK-FIXES: #include +// CHECK-FIXES: unsigned const int Uval1 = std::numeric_limits::max(); + +unsigned const long Uval2 = -1; +// CHECK-MESSAGES: :[[@LINE-1]]:30: warning: use 'std::numeric_limits::max()' instead of '-1' for unsigned constant int [readability-numerical-costants-to-max-int] +// CHECK-FIXES: unsigned const long Uval2 = std::numeric_limits::max(); + +unsigned const long int Uval3 = -1; +// CHECK-MESSAGES: :[[@LINE-1]]:34: warning: use 'std::numeric_limits::max()' instead of '-1' for unsigned constant int [readability-numerical-costants-to-max-int] +// CHECK-FIXES: unsigned const long int Uval3 = std::numeric_limits::max(); + +unsigned const long long int Uval4 = -1; +// CHECK-MESSAGES: :[[@LINE-1]]:39: warning: use 'std::numeric_limits::max()' instead of '-1' for unsigned constant int [readability-numerical-costants-to-max-int] +// CHECK-FIXES: unsigned const long long int Uval4 = std::numeric_limits::max(); + +unsigned const short int Uval5 = -1; +// CHECK-MESSAGES: :[[@LINE-1]]:35: warning: use 'std::numeric_limits::max()' instead of '-1' for unsigned constant int [readability-numerical-costants-to-max-int] +// CHECK-FIXES: unsigned const short int Uval5 = std::numeric_limits::max(); + +unsigned const Uval6 = -1; +// CHECK-MESSAGES: :[[@LINE-1]]:25: warning: use 'std::numeric_limits::max()' instead of '-1' for unsigned constant int [readability-numerical-costants-to-max-int] +// CHECK-FIXES: unsigned const Uval6 = std::numeric_limits::max(); + +unsigned const char Uval7 = -1; +// CHECK-MESSAGES: :[[@LINE-1]]:30: warning: use 'std::numeric_limits::max()' instead of '-1' for unsigned constant int [readability-numerical-costants-to-max-int] +// CHECK-FIXES: unsigned const char Uval7 = std::numeric_limits::max(); + +//if not constants do nothing +unsigned int Uval8 = -1; +unsigned long Uval9 = -1; +unsigned long int Uval10 = -1; +unsigned long long int Uval11 = -1; +unsigned short int Uval12 = -1; +unsigned Uval13 = -1; +unsigned char Uval14 = -1; + +unsigned const long Uval15 = ~0; +// CHECK-MESSAGES: :[[@LINE-1]]:31: warning: use 'std::numeric_limits::max()' instead of '~0' for unsigned constant int [readability-numerical-costants-to-max-int] +// CHECK-FIXES: unsigned const long Uval15 = std::numeric_limits::max(); + +unsigned const long int Uval16 = ~0; +// CHECK-MESSAGES: :[[@LINE-1]]:35: warning: use 'std::numeric_limits::max()' instead of '~0' for unsigned constant int [readability-numerical-costants-to-max-int] +// CHECK-FIXES: unsigned const long int Uval16 = std::numeric_limits::max(); + +unsigned const long long int Uval17 = ~0; +// CHECK-MESSAGES: :[[@LINE-1]]:40: warning: use 'std::numeric_limits::max()' instead of '~0' for unsigned constant int [readability-numerical-costants-to-max-int] +// CHECK-FIXES: unsigned const long long int Uval17 = std::numeric_limits::max(); + +unsigned const short int Uval18 = ~0; +// CHECK-MESSAGES: :[[@LINE-1]]:36: warning: use 'std::numeric_limits::max()' instead of '~0' for unsigned constant int [readability-numerical-costants-to-max-int] +// CHECK-FIXES: unsigned const short int Uval18 = std::numeric_limits::max(); + +unsigned const Uval19 = ~0; +// CHECK-MESSAGES: :[[@LINE-1]]:26: warning: use 'std::numeric_limits::max()' instead of '~0' for unsigned constant int [readability-numerical-costants-to-max-int] +// CHECK-FIXES: unsigned const Uval19 = std::numeric_limits::max(); + +unsigned const char Uval20 = ~0; +// CHECK-MESSAGES: :[[@LINE-1]]:31: warning: use 'std::numeric_limits::max()' instead of '~0' for unsigned constant int [readability-numerical-costants-to-max-int] +// CHECK-FIXES: unsigned const char Uval20 = std::numeric_limits::max(); + +//if not constants do nothing +unsigned int Uval21 = ~0; +unsigned long Uva22 = ~0; +unsigned long int Uval23 = ~0; +unsigned long long int Uval24 = ~0; +unsigned short int Uval25 = ~0; +unsigned Uval26 = ~0; +unsigned char Uval27 = ~0; + +#define UNSIGNED unsigned +#define CONST const +#define UNSIGNEDCONST unsigned const +#define UNSIGNEDCONSTDECLMINUS unsigned const x1 = -1; +// CHECK-FIXES: #define UNSIGNEDCONSTDECLMINUS unsigned const x1 = std::numeric_limits::max(); + +#define UNSIGNEDCONSTDECLBITWISE unsigned const x2 = ~0; +// CHECK-FIXES: #define UNSIGNEDCONSTDECLBITWISE unsigned const x2 = std::numeric_limits::max(); + +#define MINUSONE -1; +// CHECK-FIXES: #define MINUSONE std::numeric_limits::max(); + +#define BITWISEZERO ~0; +// CHECK-FIXES: #define BITWISEZERO std::numeric_limits::max(); +template +void f() { + Foo f = -1; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use 'std::numeric_limits::max()' instead of '-1' for unsigned constant int [readability-numerical-costants-to-max-int] + // CHECK-FIXES: Foo f = std::numeric_limits::max(); +} + +void testFunction() { + f(); + + const UNSIGNED int y = -1; + // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: use 'std::numeric_limits::max()' instead of '-1' for unsigned constant int [readability-numerical-costants-to-max-int] + // CHECK-FIXES: const UNSIGNED int y = std::numeric_limits::max(); + + UNSIGNED CONST z = -1; + // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: use 'std::numeric_limits::max()' instead of '-1' for unsigned constant int [readability-numerical-costants-to-max-int] + // CHECK-FIXES: UNSIGNED CONST z = std::numeric_limits::max(); + + UNSIGNEDCONST w = -1; + // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: use 'std::numeric_limits::max()' instead of '-1' for unsigned constant int [readability-numerical-costants-to-max-int] + // CHECK-FIXES: UNSIGNEDCONST w = std::numeric_limits::max(); + + UNSIGNEDCONSTDECLMINUS + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use 'std::numeric_limits::max()' instead of '-1' for unsigned constant int [readability-numerical-costants-to-max-int] + + UNSIGNEDCONSTDECLBITWISE + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use 'std::numeric_limits::max()' instead of '~0' for unsigned constant int [readability-numerical-costants-to-max-int] + + UNSIGNEDCONST int a = MINUSONE; + // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: use 'std::numeric_limits::max()' instead of '-1' for unsigned constant int [readability-numerical-costants-to-max-int] + + UNSIGNEDCONST int b = BITWISEZERO; + // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: use 'std::numeric_limits::max()' instead of '~0' for unsigned constant int [readability-numerical-costants-to-max-int] +}