1
1
use clippy_utils:: diagnostics:: span_lint_and_sugg;
2
2
use clippy_utils:: source:: snippet;
3
+ use rustc_ast:: ast:: BinOpKind ;
3
4
use rustc_errors:: Applicability ;
4
5
use rustc_hir:: { Expr , ExprKind } ;
5
6
use rustc_lint:: { LateContext , LateLintPass } ;
@@ -48,23 +49,42 @@ declare_lint_pass!(NonZeroSuggestions => [NON_ZERO_SUGGESTIONS]);
48
49
49
50
impl < ' tcx > LateLintPass < ' tcx > for NonZeroSuggestions {
50
51
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 )
55
54
{
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
+ } ) ;
59
61
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) ;
68
88
}
69
89
}
70
90
}
@@ -85,6 +105,7 @@ fn suggest_non_zero_conversion(
85
105
fn_name : rustc_span:: Symbol ,
86
106
target_non_zero_type : & str ,
87
107
arg_snippet : & str ,
108
+ applicability : Applicability ,
88
109
) {
89
110
let suggestion = format ! ( "{target_non_zero_type}::{fn_name}({arg_snippet})" ) ;
90
111
span_lint_and_sugg (
@@ -94,7 +115,7 @@ fn suggest_non_zero_conversion(
94
115
format ! ( "consider using `{target_non_zero_type}::{fn_name}()` for more efficient and type-safe conversion" ) ,
95
116
"replace with" ,
96
117
suggestion,
97
- Applicability :: MachineApplicable ,
118
+ applicability ,
98
119
) ;
99
120
}
100
121
0 commit comments