Index: clang-tidy/bugprone/BugproneTidyModule.cpp =================================================================== --- clang-tidy/bugprone/BugproneTidyModule.cpp +++ clang-tidy/bugprone/BugproneTidyModule.cpp @@ -10,6 +10,7 @@ #include "../ClangTidy.h" #include "../ClangTidyModule.h" #include "../ClangTidyModuleRegistry.h" +#include "IntegerDivisionCheck.h" #include "SuspiciousMemsetUsageCheck.h" #include "UndefinedMemoryManipulationCheck.h" @@ -20,6 +21,8 @@ class BugproneModule : public ClangTidyModule { public: void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override { + CheckFactories.registerCheck( + "bugprone-integer-division"); CheckFactories.registerCheck( "bugprone-suspicious-memset-usage"); CheckFactories.registerCheck( Index: clang-tidy/bugprone/CMakeLists.txt =================================================================== --- clang-tidy/bugprone/CMakeLists.txt +++ clang-tidy/bugprone/CMakeLists.txt @@ -2,6 +2,7 @@ add_clang_library(clangTidyBugproneModule BugproneTidyModule.cpp + IntegerDivisionCheck.cpp SuspiciousMemsetUsageCheck.cpp UndefinedMemoryManipulationCheck.cpp Index: clang-tidy/bugprone/IntegerDivisionCheck.h =================================================================== --- /dev/null +++ clang-tidy/bugprone/IntegerDivisionCheck.h @@ -0,0 +1,36 @@ +//===--- IntegerDivisionCheck.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_BUGPRONE_INTEGER_DIVISION_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_INTEGER_DIVISION_H + +#include "../ClangTidy.h" + +namespace clang { +namespace tidy { +namespace bugprone { + +/// Finds integer divisions in environments otherwise requiring floating-point +/// values indicating unintended precision loss. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone-integer-division.html +class IntegerDivisionCheck : public ClangTidyCheck { +public: + IntegerDivisionCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; +}; + +} // namespace bugprone +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_INTEGER_DIVISION_H Index: clang-tidy/bugprone/IntegerDivisionCheck.cpp =================================================================== --- /dev/null +++ clang-tidy/bugprone/IntegerDivisionCheck.cpp @@ -0,0 +1,41 @@ +//===--- IntegerDivisionCheck.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 "IntegerDivisionCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace bugprone { + +void IntegerDivisionCheck::registerMatchers(MatchFinder *Finder) { + Finder->addMatcher( + binaryOperator( + hasOperatorName("/"), hasLHS(expr(hasType(isInteger())).bind("LHS")), + hasRHS(expr(hasType(isInteger())).bind("RHS")), + hasAncestor(castExpr(hasCastKind(CK_IntegralToFloating), + unless(hasDescendant(callExpr( + hasType(isInteger()), + unless(anyOf(equalsBoundNode("LHS"), + equalsBoundNode("RHS"))))))))) + .bind("BinOp"), + this); +} + +void IntegerDivisionCheck::check(const MatchFinder::MatchResult &Result) { + const Expr *BinOp = Result.Nodes.getNodeAs("BinOp"); + diag(BinOp->getLocStart(), "integer division; possible precision loss"); +} + +} // namespace bugprone +} // namespace tidy +} // namespace clang Index: docs/ReleaseNotes.rst =================================================================== --- docs/ReleaseNotes.rst +++ docs/ReleaseNotes.rst @@ -57,6 +57,12 @@ Improvements to clang-tidy -------------------------- +- New `bugprone-integer-division + `_ check + + Finds integer divisions in environments otherwise requiring floating-point + values indicating unintended precision loss. + The improvements are... Improvements to include-fixer Index: docs/clang-tidy/checks/bugprone-integer-division.rst =================================================================== --- /dev/null +++ docs/clang-tidy/checks/bugprone-integer-division.rst @@ -0,0 +1,24 @@ +.. title:: clang-tidy - bugprone-integer-division + +bugprone-integer-division +========================= + +Finds integer divisions in environments otherwise requiring floating-point +values indicating unintended precision loss. + +Examples: + +.. code-block:: c++ + + float floatFunc(float); + int intFunc(int); + + // Warn, floating-point values expected. + floatFunc(1 + 7 / 2); + floatFunc(7 / (2 + 3)); + intFunc(floatFunc(1 + 7 / 2)); + + // Do not warn, there are signs of deliberateness. + floatFunc(intFunc(3) / 5); + floatFunc(1 + intFunc(1 + 7 / 2)); + 1 << 2 / 3; Index: docs/clang-tidy/checks/list.rst =================================================================== --- docs/clang-tidy/checks/list.rst +++ docs/clang-tidy/checks/list.rst @@ -9,6 +9,7 @@ android-cloexec-open android-cloexec-socket boost-use-to-string + bugprone-integer-division bugprone-suspicious-memset-usage bugprone-undefined-memory-manipulation cert-dcl03-c (redirects to misc-static-assert) Index: test/clang-tidy/bugprone-integer-division.cpp =================================================================== --- /dev/null +++ test/clang-tidy/bugprone-integer-division.cpp @@ -0,0 +1,130 @@ +// RUN: %check_clang_tidy %s bugprone-integer-division %t + +// Functions expecting a floating-point parameter. +void floatArg(float x) {} +void doubleArg(double x) {} +void longDoubleArg(long double x) {} + +// Functions expected to return a floating-point value. +float singleDiv() { + int x = -5; + int y = 2; + return x/y; +// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: integer division; possible precision loss [bugprone-integer-division] +} + +double wrongOrder(int x, int y) { + return x/y/0.1; +// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: integer division; possible precision loss [bugprone-integer-division] +} + +long double rightOrder(int x, int y) { + return 0.1/x/y; // OK +} + +// Typical mathematical functions. +float sin(float); +double acos(double); +long double tanh(long double); + +namespace std { + using ::sin; +} + +template +void intDivSin(T x) { + sin(x); +} + +int intFunc(int); + +struct X { + int n; + void m() { + sin(n / 3); +// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: integer division; possible precision loss [bugprone-integer-division] + } +}; + +void integerDivision() { + char a = 2; + short b = -5; + int c = 9784; + enum third { x, y, z=2 }; + third d = z; + char e[] = {'a', 'b', 'c'}; + char f = *(e + 1 / a); + bool g = 1; + + sin(1 + c / (2 + 2)); +// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: integer division; possible precision loss [bugprone-integer-division] + sin(c / (1 + .5)); + sin((c + .5) / 3); + + sin(intFunc(3) / 5); +// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: integer division; possible precision loss [bugprone-integer-division] + acos(2 / intFunc(7)); +// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: integer division; possible precision loss [bugprone-integer-division] + + floatArg(1 + 2 / 3); +// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: integer division; possible precision loss [bugprone-integer-division] + sin(1 + 2 / 3); +// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: integer division; possible precision loss [bugprone-integer-division] + intFunc(sin(1 + 2 / 3)); +// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: integer division; possible precision loss [bugprone-integer-division] + + floatArg(1 + intFunc(1 + 2 / 3)); + floatArg(1 + 3 * intFunc(a / b)); + + 1 << (2 / 3); + 1 << intFunc(2 / 3); + +#define M_SIN sin(a / b); + M_SIN +// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: integer division; possible precision loss [bugprone-integer-division] + + intDivSin(a / b); +// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: integer division; possible precision loss [bugprone-integer-division] + intDivSin(c / d); +// CHECK-MESSAGES: :[[@LINE-1]]:21: warning: integer division; possible precision loss [bugprone-integer-division] + intDivSin(f / g); +// CHECK-MESSAGES: :[[@LINE-1]]:26: warning: integer division; possible precision loss [bugprone-integer-division] + + floatArg(1 / 3); +// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: integer division; possible precision loss [bugprone-integer-division] + doubleArg(a / b); +// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: integer division; possible precision loss [bugprone-integer-division] + longDoubleArg(3 / d); +// CHECK-MESSAGES: :[[@LINE-1]]:17: warning: integer division; possible precision loss [bugprone-integer-division] + floatArg(a / b / 0.1); +// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: integer division; possible precision loss [bugprone-integer-division] + doubleArg(1 / 3 / 0.1); +// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: integer division; possible precision loss [bugprone-integer-division] + longDoubleArg(2 / 3 / 5); +// CHECK-MESSAGES: :[[@LINE-1]]:17: warning: integer division; possible precision loss [bugprone-integer-division] + + std::sin(2 / 3); +// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: integer division; possible precision loss [bugprone-integer-division] + ::acos(7 / d); +// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: integer division; possible precision loss [bugprone-integer-division] + tanh(f / g); +// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: integer division; possible precision loss [bugprone-integer-division] + + floatArg(0.1 / a / b); + doubleArg(0.1 / 3 / 1); + + singleDiv(); + wrongOrder(a,b); + rightOrder(a,b); + + sin(a / b); +// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: integer division; possible precision loss [bugprone-integer-division] + acos(f / d); +// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: integer division; possible precision loss [bugprone-integer-division] + tanh(c / g); +// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: integer division; possible precision loss [bugprone-integer-division] + + sin(3.0 / a); + acos(b / 3.14); + tanh(3.14 / f / g); +}