11use clippy_utils:: diagnostics:: span_lint_and_sugg;
22use clippy_utils:: source:: snippet;
3+ use rustc_ast:: ast:: BinOpKind ;
34use rustc_errors:: Applicability ;
45use rustc_hir:: { Expr , ExprKind } ;
56use rustc_lint:: { LateContext , LateLintPass } ;
@@ -48,23 +49,42 @@ declare_lint_pass!(NonZeroSuggestions => [NON_ZERO_SUGGESTIONS]);
4849
4950impl < ' tcx > LateLintPass < ' tcx > for NonZeroSuggestions {
5051 fn check_expr ( & mut self , cx : & LateContext < ' tcx > , expr : & ' tcx Expr < ' tcx > ) {
51- if let ExprKind :: Call ( func, [ arg] ) = expr. kind
52- && let ExprKind :: Path ( qpath) = & func. kind
53- && let Some ( def_id) = cx. qpath_res ( qpath, func. hir_id ) . opt_def_id ( )
54- && let ExprKind :: MethodCall ( rcv_path, receiver, _, _) = & arg. kind
52+ if let ExprKind :: Binary ( op, _, rhs) = expr. kind
53+ && matches ! ( op. node, BinOpKind :: Div | BinOpKind :: Rem )
5554 {
56- let fn_name = cx. tcx . item_name ( def_id) ;
57- let target_ty = cx. typeck_results ( ) . expr_ty ( expr) ;
58- let receiver_ty = cx. typeck_results ( ) . expr_ty ( receiver) ;
55+ check_non_zero_conversion ( cx, rhs, Applicability :: MachineApplicable ) ;
56+ } else {
57+ // Check if the parent expression is a binary operation
58+ let parent_is_binary = cx. tcx . hir ( ) . parent_iter ( expr. hir_id ) . any ( |( _, node) | {
59+ matches ! ( node, rustc_hir:: Node :: Expr ( parent_expr) if matches!( parent_expr. kind, ExprKind :: Binary ( ..) ) )
60+ } ) ;
5961
60- if let ty:: Adt ( adt_def, _) = receiver_ty. kind ( )
61- && adt_def. is_struct ( )
62- && cx. tcx . get_diagnostic_name ( adt_def. did ( ) ) == Some ( sym:: NonZero )
63- {
64- if let Some ( target_non_zero_type) = get_target_non_zero_type ( target_ty) {
65- let arg_snippet = get_arg_snippet ( cx, arg, rcv_path) ;
66- suggest_non_zero_conversion ( cx, expr, fn_name, target_non_zero_type, & arg_snippet) ;
67- }
62+ if !parent_is_binary {
63+ check_non_zero_conversion ( cx, expr, Applicability :: MaybeIncorrect ) ;
64+ }
65+ }
66+ }
67+ }
68+
69+ fn check_non_zero_conversion ( cx : & LateContext < ' _ > , expr : & Expr < ' _ > , applicability : Applicability ) {
70+ // Check if the expression is a function call with one argument
71+ if let ExprKind :: Call ( func, [ arg] ) = expr. kind
72+ && let ExprKind :: Path ( qpath) = & func. kind
73+ && let Some ( def_id) = cx. qpath_res ( qpath, func. hir_id ) . opt_def_id ( )
74+ && let ExprKind :: MethodCall ( rcv_path, receiver, _, _) = & arg. kind
75+ {
76+ let fn_name = cx. tcx . item_name ( def_id) ;
77+ let target_ty = cx. typeck_results ( ) . expr_ty ( expr) ;
78+ let receiver_ty = cx. typeck_results ( ) . expr_ty ( receiver) ;
79+
80+ // Check if the receiver type is a NonZero type
81+ if let ty:: Adt ( adt_def, _) = receiver_ty. kind ( )
82+ && adt_def. is_struct ( )
83+ && cx. tcx . get_diagnostic_name ( adt_def. did ( ) ) == Some ( sym:: NonZero )
84+ {
85+ if let Some ( target_non_zero_type) = get_target_non_zero_type ( target_ty) {
86+ let arg_snippet = get_arg_snippet ( cx, arg, rcv_path) ;
87+ suggest_non_zero_conversion ( cx, expr, fn_name, target_non_zero_type, & arg_snippet, applicability) ;
6888 }
6989 }
7090 }
@@ -85,6 +105,7 @@ fn suggest_non_zero_conversion(
85105 fn_name : rustc_span:: Symbol ,
86106 target_non_zero_type : & str ,
87107 arg_snippet : & str ,
108+ applicability : Applicability ,
88109) {
89110 let suggestion = format ! ( "{target_non_zero_type}::{fn_name}({arg_snippet})" ) ;
90111 span_lint_and_sugg (
@@ -94,7 +115,7 @@ fn suggest_non_zero_conversion(
94115 format ! ( "consider using `{target_non_zero_type}::{fn_name}()` for more efficient and type-safe conversion" ) ,
95116 "replace with" ,
96117 suggestion,
97- Applicability :: MachineApplicable ,
118+ applicability ,
98119 ) ;
99120}
100121
0 commit comments