Skip to content

Commit e8c1b54

Browse files
committed
Auto merge of #9559 - c410-f3r:arith, r=Alexendoo
Fix #9544 Fix #9544 r? `@Alexendoo` changelog: [`arithmetic_side_effects`]: Fix false negative for `CustomType / usize`, `CustomType * float` and similar
2 parents 5825ae7 + 99363fe commit e8c1b54

File tree

3 files changed

+270
-60
lines changed

3 files changed

+270
-60
lines changed

clippy_lints/src/operators/arithmetic_side_effects.rs

+25-28
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,17 @@ use rustc_ast as ast;
99
use rustc_data_structures::fx::FxHashSet;
1010
use rustc_hir as hir;
1111
use rustc_lint::{LateContext, LateLintPass};
12+
use rustc_middle::ty::Ty;
1213
use rustc_session::impl_lint_pass;
1314
use rustc_span::source_map::{Span, Spanned};
1415

1516
const HARD_CODED_ALLOWED: &[&str] = &[
1617
"f32",
1718
"f64",
1819
"std::num::Saturating",
19-
"std::string::String",
2020
"std::num::Wrapping",
21+
"std::string::String",
22+
"&str",
2123
];
2224

2325
#[derive(Debug)]
@@ -60,15 +62,14 @@ impl ArithmeticSideEffects {
6062
}
6163

6264
/// Checks if the given `expr` has any of the inner `allowed` elements.
63-
fn is_allowed_ty(&self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
64-
self.allowed.contains(
65-
cx.typeck_results()
66-
.expr_ty(expr)
67-
.to_string()
68-
.split('<')
69-
.next()
70-
.unwrap_or_default(),
71-
)
65+
fn is_allowed_ty(&self, ty: Ty<'_>) -> bool {
66+
self.allowed
67+
.contains(ty.to_string().split('<').next().unwrap_or_default())
68+
}
69+
70+
// For example, 8i32 or &i64::MAX.
71+
fn is_integral(ty: Ty<'_>) -> bool {
72+
ty.peel_refs().is_integral()
7273
}
7374

7475
// Common entry-point to avoid code duplication.
@@ -82,24 +83,13 @@ impl ArithmeticSideEffects {
8283
/// * Is `expr` is a literal integer reference like `&199`, returns the literal integer without
8384
/// references.
8485
/// * If `expr` is anything else, returns `None`.
85-
fn literal_integer<'expr, 'tcx>(
86-
cx: &LateContext<'tcx>,
87-
expr: &'expr hir::Expr<'tcx>,
88-
) -> Option<&'expr hir::Expr<'tcx>> {
89-
let expr_refs = cx.typeck_results().expr_ty(expr).peel_refs();
90-
91-
if !expr_refs.is_integral() {
92-
return None;
93-
}
94-
86+
fn literal_integer<'expr, 'tcx>(expr: &'expr hir::Expr<'tcx>) -> Option<&'expr hir::Expr<'tcx>> {
9587
if matches!(expr.kind, hir::ExprKind::Lit(_)) {
9688
return Some(expr);
9789
}
98-
9990
if let hir::ExprKind::AddrOf(.., inn) = expr.kind && let hir::ExprKind::Lit(_) = inn.kind {
10091
return Some(inn)
10192
}
102-
10393
None
10494
}
10595

@@ -128,14 +118,21 @@ impl ArithmeticSideEffects {
128118
) {
129119
return;
130120
};
131-
if self.is_allowed_ty(cx, lhs) || self.is_allowed_ty(cx, rhs) {
121+
let lhs_ty = cx.typeck_results().expr_ty(lhs);
122+
let rhs_ty = cx.typeck_results().expr_ty(rhs);
123+
let lhs_and_rhs_have_the_same_ty = lhs_ty == rhs_ty;
124+
if lhs_and_rhs_have_the_same_ty && self.is_allowed_ty(lhs_ty) && self.is_allowed_ty(rhs_ty) {
132125
return;
133126
}
134-
let has_valid_op = match (Self::literal_integer(cx, lhs), Self::literal_integer(cx, rhs)) {
135-
(None, None) => false,
136-
(None, Some(local_expr)) => Self::has_valid_op(op, local_expr),
137-
(Some(local_expr), None) => Self::has_valid_op(op, local_expr),
138-
(Some(_), Some(_)) => true,
127+
let has_valid_op = if Self::is_integral(lhs_ty) && Self::is_integral(rhs_ty) {
128+
match (Self::literal_integer(lhs), Self::literal_integer(rhs)) {
129+
(None, None) => false,
130+
(None, Some(local_expr)) => Self::has_valid_op(op, local_expr),
131+
(Some(local_expr), None) => Self::has_valid_op(op, local_expr),
132+
(Some(_), Some(_)) => true,
133+
}
134+
} else {
135+
false
139136
};
140137
if !has_valid_op {
141138
self.issue_lint(cx, expr);

tests/ui/arithmetic_side_effects.rs

+52-1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,31 @@
1212

1313
use core::num::{Saturating, Wrapping};
1414

15+
pub struct Custom;
16+
17+
macro_rules! impl_arith {
18+
( $( $_trait:ident, $ty:ty, $method:ident; )* ) => {
19+
$(
20+
impl core::ops::$_trait<$ty> for Custom {
21+
type Output = Self;
22+
fn $method(self, _: $ty) -> Self::Output { Self }
23+
}
24+
)*
25+
}
26+
}
27+
28+
impl_arith!(
29+
Add, i32, add;
30+
Div, i32, div;
31+
Mul, i32, mul;
32+
Sub, i32, sub;
33+
34+
Add, f64, add;
35+
Div, f64, div;
36+
Mul, f64, mul;
37+
Sub, f64, sub;
38+
);
39+
1540
pub fn association_with_structures_should_not_trigger_the_lint() {
1641
enum Foo {
1742
Bar = -2,
@@ -130,7 +155,7 @@ pub fn non_overflowing_ops_or_ops_already_handled_by_the_compiler_should_not_tri
130155
_n = -(-1);
131156
}
132157

133-
pub fn overflowing_runtime_ops() {
158+
pub fn runtime_ops() {
134159
let mut _n = i32::MAX;
135160

136161
// Assign
@@ -163,6 +188,32 @@ pub fn overflowing_runtime_ops() {
163188
_n = 2 * _n;
164189
_n = &2 * _n;
165190

191+
// Custom
192+
let _ = Custom + 0;
193+
let _ = Custom + 1;
194+
let _ = Custom + 2;
195+
let _ = Custom + 0.0;
196+
let _ = Custom + 1.0;
197+
let _ = Custom + 2.0;
198+
let _ = Custom - 0;
199+
let _ = Custom - 1;
200+
let _ = Custom - 2;
201+
let _ = Custom - 0.0;
202+
let _ = Custom - 1.0;
203+
let _ = Custom - 2.0;
204+
let _ = Custom / 0;
205+
let _ = Custom / 1;
206+
let _ = Custom / 2;
207+
let _ = Custom / 0.0;
208+
let _ = Custom / 1.0;
209+
let _ = Custom / 2.0;
210+
let _ = Custom * 0;
211+
let _ = Custom * 1;
212+
let _ = Custom * 2;
213+
let _ = Custom * 0.0;
214+
let _ = Custom * 1.0;
215+
let _ = Custom * 2.0;
216+
166217
// Unary
167218
_n = -_n;
168219
_n = -&_n;

0 commit comments

Comments
 (0)