1 use clippy_utils
::consts
::constant_simple
;
2 use clippy_utils
::diagnostics
::span_lint
;
4 use rustc_lint
::LateContext
;
5 use rustc_span
::source_map
::Span
;
7 use super::{FLOAT_ARITHMETIC, INTEGER_ARITHMETIC}
;
11 expr_id
: Option
<hir
::HirId
>,
12 /// This field is used to check whether expressions are constants, such as in enum discriminants
14 const_span
: Option
<Span
>,
17 fn skip_expr(&mut self, e
: &hir
::Expr
<'_
>) -> bool
{
18 self.expr_id
.is_some() || self.const_span
.map_or(false, |span
| span
.contains(e
.span
))
21 pub fn check_binary
<'tcx
>(
23 cx
: &LateContext
<'tcx
>,
24 expr
: &'tcx hir
::Expr
<'_
>,
26 l
: &'tcx hir
::Expr
<'_
>,
27 r
: &'tcx hir
::Expr
<'_
>,
29 if self.skip_expr(expr
) {
35 | hir
::BinOpKind
::BitAnd
36 | hir
::BinOpKind
::BitOr
37 | hir
::BinOpKind
::BitXor
43 | hir
::BinOpKind
::Gt
=> return,
47 let (l_ty
, r_ty
) = (cx
.typeck_results().expr_ty(l
), cx
.typeck_results().expr_ty(r
));
48 if l_ty
.peel_refs().is_integral() && r_ty
.peel_refs().is_integral() {
50 hir
::BinOpKind
::Div
| hir
::BinOpKind
::Rem
=> match &r
.kind
{
51 hir
::ExprKind
::Lit(_lit
) => (),
52 hir
::ExprKind
::Unary(hir
::UnOp
::Neg
, expr
) => {
53 if let hir
::ExprKind
::Lit(lit
) = &expr
.kind
{
54 if let rustc_ast
::ast
::LitKind
::Int(1, _
) = lit
.node
{
55 span_lint(cx
, INTEGER_ARITHMETIC
, expr
.span
, "integer arithmetic detected");
56 self.expr_id
= Some(expr
.hir_id
);
61 span_lint(cx
, INTEGER_ARITHMETIC
, expr
.span
, "integer arithmetic detected");
62 self.expr_id
= Some(expr
.hir_id
);
66 span_lint(cx
, INTEGER_ARITHMETIC
, expr
.span
, "integer arithmetic detected");
67 self.expr_id
= Some(expr
.hir_id
);
70 } else if r_ty
.peel_refs().is_floating_point() && r_ty
.peel_refs().is_floating_point() {
71 span_lint(cx
, FLOAT_ARITHMETIC
, expr
.span
, "floating-point arithmetic detected");
72 self.expr_id
= Some(expr
.hir_id
);
76 pub fn check_negate
<'tcx
>(&mut self, cx
: &LateContext
<'tcx
>, expr
: &'tcx hir
::Expr
<'_
>, arg
: &'tcx hir
::Expr
<'_
>) {
77 if self.skip_expr(expr
) {
80 let ty
= cx
.typeck_results().expr_ty(arg
);
81 if constant_simple(cx
, cx
.typeck_results(), expr
).is_none() {
83 span_lint(cx
, INTEGER_ARITHMETIC
, expr
.span
, "integer arithmetic detected");
84 self.expr_id
= Some(expr
.hir_id
);
85 } else if ty
.is_floating_point() {
86 span_lint(cx
, FLOAT_ARITHMETIC
, expr
.span
, "floating-point arithmetic detected");
87 self.expr_id
= Some(expr
.hir_id
);
92 pub fn expr_post(&mut self, id
: hir
::HirId
) {
93 if Some(id
) == self.expr_id
{
98 pub fn enter_body(&mut self, cx
: &LateContext
<'_
>, body
: &hir
::Body
<'_
>) {
99 let body_owner
= cx
.tcx
.hir().body_owner(body
.id());
100 let body_owner_def_id
= cx
.tcx
.hir().local_def_id(body_owner
);
102 match cx
.tcx
.hir().body_owner_kind(body_owner_def_id
) {
103 hir
::BodyOwnerKind
::Static(_
) | hir
::BodyOwnerKind
::Const
=> {
104 let body_span
= cx
.tcx
.hir().span_with_body(body_owner
);
106 if let Some(span
) = self.const_span
{
107 if span
.contains(body_span
) {
111 self.const_span
= Some(body_span
);
113 hir
::BodyOwnerKind
::Fn
| hir
::BodyOwnerKind
::Closure
=> (),
117 pub fn body_post(&mut self, cx
: &LateContext
<'_
>, body
: &hir
::Body
<'_
>) {
118 let body_owner
= cx
.tcx
.hir().body_owner(body
.id());
119 let body_span
= cx
.tcx
.hir().span_with_body(body_owner
);
121 if let Some(span
) = self.const_span
{
122 if span
.contains(body_span
) {
126 self.const_span
= None
;