Skip to content

Commit edfd2b9

Browse files
committed
upgrade equatable_if_let to style
1 parent b9d753e commit edfd2b9

30 files changed

+487
-113
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -2696,6 +2696,7 @@ Released 2018-09-13
26962696
[`enum_variant_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#enum_variant_names
26972697
[`eq_op`]: https://rust-lang.github.io/rust-clippy/master/index.html#eq_op
26982698
[`equatable_if_let`]: https://rust-lang.github.io/rust-clippy/master/index.html#equatable_if_let
2699+
[`equatable_matches`]: https://rust-lang.github.io/rust-clippy/master/index.html#equatable_matches
26992700
[`erasing_op`]: https://rust-lang.github.io/rust-clippy/master/index.html#erasing_op
27002701
[`eval_order_dependence`]: https://rust-lang.github.io/rust-clippy/master/index.html#eval_order_dependence
27012702
[`excessive_precision`]: https://rust-lang.github.io/rust-clippy/master/index.html#excessive_precision

clippy_lints/src/casts/cast_lossless.rs

+2-4
Original file line numberDiff line numberDiff line change
@@ -65,17 +65,15 @@ fn should_lint(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, cast_to
6565

6666
(true, false) => {
6767
let from_nbits = utils::int_ty_to_nbits(cast_from, cx.tcx);
68-
let to_nbits = if let ty::Float(FloatTy::F32) = cast_to.kind() {
68+
let to_nbits = if cast_to.kind() == &ty::Float(FloatTy::F32) {
6969
32
7070
} else {
7171
64
7272
};
7373
from_nbits < to_nbits
7474
},
7575

76-
(_, _) => {
77-
matches!(cast_from.kind(), ty::Float(FloatTy::F32)) && matches!(cast_to.kind(), ty::Float(FloatTy::F64))
78-
},
76+
(_, _) => cast_from.kind() == &ty::Float(FloatTy::F32) && cast_to.kind() == &ty::Float(FloatTy::F64),
7977
}
8078
}
8179

clippy_lints/src/casts/cast_possible_truncation.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, ca
4040
},
4141

4242
(_, _) => {
43-
if matches!(cast_from.kind(), &ty::Float(FloatTy::F64))
44-
&& matches!(cast_to.kind(), &ty::Float(FloatTy::F32))
45-
{
43+
if cast_from.kind() == &ty::Float(FloatTy::F64) && cast_to.kind() == &ty::Float(FloatTy::F32) {
4644
"casting `f64` to `f32` may truncate the value".to_string()
4745
} else {
4846
return;

clippy_lints/src/equatable_if_let.rs

+179-50
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,21 @@
1-
use clippy_utils::diagnostics::span_lint_and_sugg;
21
use clippy_utils::source::snippet_with_applicability;
32
use clippy_utils::ty::implements_trait;
3+
use clippy_utils::{diagnostics::span_lint_and_sugg, higher::MatchesExpn};
44
use if_chain::if_chain;
55
use rustc_errors::Applicability;
6-
use rustc_hir::{Expr, ExprKind, Pat, PatKind};
7-
use rustc_lint::{LateContext, LateLintPass};
8-
use rustc_middle::ty::Ty;
6+
use rustc_hir::{
7+
def::{DefKind, Res},
8+
Arm, Expr, ExprKind, Pat, PatKind, QPath,
9+
};
10+
use rustc_lint::{LateContext, LateLintPass, Lint};
11+
use rustc_middle::ty::{Adt, Ty};
912
use rustc_session::{declare_lint_pass, declare_tool_lint};
13+
use rustc_span::Span;
1014

1115
declare_clippy_lint! {
1216
/// ### What it does
13-
/// Checks for pattern matchings that can be expressed using equality.
17+
/// Checks for `if let <pat> = <expr>` (and `while let` and similars) that can be expressed
18+
/// using `if <expr> == <pat>`.
1419
///
1520
/// ### Why is this bad?
1621
///
@@ -33,68 +38,192 @@ declare_clippy_lint! {
3338
/// }
3439
/// ```
3540
pub EQUATABLE_IF_LET,
36-
nursery,
37-
"using pattern matching instead of equality"
41+
style,
42+
"using if let instead of if with a equality condition"
3843
}
3944

40-
declare_lint_pass!(PatternEquality => [EQUATABLE_IF_LET]);
45+
declare_clippy_lint! {
46+
/// ### What it does
47+
/// Checks for `matches!(<expr>, <pat>)` that can be expressed
48+
/// using `<expr> == <pat>`.
49+
///
50+
/// ### Why is this bad?
51+
///
52+
/// It is less concise and less clear.
53+
///
54+
/// ### Example
55+
/// ```rust,ignore
56+
/// let condition = matches!(x, Some(2));
57+
/// ```
58+
/// Should be written
59+
/// ```rust,ignore
60+
/// let condition = x == Some(2);
61+
/// ```
62+
pub EQUATABLE_MATCHES,
63+
pedantic,
64+
"using `matches!` instead of equality"
65+
}
66+
67+
declare_lint_pass!(PatternEquality => [EQUATABLE_IF_LET, EQUATABLE_MATCHES]);
4168

42-
/// detects if pattern matches just one thing
43-
fn unary_pattern(pat: &Pat<'_>) -> bool {
44-
fn array_rec(pats: &[Pat<'_>]) -> bool {
45-
pats.iter().all(unary_pattern)
69+
fn equatable_pattern(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool {
70+
fn array_rec(cx: &LateContext<'_>, pats: &[Pat<'_>]) -> bool {
71+
pats.iter().all(|x| equatable_pattern(cx, x))
4672
}
47-
match &pat.kind {
48-
PatKind::Slice(_, _, _) | PatKind::Range(_, _, _) | PatKind::Binding(..) | PatKind::Wild | PatKind::Or(_) => {
73+
fn is_derived(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool {
74+
let ty = cx.typeck_results().pat_ty(pat);
75+
if let Some(def_id) = cx.tcx.lang_items().structural_peq_trait() {
76+
implements_trait(cx, ty, def_id, &[ty.into()])
77+
} else {
4978
false
79+
}
80+
}
81+
match &pat.kind {
82+
PatKind::Slice(a, None, []) => array_rec(cx, a),
83+
PatKind::Struct(_, a, etc) => !etc && is_derived(cx, pat) && a.iter().all(|x| equatable_pattern(cx, x.pat)),
84+
PatKind::Tuple(a, etc) => !etc.is_some() && array_rec(cx, a),
85+
PatKind::TupleStruct(_, a, etc) => !etc.is_some() && is_derived(cx, pat) && array_rec(cx, a),
86+
PatKind::Ref(x, _) | PatKind::Box(x) => equatable_pattern(cx, x),
87+
PatKind::Path(QPath::Resolved(_, b)) => match b.res {
88+
Res::Def(DefKind::Const, _) => true,
89+
_ => is_derived(cx, pat),
5090
},
51-
PatKind::Struct(_, a, etc) => !etc && a.iter().all(|x| unary_pattern(x.pat)),
52-
PatKind::Tuple(a, etc) | PatKind::TupleStruct(_, a, etc) => !etc.is_some() && array_rec(a),
53-
PatKind::Ref(x, _) | PatKind::Box(x) => unary_pattern(x),
54-
PatKind::Path(_) | PatKind::Lit(_) => true,
91+
PatKind::Path(_) => is_derived(cx, pat),
92+
PatKind::Lit(_) => true,
93+
PatKind::Slice(..) | PatKind::Range(..) | PatKind::Binding(..) | PatKind::Wild | PatKind::Or(_) => false,
5594
}
5695
}
5796

58-
fn is_structural_partial_eq(cx: &LateContext<'tcx>, ty: Ty<'tcx>, other: Ty<'tcx>) -> bool {
97+
fn is_partial_eq(cx: &LateContext<'tcx>, t1: Ty<'tcx>, t2: Ty<'tcx>) -> bool {
5998
if let Some(def_id) = cx.tcx.lang_items().eq_trait() {
60-
implements_trait(cx, ty, def_id, &[other.into()])
99+
implements_trait(cx, t1, def_id, &[t2.into()])
61100
} else {
62101
false
63102
}
64103
}
65104

105+
fn pat_to_string(cx: &LateContext<'tcx>, app: &mut Applicability, pat: &Pat<'_>, goal: Ty<'_>) -> Option<String> {
106+
fn inner(cx: &LateContext<'tcx>, app: &mut Applicability, pat: &Pat<'_>, goal: Ty<'_>, r: &mut String) -> bool {
107+
let ty = cx.typeck_results().pat_ty(pat);
108+
if ty == goal {
109+
match &pat.kind {
110+
PatKind::TupleStruct(q, ..) | PatKind::Struct(q, ..) => {
111+
let (adt_def, generic_args) = if let Adt(x, y) = ty.kind() {
112+
(x, y)
113+
} else {
114+
return false; // shouldn't happen
115+
};
116+
let path = if let QPath::Resolved(.., p) = q {
117+
p
118+
} else {
119+
return false; // give up
120+
};
121+
let var = adt_def.variant_of_res(path.res);
122+
match &pat.kind {
123+
PatKind::TupleStruct(_, params, _) => {
124+
*r += &*snippet_with_applicability(cx, path.span, "..", app);
125+
*r += "(";
126+
for (i, (p, f)) in params.iter().zip(var.fields.iter()).enumerate() {
127+
if i != 0 {
128+
*r += ", ";
129+
}
130+
inner(cx, app, p, f.ty(cx.tcx, generic_args), r);
131+
}
132+
*r += ")";
133+
},
134+
PatKind::Struct(_, fields, _) => {
135+
*r += &*snippet_with_applicability(cx, path.span, "..", app);
136+
*r += " { ";
137+
for (i, p) in fields.iter().enumerate() {
138+
if i != 0 {
139+
*r += ", ";
140+
}
141+
*r += &*snippet_with_applicability(cx, p.ident.span, "..", app);
142+
*r += ": ";
143+
if let Some(x) = var.fields.iter().find(|f| f.ident == p.ident) {
144+
inner(cx, app, p.pat, x.ty(cx.tcx, generic_args), r);
145+
} else {
146+
return false; // won't happen
147+
}
148+
}
149+
*r += " }";
150+
},
151+
_ => return false, // won't happen
152+
}
153+
},
154+
_ => {
155+
*r += &*snippet_with_applicability(cx, pat.span, "..", app);
156+
},
157+
}
158+
return true;
159+
}
160+
if goal.is_ref() {
161+
if let Some(tam) = goal.builtin_deref(true) {
162+
*r += "&";
163+
return inner(cx, app, pat, tam.ty, r);
164+
}
165+
}
166+
false
167+
}
168+
let mut r = "".to_string();
169+
if let PatKind::Struct(..) = pat.kind {
170+
r += "(";
171+
}
172+
let success = inner(cx, app, pat, goal, &mut r);
173+
if let PatKind::Struct(..) = pat.kind {
174+
r += ")";
175+
}
176+
if !success {
177+
return None;
178+
}
179+
Some(r)
180+
}
181+
182+
fn emit_lint(cx: &LateContext<'tcx>, pat: &Pat<'_>, exp: &Expr<'_>, span: Span, lint: &'static Lint) {
183+
if_chain! {
184+
if equatable_pattern(cx, pat);
185+
let exp_ty = cx.typeck_results().expr_ty(exp);
186+
if is_partial_eq(cx, exp_ty, exp_ty);
187+
let mut app = Applicability::MachineApplicable;
188+
if let Some(pat_str) = pat_to_string(cx, &mut app, pat, exp_ty);
189+
then {
190+
/*let pat_str = match pat.kind {
191+
PatKind::Struct(..) => format!(
192+
"({})",
193+
snippet_with_applicability(cx, pat.span, "..", &mut applicability),
194+
),
195+
_ => snippet_with_applicability(cx, pat.span, "..", &mut applicability).to_string(),
196+
};*/
197+
let exp_str = snippet_with_applicability(cx, exp.span, "..", &mut app);
198+
span_lint_and_sugg(
199+
cx,
200+
lint,
201+
span,
202+
"this pattern matching can be expressed using equality",
203+
"try",
204+
format!(
205+
"{} == {}",
206+
exp_str,
207+
pat_str,
208+
),
209+
app,
210+
);
211+
}
212+
}
213+
}
214+
66215
impl<'tcx> LateLintPass<'tcx> for PatternEquality {
67216
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
68-
if_chain! {
69-
if let ExprKind::Let(pat, exp, _) = expr.kind;
70-
if unary_pattern(pat);
71-
let exp_ty = cx.typeck_results().expr_ty(exp);
72-
let pat_ty = cx.typeck_results().pat_ty(pat);
73-
if is_structural_partial_eq(cx, exp_ty, pat_ty);
74-
then {
75-
76-
let mut applicability = Applicability::MachineApplicable;
77-
let pat_str = match pat.kind {
78-
PatKind::Struct(..) => format!(
79-
"({})",
80-
snippet_with_applicability(cx, pat.span, "..", &mut applicability),
81-
),
82-
_ => snippet_with_applicability(cx, pat.span, "..", &mut applicability).to_string(),
83-
};
84-
span_lint_and_sugg(
85-
cx,
86-
EQUATABLE_IF_LET,
87-
expr.span,
88-
"this pattern matching can be expressed using equality",
89-
"try",
90-
format!(
91-
"{} == {}",
92-
snippet_with_applicability(cx, exp.span, "..", &mut applicability),
93-
pat_str,
94-
),
95-
applicability,
96-
);
97-
}
217+
if let ExprKind::Let(pat, exp, _) = expr.kind {
218+
emit_lint(cx, pat, exp, expr.span, EQUATABLE_IF_LET);
219+
}
220+
if let Some(MatchesExpn {
221+
call_site,
222+
arm: Arm { pat, guard: None, .. },
223+
exp,
224+
}) = MatchesExpn::parse(expr)
225+
{
226+
emit_lint(cx, pat, exp, call_site, EQUATABLE_MATCHES);
98227
}
99228
}
100229
}

clippy_lints/src/lib.register_all.rs

+1
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
5151
LintId::of(enum_variants::MODULE_INCEPTION),
5252
LintId::of(eq_op::EQ_OP),
5353
LintId::of(eq_op::OP_REF),
54+
LintId::of(equatable_if_let::EQUATABLE_IF_LET),
5455
LintId::of(erasing_op::ERASING_OP),
5556
LintId::of(escape::BOXED_LOCAL),
5657
LintId::of(eta_reduction::REDUNDANT_CLOSURE),

clippy_lints/src/lib.register_lints.rs

+1
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ store.register_lints(&[
117117
eq_op::EQ_OP,
118118
eq_op::OP_REF,
119119
equatable_if_let::EQUATABLE_IF_LET,
120+
equatable_if_let::EQUATABLE_MATCHES,
120121
erasing_op::ERASING_OP,
121122
escape::BOXED_LOCAL,
122123
eta_reduction::REDUNDANT_CLOSURE,

clippy_lints/src/lib.register_nursery.rs

-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![
88
LintId::of(copies::BRANCHES_SHARING_CODE),
99
LintId::of(disallowed_method::DISALLOWED_METHOD),
1010
LintId::of(disallowed_type::DISALLOWED_TYPE),
11-
LintId::of(equatable_if_let::EQUATABLE_IF_LET),
1211
LintId::of(fallible_impl_from::FALLIBLE_IMPL_FROM),
1312
LintId::of(floating_point_arithmetic::IMPRECISE_FLOPS),
1413
LintId::of(floating_point_arithmetic::SUBOPTIMAL_FLOPS),

clippy_lints/src/lib.register_pedantic.rs

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![
2828
LintId::of(doc::MISSING_PANICS_DOC),
2929
LintId::of(empty_enum::EMPTY_ENUM),
3030
LintId::of(enum_variants::MODULE_NAME_REPETITIONS),
31+
LintId::of(equatable_if_let::EQUATABLE_MATCHES),
3132
LintId::of(eta_reduction::REDUNDANT_CLOSURE_FOR_METHOD_CALLS),
3233
LintId::of(excessive_bools::FN_PARAMS_EXCESSIVE_BOOLS),
3334
LintId::of(excessive_bools::STRUCT_EXCESSIVE_BOOLS),

clippy_lints/src/lib.register_style.rs

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![
2020
LintId::of(enum_variants::ENUM_VARIANT_NAMES),
2121
LintId::of(enum_variants::MODULE_INCEPTION),
2222
LintId::of(eq_op::OP_REF),
23+
LintId::of(equatable_if_let::EQUATABLE_IF_LET),
2324
LintId::of(eta_reduction::REDUNDANT_CLOSURE),
2425
LintId::of(float_literal::EXCESSIVE_PRECISION),
2526
LintId::of(from_over_into::FROM_OVER_INTO),

clippy_lints/src/manual_async_fn.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ fn captures_all_lifetimes(inputs: &[Ty<'_>], output_lifetimes: &[LifetimeName])
165165
// - There's only one output lifetime bound using `+ '_`
166166
// - All input lifetimes are explicitly bound to the output
167167
input_lifetimes.is_empty()
168-
|| (output_lifetimes.len() == 1 && matches!(output_lifetimes[0], LifetimeName::Underscore))
168+
|| (output_lifetimes.len() == 1 && output_lifetimes[0] == LifetimeName::Underscore)
169169
|| input_lifetimes
170170
.iter()
171171
.all(|in_lt| output_lifetimes.iter().any(|out_lt| in_lt == out_lt))

clippy_lints/src/manual_map.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ impl LateLintPass<'_> for ManualMap {
170170
}
171171

172172
// `ref` and `ref mut` annotations were handled earlier.
173-
let annotation = if matches!(annotation, BindingAnnotation::Mutable) {
173+
let annotation = if annotation == BindingAnnotation::Mutable {
174174
"mut "
175175
} else {
176176
""

clippy_lints/src/map_clone.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ impl<'tcx> LateLintPass<'tcx> for MapClone {
8888
then {
8989
let obj_ty = cx.typeck_results().expr_ty(obj);
9090
if let ty::Ref(_, ty, mutability) = obj_ty.kind() {
91-
if matches!(mutability, Mutability::Not) {
91+
if mutability == &Mutability::Not {
9292
let copy = is_copy(cx, ty);
9393
lint(cx, e.span, args[0].span, copy);
9494
}

clippy_lints/src/methods/inefficient_to_string.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, method_name: Sy
5151
/// Returns whether `ty` specializes `ToString`.
5252
/// Currently, these are `str`, `String`, and `Cow<'_, str>`.
5353
fn specializes_tostring(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
54-
if let ty::Str = ty.kind() {
54+
if ty.kind() == &ty::Str {
5555
return true;
5656
}
5757

clippy_lints/src/methods/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2456,7 +2456,7 @@ impl OutType {
24562456

24572457
fn is_bool(ty: &hir::Ty<'_>) -> bool {
24582458
if let hir::TyKind::Path(QPath::Resolved(_, path)) = ty.kind {
2459-
matches!(path.res, Res::PrimTy(PrimTy::Bool))
2459+
path.res == Res::PrimTy(PrimTy::Bool)
24602460
} else {
24612461
false
24622462
}

clippy_lints/src/methods/or_fun_call.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,8 @@ pub(super) fn check<'tcx>(
5151
let path = last_path_segment(qpath).ident.name;
5252
// needs to target Default::default in particular or be *::new and have a Default impl
5353
// available
54-
if (matches!(path, kw::Default) && is_default_default())
55-
|| (matches!(path, sym::new) && implements_default(arg, default_trait_id));
54+
if (path == kw::Default && is_default_default())
55+
|| (path == sym::new && implements_default(arg, default_trait_id));
5656

5757
then {
5858
let mut applicability = Applicability::MachineApplicable;

0 commit comments

Comments
 (0)