33 #include "llvm/ADT/APFloat.h" 37 using namespace clang;
41 class ConversionChecker :
public Checker<check::PreStmt<ImplicitCastExpr>> {
46 mutable std::unique_ptr<BuiltinBug> BT;
49 CheckerContext &C)
const;
53 void reportBug(ExplodedNode *N, CheckerContext &C,
const char Msg[])
const;
58 CheckerContext &C)
const {
69 const ParentMap &PM = C.getLocationContext()->getParentMap();
74 bool LossOfSign =
false;
75 bool LossOfPrecision =
false;
78 if (
const auto *B = dyn_cast<BinaryOperator>(Parent)) {
80 if (Opc == BO_Assign) {
81 LossOfSign = isLossOfSign(Cast, C);
82 LossOfPrecision = isLossOfPrecision(Cast, Cast->
getType(), C);
83 }
else if (Opc == BO_AddAssign || Opc == BO_SubAssign) {
85 LossOfPrecision = isLossOfPrecision(Cast, B->getLHS()->
getType(), C);
86 }
else if (Opc == BO_MulAssign) {
87 LossOfSign = isLossOfSign(Cast, C);
88 LossOfPrecision = isLossOfPrecision(Cast, B->getLHS()->
getType(), C);
89 }
else if (Opc == BO_DivAssign || Opc == BO_RemAssign) {
90 LossOfSign = isLossOfSign(Cast, C);
92 }
else if (Opc == BO_AndAssign) {
93 LossOfSign = isLossOfSign(Cast, C);
95 }
else if (Opc == BO_OrAssign || Opc == BO_XorAssign) {
96 LossOfSign = isLossOfSign(Cast, C);
97 LossOfPrecision = isLossOfPrecision(Cast, B->getLHS()->
getType(), C);
98 }
else if (B->isRelationalOp() || B->isMultiplicativeOp()) {
99 LossOfSign = isLossOfSign(Cast, C);
101 }
else if (isa<DeclStmt>(Parent)) {
102 LossOfSign = isLossOfSign(Cast, C);
103 LossOfPrecision = isLossOfPrecision(Cast, Cast->
getType(), C);
106 if (LossOfSign || LossOfPrecision) {
108 ExplodedNode *N = C.generateNonFatalErrorNode(C.getState());
112 reportBug(N, C,
"Loss of sign in implicit conversion");
114 reportBug(N, C,
"Loss of precision in implicit conversion");
118 void ConversionChecker::reportBug(ExplodedNode *N, CheckerContext &C,
119 const char Msg[])
const {
122 new BuiltinBug(
this,
"Conversion",
"Possible loss of sign/precision."));
125 auto R = llvm::make_unique<BugReport>(*BT, Msg, N);
126 C.emitReport(std::move(R));
131 CheckerContext &C)
const {
143 const auto &AC = C.getASTContext();
147 unsigned RepresentsUntilExp;
150 const llvm::fltSemantics &
Sema = AC.getFloatTypeSemantics(DestType);
151 RepresentsUntilExp = llvm::APFloat::semanticsPrecision(Sema);
153 RepresentsUntilExp = AC.getIntWidth(DestType);
154 if (RepresentsUntilExp == 1) {
159 RepresentsUntilExp--;
162 if (RepresentsUntilExp >=
sizeof(
unsigned long long) *
CHAR_BIT) {
167 unsigned CorrectedSrcWidth = AC.getIntWidth(SubType);
171 if (RepresentsUntilExp >= CorrectedSrcWidth) {
176 unsigned long long MaxVal = 1ULL << RepresentsUntilExp;
181 return C.isGreaterOrEqual(Cast->
getSubExpr(), MaxVal);
186 CheckerContext &C)
const {
196 void ento::registerConversionChecker(CheckerManager &mgr) {
197 mgr.registerChecker<ConversionChecker>();
A (possibly-)qualified type.
Stmt - This represents one statement.
Stmt * getParent(Stmt *) const
bool isUnsignedIntegerType() const
Return true if this is an integer type that is unsigned, according to C99 6.2.5p6 [which returns true...
Sema - This implements semantic analysis and AST building for C.
bool isSignedIntegerType() const
Return true if this is an integer type that is signed, according to C99 6.2.5p4 [char, signed char, short, int, long..], or an enum decl which has a signed representation.
ImplicitCastExpr - Allows us to explicitly represent implicit type conversions, which have no direct ...
SourceLocation getExprLoc() const LLVM_READONLY
getExprLoc - Return the preferred location for the arrow when diagnosing a problem with a generic exp...
Dataflow Directional Tag Classes.
Expr * IgnoreParenImpCasts() LLVM_READONLY
IgnoreParenImpCasts - Ignore parentheses and implicit casts.
bool isIntegerType() const
isIntegerType() does not include complex integers (a GCC extension).
bool isEvaluatable(const ASTContext &Ctx, SideEffectsKind AllowSideEffects=SE_NoSideEffects) const
isEvaluatable - Call EvaluateAsRValue to see if this expression can be constant folded without side-e...
bool isFloatingType() const