1 //===--- IncorrectRoundingsCheck.cpp - clang-tidy ------------------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "IncorrectRoundingsCheck.h" 11 #include "clang/AST/DeclBase.h" 12 #include "clang/AST/Type.h" 13 #include "clang/ASTMatchers/ASTMatchFinder.h" 14 #include "clang/ASTMatchers/ASTMatchers.h" 15 #include "clang/Lex/Lexer.h" 16 17 using namespace clang::ast_matchers; 18 19 namespace clang { 20 namespace tidy { 21 namespace bugprone { 22 23 namespace { 24 AST_MATCHER(FloatingLiteral, floatHalf) { 25 const auto &literal = Node.getValue(); 26 if ((&Node.getSemantics()) == &llvm::APFloat::IEEEsingle()) 27 return literal.convertToFloat() == 0.5f; 28 if ((&Node.getSemantics()) == &llvm::APFloat::IEEEdouble()) 29 return literal.convertToDouble() == 0.5; 30 return false; 31 } 32 } // namespace 33 34 void IncorrectRoundingsCheck::registerMatchers(MatchFinder *MatchFinder) { 35 // Match a floating literal with value 0.5. 36 auto FloatHalf = floatLiteral(floatHalf()); 37 38 // Match a floating point expression. 39 auto FloatType = expr(hasType(realFloatingPointType())); 40 41 // Match a floating literal of 0.5 or a floating literal of 0.5 implicitly. 42 // cast to floating type. 43 auto FloatOrCastHalf = 44 anyOf(FloatHalf, 45 implicitCastExpr(FloatType, has(ignoringParenImpCasts(FloatHalf)))); 46 47 // Match if either the LHS or RHS is a floating literal of 0.5 or a floating 48 // literal of 0.5 and the other is of type double or vice versa. 49 auto OneSideHalf = anyOf(allOf(hasLHS(FloatOrCastHalf), hasRHS(FloatType)), 50 allOf(hasRHS(FloatOrCastHalf), hasLHS(FloatType))); 51 52 // Find expressions of cast to int of the sum of a floating point expression 53 // and 0.5. 54 MatchFinder->addMatcher( 55 implicitCastExpr( 56 hasImplicitDestinationType(isInteger()), 57 ignoringParenCasts(binaryOperator(hasOperatorName("+"), OneSideHalf))) 58 .bind("CastExpr"), 59 this); 60 } 61 62 void IncorrectRoundingsCheck::check(const MatchFinder::MatchResult &Result) { 63 const auto *CastExpr = Result.Nodes.getNodeAs<ImplicitCastExpr>("CastExpr"); 64 diag(CastExpr->getLocStart(), 65 "casting (double + 0.5) to integer leads to incorrect rounding; " 66 "consider using lround (#include <cmath>) instead"); 67 } 68 69 } // namespace bugprone 70 } // namespace tidy 71 } // namespace clang 72