@@ -5,24 +5,23 @@ use if_chain::if_chain;
5
5
use rustc_errors:: Applicability ;
6
6
use rustc_hir:: { Expr , ExprKind , Mutability , Param , Pat , PatKind , Path , PathSegment , QPath } ;
7
7
use rustc_lint:: { LateContext , LateLintPass } ;
8
+ use rustc_middle:: ty:: { self , subst:: GenericArgKind } ;
8
9
use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
9
10
use rustc_span:: symbol:: Ident ;
10
11
11
12
declare_clippy_lint ! {
12
13
/// **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
14
15
/// which compares the two arguments, either directly or indirectly.
15
16
///
16
17
/// **Why is this bad?**
17
18
/// 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
19
20
/// closure.
20
21
///
21
22
/// **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.
26
25
///
27
26
/// **Example:**
28
27
///
@@ -201,28 +200,41 @@ fn detect_lint(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> Option<LintTrigger>
201
200
} ;
202
201
let vec_name = Sugg :: hir( cx, & args[ 0 ] , ".." ) . to_string( ) ;
203
202
let unstable = name == "sort_unstable_by" ;
203
+
204
204
if_chain! {
205
205
if let ExprKind :: Path ( QPath :: Resolved ( _, Path {
206
206
segments: [ PathSegment { ident: left_name, .. } ] , ..
207
207
} ) ) = & left_expr. kind;
208
208
if left_name == left_ident;
209
209
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
+ }
220
221
}
221
222
}
222
- } else {
223
- None
224
223
}
225
224
}
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
226
238
}
227
239
228
240
impl LateLintPass < ' _ , ' _ > for UnnecessarySortBy {
0 commit comments