@@ -3,18 +3,19 @@ use clippy_utils::source::snippet_with_applicability;
33use clippy_utils:: { path_res, sym} ;
44use rustc_ast:: ast;
55use rustc_errors:: Applicability ;
6- use rustc_hir as hir;
76use rustc_hir:: def:: Res ;
7+ use rustc_hir:: { self as hir, Expr } ;
88use rustc_lint:: LateContext ;
9+ use rustc_middle:: ty:: Ty ;
910use rustc_middle:: ty:: layout:: LayoutOf ;
1011use rustc_span:: Symbol ;
1112
12- pub fn check (
13+ pub fn check_unwrap_or (
1314 cx : & LateContext < ' _ > ,
14- expr : & hir :: Expr < ' _ > ,
15- arith_lhs : & hir :: Expr < ' _ > ,
16- arith_rhs : & hir :: Expr < ' _ > ,
17- unwrap_arg : & hir :: Expr < ' _ > ,
15+ expr : & Expr < ' _ > ,
16+ arith_lhs : & Expr < ' _ > ,
17+ arith_rhs : & Expr < ' _ > ,
18+ unwrap_arg : & Expr < ' _ > ,
1819 arith : Symbol ,
1920) {
2021 let ty = cx. typeck_results ( ) . expr_ty ( arith_lhs) ;
@@ -30,6 +31,42 @@ pub fn check(
3031 return ;
3132 } ;
3233
34+ check ( cx, expr, arith_lhs, arith_rhs, ty, mm, checked_arith) ;
35+ }
36+
37+ /// Precondition: should be called on `x.saturating_sub(y).unwrap_or_default()`
38+ pub ( super ) fn check_unwrap_or_default (
39+ cx : & LateContext < ' _ > ,
40+ expr : & Expr < ' _ > ,
41+ arith_lhs : & Expr < ' _ > ,
42+ arith_rhs : & Expr < ' _ > ,
43+ ) {
44+ let ty = cx. typeck_results ( ) . expr_ty ( arith_lhs) ;
45+ if !ty. is_integral ( ) {
46+ return ;
47+ }
48+
49+ let mm = if ty. is_signed ( ) {
50+ return ; // iN::default() is 0, which is neither MIN nor MAX
51+ } else {
52+ MinMax :: Min // uN::default() is 0, which is also the MIN
53+ } ;
54+
55+ // See precondition
56+ let checked_arith = CheckedArith :: Sub ;
57+
58+ check ( cx, expr, arith_lhs, arith_rhs, ty, mm, checked_arith) ;
59+ }
60+
61+ fn check (
62+ cx : & LateContext < ' _ > ,
63+ expr : & Expr < ' _ > ,
64+ arith_lhs : & Expr < ' _ > ,
65+ arith_rhs : & Expr < ' _ > ,
66+ ty : Ty < ' _ > ,
67+ mm : MinMax ,
68+ checked_arith : CheckedArith ,
69+ ) {
3370 if ty. is_signed ( ) {
3471 use self :: MinMax :: { Max , Min } ;
3572 use self :: Sign :: { Neg , Pos } ;
@@ -102,7 +139,7 @@ enum MinMax {
102139 Max ,
103140}
104141
105- fn is_min_or_max ( cx : & LateContext < ' _ > , expr : & hir :: Expr < ' _ > ) -> Option < MinMax > {
142+ fn is_min_or_max ( cx : & LateContext < ' _ > , expr : & Expr < ' _ > ) -> Option < MinMax > {
106143 // `T::max_value()` `T::min_value()` inherent methods
107144 if let hir:: ExprKind :: Call ( func, [ ] ) = & expr. kind
108145 && let hir:: ExprKind :: Path ( hir:: QPath :: TypeRelative ( _, segment) ) = & func. kind
@@ -140,7 +177,7 @@ fn is_min_or_max(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<MinMax> {
140177 ( 0 , if bits == 128 { !0 } else { ( 1 << bits) - 1 } )
141178 } ;
142179
143- let check_lit = |expr : & hir :: Expr < ' _ > , check_min : bool | {
180+ let check_lit = |expr : & Expr < ' _ > , check_min : bool | {
144181 if let hir:: ExprKind :: Lit ( lit) = & expr. kind
145182 && let ast:: LitKind :: Int ( value, _) = lit. node
146183 {
@@ -175,7 +212,7 @@ enum Sign {
175212 Neg ,
176213}
177214
178- fn lit_sign ( expr : & hir :: Expr < ' _ > ) -> Option < Sign > {
215+ fn lit_sign ( expr : & Expr < ' _ > ) -> Option < Sign > {
179216 if let hir:: ExprKind :: Unary ( hir:: UnOp :: Neg , inner) = & expr. kind {
180217 if let hir:: ExprKind :: Lit ( ..) = & inner. kind {
181218 return Some ( Sign :: Neg ) ;
0 commit comments