Skip to content

Commit 5bd34a6

Browse files
committed
Added checks for signed integers
1 parent d38206b commit 5bd34a6

File tree

1 file changed

+57
-20
lines changed

1 file changed

+57
-20
lines changed

clippy_lints/src/implicit_saturating_sub.rs

Lines changed: 57 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::utils::{higher, in_macro, span_lint_and_sugg};
1+
use crate::utils::{higher, in_macro, match_qpath, span_lint_and_sugg, SpanlessEq};
22
use if_chain::if_chain;
33
use rustc_ast::ast::LitKind;
44
use rustc_errors::Applicability;
@@ -50,41 +50,78 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ImplicitSaturatingSub {
5050
}
5151
if_chain! {
5252
if let Some((ref cond, ref then, None)) = higher::if_block(&expr);
53+
5354
// Check if the conditional expression is a binary operation
54-
if let ExprKind::Binary(ref op, ref left, ref right) = cond.kind;
55+
if let ExprKind::Binary(ref op, ref cond_left, ref cond_right) = cond.kind;
56+
57+
// Check if the variable in the condition statement is an integer
58+
if cx.tables.expr_ty(cond_left).is_integral();
59+
5560
// Ensure that the binary operator is > or !=
5661
if BinOpKind::Ne == op.node || BinOpKind::Gt == op.node;
57-
if let ExprKind::Path(ref cond_path) = left.kind;
58-
// Get the literal on the right hand side
59-
if let ExprKind::Lit(ref lit) = right.kind;
60-
if let LitKind::Int(0, _) = lit.node;
62+
6163
// Check if the true condition block has only one statement
6264
if let ExprKind::Block(ref block, _) = then.kind;
6365
if block.stmts.len() == 1;
66+
6467
// Check if assign operation is done
6568
if let StmtKind::Semi(ref e) = block.stmts[0].kind;
6669
if let ExprKind::AssignOp(ref op1, ref target, ref value) = e.kind;
6770
if BinOpKind::Sub == op1.node;
6871
if let ExprKind::Path(ref assign_path) = target.kind;
72+
6973
// Check if the variable in the condition and assignment statement are the same
70-
if let (QPath::Resolved(_, ref cres_path), QPath::Resolved(_, ref ares_path)) = (cond_path, assign_path);
71-
if cres_path.res == ares_path.res;
74+
if SpanlessEq::new(cx).eq_expr(cond_left, target);
75+
76+
// Extracting out the variable name
77+
if let QPath::Resolved(_, ref ares_path) = assign_path;
78+
79+
// Get the literal being subtracted
7280
if let ExprKind::Lit(ref lit1) = value.kind;
73-
if let LitKind::Int(assign_lit, _) = lit1.node;
81+
if let LitKind::Int(1, _) = lit1.node;
82+
7483
then {
7584
// Get the variable name
76-
let var_name = ares_path.segments[0].ident.name.as_str();
77-
let applicability = Applicability::MaybeIncorrect;
78-
span_lint_and_sugg(
79-
cx,
80-
IMPLICIT_SATURATING_SUB,
81-
expr.span,
82-
"Implicitly performing saturating subtraction",
83-
"try",
84-
format!("{} = {}.saturating_sub({});", var_name, var_name, assign_lit.to_string()),
85-
applicability
86-
);
85+
let var_name = ares_path.segments[0].ident.name.as_str().to_string();
86+
87+
match cond_right.kind {
88+
ExprKind::Lit(ref cond_lit) => {
89+
// Check if the constant is zero
90+
if let LitKind::Int(0, _) = cond_lit.node {
91+
print_lint_and_sugg(cx, var_name, expr);
92+
} else {
93+
return;
94+
}
95+
},
96+
ExprKind::Path(ref cond_right_path) => {
97+
if match_qpath(cond_right_path, &["i8", "MIN"]) {
98+
print_lint_and_sugg(cx, var_name, expr);
99+
} else if match_qpath(cond_right_path, &["i16", "MIN"]) {
100+
print_lint_and_sugg(cx, var_name, expr);
101+
} else if match_qpath(cond_right_path, &["i32", "MIN"]) {
102+
print_lint_and_sugg(cx, var_name, expr);
103+
} else if match_qpath(cond_right_path, &["i64", "MIN"]) {
104+
print_lint_and_sugg(cx, var_name, expr);
105+
} else {
106+
return;
107+
}
108+
},
109+
_ => (),
110+
}
87111
}
88112
}
89113
}
90114
}
115+
116+
fn print_lint_and_sugg(cx: &LateContext<'_, '_>, var_name: String, expr: &Expr<'_>) {
117+
let applicability = Applicability::MaybeIncorrect;
118+
span_lint_and_sugg(
119+
cx,
120+
IMPLICIT_SATURATING_SUB,
121+
expr.span,
122+
"Implicitly performing saturating subtraction",
123+
"try",
124+
format!("{} = {}.saturating_sub({});", var_name, var_name, 1.to_string()),
125+
applicability,
126+
);
127+
}

0 commit comments

Comments
 (0)