From 955a25ee7db234a8ab697176a433070702aabe59 Mon Sep 17 00:00:00 2001 From: JarredAllen Date: Wed, 20 May 2020 09:23:00 -0700 Subject: [PATCH] Added negative test cases and ran cargo dev fmt --- clippy_lints/src/sort_by_key_reverse.rs | 125 ++++++++++++++++-------- tests/ui/sort_by_key_reverse.fixed | 7 ++ tests/ui/sort_by_key_reverse.rs | 9 +- tests/ui/sort_by_key_reverse.stderr | 4 +- 4 files changed, 100 insertions(+), 45 deletions(-) diff --git a/clippy_lints/src/sort_by_key_reverse.rs b/clippy_lints/src/sort_by_key_reverse.rs index 31629a1dbc1b..ea850955db12 100644 --- a/clippy_lints/src/sort_by_key_reverse.rs +++ b/clippy_lints/src/sort_by_key_reverse.rs @@ -3,7 +3,7 @@ use crate::utils::paths; use crate::utils::sugg::Sugg; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::*; +use rustc_hir::{Expr, ExprKind, Mutability, Param, Pat, PatKind, Path, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::symbol::Ident; @@ -43,64 +43,105 @@ struct LintTrigger { /// Detect if the two expressions are mirrored (identical, except one /// contains a and the other replaces it with b) -fn mirrored_exprs(cx: &LateContext<'_, '_>, a_expr: &Expr<'_>, a_ident: &Ident, b_expr: &Expr<'_>, b_ident: &Ident) -> bool { +fn mirrored_exprs( + cx: &LateContext<'_, '_>, + a_expr: &Expr<'_>, + a_ident: &Ident, + b_expr: &Expr<'_>, + b_ident: &Ident, +) -> bool { match (&a_expr.kind, &b_expr.kind) { // Two boxes with mirrored contents - (ExprKind::Box(left_expr), ExprKind::Box(right_expr)) => mirrored_exprs(cx, left_expr, a_ident, right_expr, b_ident), + (ExprKind::Box(left_expr), ExprKind::Box(right_expr)) => { + mirrored_exprs(cx, left_expr, a_ident, right_expr, b_ident) + }, // Two arrays with mirrored contents - (ExprKind::Array(left_exprs), ExprKind::Array(right_exprs)) - => left_exprs.iter().zip(right_exprs.iter()).all(|(left, right)| mirrored_exprs(cx, left, a_ident, right, b_ident)), + (ExprKind::Array(left_exprs), ExprKind::Array(right_exprs)) => left_exprs + .iter() + .zip(right_exprs.iter()) + .all(|(left, right)| mirrored_exprs(cx, left, a_ident, right, b_ident)), // The two exprs are function calls. // Check to see that the function itself and its arguments are mirrored - (ExprKind::Call(left_expr, left_args), ExprKind::Call(right_expr, right_args)) - => { - // println!("{:?}\n{:?}\n", left_expr, left_args); - // println!("{:?}\n{:?}\n", right_expr, right_args); - mirrored_exprs(cx, left_expr, a_ident, right_expr, b_ident) - && left_args.iter().zip(right_args.iter()).all(|(left, right)| mirrored_exprs(cx, left, a_ident, right, b_ident)) - }, + (ExprKind::Call(left_expr, left_args), ExprKind::Call(right_expr, right_args)) => { + mirrored_exprs(cx, left_expr, a_ident, right_expr, b_ident) + && left_args + .iter() + .zip(right_args.iter()) + .all(|(left, right)| mirrored_exprs(cx, left, a_ident, right, b_ident)) + }, // The two exprs are method calls. // Check to see that the function is the same and the arguments are mirrored // This is enough because the receiver of the method is listed in the arguments - (ExprKind::MethodCall(left_segment, _, left_args), ExprKind::MethodCall(right_segment, _, right_args)) - => left_segment.ident == right_segment.ident - && left_args.iter().zip(right_args.iter()).all(|(left, right)| mirrored_exprs(cx, left, a_ident, right, b_ident)), + (ExprKind::MethodCall(left_segment, _, left_args), ExprKind::MethodCall(right_segment, _, right_args)) => { + left_segment.ident == right_segment.ident + && left_args + .iter() + .zip(right_args.iter()) + .all(|(left, right)| mirrored_exprs(cx, left, a_ident, right, b_ident)) + }, // Two tuples with mirrored contents - (ExprKind::Tup(left_exprs), ExprKind::Tup(right_exprs)) - => left_exprs.iter().zip(right_exprs.iter()).all(|(left, right)| mirrored_exprs(cx, left, a_ident, right, b_ident)), + (ExprKind::Tup(left_exprs), ExprKind::Tup(right_exprs)) => left_exprs + .iter() + .zip(right_exprs.iter()) + .all(|(left, right)| mirrored_exprs(cx, left, a_ident, right, b_ident)), // Two binary ops, which are the same operation and which have mirrored arguments - (ExprKind::Binary(left_op, left_left, left_right), ExprKind::Binary(right_op, right_left, right_right)) - => left_op.node == right_op.node + (ExprKind::Binary(left_op, left_left, left_right), ExprKind::Binary(right_op, right_left, right_right)) => { + left_op.node == right_op.node && mirrored_exprs(cx, left_left, a_ident, right_left, b_ident) - && mirrored_exprs(cx, left_right, a_ident, right_right, b_ident), + && mirrored_exprs(cx, left_right, a_ident, right_right, b_ident) + }, // Two unary ops, which are the same operation and which have the same argument - (ExprKind::Unary(left_op, left_expr), ExprKind::Unary(right_op, right_expr)) - => left_op == right_op && mirrored_exprs(cx, left_expr, a_ident, right_expr, b_ident), + (ExprKind::Unary(left_op, left_expr), ExprKind::Unary(right_op, right_expr)) => { + left_op == right_op && mirrored_exprs(cx, left_expr, a_ident, right_expr, b_ident) + }, // The two exprs are literals of some kind (ExprKind::Lit(left_lit), ExprKind::Lit(right_lit)) => left_lit.node == right_lit.node, - (ExprKind::Cast(left_expr, left_ty), ExprKind::Cast(right_expr, right_ty)) - => mirrored_exprs(cx, left_expr, a_ident, right_expr, b_ident), - (ExprKind::DropTemps(left), ExprKind::DropTemps(right)) => mirrored_exprs(cx, left, a_ident, right, b_ident), - (ExprKind::Field(left_expr, left_ident), ExprKind::Field(right_expr, right_ident)) - => left_ident.name == right_ident.name && mirrored_exprs(cx, left_expr, a_ident, right_expr, right_ident), + (ExprKind::Cast(left, _), ExprKind::Cast(right, _)) => mirrored_exprs(cx, left, a_ident, right, b_ident), + (ExprKind::DropTemps(left_block), ExprKind::DropTemps(right_block)) => { + mirrored_exprs(cx, left_block, a_ident, right_block, b_ident) + }, + (ExprKind::Field(left_expr, left_ident), ExprKind::Field(right_expr, right_ident)) => { + left_ident.name == right_ident.name && mirrored_exprs(cx, left_expr, a_ident, right_expr, right_ident) + }, // Two paths: either one is a and the other is b, or they're identical to each other - (ExprKind::Path(QPath::Resolved(_, Path { segments: left_segments, .. })), - ExprKind::Path(QPath::Resolved(_, Path { segments: right_segments, .. }))) - => (left_segments.iter().zip(right_segments.iter()).all(|(left, right)| left.ident == right.ident) - && left_segments.iter().all(|seg| &seg.ident != a_ident && &seg.ident != b_ident)) - || (left_segments.len() == 1 && &left_segments[0].ident == a_ident && right_segments.len() == 1 && &right_segments[0].ident == b_ident), + ( + ExprKind::Path(QPath::Resolved( + _, + Path { + segments: left_segments, + .. + }, + )), + ExprKind::Path(QPath::Resolved( + _, + Path { + segments: right_segments, + .. + }, + )), + ) => { + (left_segments + .iter() + .zip(right_segments.iter()) + .all(|(left, right)| left.ident == right.ident) + && left_segments + .iter() + .all(|seg| &seg.ident != a_ident && &seg.ident != b_ident)) + || (left_segments.len() == 1 + && &left_segments[0].ident == a_ident + && right_segments.len() == 1 + && &right_segments[0].ident == b_ident) + }, // Matching expressions, but one or both is borrowed - (ExprKind::AddrOf(left_kind, Mutability::Not, left_expr), ExprKind::AddrOf(right_kind, Mutability::Not, right_expr)) - => left_kind == right_kind && mirrored_exprs(cx, left_expr, a_ident, right_expr, b_ident), - (_, ExprKind::AddrOf(_, Mutability::Not, right_expr)) - => mirrored_exprs(cx, a_expr, a_ident, right_expr, b_ident), - (ExprKind::AddrOf(_, Mutability::Not, left_expr), _) - => mirrored_exprs(cx, left_expr, a_ident, b_expr, b_ident), + ( + ExprKind::AddrOf(left_kind, Mutability::Not, left_expr), + ExprKind::AddrOf(right_kind, Mutability::Not, right_expr), + ) => left_kind == right_kind && mirrored_exprs(cx, left_expr, a_ident, right_expr, b_ident), + (_, ExprKind::AddrOf(_, Mutability::Not, right_expr)) => { + mirrored_exprs(cx, a_expr, a_ident, right_expr, b_ident) + }, + (ExprKind::AddrOf(_, Mutability::Not, left_expr), _) => mirrored_exprs(cx, left_expr, a_ident, b_expr, b_ident), _ => false, - // (left, right) => { - // println!("{:?}\n{:?}", left, right); - // false - // }, } } diff --git a/tests/ui/sort_by_key_reverse.fixed b/tests/ui/sort_by_key_reverse.fixed index d536dc385d53..722675a6b71a 100644 --- a/tests/ui/sort_by_key_reverse.fixed +++ b/tests/ui/sort_by_key_reverse.fixed @@ -12,4 +12,11 @@ fn main() { vec.sort_by_key(|&b| Reverse(b)); vec.sort_by_key(|&b| Reverse((b + 5).abs())); vec.sort_by_key(|&b| Reverse(id(-b))); + // Negative examples (shouldn't be changed) + let c = &7; + vec.sort_by(|a, b| (b - a).cmp(&(a - b))); + vec.sort_by(|_, b| b.cmp(&5)); + vec.sort_by(|_, b| b.cmp(c)); + vec.sort_by(|a, _| a.cmp(c)); + vec.sort_by(|a, b| a.cmp(b)); } diff --git a/tests/ui/sort_by_key_reverse.rs b/tests/ui/sort_by_key_reverse.rs index 9c42d401755a..601621ffa9f8 100644 --- a/tests/ui/sort_by_key_reverse.rs +++ b/tests/ui/sort_by_key_reverse.rs @@ -10,6 +10,13 @@ fn id(x: isize) -> isize { fn main() { let mut vec: Vec = vec![3, 6, 1, 2, 5]; vec.sort_by(|a, b| b.cmp(a)); - vec.sort_by(|a, b| (b + 5).abs().cmp(&(a+5).abs())); + vec.sort_by(|a, b| (b + 5).abs().cmp(&(a + 5).abs())); vec.sort_by(|a, b| id(-b).cmp(&id(-a))); + // Negative examples (shouldn't be changed) + let c = &7; + vec.sort_by(|a, b| (b - a).cmp(&(a - b))); + vec.sort_by(|_, b| b.cmp(&5)); + vec.sort_by(|_, b| b.cmp(c)); + vec.sort_by(|a, _| a.cmp(c)); + vec.sort_by(|a, b| a.cmp(b)); } diff --git a/tests/ui/sort_by_key_reverse.stderr b/tests/ui/sort_by_key_reverse.stderr index 3d26ddae78ad..b757c8a6176d 100644 --- a/tests/ui/sort_by_key_reverse.stderr +++ b/tests/ui/sort_by_key_reverse.stderr @@ -9,8 +9,8 @@ LL | vec.sort_by(|a, b| b.cmp(a)); error: use Vec::sort_by_key here instead --> $DIR/sort_by_key_reverse.rs:13:5 | -LL | vec.sort_by(|a, b| (b + 5).abs().cmp(&(a+5).abs())); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|&b| Reverse((b + 5).abs()))` +LL | vec.sort_by(|a, b| (b + 5).abs().cmp(&(a + 5).abs())); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|&b| Reverse((b + 5).abs()))` error: use Vec::sort_by_key here instead --> $DIR/sort_by_key_reverse.rs:14:5