Skip to content

Commit b3d0a09

Browse files
authored
unnecessary_mut_passed: add structured suggestion (#15438)
resolves #8943 changelog: [`unnecessary_mut_passed`]: add structured suggestion
2 parents 1dee616 + 597d5a5 commit b3d0a09

File tree

4 files changed

+376
-35
lines changed

4 files changed

+376
-35
lines changed

clippy_lints/src/mut_reference.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
use clippy_utils::diagnostics::span_lint;
1+
use clippy_utils::diagnostics::span_lint_and_sugg;
2+
use clippy_utils::sugg::Sugg;
3+
use rustc_errors::Applicability;
24
use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability};
35
use rustc_lint::{LateContext, LateLintPass};
46
use rustc_middle::ty::{self, Ty};
@@ -83,13 +85,18 @@ fn check_arguments<'tcx>(
8385
let parameters = type_definition.fn_sig(cx.tcx).skip_binder().inputs();
8486
for (argument, parameter) in iter::zip(arguments, parameters) {
8587
if let ty::Ref(_, _, Mutability::Not) | ty::RawPtr(_, Mutability::Not) = parameter.kind()
86-
&& let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, _) = argument.kind
88+
&& let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, arg) = argument.kind
8789
{
88-
span_lint(
90+
let mut applicability = Applicability::MachineApplicable;
91+
let sugg = Sugg::hir_with_applicability(cx, arg, "_", &mut applicability).addr();
92+
span_lint_and_sugg(
8993
cx,
9094
UNNECESSARY_MUT_PASSED,
9195
argument.span,
9296
format!("the {fn_kind} `{name}` doesn't need a mutable reference"),
97+
"remove this `mut`",
98+
sugg.to_string(),
99+
applicability,
93100
);
94101
}
95102
}

tests/ui/mut_reference.fixed

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
#![allow(clippy::mut_mut)]
2+
3+
fn takes_ref(a: &i32) {}
4+
fn takes_refmut(a: &mut i32) {}
5+
fn takes_ref_ref(a: &&i32) {}
6+
fn takes_refmut_ref(a: &mut &i32) {}
7+
fn takes_ref_refmut(a: &&mut i32) {}
8+
fn takes_refmut_refmut(a: &mut &mut i32) {}
9+
fn takes_raw_const(a: *const i32) {}
10+
fn takes_raw_mut(a: *mut i32) {}
11+
12+
mod issue11268 {
13+
macro_rules! x {
14+
(1 $f:expr) => {
15+
$f(&mut 1);
16+
};
17+
(2 $f:expr) => {
18+
$f(&mut &1)
19+
};
20+
(3 $f:expr) => {
21+
$f(&mut &mut 1)
22+
};
23+
(4 $f:expr) => {
24+
let mut a = 1;
25+
$f(&raw mut a)
26+
};
27+
}
28+
29+
fn f() {
30+
x!(1 super::takes_ref);
31+
x!(1 super::takes_refmut);
32+
x!(2 super::takes_refmut_ref);
33+
x!(3 super::takes_ref_refmut);
34+
x!(3 super::takes_refmut_refmut);
35+
x!(4 super::takes_raw_const);
36+
x!(4 super::takes_raw_mut);
37+
}
38+
}
39+
40+
struct MyStruct;
41+
42+
impl MyStruct {
43+
fn takes_ref(&self, a: &i32) {}
44+
fn takes_refmut(&self, a: &mut i32) {}
45+
fn takes_ref_ref(&self, a: &&i32) {}
46+
fn takes_refmut_ref(&self, a: &mut &i32) {}
47+
fn takes_ref_refmut(&self, a: &&mut i32) {}
48+
fn takes_refmut_refmut(&self, a: &mut &mut i32) {}
49+
fn takes_raw_const(&self, a: *const i32) {}
50+
fn takes_raw_mut(&self, a: *mut i32) {}
51+
}
52+
53+
#[warn(clippy::unnecessary_mut_passed)]
54+
fn main() {
55+
// Functions
56+
takes_ref(&42);
57+
//~^ unnecessary_mut_passed
58+
takes_ref_ref(&&42);
59+
//~^ unnecessary_mut_passed
60+
takes_ref_refmut(&&mut 42);
61+
//~^ unnecessary_mut_passed
62+
takes_raw_const(&42);
63+
//~^ unnecessary_mut_passed
64+
65+
let as_ptr: fn(&i32) = takes_ref;
66+
as_ptr(&42);
67+
//~^ unnecessary_mut_passed
68+
let as_ptr: fn(&&i32) = takes_ref_ref;
69+
as_ptr(&&42);
70+
//~^ unnecessary_mut_passed
71+
let as_ptr: fn(&&mut i32) = takes_ref_refmut;
72+
as_ptr(&&mut 42);
73+
//~^ unnecessary_mut_passed
74+
let as_ptr: fn(*const i32) = takes_raw_const;
75+
as_ptr(&42);
76+
//~^ unnecessary_mut_passed
77+
78+
// Methods
79+
let my_struct = MyStruct;
80+
my_struct.takes_ref(&42);
81+
//~^ unnecessary_mut_passed
82+
my_struct.takes_ref_ref(&&42);
83+
//~^ unnecessary_mut_passed
84+
my_struct.takes_ref_refmut(&&mut 42);
85+
//~^ unnecessary_mut_passed
86+
my_struct.takes_raw_const(&42);
87+
//~^ unnecessary_mut_passed
88+
89+
// No error
90+
91+
// Functions
92+
takes_ref(&42);
93+
let as_ptr: fn(&i32) = takes_ref;
94+
as_ptr(&42);
95+
96+
takes_refmut(&mut 42);
97+
let as_ptr: fn(&mut i32) = takes_refmut;
98+
as_ptr(&mut 42);
99+
100+
takes_ref_ref(&&42);
101+
let as_ptr: fn(&&i32) = takes_ref_ref;
102+
as_ptr(&&42);
103+
104+
takes_refmut_ref(&mut &42);
105+
let as_ptr: fn(&mut &i32) = takes_refmut_ref;
106+
as_ptr(&mut &42);
107+
108+
takes_ref_refmut(&&mut 42);
109+
let as_ptr: fn(&&mut i32) = takes_ref_refmut;
110+
as_ptr(&&mut 42);
111+
112+
takes_refmut_refmut(&mut &mut 42);
113+
let as_ptr: fn(&mut &mut i32) = takes_refmut_refmut;
114+
as_ptr(&mut &mut 42);
115+
116+
takes_raw_const(&42);
117+
let as_ptr: fn(*const i32) = takes_raw_const;
118+
as_ptr(&42);
119+
120+
takes_raw_mut(&mut 42);
121+
let as_ptr: fn(*mut i32) = takes_raw_mut;
122+
as_ptr(&mut 42);
123+
124+
let a = &mut 42;
125+
let b = &mut &42;
126+
let c = &mut &mut 42;
127+
takes_ref(a);
128+
takes_ref_ref(b);
129+
takes_ref_refmut(c);
130+
takes_raw_const(a);
131+
132+
// Methods
133+
my_struct.takes_ref(&42);
134+
my_struct.takes_refmut(&mut 42);
135+
my_struct.takes_ref_ref(&&42);
136+
my_struct.takes_refmut_ref(&mut &42);
137+
my_struct.takes_ref_refmut(&&mut 42);
138+
my_struct.takes_refmut_refmut(&mut &mut 42);
139+
my_struct.takes_raw_const(&42);
140+
my_struct.takes_raw_mut(&mut 42);
141+
my_struct.takes_ref(a);
142+
my_struct.takes_ref_ref(b);
143+
my_struct.takes_ref_refmut(c);
144+
my_struct.takes_raw_const(a);
145+
my_struct.takes_raw_mut(a);
146+
}
147+
148+
// not supported currently
149+
fn raw_ptrs(my_struct: MyStruct) {
150+
let mut n = 42;
151+
152+
takes_raw_const(&raw mut n);
153+
154+
let as_ptr: fn(*const i32) = takes_raw_const;
155+
as_ptr(&raw mut n);
156+
157+
my_struct.takes_raw_const(&raw mut n);
158+
159+
// No error
160+
161+
takes_raw_const(&raw const n);
162+
takes_raw_mut(&raw mut n);
163+
164+
let a = &raw mut n;
165+
takes_raw_const(a);
166+
167+
my_struct.takes_raw_const(&raw const n);
168+
my_struct.takes_raw_mut(&raw mut n);
169+
my_struct.takes_raw_const(a);
170+
}

tests/ui/mut_reference.rs

Lines changed: 131 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,170 @@
1-
#![allow(unused_variables, dead_code)]
2-
//@no-rustfix
3-
fn takes_an_immutable_reference(a: &i32) {}
4-
fn takes_a_mutable_reference(a: &mut i32) {}
1+
#![allow(clippy::mut_mut)]
2+
3+
fn takes_ref(a: &i32) {}
4+
fn takes_refmut(a: &mut i32) {}
5+
fn takes_ref_ref(a: &&i32) {}
6+
fn takes_refmut_ref(a: &mut &i32) {}
7+
fn takes_ref_refmut(a: &&mut i32) {}
8+
fn takes_refmut_refmut(a: &mut &mut i32) {}
9+
fn takes_raw_const(a: *const i32) {}
10+
fn takes_raw_mut(a: *mut i32) {}
511

612
mod issue11268 {
713
macro_rules! x {
8-
($f:expr) => {
14+
(1 $f:expr) => {
915
$f(&mut 1);
1016
};
17+
(2 $f:expr) => {
18+
$f(&mut &1)
19+
};
20+
(3 $f:expr) => {
21+
$f(&mut &mut 1)
22+
};
23+
(4 $f:expr) => {
24+
let mut a = 1;
25+
$f(&raw mut a)
26+
};
1127
}
1228

1329
fn f() {
14-
x!(super::takes_an_immutable_reference);
15-
x!(super::takes_a_mutable_reference);
30+
x!(1 super::takes_ref);
31+
x!(1 super::takes_refmut);
32+
x!(2 super::takes_refmut_ref);
33+
x!(3 super::takes_ref_refmut);
34+
x!(3 super::takes_refmut_refmut);
35+
x!(4 super::takes_raw_const);
36+
x!(4 super::takes_raw_mut);
1637
}
1738
}
1839

1940
struct MyStruct;
2041

2142
impl MyStruct {
22-
fn takes_an_immutable_reference(&self, a: &i32) {}
23-
24-
fn takes_a_mutable_reference(&self, a: &mut i32) {}
43+
fn takes_ref(&self, a: &i32) {}
44+
fn takes_refmut(&self, a: &mut i32) {}
45+
fn takes_ref_ref(&self, a: &&i32) {}
46+
fn takes_refmut_ref(&self, a: &mut &i32) {}
47+
fn takes_ref_refmut(&self, a: &&mut i32) {}
48+
fn takes_refmut_refmut(&self, a: &mut &mut i32) {}
49+
fn takes_raw_const(&self, a: *const i32) {}
50+
fn takes_raw_mut(&self, a: *mut i32) {}
2551
}
2652

2753
#[warn(clippy::unnecessary_mut_passed)]
2854
fn main() {
2955
// Functions
30-
takes_an_immutable_reference(&mut 42);
56+
takes_ref(&mut 42);
57+
//~^ unnecessary_mut_passed
58+
takes_ref_ref(&mut &42);
59+
//~^ unnecessary_mut_passed
60+
takes_ref_refmut(&mut &mut 42);
61+
//~^ unnecessary_mut_passed
62+
takes_raw_const(&mut 42);
3163
//~^ unnecessary_mut_passed
3264

33-
let as_ptr: fn(&i32) = takes_an_immutable_reference;
65+
let as_ptr: fn(&i32) = takes_ref;
66+
as_ptr(&mut 42);
67+
//~^ unnecessary_mut_passed
68+
let as_ptr: fn(&&i32) = takes_ref_ref;
69+
as_ptr(&mut &42);
70+
//~^ unnecessary_mut_passed
71+
let as_ptr: fn(&&mut i32) = takes_ref_refmut;
72+
as_ptr(&mut &mut 42);
73+
//~^ unnecessary_mut_passed
74+
let as_ptr: fn(*const i32) = takes_raw_const;
3475
as_ptr(&mut 42);
3576
//~^ unnecessary_mut_passed
3677

3778
// Methods
3879
let my_struct = MyStruct;
39-
my_struct.takes_an_immutable_reference(&mut 42);
80+
my_struct.takes_ref(&mut 42);
81+
//~^ unnecessary_mut_passed
82+
my_struct.takes_ref_ref(&mut &42);
83+
//~^ unnecessary_mut_passed
84+
my_struct.takes_ref_refmut(&mut &mut 42);
85+
//~^ unnecessary_mut_passed
86+
my_struct.takes_raw_const(&mut 42);
4087
//~^ unnecessary_mut_passed
4188

4289
// No error
4390

4491
// Functions
45-
takes_an_immutable_reference(&42);
46-
let as_ptr: fn(&i32) = takes_an_immutable_reference;
92+
takes_ref(&42);
93+
let as_ptr: fn(&i32) = takes_ref;
4794
as_ptr(&42);
4895

49-
takes_a_mutable_reference(&mut 42);
50-
let as_ptr: fn(&mut i32) = takes_a_mutable_reference;
96+
takes_refmut(&mut 42);
97+
let as_ptr: fn(&mut i32) = takes_refmut;
98+
as_ptr(&mut 42);
99+
100+
takes_ref_ref(&&42);
101+
let as_ptr: fn(&&i32) = takes_ref_ref;
102+
as_ptr(&&42);
103+
104+
takes_refmut_ref(&mut &42);
105+
let as_ptr: fn(&mut &i32) = takes_refmut_ref;
106+
as_ptr(&mut &42);
107+
108+
takes_ref_refmut(&&mut 42);
109+
let as_ptr: fn(&&mut i32) = takes_ref_refmut;
110+
as_ptr(&&mut 42);
111+
112+
takes_refmut_refmut(&mut &mut 42);
113+
let as_ptr: fn(&mut &mut i32) = takes_refmut_refmut;
114+
as_ptr(&mut &mut 42);
115+
116+
takes_raw_const(&42);
117+
let as_ptr: fn(*const i32) = takes_raw_const;
118+
as_ptr(&42);
119+
120+
takes_raw_mut(&mut 42);
121+
let as_ptr: fn(*mut i32) = takes_raw_mut;
51122
as_ptr(&mut 42);
52123

53124
let a = &mut 42;
54-
takes_an_immutable_reference(a);
125+
let b = &mut &42;
126+
let c = &mut &mut 42;
127+
takes_ref(a);
128+
takes_ref_ref(b);
129+
takes_ref_refmut(c);
130+
takes_raw_const(a);
55131

56132
// Methods
57-
my_struct.takes_an_immutable_reference(&42);
58-
my_struct.takes_a_mutable_reference(&mut 42);
59-
my_struct.takes_an_immutable_reference(a);
133+
my_struct.takes_ref(&42);
134+
my_struct.takes_refmut(&mut 42);
135+
my_struct.takes_ref_ref(&&42);
136+
my_struct.takes_refmut_ref(&mut &42);
137+
my_struct.takes_ref_refmut(&&mut 42);
138+
my_struct.takes_refmut_refmut(&mut &mut 42);
139+
my_struct.takes_raw_const(&42);
140+
my_struct.takes_raw_mut(&mut 42);
141+
my_struct.takes_ref(a);
142+
my_struct.takes_ref_ref(b);
143+
my_struct.takes_ref_refmut(c);
144+
my_struct.takes_raw_const(a);
145+
my_struct.takes_raw_mut(a);
146+
}
147+
148+
// not supported currently
149+
fn raw_ptrs(my_struct: MyStruct) {
150+
let mut n = 42;
151+
152+
takes_raw_const(&raw mut n);
153+
154+
let as_ptr: fn(*const i32) = takes_raw_const;
155+
as_ptr(&raw mut n);
156+
157+
my_struct.takes_raw_const(&raw mut n);
158+
159+
// No error
160+
161+
takes_raw_const(&raw const n);
162+
takes_raw_mut(&raw mut n);
163+
164+
let a = &raw mut n;
165+
takes_raw_const(a);
166+
167+
my_struct.takes_raw_const(&raw const n);
168+
my_struct.takes_raw_mut(&raw mut n);
169+
my_struct.takes_raw_const(a);
60170
}

0 commit comments

Comments
 (0)