Index: clang-tidy/misc/CMakeLists.txt =================================================================== --- clang-tidy/misc/CMakeLists.txt +++ clang-tidy/misc/CMakeLists.txt @@ -3,6 +3,7 @@ add_clang_library(clangTidyMiscModule ArgumentCommentCheck.cpp AssertSideEffectCheck.cpp + DefaultNumericsCheck.cpp ForwardingReferenceOverloadCheck.cpp MisplacedConstCheck.cpp UnconventionalAssignOperatorCheck.cpp Index: clang-tidy/misc/DefaultNumericsCheck.h =================================================================== --- /dev/null +++ clang-tidy/misc/DefaultNumericsCheck.h @@ -0,0 +1,37 @@ +//===--- DefaultNumericsCheck.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_MISC_DEFAULT_NUMERICS_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_DEFAULT_NUMERICS_H + +#include "../ClangTidy.h" + +namespace clang { +namespace tidy { +namespace misc { + +/// This check flags usages of ``std::numeric_limits::{min,max}()`` for +/// unspecialized types. It is dangerous because returns T(), which might is +/// rarely minimum or maximum for this type. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/misc-default-numerics.html +class DefaultNumericsCheck : public ClangTidyCheck { +public: + DefaultNumericsCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; +}; + +} // namespace misc +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_DEFAULT_NUMERICS_H Index: clang-tidy/misc/DefaultNumericsCheck.cpp =================================================================== --- /dev/null +++ clang-tidy/misc/DefaultNumericsCheck.cpp @@ -0,0 +1,46 @@ +//===--- DefaultNumericsCheck.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 "DefaultNumericsCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace misc { + +void DefaultNumericsCheck::registerMatchers(MatchFinder *Finder) { + if (!getLangOpts().CPlusPlus) + return; + // FIXME: We should also warn in template intantiations, but it would require + // printing backtrace. + Finder->addMatcher( + callExpr( + callee(cxxMethodDecl( + hasAnyName("min", "max"), + ofClass(cxxRecordDecl(unless(isExplicitTemplateSpecialization()), + hasName("::std::numeric_limit"))))), + unless(isInTemplateInstantiation())) + .bind("call"), + this); +} + +void DefaultNumericsCheck::check(const MatchFinder::MatchResult &Result) { + + const auto *MatchedDecl = Result.Nodes.getNodeAs("call"); + + diag(MatchedDecl->getLocStart(), + "called std::numeric_limit method on not specialized type"); +} + +} // namespace misc +} // namespace tidy +} // namespace clang Index: clang-tidy/misc/MiscTidyModule.cpp =================================================================== --- clang-tidy/misc/MiscTidyModule.cpp +++ clang-tidy/misc/MiscTidyModule.cpp @@ -14,6 +14,7 @@ #include "AssertSideEffectCheck.h" #include "BoolPointerImplicitConversionCheck.h" #include "DanglingHandleCheck.h" +#include "DefaultNumericsCheck.h" #include "DefinitionsInHeadersCheck.h" #include "FoldInitTypeCheck.h" #include "ForwardDeclarationNamespaceCheck.h" @@ -66,6 +67,7 @@ CheckFactories.registerCheck("misc-argument-comment"); CheckFactories.registerCheck( "misc-assert-side-effect"); + CheckFactories.registerCheck("misc-default-numerics"); CheckFactories.registerCheck( "misc-forwarding-reference-overload"); CheckFactories.registerCheck("misc-misplaced-const"); Index: docs/ReleaseNotes.rst =================================================================== --- docs/ReleaseNotes.rst +++ docs/ReleaseNotes.rst @@ -71,7 +71,11 @@ `_ check Allow custom memory management functions to be considered as well. - + +- New `misc-default-numerics + `_ check + Finds uses of ``std::numeric_limit`` for unspecialized types + - New `misc-forwarding-reference-overload `_ check Index: docs/clang-tidy/checks/list.rst =================================================================== --- docs/clang-tidy/checks/list.rst +++ docs/clang-tidy/checks/list.rst @@ -75,6 +75,7 @@ misc-assert-side-effect misc-bool-pointer-implicit-conversion misc-dangling-handle + misc-default-numerics misc-definitions-in-headers misc-fold-init-type misc-forward-declaration-namespace Index: docs/clang-tidy/checks/misc-default-numerics.rst =================================================================== --- /dev/null +++ docs/clang-tidy/checks/misc-default-numerics.rst @@ -0,0 +1,24 @@ +.. title:: clang-tidy - misc-default-numerics + +misc-default-numerics +===================== + +This check flags usages of ``std::numeric_limits::{min,max}()`` for +unspecialized types. It is dangerous because returns T(), which might is rarely +minimum or maximum for this type. + +Consider scenario: +.. code-block:: c++ + + // 1. Have a: + typedef long long BigInt + + // 2. Use + std::numeric_limits::min() + + + // 3. Replace the BigInt typedef with class implementing BigIntegers + class BigInt { ;;; }; + + // 4. Your code compiles silently and you a few years later you find an + // of by 9223372036854775808 error. Index: test/clang-tidy/misc-default-numerics.cpp =================================================================== --- /dev/null +++ test/clang-tidy/misc-default-numerics.cpp @@ -0,0 +1,42 @@ +// RUN: %check_clang_tidy %s misc-default-numerics %t + +namespace std { + +template +struct numeric_limit { + static T min() { return T(); } + static T max() { return T(); } +}; + +template <> +struct numeric_limit { + static int min() { return -1; } + static int max() { return 1; } +}; + +} // namespace std + +class MyType {}; +template +class MyTemplate {}; + +void test() { + auto x = std::numeric_limit::min(); + + auto y = std::numeric_limit::min(); + // CHECK-MESSAGES: [[@LINE-1]]:12: warning: called std::numeric_limit method on not specialized type + + auto z = std::numeric_limit>::max(); + // CHECK-MESSAGES: [[@LINE-1]]:12: warning: called std::numeric_limit method on not specialized type +} + +template +void fun() { + auto x = std::numeric_limit::min(); +} + +void testTemplate() { + fun(); + // FIXME: This should generate warning with backtrace. + fun; +}