]> git.proxmox.com Git - rustc.git/blob - src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs
New upstream version 1.66.0+dfsg1
[rustc.git] / src / tools / clippy / clippy_lints / src / operators / numeric_arithmetic.rs
1 use clippy_utils::consts::constant_simple;
2 use clippy_utils::diagnostics::span_lint;
3 use clippy_utils::is_integer_literal;
4 use rustc_hir as hir;
5 use rustc_lint::LateContext;
6 use rustc_span::source_map::Span;
7
8 use super::{FLOAT_ARITHMETIC, INTEGER_ARITHMETIC};
9
10 #[derive(Default)]
11 pub struct Context {
12 expr_id: Option<hir::HirId>,
13 /// This field is used to check whether expressions are constants, such as in enum discriminants
14 /// and consts
15 const_span: Option<Span>,
16 }
17 impl Context {
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))
20 }
21
22 pub fn check_binary<'tcx>(
23 &mut self,
24 cx: &LateContext<'tcx>,
25 expr: &'tcx hir::Expr<'_>,
26 op: hir::BinOpKind,
27 l: &'tcx hir::Expr<'_>,
28 r: &'tcx hir::Expr<'_>,
29 ) {
30 if self.skip_expr(expr) {
31 return;
32 }
33 match op {
34 hir::BinOpKind::And
35 | hir::BinOpKind::Or
36 | hir::BinOpKind::BitAnd
37 | hir::BinOpKind::BitOr
38 | hir::BinOpKind::BitXor
39 | hir::BinOpKind::Eq
40 | hir::BinOpKind::Lt
41 | hir::BinOpKind::Le
42 | hir::BinOpKind::Ne
43 | hir::BinOpKind::Ge
44 | hir::BinOpKind::Gt => return,
45 _ => (),
46 }
47
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() {
50 match op {
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);
57 }
58 },
59 _ => {
60 span_lint(cx, INTEGER_ARITHMETIC, expr.span, "integer arithmetic detected");
61 self.expr_id = Some(expr.hir_id);
62 },
63 },
64 _ => {
65 span_lint(cx, INTEGER_ARITHMETIC, expr.span, "integer arithmetic detected");
66 self.expr_id = Some(expr.hir_id);
67 },
68 }
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);
72 }
73 }
74
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) {
77 return;
78 }
79 let ty = cx.typeck_results().expr_ty(arg);
80 if constant_simple(cx, cx.typeck_results(), expr).is_none() {
81 if ty.is_integral() {
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);
87 }
88 }
89 }
90
91 pub fn expr_post(&mut self, id: hir::HirId) {
92 if Some(id) == self.expr_id {
93 self.expr_id = None;
94 }
95 }
96
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);
100
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);
104
105 if let Some(span) = self.const_span {
106 if span.contains(body_span) {
107 return;
108 }
109 }
110 self.const_span = Some(body_span);
111 },
112 hir::BodyOwnerKind::Fn | hir::BodyOwnerKind::Closure => (),
113 }
114 }
115
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);
119
120 if let Some(span) = self.const_span {
121 if span.contains(body_span) {
122 return;
123 }
124 }
125 self.const_span = None;
126 }
127 }