@@ -5,7 +5,7 @@ use rustc_lint::{LateContext, LateLintPass};
55use rustc_middle:: ty;
66use rustc_middle:: ty:: { ClauseKind , GenericPredicates , ProjectionPredicate , TraitPredicate } ;
77use rustc_session:: declare_lint_pass;
8- use rustc_span:: { BytePos , Span , sym} ;
8+ use rustc_span:: { BytePos , Span , Symbol , sym} ;
99
1010declare_clippy_lint ! {
1111 /// ### What it does
@@ -36,21 +36,26 @@ declare_clippy_lint! {
3636
3737declare_lint_pass ! ( UnitReturnExpectingOrd => [ UNIT_RETURN_EXPECTING_ORD ] ) ;
3838
39- fn get_trait_predicates_for_trait_id < ' tcx > (
39+ // For each
40+ fn get_trait_predicates_for_trait_ids < ' tcx > (
4041 cx : & LateContext < ' tcx > ,
4142 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 ( ) ] ;
4547 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
4850 . 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+ }
5459 }
5560 }
5661 preds
@@ -74,15 +79,24 @@ fn get_projection_pred<'tcx>(
7479 } )
7580}
7681
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 , Symbol ) > {
7890 let mut args_to_check = Vec :: new ( ) ;
7991 if let Some ( def_id) = cx. typeck_results ( ) . type_dependent_def_id ( expr. hir_id ) {
8092 let fn_sig = cx. tcx . fn_sig ( def_id) . instantiate_identity ( ) ;
8193 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+
86100 // Trying to call instantiate_bound_regions_with_erased on fn_sig.inputs() gives the following error
87101 // The trait `rustc::ty::TypeFoldable<'_>` is not implemented for
88102 // `&[rustc_middle::ty::Ty<'_>]`
@@ -102,12 +116,18 @@ fn get_args_to_check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Ve
102116 . iter ( )
103117 . any ( |ord| Some ( ord. self_ty ( ) ) == return_ty_pred. term . as_type ( ) )
104118 {
105- args_to_check. push ( ( i, "Ord" . to_string ( ) ) ) ;
119+ args_to_check. push ( ( i, sym:: Ord ) ) ;
120+ if args_to_check. len ( ) == args_len - 1 {
121+ break ;
122+ }
106123 } else if partial_ord_preds
107124 . iter ( )
108125 . any ( |pord| pord. self_ty ( ) == return_ty_pred. term . expect_type ( ) )
109126 {
110- args_to_check. push ( ( i, "PartialOrd" . to_string ( ) ) ) ;
127+ args_to_check. push ( ( i, sym:: PartialOrd ) ) ;
128+ if args_to_check. len ( ) == args_len - 1 {
129+ break ;
130+ }
111131 }
112132 }
113133 }
@@ -142,38 +162,50 @@ fn check_arg<'tcx>(cx: &LateContext<'tcx>, arg: &'tcx Expr<'tcx>) -> Option<(Spa
142162
143163impl < ' tcx > LateLintPass < ' tcx > for UnitReturnExpectingOrd {
144164 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+
147180 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) ;
148182 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 \
158191 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 \
169202 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 => { } ,
177209 }
178210 }
179211 }
0 commit comments