@@ -55,16 +55,27 @@ impl LateLintPass<'_> for ManualCheckedDiv {
5555 && is_integer ( cx, divisor)
5656 && let Some ( block) = branch_block ( then, r#else, branch)
5757 {
58- let mut eq = SpanlessEq :: new ( cx) ;
58+ let mut eq = SpanlessEq :: new ( cx) . deny_side_effects ( ) . paths_by_resolution ( ) ;
59+ if !eq. eq_expr ( divisor, divisor) {
60+ return ;
61+ }
62+
5963 let mut applicability = Applicability :: MaybeIncorrect ;
6064 let mut divisions = Vec :: new ( ) ;
65+ let mut first_use = None ;
6166
62- for_each_expr_without_closures ( block, |e| {
67+ let found_early_use = for_each_expr_without_closures ( block, |e| {
6368 if let ExprKind :: Binary ( binop, lhs, rhs) = e. kind
6469 && binop. node == BinOpKind :: Div
6570 && eq. eq_expr ( rhs, divisor)
6671 && is_integer ( cx, lhs)
6772 {
73+ match first_use {
74+ None => first_use = Some ( UseKind :: Division ) ,
75+ Some ( UseKind :: Other ) => return ControlFlow :: Break ( ( ) ) ,
76+ Some ( UseKind :: Division ) => { } ,
77+ }
78+
6879 let lhs_snip = Sugg :: hir_with_applicability ( cx, lhs, "_" , & mut applicability) ;
6980 let rhs_snip = Sugg :: hir_with_applicability ( cx, rhs, "_" , & mut applicability) ;
7081 let lhs_ty = cx. typeck_results ( ) . expr_ty ( lhs) ;
@@ -93,28 +104,41 @@ impl LateLintPass<'_> for ManualCheckedDiv {
93104 divisions. push ( ( e. span , suggestion) ) ;
94105
95106 ControlFlow :: < ( ) , _ > :: Continue ( Descend :: No )
107+ } else if eq. eq_expr ( e, divisor) {
108+ if first_use. is_none ( ) {
109+ first_use = Some ( UseKind :: Other ) ;
110+ }
111+ ControlFlow :: < ( ) , _ > :: Continue ( Descend :: Yes )
96112 } else {
97113 ControlFlow :: < ( ) , _ > :: Continue ( Descend :: Yes )
98114 }
99115 } ) ;
100116
101- if !divisions. is_empty ( ) {
102- let mut spans: Vec < _ > = divisions. iter ( ) . map ( |( span, _) | * span) . collect ( ) ;
103- spans. push ( cond. span ) ;
104- span_lint_and_then (
105- cx,
106- MANUAL_CHECKED_DIV ,
107- MultiSpan :: from_spans ( spans) ,
108- "manual checked division" ,
109- |diag| {
110- diag. multipart_suggestion ( "consider using `checked_div`" , divisions, applicability) ;
111- } ,
112- ) ;
117+ if found_early_use. is_some ( ) || first_use != Some ( UseKind :: Division ) || divisions. is_empty ( ) {
118+ return ;
113119 }
120+
121+ let mut spans: Vec < _ > = divisions. iter ( ) . map ( |( span, _) | * span) . collect ( ) ;
122+ spans. push ( cond. span ) ;
123+ span_lint_and_then (
124+ cx,
125+ MANUAL_CHECKED_DIV ,
126+ MultiSpan :: from_spans ( spans) ,
127+ "manual checked division" ,
128+ |diag| {
129+ diag. multipart_suggestion ( "consider using `checked_div`" , divisions, applicability) ;
130+ } ,
131+ ) ;
114132 }
115133 }
116134}
117135
136+ #[ derive( Copy , Clone , Eq , PartialEq ) ]
137+ enum UseKind {
138+ Division ,
139+ Other ,
140+ }
141+
118142fn divisor_from_condition < ' tcx > ( cond : & ' tcx Expr < ' tcx > ) -> Option < ( & ' tcx Expr < ' tcx > , NonZeroBranch ) > {
119143 let ExprKind :: Binary ( binop, lhs, rhs) = cond. kind else {
120144 return None ;
0 commit comments