1 use clippy_utils
::consts
::constant_simple
;
2 use clippy_utils
::diagnostics
::span_lint
;
3 use clippy_utils
::is_integer_literal
;
5 use rustc_lint
::LateContext
;
6 use rustc_span
::source_map
::Span
;
8 use super::{FLOAT_ARITHMETIC, INTEGER_ARITHMETIC}
;
12 expr_id
: Option
<hir
::HirId
>,
13 /// This field is used to check whether expressions are constants, such as in enum discriminants
15 const_span
: Option
<Span
>,
18 fn skip_expr(&mut self, e
: &hir
::Expr
<'_
>) -> bool
{
19 self.expr_id
.is_some() || self.const_span
.map_or(false, |span
| span
.contains(e
.span
))
22 pub fn check_binary
<'tcx
>(
24 cx
: &LateContext
<'tcx
>,
25 expr
: &'tcx hir
::Expr
<'_
>,
27 l
: &'tcx hir
::Expr
<'_
>,
28 r
: &'tcx hir
::Expr
<'_
>,
30 if self.skip_expr(expr
) {
36 | hir
::BinOpKind
::BitAnd
37 | hir
::BinOpKind
::BitOr
38 | hir
::BinOpKind
::BitXor
44 | hir
::BinOpKind
::Gt
=> return,
48 let (l_ty
, r_ty
) = (cx
.typeck_results().expr_ty(l
), cx
.typeck_results().expr_ty(r
));
49 if l_ty
.peel_refs().is_integral() && r_ty
.peel_refs().is_integral() {
51 hir
::BinOpKind
::Div
| hir
::BinOpKind
::Rem
=> match &r
.kind
{
52 hir
::ExprKind
::Lit(_lit
) => (),
53 hir
::ExprKind
::Unary(hir
::UnOp
::Neg
, expr
) => {
54 if is_integer_literal(expr
, 1) {
55 span_lint(cx
, INTEGER_ARITHMETIC
, expr
.span
, "integer arithmetic detected");
56 self.expr_id
= Some(expr
.hir_id
);
60 span_lint(cx
, INTEGER_ARITHMETIC
, expr
.span
, "integer arithmetic detected");
61 self.expr_id
= Some(expr
.hir_id
);
65 span_lint(cx
, INTEGER_ARITHMETIC
, expr
.span
, "integer arithmetic detected");
66 self.expr_id
= Some(expr
.hir_id
);
69 } else if r_ty
.peel_refs().is_floating_point() && r_ty
.peel_refs().is_floating_point() {
70 span_lint(cx
, FLOAT_ARITHMETIC
, expr
.span
, "floating-point arithmetic detected");
71 self.expr_id
= Some(expr
.hir_id
);
75 pub fn check_negate
<'tcx
>(&mut self, cx
: &LateContext
<'tcx
>, expr
: &'tcx hir
::Expr
<'_
>, arg
: &'tcx hir
::Expr
<'_
>) {
76 if self.skip_expr(expr
) {
79 let ty
= cx
.typeck_results().expr_ty(arg
);
80 if constant_simple(cx
, cx
.typeck_results(), expr
).is_none() {
82 span_lint(cx
, INTEGER_ARITHMETIC
, expr
.span
, "integer arithmetic detected");
83 self.expr_id
= Some(expr
.hir_id
);
84 } else if ty
.is_floating_point() {
85 span_lint(cx
, FLOAT_ARITHMETIC
, expr
.span
, "floating-point arithmetic detected");
86 self.expr_id
= Some(expr
.hir_id
);
91 pub fn expr_post(&mut self, id
: hir
::HirId
) {
92 if Some(id
) == self.expr_id
{
97 pub fn enter_body(&mut self, cx
: &LateContext
<'_
>, body
: &hir
::Body
<'_
>) {
98 let body_owner
= cx
.tcx
.hir().body_owner(body
.id());
99 let body_owner_def_id
= cx
.tcx
.hir().local_def_id(body_owner
);
101 match cx
.tcx
.hir().body_owner_kind(body_owner_def_id
) {
102 hir
::BodyOwnerKind
::Static(_
) | hir
::BodyOwnerKind
::Const
=> {
103 let body_span
= cx
.tcx
.hir().span_with_body(body_owner
);
105 if let Some(span
) = self.const_span
{
106 if span
.contains(body_span
) {
110 self.const_span
= Some(body_span
);
112 hir
::BodyOwnerKind
::Fn
| hir
::BodyOwnerKind
::Closure
=> (),
116 pub fn body_post(&mut self, cx
: &LateContext
<'_
>, body
: &hir
::Body
<'_
>) {
117 let body_owner
= cx
.tcx
.hir().body_owner(body
.id());
118 let body_span
= cx
.tcx
.hir().span_with_body(body_owner
);
120 if let Some(span
) = self.const_span
{
121 if span
.contains(body_span
) {
125 self.const_span
= None
;