Skip to content

Commit 4aaa667

Browse files
committed
fix ignored_unit_patterns: include refs in the suggestion
1 parent 8779679 commit 4aaa667

File tree

4 files changed

+87
-5
lines changed

4 files changed

+87
-5
lines changed

clippy_lints/src/ignored_unit_patterns.rs

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ use hir::{Node, PatKind};
33
use rustc_errors::Applicability;
44
use rustc_hir as hir;
55
use rustc_lint::{LateContext, LateLintPass};
6+
use rustc_middle::mir::Mutability;
7+
use rustc_middle::ty::{self, Ty};
68
use rustc_session::declare_lint_pass;
79

810
declare_clippy_lint! {
@@ -39,7 +41,9 @@ impl<'tcx> LateLintPass<'tcx> for IgnoredUnitPatterns {
3941
fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx hir::Pat<'tcx>) {
4042
if matches!(pat.kind, PatKind::Wild)
4143
&& !pat.span.from_expansion()
42-
&& cx.typeck_results().pat_ty(pat).peel_refs().is_unit()
44+
&& let pat_ty = cx.typeck_results().pat_ty(pat)
45+
&& let (pat_ty, refs) = peel_refs_with_mutabilities(pat_ty)
46+
&& pat_ty.is_unit()
4347
{
4448
match cx.tcx.parent_hir_node(pat.hir_id) {
4549
Node::Param(param) if matches!(cx.tcx.parent_hir_node(param.hir_id), Node::Item(_)) => {
@@ -52,15 +56,29 @@ impl<'tcx> LateLintPass<'tcx> for IgnoredUnitPatterns {
5256
},
5357
_ => {},
5458
}
59+
60+
let sugg = refs.into_iter().map(Mutability::ref_prefix_str).chain(["()"]).collect();
5561
span_lint_and_sugg(
5662
cx,
5763
IGNORED_UNIT_PATTERNS,
5864
pat.span,
5965
"matching over `()` is more explicit",
6066
"use `()` instead of `_`",
61-
String::from("()"),
67+
sugg,
6268
Applicability::MachineApplicable,
6369
);
6470
}
6571
}
6672
}
73+
74+
/// Like [`rustc_middle::ty::Ty::peel_refs`], but returns the mutability of each peeled ref
75+
///
76+
/// `&&mut &mut &mut T` returns `(T, [Not, Mut, Mut, Mut])`
77+
fn peel_refs_with_mutabilities(ty: Ty<'_>) -> (Ty<'_>, Vec<Mutability>) {
78+
let (mut ty, mut refs) = (ty, vec![]);
79+
while let ty::Ref(_, dest_ty, mutbl) = ty.kind() {
80+
ty = *dest_ty;
81+
refs.push(*mutbl);
82+
}
83+
(ty, refs)
84+
}

tests/ui/ignored_unit_patterns.fixed

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ pub fn moo(_: ()) {
4747
fn test_unit_ref_1() {
4848
let x: (usize, &&&&&()) = (1, &&&&&&());
4949
match x {
50-
(1, ()) => unimplemented!(),
50+
(1, &&&&&()) => unimplemented!(),
5151
//~^ ERROR: matching over `()` is more explicit
5252
_ => unimplemented!(),
5353
};
@@ -59,3 +59,20 @@ fn test_unit_ref_2(v: &[(usize, ())]) {
5959
let _ = x;
6060
}
6161
}
62+
63+
fn issue15187() {
64+
let func: fn(&()) = |&()| {};
65+
//~^ ERROR: matching over `()` is more explicit
66+
let func: fn(&mut ()) = |&mut ()| {};
67+
//~^ ERROR: matching over `()` is more explicit
68+
let func: fn(&&mut ()) = |&&mut ()| {};
69+
//~^ ERROR: matching over `()` is more explicit
70+
let func: fn(&&mut &()) = |&&mut &()| {};
71+
//~^ ERROR: matching over `()` is more explicit
72+
73+
#[allow(clippy::match_single_binding)]
74+
match &() {
75+
&() => todo!(),
76+
//~^ ERROR: matching over `()` is more explicit
77+
}
78+
}

tests/ui/ignored_unit_patterns.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,3 +59,20 @@ fn test_unit_ref_2(v: &[(usize, ())]) {
5959
let _ = x;
6060
}
6161
}
62+
63+
fn issue15187() {
64+
let func: fn(&()) = |_| {};
65+
//~^ ERROR: matching over `()` is more explicit
66+
let func: fn(&mut ()) = |_| {};
67+
//~^ ERROR: matching over `()` is more explicit
68+
let func: fn(&&mut ()) = |_| {};
69+
//~^ ERROR: matching over `()` is more explicit
70+
let func: fn(&&mut &()) = |_| {};
71+
//~^ ERROR: matching over `()` is more explicit
72+
73+
#[allow(clippy::match_single_binding)]
74+
match &() {
75+
_ => todo!(),
76+
//~^ ERROR: matching over `()` is more explicit
77+
}
78+
}

tests/ui/ignored_unit_patterns.stderr

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,43 @@ error: matching over `()` is more explicit
4747
--> tests/ui/ignored_unit_patterns.rs:50:13
4848
|
4949
LL | (1, _) => unimplemented!(),
50-
| ^ help: use `()` instead of `_`: `()`
50+
| ^ help: use `()` instead of `_`: `&&&&&()`
5151

5252
error: matching over `()` is more explicit
5353
--> tests/ui/ignored_unit_patterns.rs:57:13
5454
|
5555
LL | for (x, _) in v {
5656
| ^ help: use `()` instead of `_`: `()`
5757

58-
error: aborting due to 9 previous errors
58+
error: matching over `()` is more explicit
59+
--> tests/ui/ignored_unit_patterns.rs:64:26
60+
|
61+
LL | let func: fn(&()) = |_| {};
62+
| ^ help: use `()` instead of `_`: `&()`
63+
64+
error: matching over `()` is more explicit
65+
--> tests/ui/ignored_unit_patterns.rs:66:30
66+
|
67+
LL | let func: fn(&mut ()) = |_| {};
68+
| ^ help: use `()` instead of `_`: `&mut ()`
69+
70+
error: matching over `()` is more explicit
71+
--> tests/ui/ignored_unit_patterns.rs:68:31
72+
|
73+
LL | let func: fn(&&mut ()) = |_| {};
74+
| ^ help: use `()` instead of `_`: `&&mut ()`
75+
76+
error: matching over `()` is more explicit
77+
--> tests/ui/ignored_unit_patterns.rs:70:32
78+
|
79+
LL | let func: fn(&&mut &()) = |_| {};
80+
| ^ help: use `()` instead of `_`: `&&mut &()`
81+
82+
error: matching over `()` is more explicit
83+
--> tests/ui/ignored_unit_patterns.rs:75:9
84+
|
85+
LL | _ => todo!(),
86+
| ^ help: use `()` instead of `_`: `&()`
87+
88+
error: aborting due to 14 previous errors
5989

0 commit comments

Comments
 (0)