@@ -5,24 +5,23 @@ use if_chain::if_chain;
55use rustc_errors:: Applicability ;
66use rustc_hir:: { Expr , ExprKind , Mutability , Param , Pat , PatKind , Path , PathSegment , QPath } ;
77use rustc_lint:: { LateContext , LateLintPass } ;
8+ use rustc_middle:: ty:: { self , subst:: GenericArgKind } ;
89use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
910use rustc_span:: symbol:: Ident ;
1011
1112declare_clippy_lint ! {
1213 /// **What it does:**
13- /// Detects when people use `Vec::sort_by` and pass in a function
14+ /// Detects uses of `Vec::sort_by` passing in a closure
1415 /// which compares the two arguments, either directly or indirectly.
1516 ///
1617 /// **Why is this bad?**
1718 /// It is more clear to use `Vec::sort_by_key` (or `Vec::sort` if
18- /// possible) than to use `Vec::sort_by` and and a more complicated
19+ /// possible) than to use `Vec::sort_by` and a more complicated
1920 /// closure.
2021 ///
2122 /// **Known problems:**
22- /// If the suggested `Vec::sort_by_key` uses Reverse and it isn't
23- /// imported by a use statement in the current frame, then a `use`
24- /// statement that imports it will need to be added (which this lint
25- /// can't do).
23+ /// If the suggested `Vec::sort_by_key` uses Reverse and it isn't already
24+ /// imported by a use statement, then it will need to be added manually.
2625 ///
2726 /// **Example:**
2827 ///
@@ -201,28 +200,41 @@ fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<LintTrigger> {
201200 } ;
202201 let vec_name = Sugg :: hir( cx, & args[ 0 ] , ".." ) . to_string( ) ;
203202 let unstable = name == "sort_unstable_by" ;
203+
204204 if_chain! {
205205 if let ExprKind :: Path ( QPath :: Resolved ( _, Path {
206206 segments: [ PathSegment { ident: left_name, .. } ] , ..
207207 } ) ) = & left_expr. kind;
208208 if left_name == left_ident;
209209 then {
210- Some ( LintTrigger :: Sort ( SortDetection { vec_name, unstable } ) )
211- }
212- else {
213- Some ( LintTrigger :: SortByKey ( SortByKeyDetection {
214- vec_name,
215- unstable,
216- closure_arg,
217- closure_body,
218- reverse
219- } ) )
210+ return Some ( LintTrigger :: Sort ( SortDetection { vec_name, unstable } ) )
211+ } else {
212+ if !key_returns_borrow( cx, left_expr) {
213+ return Some ( LintTrigger :: SortByKey ( SortByKeyDetection {
214+ vec_name,
215+ unstable,
216+ closure_arg,
217+ closure_body,
218+ reverse
219+ } ) )
220+ }
220221 }
221222 }
222- } else {
223- None
224223 }
225224 }
225+
226+ None
227+ }
228+
229+ fn key_returns_borrow ( cx : & LateContext < ' _ > , expr : & Expr < ' _ > ) -> bool {
230+ if let Some ( def_id) = utils:: fn_def_id ( cx, expr) {
231+ let output = cx. tcx . fn_sig ( def_id) . output ( ) ;
232+ let ty = output. skip_binder ( ) ;
233+ return matches ! ( ty. kind, ty:: Ref ( ..) )
234+ || ty. walk ( ) . any ( |arg| matches ! ( arg. unpack( ) , GenericArgKind :: Lifetime ( _) ) ) ;
235+ }
236+
237+ false
226238}
227239
228240impl LateLintPass < ' _ > for UnnecessarySortBy {
0 commit comments