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,41 @@ +//===--- 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" + +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 it adds the library 'limits'. +/// +class NumericalCostantsToMaxIntCheck : public ClangTidyCheck { +public: + NumericalCostantsToMaxIntCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; + void registerPPCallbacks(CompilerInstance &Compiler) override; + +private: + bool InsertLimits; + SourceLocation IncludeLocation; +}; + +} // 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,125 @@ +//===--- 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 { + +namespace { +class NumericalConstCheckPPCallbacks : public PPCallbacks { +public: + explicit NumericalConstCheckPPCallbacks(bool &IL, SourceLocation *IS); + void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok, + StringRef FileName, bool IsAngled, + CharSourceRange FilenameRange, const FileEntry *File, + StringRef SearchPath, StringRef RelativePath, + const Module *Imported, + SrcMgr::CharacteristicKind FileType) override; + +private: + bool *IL; + bool AtLeastOneInclude; + SourceLocation *IS; +}; +} // namespace + +void NumericalConstCheckPPCallbacks::InclusionDirective( + SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName, + bool IsAngled, CharSourceRange FilenameRange, const FileEntry *File, + StringRef SearchPath, StringRef RelativePath, const Module *Imported, + SrcMgr::CharacteristicKind FileType) { + + if (FileName == "limits") { + *IL = true; + return; + } + if (AtLeastOneInclude) + return; + + *IS = HashLoc; + AtLeastOneInclude = true; +} + +NumericalConstCheckPPCallbacks::NumericalConstCheckPPCallbacks( + bool &IL, SourceLocation *IS) + : IL(&IL), AtLeastOneInclude(false), IS(IS){}; + +void NumericalCostantsToMaxIntCheck::registerPPCallbacks( + CompilerInstance &Compiler) { + if (this->getLangOpts().CPlusPlus) { + Compiler.getPreprocessor().addPPCallbacks( + ::llvm::make_unique(InsertLimits, + &IncludeLocation)); + } +} + +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("Lit"))))), + hasInitializer(ignoringImpCasts(unaryOperator( + hasOperatorName("~"), + hasUnaryOperand(integerLiteral(equals(0)).bind("Lit"))))))) + .bind("VarDecl"), + this); +} + +void NumericalCostantsToMaxIntCheck::check( + const MatchFinder::MatchResult &Result) { + + const auto *Decl = Result.Nodes.getNodeAs("VarDecl"); + const auto *Lit = Result.Nodes.getNodeAs("Lit"); + if (Decl == nullptr || Lit == nullptr) + return; + + SourceManager *SM = Result.SourceManager; + std::string InsteadOf = "-1"; + std::string Replacement = + ("std::numeric_limits<" + + StringRef(Decl->getType().getAtomicUnqualifiedType().getAsString()) + + ">::max()") + .str(); + + if (Lit->getValue() == 0) + InsteadOf = "~0"; + + diag(Lit->getLocation(), "use '%0' instead of '%1' for unsigned constant int") + << Replacement << InsteadOf + << FixItHint::CreateReplacement( + SourceRange(Lit->getBeginLoc().getLocWithOffset(-1), + Lit->getEndLoc()), + Replacement); + + if (InsertLimits) + return; + + if (IncludeLocation.isInvalid()) + IncludeLocation = + SM->getLocForStartOfFile(SM->getFileID(Lit->getBeginLoc())); + + diag(IncludeLocation, "Add '#include' to use " + "std::numeric_limits::max() function") + << FixItHint::CreateInsertion(IncludeLocation, "#include \n"); +} + +} // 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 @@ -57,6 +57,12 @@ Improvements to clang-tidy -------------------------- +- 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(). + - New :doc:`abseil-duration-division ` check. Index: docs/clang-tidy/checks/list.rst =================================================================== --- docs/clang-tidy/checks/list.rst +++ docs/clang-tidy/checks/list.rst @@ -9,8 +9,8 @@ abseil-no-internal-dependencies abseil-no-namespace abseil-redundant-strcat-calls - abseil-string-find-startswith abseil-str-cat-append + abseil-string-find-startswith android-cloexec-accept android-cloexec-accept4 android-cloexec-creat @@ -216,6 +216,7 @@ performance-unnecessary-copy-initialization performance-unnecessary-value-param portability-simd-intrinsics + readability-NumericalCostantsToMaxInt readability-avoid-const-params-in-decls readability-braces-around-statements readability-container-size-empty 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,36 @@ +.. title:: clang-tidy - readability-numerical-costants-to-max-int + +readability-numerical-costants-to-max-int +================================== + + +This check looks for numerical unsigned constants that are equal to -1 or ~0 +and substitutes them with std::numeric_limits::max(). + +If necessary it adds the library 'limits'. + +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(); + \ 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,76 @@ +// RUN: %check_clang_tidy %s readability-numerical-costants-to-max-int %t +unsigned const int Uval1 = -1; +// CHECK-MESSAGES: :[[@LINE-2]]:1: warning: Add '#include' to use std::numeric_limits::max() function [readability-numerical-costants-to-max-int] +// CHECK-MESSAGES: :[[@LINE-2]]: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;