@@ -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 } ;
@@ -39,15 +76,15 @@ pub fn check(
3976 return ;
4077 } ;
4178
42- match ( & checked_arith, sign, mm) {
79+ match ( checked_arith, sign, mm) {
4380 ( Add , Pos , Max ) | ( Add , Neg , Min ) | ( Sub , Neg , Max ) | ( Sub , Pos , Min ) => ( ) ,
4481 // "mul" is omitted because lhs can be negative.
4582 _ => return ,
4683 }
4784 } else {
4885 use self :: MinMax :: { Max , Min } ;
4986 use CheckedArith :: { Add , Mul , Sub } ;
50- match ( mm, & checked_arith) {
87+ match ( mm, checked_arith) {
5188 ( Max , Add | Mul ) | ( Min , Sub ) => ( ) ,
5289 _ => return ,
5390 }
@@ -70,6 +107,7 @@ pub fn check(
70107 ) ;
71108}
72109
110+ #[ derive( Clone , Copy ) ]
73111enum CheckedArith {
74112 Add ,
75113 Sub ,
@@ -87,7 +125,7 @@ impl CheckedArith {
87125 Some ( res)
88126 }
89127
90- fn as_saturating ( & self ) -> & ' static str {
128+ fn as_saturating ( self ) -> & ' static str {
91129 match self {
92130 Self :: Add => "saturating_add" ,
93131 Self :: Sub => "saturating_sub" ,
@@ -102,7 +140,7 @@ enum MinMax {
102140 Max ,
103141}
104142
105- fn is_min_or_max ( cx : & LateContext < ' _ > , expr : & hir :: Expr < ' _ > ) -> Option < MinMax > {
143+ fn is_min_or_max ( cx : & LateContext < ' _ > , expr : & Expr < ' _ > ) -> Option < MinMax > {
106144 // `T::max_value()` `T::min_value()` inherent methods
107145 if let hir:: ExprKind :: Call ( func, [ ] ) = & expr. kind
108146 && let hir:: ExprKind :: Path ( hir:: QPath :: TypeRelative ( _, segment) ) = & func. kind
@@ -140,7 +178,7 @@ fn is_min_or_max(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<MinMax> {
140178 ( 0 , if bits == 128 { !0 } else { ( 1 << bits) - 1 } )
141179 } ;
142180
143- let check_lit = |expr : & hir :: Expr < ' _ > , check_min : bool | {
181+ let check_lit = |expr : & Expr < ' _ > , check_min : bool | {
144182 if let hir:: ExprKind :: Lit ( lit) = & expr. kind
145183 && let ast:: LitKind :: Int ( value, _) = lit. node
146184 {
@@ -175,7 +213,7 @@ enum Sign {
175213 Neg ,
176214}
177215
178- fn lit_sign ( expr : & hir :: Expr < ' _ > ) -> Option < Sign > {
216+ fn lit_sign ( expr : & Expr < ' _ > ) -> Option < Sign > {
179217 if let hir:: ExprKind :: Unary ( hir:: UnOp :: Neg , inner) = & expr. kind {
180218 if let hir:: ExprKind :: Lit ( ..) = & inner. kind {
181219 return Some ( Sign :: Neg ) ;
0 commit comments