|
1 | 1 | use super::ARITHMETIC_SIDE_EFFECTS;
|
2 | 2 | use clippy_utils::{
|
3 |
| - consts::{constant, constant_simple}, |
| 3 | + consts::{constant, constant_simple, Constant}, |
4 | 4 | diagnostics::span_lint,
|
5 |
| - peel_hir_expr_refs, peel_hir_expr_unary, |
| 5 | + is_lint_allowed, peel_hir_expr_refs, peel_hir_expr_unary, |
6 | 6 | };
|
7 | 7 | use rustc_ast as ast;
|
8 | 8 | use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
@@ -97,17 +97,19 @@ impl ArithmeticSideEffects {
|
97 | 97 | self.expr_span = Some(expr.span);
|
98 | 98 | }
|
99 | 99 |
|
100 |
| - /// If `expr` is not a literal integer like `1`, returns `None`. |
| 100 | + /// Returns the numeric value of a literal integer originated from `expr`, if any. |
101 | 101 | ///
|
102 |
| - /// Returns the absolute value of the expression, if this is an integer literal. |
103 |
| - fn literal_integer(expr: &hir::Expr<'_>) -> Option<u128> { |
| 102 | + /// Literal integers can be originated from adhoc declarations like `1`, associated constants |
| 103 | + /// like `i32::MAX` or constant references like `N` from `const N: i32 = 1;`, |
| 104 | + fn literal_integer(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<u128> { |
104 | 105 | let actual = peel_hir_expr_unary(expr).0;
|
105 | 106 | if let hir::ExprKind::Lit(ref lit) = actual.kind && let ast::LitKind::Int(n, _) = lit.node {
|
106 |
| - Some(n) |
| 107 | + return Some(n) |
107 | 108 | }
|
108 |
| - else { |
109 |
| - None |
| 109 | + if let Some((Constant::Int(n), _)) = constant(cx, cx.typeck_results(), expr) { |
| 110 | + return Some(n); |
110 | 111 | }
|
| 112 | + None |
111 | 113 | }
|
112 | 114 |
|
113 | 115 | /// Manages when the lint should be triggered. Operations in constant environments, hard coded
|
@@ -143,7 +145,10 @@ impl ArithmeticSideEffects {
|
143 | 145 | let has_valid_op = if Self::is_integral(lhs_ty) && Self::is_integral(rhs_ty) {
|
144 | 146 | let (actual_lhs, lhs_ref_counter) = peel_hir_expr_refs(lhs);
|
145 | 147 | let (actual_rhs, rhs_ref_counter) = peel_hir_expr_refs(rhs);
|
146 |
| - match (Self::literal_integer(actual_lhs), Self::literal_integer(actual_rhs)) { |
| 148 | + match ( |
| 149 | + Self::literal_integer(cx, actual_lhs), |
| 150 | + Self::literal_integer(cx, actual_rhs), |
| 151 | + ) { |
147 | 152 | (None, None) => false,
|
148 | 153 | (None, Some(n)) | (Some(n), None) => match (&op.node, n) {
|
149 | 154 | (hir::BinOpKind::Div | hir::BinOpKind::Rem, 0) => false,
|
@@ -180,20 +185,22 @@ impl ArithmeticSideEffects {
|
180 | 185 | return;
|
181 | 186 | }
|
182 | 187 | let actual_un_expr = peel_hir_expr_refs(un_expr).0;
|
183 |
| - if Self::literal_integer(actual_un_expr).is_some() { |
| 188 | + if Self::literal_integer(cx, actual_un_expr).is_some() { |
184 | 189 | return;
|
185 | 190 | }
|
186 | 191 | self.issue_lint(cx, expr);
|
187 | 192 | }
|
188 | 193 |
|
189 |
| - fn should_skip_expr(&mut self, expr: &hir::Expr<'_>) -> bool { |
190 |
| - self.expr_span.is_some() || self.const_span.map_or(false, |sp| sp.contains(expr.span)) |
| 194 | + fn should_skip_expr(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { |
| 195 | + is_lint_allowed(cx, ARITHMETIC_SIDE_EFFECTS, expr.hir_id) |
| 196 | + || self.expr_span.is_some() |
| 197 | + || self.const_span.map_or(false, |sp| sp.contains(expr.span)) |
191 | 198 | }
|
192 | 199 | }
|
193 | 200 |
|
194 | 201 | impl<'tcx> LateLintPass<'tcx> for ArithmeticSideEffects {
|
195 | 202 | fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &hir::Expr<'tcx>) {
|
196 |
| - if self.should_skip_expr(expr) { |
| 203 | + if self.should_skip_expr(cx, expr) { |
197 | 204 | return;
|
198 | 205 | }
|
199 | 206 | match &expr.kind {
|
|
0 commit comments