Index: clang-tidy/cppcoreguidelines/CMakeLists.txt =================================================================== --- clang-tidy/cppcoreguidelines/CMakeLists.txt +++ clang-tidy/cppcoreguidelines/CMakeLists.txt @@ -3,6 +3,7 @@ add_clang_library(clangTidyCppCoreGuidelinesModule CppCoreGuidelinesTidyModule.cpp InterfacesGlobalInitCheck.cpp + NarrowingConversionsCheck.cpp NoMallocCheck.cpp OwningMemoryCheck.cpp ProBoundsArrayToPointerDecayCheck.cpp Index: clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp =================================================================== --- clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp +++ clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp @@ -12,6 +12,7 @@ #include "../ClangTidyModuleRegistry.h" #include "../misc/UnconventionalAssignOperatorCheck.h" #include "InterfacesGlobalInitCheck.h" +#include "NarrowingConversionsCheck.h" #include "NoMallocCheck.h" #include "OwningMemoryCheck.h" #include "ProBoundsArrayToPointerDecayCheck.h" @@ -37,6 +38,8 @@ void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override { CheckFactories.registerCheck( "cppcoreguidelines-interfaces-global-init"); + CheckFactories.registerCheck( + "cppcoreguidelines-narrowing-conversions"); CheckFactories.registerCheck("cppcoreguidelines-no-malloc"); CheckFactories.registerCheck( "cppcoreguidelines-owning-memory"); Index: clang-tidy/cppcoreguidelines/NarrowingConversionsCheck.h =================================================================== --- /dev/null +++ clang-tidy/cppcoreguidelines/NarrowingConversionsCheck.h @@ -0,0 +1,37 @@ +//===--- NarrowingConversionsCheck.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_CPPCOREGUIDELINES_NARROWING_CONVERSIONS_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_NARROWING_CONVERSIONS_H + +#include "../ClangTidy.h" + +namespace clang { +namespace tidy { +namespace cppcoreguidelines { + +/// Checks for narrowing conversions, e.g: +/// int i = 0; +/// i += 0.1; +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/cppcoreguidelines-narrowing-conversions.html +class NarrowingConversionsCheck : public ClangTidyCheck { +public: + NarrowingConversionsCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; +}; + +} // namespace cppcoreguidelines +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_NARROWING_CONVERSIONS_H Index: clang-tidy/cppcoreguidelines/NarrowingConversionsCheck.cpp =================================================================== --- /dev/null +++ clang-tidy/cppcoreguidelines/NarrowingConversionsCheck.cpp @@ -0,0 +1,38 @@ +//===--- NarrowingConversionsCheck.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 "NarrowingConversionsCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace cppcoreguidelines { + +void NarrowingConversionsCheck::registerMatchers(MatchFinder *Finder) { + Finder->addMatcher( + binaryOperator(anyOf(hasOperatorName("+="), hasOperatorName("-=")), + hasLHS(hasType(isInteger())), + hasRHS(hasType(realFloatingPointType()))).bind("op"), + this); +} + +void NarrowingConversionsCheck::check(const MatchFinder::MatchResult &Result) { + const auto* Op = Result.Nodes.getNodeAs("op"); + diag(Op->getOperatorLoc(), + "narrowing conversion from %0 to %1") + << Op->getRHS()->getType() + << Op->getLHS()->getType(); +} + +} // namespace cppcoreguidelines +} // namespace tidy +} // namespace clang Index: docs/ReleaseNotes.rst =================================================================== --- docs/ReleaseNotes.rst +++ docs/ReleaseNotes.rst @@ -57,6 +57,11 @@ Improvements to clang-tidy -------------------------- +- New `cppcoreguidelines-narrowing-conversions + `_ check + + Checks for narrowing conversions, e.g. ``int i = 0; i += 0.1;``. + - Renamed checks to use correct term "implicit conversion" instead of "implicit cast" and modified messages and option names accordingly: Index: docs/clang-tidy/checks/cppcoreguidelines-narrowing-conversions.rst =================================================================== --- /dev/null +++ docs/clang-tidy/checks/cppcoreguidelines-narrowing-conversions.rst @@ -0,0 +1,13 @@ +.. title:: clang-tidy - cppcoreguidelines-narrowing-conversions + +cppcoreguidelines-narrowing-conversions +======================================= + +Checks for silent narrowing conversions, e.g: ``int i = 0; i += 0.1;``. While +the issue is obvious in this former example, it might not be so in the +following: ``void MyClass::f(double d) { int_member_ += d; }``. + +This rule is part of the "Expressions and statements" profile of the C++ Core +Guidelines, corresponding to rule ES.46. See + +https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Res-narrowing. Index: docs/clang-tidy/checks/list.rst =================================================================== --- docs/clang-tidy/checks/list.rst +++ docs/clang-tidy/checks/list.rst @@ -7,9 +7,9 @@ android-cloexec-accept android-cloexec-accept4 android-cloexec-creat + android-cloexec-dup android-cloexec-epoll-create android-cloexec-epoll-create1 - android-cloexec-dup android-cloexec-fopen android-cloexec-inotify-init android-cloexec-inotify-init1 @@ -38,8 +38,9 @@ cert-msc30-c (redirects to cert-msc50-cpp) cert-msc50-cpp cert-oop11-cpp (redirects to misc-move-constructor-init) - cppcoreguidelines-c-copy-assignment-signature + cppcoreguidelines-c-copy-assignment-signature (redirects to misc-unconventional-assign-operator) cppcoreguidelines-interfaces-global-init + cppcoreguidelines-narrowing-conversions cppcoreguidelines-no-malloc cppcoreguidelines-owning-memory cppcoreguidelines-pro-bounds-array-to-pointer-decay @@ -76,8 +77,8 @@ hicpp-explicit-conversions (redirects to google-explicit-constructor) hicpp-function-size (redirects to readability-function-size) hicpp-invalid-access-moved (redirects to misc-use-after-move) - hicpp-move-const-arg (redirects to misc-move-const-arg) hicpp-member-init (redirects to cppcoreguidelines-pro-type-member-init) + hicpp-move-const-arg (redirects to misc-move-const-arg) hicpp-named-parameter (redirects to readability-named-parameter) hicpp-new-delete-operators (redirects to misc-new-delete-overloads) hicpp-no-array-decay (redirects to cppcoreguidelines-pro-bounds-array-to-pointer-decay) @@ -95,7 +96,7 @@ hicpp-use-noexcept (redirects to modernize-use-noexcept) hicpp-use-nullptr (redirects to modernize-use-nullptr) hicpp-use-override (redirects to modernize-use-override) - hicpp-vararg (redirects to cppcoreguidelines-pro-type-varg) + hicpp-vararg (redirects to cppcoreguidelines-pro-type-vararg) llvm-header-guard llvm-include-order llvm-namespace-comment Index: test/clang-tidy/cppcoreguidelines-narrowing-conversions.cpp =================================================================== --- /dev/null +++ test/clang-tidy/cppcoreguidelines-narrowing-conversions.cpp @@ -0,0 +1,25 @@ +// RUN: %check_clang_tidy %s cppcoreguidelines-narrowing-conversions %t + +void not_ok(double d) { + int i = 0; + i += 0.5; + // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: narrowing conversion from 'double' to 'int' [cppcoreguidelines-narrowing-conversions] + i += 0.5f; + // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: narrowing conversion from 'float' to 'int' [cppcoreguidelines-narrowing-conversions] + i += d; + // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: narrowing conversion from 'double' to 'int' [cppcoreguidelines-narrowing-conversions] + // We warn on the following even though it's not dangerous because there is no + // reason to use a double literal here. + // TODO(courbet): Provide an automatic fix. + i += 2.0; + // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: narrowing conversion from 'double' to 'int' [cppcoreguidelines-narrowing-conversions] + i += 2.0f; + // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: narrowing conversion from 'float' to 'int' [cppcoreguidelines-narrowing-conversions] +} + +void ok(double d) { + int i = 0; + i += 1; + i += static_cast(3.0); + i += static_cast(d); +}