@@ -11,33 +11,35 @@ use rustc_span::symbol::Ident;
1111declare_clippy_lint ! {
1212 /// **What it does:**
1313 /// Detects when people use `Vec::sort_by` and pass in a function
14- /// which compares the second argument to the first .
14+ /// which compares the two arguments, either directly or indirectly .
1515 ///
1616 /// **Why is this bad?**
17- /// It is more clear to use `Vec::sort_by_key` and `std::cmp::Reverse`
17+ /// It is more clear to use `Vec::sort_by_key` (or
18+ /// `Vec::sort_by_key` and `std::cmp::Reverse` if necessary) than
19+ /// using
1820 ///
1921 /// **Known problems:** None.
2022 ///
2123 /// **Example:**
2224 ///
2325 /// ```rust
24- /// vec.sort_by(|a, b| b .foo().cmp(&a .foo()));
26+ /// vec.sort_by(|a, b| a .foo().cmp(b .foo()));
2527 /// ```
2628 /// Use instead:
2729 /// ```rust
28- /// vec.sort_by_key(|e| Reverse(e .foo() ));
30+ /// vec.sort_by_key(|a| a .foo());
2931 /// ```
30- pub SORT_BY_KEY_REVERSE ,
32+ pub SORT_BY_KEY ,
3133 complexity,
3234 "Use of `Vec::sort_by` when `Vec::sort_by_key` would be clearer"
3335}
3436
35- declare_lint_pass ! ( SortByKeyReverse => [ SORT_BY_KEY_REVERSE ] ) ;
37+ declare_lint_pass ! ( SortByKey => [ SORT_BY_KEY ] ) ;
3638
3739struct LintTrigger {
3840 vec_name : String ,
3941 closure_arg : String ,
40- closure_reverse_body : String ,
42+ closure_body : String ,
4143 unstable : bool ,
4244}
4345
@@ -154,43 +156,49 @@ fn detect_lint(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> Option<LintTrigger>
154156 if utils:: match_type( cx, & cx. tables. expr_ty( vec) , & paths:: VEC ) ;
155157 if let closure_body = cx. tcx. hir( ) . body( * closure_body_id) ;
156158 if let & [
157- Param { pat: Pat { kind: PatKind :: Binding ( _, _, a_ident , _) , .. } , ..} ,
158- Param { pat: Pat { kind: PatKind :: Binding ( _, _, b_ident , _) , .. } , .. }
159+ Param { pat: Pat { kind: PatKind :: Binding ( _, _, left_ident , _) , .. } , ..} ,
160+ Param { pat: Pat { kind: PatKind :: Binding ( _, _, right_ident , _) , .. } , .. }
159161 ] = & closure_body. params;
160- if let ExprKind :: MethodCall ( method_path, _, [ ref b_expr , ref a_expr ] ) = & closure_body. value. kind;
162+ if let ExprKind :: MethodCall ( method_path, _, [ ref left_expr , ref right_expr ] ) = & closure_body. value. kind;
161163 if method_path. ident. name. to_ident_string( ) == "cmp" ;
162- if mirrored_exprs( & cx, & a_expr, & a_ident, & b_expr, & b_ident) ;
163164 then {
165+ let ( closure_body, closure_arg) = if mirrored_exprs(
166+ & cx,
167+ & left_expr,
168+ & left_ident,
169+ & right_expr,
170+ & right_ident
171+ ) {
172+ ( Sugg :: hir( cx, & left_expr, ".." ) . to_string( ) , left_ident. name. to_string( ) )
173+ } else if mirrored_exprs( & cx, & left_expr, & right_ident, & right_expr, & left_ident) {
174+ ( format!( "Reverse({})" , Sugg :: hir( cx, & left_expr, ".." ) . to_string( ) ) , right_ident. name. to_string( ) )
175+ } else {
176+ return None ;
177+ } ;
164178 let vec_name = Sugg :: hir( cx, & args[ 0 ] , ".." ) . to_string( ) ;
165179 let unstable = name == "sort_unstable_by" ;
166- let closure_arg = format!( "&{}" , b_ident. name. to_ident_string( ) ) ;
167- let closure_reverse_body = Sugg :: hir( cx, & b_expr, ".." ) . to_string( ) ;
168- // Get rid of parentheses, because they aren't needed anymore
169- // while closure_reverse_body.chars().next() == Some('(') && closure_reverse_body.chars().last() == Some(')') {
170- // closure_reverse_body = String::from(&closure_reverse_body[1..closure_reverse_body.len()-1]);
171- // }
172- Some ( LintTrigger { vec_name, unstable, closure_arg, closure_reverse_body } )
180+ Some ( LintTrigger { vec_name, unstable, closure_arg, closure_body } )
173181 } else {
174182 None
175183 }
176184 }
177185}
178186
179- impl LateLintPass < ' _ , ' _ > for SortByKeyReverse {
187+ impl LateLintPass < ' _ , ' _ > for SortByKey {
180188 fn check_expr ( & mut self , cx : & LateContext < ' _ , ' _ > , expr : & Expr < ' _ > ) {
181189 if let Some ( trigger) = detect_lint ( cx, expr) {
182190 utils:: span_lint_and_sugg (
183191 cx,
184- SORT_BY_KEY_REVERSE ,
192+ SORT_BY_KEY ,
185193 expr. span ,
186194 "use Vec::sort_by_key here instead" ,
187195 "try" ,
188196 format ! (
189- "{}.sort{}_by_key(|{}| Reverse({}) )" ,
197+ "{}.sort{}_by_key(|& {}| {} )" ,
190198 trigger. vec_name,
191199 if trigger. unstable { "_unstable" } else { "" } ,
192200 trigger. closure_arg,
193- trigger. closure_reverse_body ,
201+ trigger. closure_body ,
194202 ) ,
195203 Applicability :: MachineApplicable ,
196204 ) ;
0 commit comments