@@ -4,18 +4,20 @@ 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 ;
12+ use rustc_span:: Symbol ;
1113
12- pub fn check (
14+ pub fn check_unwrap_or (
1315 cx : & LateContext < ' _ > ,
14- expr : & hir :: Expr < ' _ > ,
15- arith_lhs : & hir :: Expr < ' _ > ,
16- arith_rhs : & hir :: Expr < ' _ > ,
17- unwrap_arg : & hir :: Expr < ' _ > ,
18- arith : & str ,
16+ expr : & Expr < ' _ > ,
17+ arith_lhs : & Expr < ' _ > ,
18+ arith_rhs : & Expr < ' _ > ,
19+ unwrap_arg : & Expr < ' _ > ,
20+ arith : Symbol ,
1921) {
2022 let ty = cx. typeck_results ( ) . expr_ty ( arith_lhs) ;
2123 if !ty. is_integral ( ) {
@@ -26,49 +28,116 @@ pub fn check(
2628 return ;
2729 } ;
2830
29- if ty. is_signed ( ) {
30- use self :: MinMax :: { Max , Min } ;
31- use self :: Sign :: { Neg , Pos } ;
31+ let Some ( checked_arith) = CheckedArith :: new ( arith) else {
32+ return ;
33+ } ;
34+
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 ;
3256
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 ( ) {
3374 let Some ( sign) = lit_sign ( arith_rhs) else {
3475 return ;
3576 } ;
3677
37- match ( arith , sign, mm) {
38- ( "add" , Pos , Max ) | ( "add" , Neg , Min ) | ( "sub" , Neg , Max ) | ( "sub" , Pos , Min ) => ( ) ,
78+ match ( checked_arith , sign, mm) {
79+ ( Add , Pos , Max ) | ( Add , Neg , Min ) | ( Sub , Neg , Max ) | ( Sub , Pos , Min ) => ( ) ,
3980 // "mul" is omitted because lhs can be negative.
4081 _ => return ,
4182 }
4283 } else {
43- match ( mm, arith ) {
44- ( MinMax :: Max , "add" | "mul" ) | ( MinMax :: Min , "sub" ) => ( ) ,
84+ match ( mm, checked_arith ) {
85+ ( Max , Add | Mul ) | ( Min , Sub ) => ( ) ,
4586 _ => return ,
4687 }
4788 }
4889
4990 let mut applicability = Applicability :: MachineApplicable ;
91+ let saturating_arith = checked_arith. as_saturating ( ) ;
5092 span_lint_and_sugg (
5193 cx,
5294 super :: MANUAL_SATURATING_ARITHMETIC ,
5395 expr. span ,
5496 "manual saturating arithmetic" ,
55- format ! ( "consider using `saturating_{arith }`" ) ,
97+ format ! ( "consider using `{saturating_arith }`" ) ,
5698 format ! (
57- "{}.saturating_{arith }({})" ,
99+ "{}.{saturating_arith }({})" ,
58100 snippet_with_applicability( cx, arith_lhs. span, ".." , & mut applicability) ,
59101 snippet_with_applicability( cx, arith_rhs. span, ".." , & mut applicability) ,
60102 ) ,
61103 applicability,
62104 ) ;
63105}
64106
107+ #[ derive( Clone , Copy ) ]
108+ enum CheckedArith {
109+ Add ,
110+ Sub ,
111+ Mul ,
112+ }
113+
114+ impl CheckedArith {
115+ fn new ( sym : Symbol ) -> Option < Self > {
116+ let res = match sym {
117+ sym:: checked_add => Self :: Add ,
118+ sym:: checked_sub => Self :: Sub ,
119+ sym:: checked_mul => Self :: Mul ,
120+ _ => return None ,
121+ } ;
122+ Some ( res)
123+ }
124+
125+ fn as_saturating ( self ) -> & ' static str {
126+ match self {
127+ Self :: Add => "saturating_add" ,
128+ Self :: Sub => "saturating_sub" ,
129+ Self :: Mul => "saturating_mul" ,
130+ }
131+ }
132+ }
133+
65134#[ derive( PartialEq , Eq ) ]
66135enum MinMax {
67136 Min ,
68137 Max ,
69138}
70139
71- fn is_min_or_max ( cx : & LateContext < ' _ > , expr : & hir :: Expr < ' _ > ) -> Option < MinMax > {
140+ fn is_min_or_max ( cx : & LateContext < ' _ > , expr : & Expr < ' _ > ) -> Option < MinMax > {
72141 // `T::max_value()` `T::min_value()` inherent methods
73142 if let hir:: ExprKind :: Call ( func, [ ] ) = & expr. kind
74143 && let hir:: ExprKind :: Path ( hir:: QPath :: TypeRelative ( _, segment) ) = & func. kind
@@ -106,7 +175,7 @@ fn is_min_or_max(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<MinMax> {
106175 ( 0 , if bits == 128 { !0 } else { ( 1 << bits) - 1 } )
107176 } ;
108177
109- let check_lit = |expr : & hir :: Expr < ' _ > , check_min : bool | {
178+ let check_lit = |expr : & Expr < ' _ > , check_min : bool | {
110179 if let hir:: ExprKind :: Lit ( lit) = & expr. kind
111180 && let ast:: LitKind :: Int ( value, _) = lit. node
112181 {
@@ -141,7 +210,7 @@ enum Sign {
141210 Neg ,
142211}
143212
144- fn lit_sign ( expr : & hir :: Expr < ' _ > ) -> Option < Sign > {
213+ fn lit_sign ( expr : & Expr < ' _ > ) -> Option < Sign > {
145214 if let hir:: ExprKind :: Unary ( hir:: UnOp :: Neg , inner) = & expr. kind {
146215 if let hir:: ExprKind :: Lit ( ..) = & inner. kind {
147216 return Some ( Sign :: Neg ) ;
0 commit comments