@@ -4,18 +4,19 @@ use clippy_utils::source::snippet_with_applicability;
44use clippy_utils:: sym;
55use rustc_ast:: ast;
66use rustc_errors:: Applicability ;
7- use rustc_hir as hir;
87use rustc_hir:: def:: Res ;
8+ use rustc_hir:: { self as hir, Expr } ;
99use rustc_lint:: LateContext ;
10+ use rustc_middle:: ty:: Ty ;
1011use rustc_middle:: ty:: layout:: LayoutOf ;
1112use rustc_span:: Symbol ;
1213
13- pub fn check (
14+ pub fn check_unwrap_or (
1415 cx : & LateContext < ' _ > ,
15- expr : & hir :: Expr < ' _ > ,
16- arith_lhs : & hir :: Expr < ' _ > ,
17- arith_rhs : & hir :: Expr < ' _ > ,
18- unwrap_arg : & hir :: Expr < ' _ > ,
16+ expr : & Expr < ' _ > ,
17+ arith_lhs : & Expr < ' _ > ,
18+ arith_rhs : & Expr < ' _ > ,
19+ unwrap_arg : & Expr < ' _ > ,
1920 arith : Symbol ,
2021) {
2122 let ty = cx. typeck_results ( ) . expr_ty ( arith_lhs) ;
@@ -31,26 +32,58 @@ pub fn check(
3132 return ;
3233 } ;
3334
34- {
35- use self :: MinMax :: { Max , Min } ;
36- use self :: Sign :: { Neg , Pos } ;
37- use CheckedArith :: { Add , Mul , Sub } ;
38-
39- if ty. is_signed ( ) {
40- let Some ( sign) = lit_sign ( arith_rhs) else {
41- return ;
42- } ;
43-
44- match ( & checked_arith, sign, mm) {
45- ( Add , Pos , Max ) | ( Add , Neg , Min ) | ( Sub , Neg , Max ) | ( Sub , Pos , Min ) => ( ) ,
46- // "mul" is omitted because lhs can be negative.
47- _ => return ,
48- }
49- } else {
50- match ( mm, & checked_arith) {
51- ( Max , Add | Mul ) | ( Min , Sub ) => ( ) ,
52- _ => return ,
53- }
35+ check ( cx, expr, arith_lhs, arith_rhs, ty, mm, checked_arith) ;
36+ }
37+
38+ pub ( super ) fn check_sub_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+ let checked_arith = CheckedArith :: Sub ;
56+
57+ check ( cx, expr, arith_lhs, arith_rhs, ty, mm, checked_arith) ;
58+ }
59+
60+ fn check (
61+ cx : & LateContext < ' _ > ,
62+ expr : & Expr < ' _ > ,
63+ arith_lhs : & Expr < ' _ > ,
64+ arith_rhs : & Expr < ' _ > ,
65+ ty : Ty < ' _ > ,
66+ mm : MinMax ,
67+ checked_arith : CheckedArith ,
68+ ) {
69+ use self :: MinMax :: { Max , Min } ;
70+ use self :: Sign :: { Neg , Pos } ;
71+ use CheckedArith :: { Add , Mul , Sub } ;
72+
73+ if ty. is_signed ( ) {
74+ let Some ( sign) = lit_sign ( arith_rhs) else {
75+ return ;
76+ } ;
77+
78+ match ( checked_arith, sign, mm) {
79+ ( Add , Pos , Max ) | ( Add , Neg , Min ) | ( Sub , Neg , Max ) | ( Sub , Pos , Min ) => ( ) ,
80+ // "mul" is omitted because lhs can be negative.
81+ _ => return ,
82+ }
83+ } else {
84+ match ( mm, checked_arith) {
85+ ( Max , Add | Mul ) | ( Min , Sub ) => ( ) ,
86+ _ => return ,
5487 }
5588 }
5689
@@ -71,6 +104,7 @@ pub fn check(
71104 ) ;
72105}
73106
107+ #[ derive( Clone , Copy ) ]
74108enum CheckedArith {
75109 Add ,
76110 Sub ,
@@ -88,7 +122,7 @@ impl CheckedArith {
88122 Some ( res)
89123 }
90124
91- fn as_saturating ( & self ) -> & ' static str {
125+ fn as_saturating ( self ) -> & ' static str {
92126 match self {
93127 Self :: Add => "saturating_add" ,
94128 Self :: Sub => "saturating_sub" ,
@@ -103,7 +137,7 @@ enum MinMax {
103137 Max ,
104138}
105139
106- fn is_min_or_max ( cx : & LateContext < ' _ > , expr : & hir :: Expr < ' _ > ) -> Option < MinMax > {
140+ fn is_min_or_max ( cx : & LateContext < ' _ > , expr : & Expr < ' _ > ) -> Option < MinMax > {
107141 // `T::max_value()` `T::min_value()` inherent methods
108142 if let hir:: ExprKind :: Call ( func, [ ] ) = & expr. kind
109143 && let hir:: ExprKind :: Path ( hir:: QPath :: TypeRelative ( _, segment) ) = & func. kind
@@ -141,7 +175,7 @@ fn is_min_or_max(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<MinMax> {
141175 ( 0 , if bits == 128 { !0 } else { ( 1 << bits) - 1 } )
142176 } ;
143177
144- let check_lit = |expr : & hir :: Expr < ' _ > , check_min : bool | {
178+ let check_lit = |expr : & Expr < ' _ > , check_min : bool | {
145179 if let hir:: ExprKind :: Lit ( lit) = & expr. kind
146180 && let ast:: LitKind :: Int ( value, _) = lit. node
147181 {
@@ -176,7 +210,7 @@ enum Sign {
176210 Neg ,
177211}
178212
179- fn lit_sign ( expr : & hir :: Expr < ' _ > ) -> Option < Sign > {
213+ fn lit_sign ( expr : & Expr < ' _ > ) -> Option < Sign > {
180214 if let hir:: ExprKind :: Unary ( hir:: UnOp :: Neg , inner) = & expr. kind {
181215 if let hir:: ExprKind :: Lit ( ..) = & inner. kind {
182216 return Some ( Sign :: Neg ) ;
0 commit comments