Skip to content

Commit 59f3444

Browse files
committed
Detect also a non-reversed comparison
1 parent a552a1c commit 59f3444

File tree

6 files changed

+94
-52
lines changed

6 files changed

+94
-52
lines changed

clippy_lints/src/lib.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,7 @@ mod serde_api;
305305
mod shadow;
306306
mod single_component_path_imports;
307307
mod slow_vector_initialization;
308-
mod sort_by_key_reverse;
308+
mod sort_by_key;
309309
mod strings;
310310
mod suspicious_trait_impl;
311311
mod swap;
@@ -790,7 +790,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
790790
&shadow::SHADOW_UNRELATED,
791791
&single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS,
792792
&slow_vector_initialization::SLOW_VECTOR_INITIALIZATION,
793-
&sort_by_key_reverse::SORT_BY_KEY_REVERSE,
793+
&sort_by_key::SORT_BY_KEY,
794794
&strings::STRING_ADD,
795795
&strings::STRING_ADD_ASSIGN,
796796
&strings::STRING_LIT_AS_BYTES,
@@ -1006,7 +1006,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
10061006
store.register_late_pass(|| box ptr_offset_with_cast::PtrOffsetWithCast);
10071007
store.register_late_pass(|| box redundant_clone::RedundantClone);
10081008
store.register_late_pass(|| box slow_vector_initialization::SlowVectorInit);
1009-
store.register_late_pass(|| box sort_by_key_reverse::SortByKeyReverse);
1009+
store.register_late_pass(|| box sort_by_key::SortByKey);
10101010
store.register_late_pass(|| box types::RefToMut);
10111011
store.register_late_pass(|| box assertions_on_constants::AssertionsOnConstants);
10121012
store.register_late_pass(|| box missing_const_for_fn::MissingConstForFn);
@@ -1402,7 +1402,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
14021402
LintId::of(&serde_api::SERDE_API_MISUSE),
14031403
LintId::of(&single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS),
14041404
LintId::of(&slow_vector_initialization::SLOW_VECTOR_INITIALIZATION),
1405-
LintId::of(&sort_by_key_reverse::SORT_BY_KEY_REVERSE),
1405+
LintId::of(&sort_by_key::SORT_BY_KEY),
14061406
LintId::of(&strings::STRING_LIT_AS_BYTES),
14071407
LintId::of(&suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL),
14081408
LintId::of(&suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL),
@@ -1607,7 +1607,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
16071607
LintId::of(&ranges::RANGE_ZIP_WITH_LEN),
16081608
LintId::of(&reference::DEREF_ADDROF),
16091609
LintId::of(&reference::REF_IN_DEREF),
1610-
LintId::of(&sort_by_key_reverse::SORT_BY_KEY_REVERSE),
1610+
LintId::of(&sort_by_key::SORT_BY_KEY),
16111611
LintId::of(&swap::MANUAL_SWAP),
16121612
LintId::of(&temporary_assignment::TEMPORARY_ASSIGNMENT),
16131613
LintId::of(&transmute::CROSSPOINTER_TRANSMUTE),

clippy_lints/src/sort_by_key_reverse.rs renamed to clippy_lints/src/sort_by_key.rs

Lines changed: 30 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -11,33 +11,35 @@ use rustc_span::symbol::Ident;
1111
declare_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

3739
struct 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
);

tests/ui/sort_by_key_reverse.fixed renamed to tests/ui/sort_by_key.fixed

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// run-rustfix
2-
#![warn(clippy::sort_by_key_reverse)]
2+
#![warn(clippy::sort_by_key)]
33

44
use std::cmp::Reverse;
55

@@ -9,6 +9,11 @@ fn id(x: isize) -> isize {
99

1010
fn main() {
1111
let mut vec: Vec<isize> = vec![3, 6, 1, 2, 5];
12+
// Forward examples
13+
vec.sort_by_key(|&a| a);
14+
vec.sort_by_key(|&a| (a + 5).abs());
15+
vec.sort_by_key(|&a| id(-a));
16+
// Reverse examples
1217
vec.sort_by_key(|&b| Reverse(b));
1318
vec.sort_by_key(|&b| Reverse((b + 5).abs()));
1419
vec.sort_by_key(|&b| Reverse(id(-b)));
@@ -18,5 +23,4 @@ fn main() {
1823
vec.sort_by(|_, b| b.cmp(&5));
1924
vec.sort_by(|_, b| b.cmp(c));
2025
vec.sort_by(|a, _| a.cmp(c));
21-
vec.sort_by(|a, b| a.cmp(b));
2226
}

tests/ui/sort_by_key_reverse.rs renamed to tests/ui/sort_by_key.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@ fn id(x: isize) -> isize {
99

1010
fn main() {
1111
let mut vec: Vec<isize> = vec![3, 6, 1, 2, 5];
12+
// Forward examples
13+
vec.sort_by(|a, b| a.cmp(b));
14+
vec.sort_by(|a, b| (a + 5).abs().cmp(&(b + 5).abs()));
15+
vec.sort_by(|a, b| id(-a).cmp(&id(-b)));
16+
// Reverse examples
1217
vec.sort_by(|a, b| b.cmp(a));
1318
vec.sort_by(|a, b| (b + 5).abs().cmp(&(a + 5).abs()));
1419
vec.sort_by(|a, b| id(-b).cmp(&id(-a)));
@@ -18,5 +23,4 @@ fn main() {
1823
vec.sort_by(|_, b| b.cmp(&5));
1924
vec.sort_by(|_, b| b.cmp(c));
2025
vec.sort_by(|a, _| a.cmp(c));
21-
vec.sort_by(|a, b| a.cmp(b));
2226
}

tests/ui/sort_by_key.stderr

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
error: use Vec::sort_by_key here instead
2+
--> $DIR/sort_by_key.rs:13:5
3+
|
4+
LL | vec.sort_by(|a, b| a.cmp(b));
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|&a| a)`
6+
|
7+
= note: `-D clippy::sort-by-key` implied by `-D warnings`
8+
9+
error: use Vec::sort_by_key here instead
10+
--> $DIR/sort_by_key.rs:14:5
11+
|
12+
LL | vec.sort_by(|a, b| (a + 5).abs().cmp(&(b + 5).abs()));
13+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|&a| (a + 5).abs())`
14+
15+
error: use Vec::sort_by_key here instead
16+
--> $DIR/sort_by_key.rs:15:5
17+
|
18+
LL | vec.sort_by(|a, b| id(-a).cmp(&id(-b)));
19+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|&a| id(-a))`
20+
21+
error: use Vec::sort_by_key here instead
22+
--> $DIR/sort_by_key.rs:17:5
23+
|
24+
LL | vec.sort_by(|a, b| b.cmp(a));
25+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|&b| Reverse(b))`
26+
27+
error: use Vec::sort_by_key here instead
28+
--> $DIR/sort_by_key.rs:18:5
29+
|
30+
LL | vec.sort_by(|a, b| (b + 5).abs().cmp(&(a + 5).abs()));
31+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|&b| Reverse((b + 5).abs()))`
32+
33+
error: use Vec::sort_by_key here instead
34+
--> $DIR/sort_by_key.rs:19:5
35+
|
36+
LL | vec.sort_by(|a, b| id(-b).cmp(&id(-a)));
37+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|&b| Reverse(id(-b)))`
38+
39+
error: unknown clippy lint: clippy::sort_by_key_reverse
40+
--> $DIR/sort_by_key.rs:2:9
41+
|
42+
LL | #![warn(clippy::sort_by_key_reverse)]
43+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: did you mean: `clippy::sort_by_key`
44+
|
45+
= note: `-D clippy::unknown-clippy-lints` implied by `-D warnings`
46+
47+
error: aborting due to 7 previous errors
48+

tests/ui/sort_by_key_reverse.stderr

Lines changed: 0 additions & 22 deletions
This file was deleted.

0 commit comments

Comments
 (0)