@@ -36,21 +36,26 @@ declare_clippy_lint! {
36
36
37
37
declare_lint_pass ! ( UnitReturnExpectingOrd => [ UNIT_RETURN_EXPECTING_ORD ] ) ;
38
38
39
- fn get_trait_predicates_for_trait_id < ' tcx > (
39
+ // For each
40
+ fn get_trait_predicates_for_trait_ids < ' tcx > (
40
41
cx : & LateContext < ' tcx > ,
41
42
generics : GenericPredicates < ' tcx > ,
42
- trait_id : Option < DefId > ,
43
- ) -> Vec < TraitPredicate < ' tcx > > {
44
- let mut preds = Vec :: new ( ) ;
43
+ trait_ids : & [ Option < DefId > ] , // At least 2 ids
44
+ ) -> [ Vec < TraitPredicate < ' tcx > > ; 3 ] {
45
+ debug_assert ! ( trait_ids. len( ) >= 2 ) ;
46
+ let mut preds = [ Vec :: new ( ) , Vec :: new ( ) , Vec :: new ( ) ] ;
45
47
for ( pred, _) in generics. predicates {
46
- if let ClauseKind :: Trait ( poly_trait_pred) = pred. kind ( ) . skip_binder ( )
47
- && let trait_pred = cx
48
+ if let ClauseKind :: Trait ( poly_trait_pred) = pred. kind ( ) . skip_binder ( ) {
49
+ let trait_pred = cx
48
50
. tcx
49
- . instantiate_bound_regions_with_erased ( pred. kind ( ) . rebind ( poly_trait_pred) )
50
- && let Some ( trait_def_id) = trait_id
51
- && trait_def_id == trait_pred. trait_ref . def_id
52
- {
53
- preds. push ( trait_pred) ;
51
+ . instantiate_bound_regions_with_erased ( pred. kind ( ) . rebind ( poly_trait_pred) ) ;
52
+ for ( i, tid) in trait_ids. iter ( ) . enumerate ( ) {
53
+ if let Some ( tid) = tid
54
+ && * tid == trait_pred. trait_ref . def_id
55
+ {
56
+ preds[ i] . push ( trait_pred) ;
57
+ }
58
+ }
54
59
}
55
60
}
56
61
preds
@@ -74,15 +79,24 @@ fn get_projection_pred<'tcx>(
74
79
} )
75
80
}
76
81
77
- fn get_args_to_check < ' tcx > ( cx : & LateContext < ' tcx > , expr : & ' tcx Expr < ' tcx > ) -> Vec < ( usize , String ) > {
82
+ fn get_args_to_check < ' tcx > (
83
+ cx : & LateContext < ' tcx > ,
84
+ expr : & ' tcx Expr < ' tcx > ,
85
+ args_len : usize ,
86
+ fn_mut_trait : DefId ,
87
+ ord_trait : Option < DefId > ,
88
+ partial_ord_trait : Option < DefId > ,
89
+ ) -> Vec < ( usize , String ) > {
78
90
let mut args_to_check = Vec :: new ( ) ;
79
91
if let Some ( def_id) = cx. typeck_results ( ) . type_dependent_def_id ( expr. hir_id ) {
80
92
let fn_sig = cx. tcx . fn_sig ( def_id) . instantiate_identity ( ) ;
81
93
let generics = cx. tcx . predicates_of ( def_id) ;
82
- let fn_mut_preds = get_trait_predicates_for_trait_id ( cx, generics, cx. tcx . lang_items ( ) . fn_mut_trait ( ) ) ;
83
- let ord_preds = get_trait_predicates_for_trait_id ( cx, generics, cx. tcx . get_diagnostic_item ( sym:: Ord ) ) ;
84
- let partial_ord_preds =
85
- get_trait_predicates_for_trait_id ( cx, generics, cx. tcx . lang_items ( ) . partial_ord_trait ( ) ) ;
94
+ let [ fn_mut_preds, ord_preds, partial_ord_preds] =
95
+ get_trait_predicates_for_trait_ids ( cx, generics, & [ Some ( fn_mut_trait) , ord_trait, partial_ord_trait] ) ;
96
+ if fn_mut_preds. is_empty ( ) {
97
+ return vec ! [ ] ;
98
+ }
99
+
86
100
// Trying to call instantiate_bound_regions_with_erased on fn_sig.inputs() gives the following error
87
101
// The trait `rustc::ty::TypeFoldable<'_>` is not implemented for
88
102
// `&[rustc_middle::ty::Ty<'_>]`
@@ -102,12 +116,18 @@ fn get_args_to_check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Ve
102
116
. iter ( )
103
117
. any ( |ord| Some ( ord. self_ty ( ) ) == return_ty_pred. term . as_type ( ) )
104
118
{
105
- args_to_check. push ( ( i, "Ord" . to_string ( ) ) ) ;
119
+ args_to_check. push ( ( i, String :: from ( "Ord" ) ) ) ;
120
+ if args_to_check. len ( ) == args_len - 1 {
121
+ break ;
122
+ }
106
123
} else if partial_ord_preds
107
124
. iter ( )
108
125
. any ( |pord| pord. self_ty ( ) == return_ty_pred. term . expect_type ( ) )
109
126
{
110
- args_to_check. push ( ( i, "PartialOrd" . to_string ( ) ) ) ;
127
+ args_to_check. push ( ( i, String :: from ( "PartialOrd" ) ) ) ;
128
+ if args_to_check. len ( ) == args_len - 1 {
129
+ break ;
130
+ }
111
131
}
112
132
}
113
133
}
@@ -142,38 +162,50 @@ fn check_arg<'tcx>(cx: &LateContext<'tcx>, arg: &'tcx Expr<'tcx>) -> Option<(Spa
142
162
143
163
impl < ' tcx > LateLintPass < ' tcx > for UnitReturnExpectingOrd {
144
164
fn check_expr ( & mut self , cx : & LateContext < ' tcx > , expr : & ' tcx Expr < ' tcx > ) {
145
- if let ExprKind :: MethodCall ( _, receiver, args, _) = expr. kind {
146
- let arg_indices = get_args_to_check ( cx, expr) ;
165
+ if let ExprKind :: MethodCall ( _, receiver, args, _) = expr. kind
166
+ && args. iter ( ) . any ( |arg| {
167
+ matches ! (
168
+ arg. peel_blocks( ) . peel_borrows( ) . peel_drop_temps( ) . kind,
169
+ ExprKind :: Path ( _) | ExprKind :: Closure ( _)
170
+ )
171
+ } )
172
+ && let Some ( fn_mut_trait) = cx. tcx . lang_items ( ) . fn_mut_trait ( )
173
+ {
174
+ let ord_trait = cx. tcx . get_diagnostic_item ( sym:: Ord ) ;
175
+ let partial_ord_trait = cx. tcx . lang_items ( ) . partial_ord_trait ( ) ;
176
+ if ( ord_trait, partial_ord_trait) == ( None , None ) {
177
+ return ;
178
+ }
179
+
147
180
let args = std:: iter:: once ( receiver) . chain ( args. iter ( ) ) . collect :: < Vec < _ > > ( ) ;
181
+ let arg_indices = get_args_to_check ( cx, expr, args. len ( ) , fn_mut_trait, ord_trait, partial_ord_trait) ;
148
182
for ( i, trait_name) in arg_indices {
149
- if i < args. len ( ) {
150
- match check_arg ( cx, args[ i] ) {
151
- Some ( ( span, None ) ) => {
152
- span_lint (
153
- cx,
154
- UNIT_RETURN_EXPECTING_ORD ,
155
- span,
156
- format ! (
157
- "this closure returns \
183
+ match check_arg ( cx, args[ i] ) {
184
+ Some ( ( span, None ) ) => {
185
+ span_lint (
186
+ cx,
187
+ UNIT_RETURN_EXPECTING_ORD ,
188
+ span,
189
+ format ! (
190
+ "this closure returns \
158
191
the unit type which also implements {trait_name}"
159
- ) ,
160
- ) ;
161
- } ,
162
- Some ( ( span, Some ( last_semi) ) ) => {
163
- span_lint_and_help (
164
- cx,
165
- UNIT_RETURN_EXPECTING_ORD ,
166
- span,
167
- format ! (
168
- "this closure returns \
192
+ ) ,
193
+ ) ;
194
+ } ,
195
+ Some ( ( span, Some ( last_semi) ) ) => {
196
+ span_lint_and_help (
197
+ cx,
198
+ UNIT_RETURN_EXPECTING_ORD ,
199
+ span,
200
+ format ! (
201
+ "this closure returns \
169
202
the unit type which also implements {trait_name}"
170
- ) ,
171
- Some ( last_semi) ,
172
- "probably caused by this trailing semicolon" ,
173
- ) ;
174
- } ,
175
- None => { } ,
176
- }
203
+ ) ,
204
+ Some ( last_semi) ,
205
+ "probably caused by this trailing semicolon" ,
206
+ ) ;
207
+ } ,
208
+ None => { } ,
177
209
}
178
210
}
179
211
}
0 commit comments