Skip to content

Commit 9cb82d7

Browse files
committed
fix(unnecessary_mut_passed): retain parens around the arguments
1 parent 0ed31be commit 9cb82d7

File tree

4 files changed

+233
-33
lines changed

4 files changed

+233
-33
lines changed

clippy_lints/src/unnecessary_mut_passed.rs

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
use clippy_utils::diagnostics::span_lint_and_sugg;
2-
use clippy_utils::sugg::Sugg;
1+
use clippy_utils::diagnostics::span_lint_and_then;
2+
use clippy_utils::source::SpanRangeExt;
33
use rustc_errors::Applicability;
44
use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability};
55
use rustc_lint::{LateContext, LateLintPass};
@@ -87,16 +87,33 @@ fn check_arguments<'tcx>(
8787
if let ty::Ref(_, _, Mutability::Not) | ty::RawPtr(_, Mutability::Not) = parameter.kind()
8888
&& let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, arg) = argument.kind
8989
{
90-
let mut applicability = Applicability::MachineApplicable;
91-
let sugg = Sugg::hir_with_applicability(cx, arg, "_", &mut applicability).addr();
92-
span_lint_and_sugg(
90+
let applicability = Applicability::MachineApplicable;
91+
92+
let span_to_remove = {
93+
let span_until_arg = argument.span.until(arg.span);
94+
if let Some(Some(ref_pos)) = span_until_arg.with_source_text(cx, |src| {
95+
src
96+
// we don't use `strip_prefix` here, because `argument` might be enclosed in parens, in
97+
// which case `&` is no longer the prefix
98+
.find('&')
99+
// just a sanity check, in case some proc-macro messes up the spans
100+
.filter(|ref_pos| src[*ref_pos..].contains("mut"))
101+
}) && let Ok(lo) = u32::try_from(ref_pos + '&'.len_utf8())
102+
{
103+
span_until_arg.split_at(lo).1
104+
} else {
105+
return;
106+
}
107+
};
108+
109+
span_lint_and_then(
93110
cx,
94111
UNNECESSARY_MUT_PASSED,
95112
argument.span,
96113
format!("the {fn_kind} `{name}` doesn't need a mutable reference"),
97-
"remove this `mut`",
98-
sugg.to_string(),
99-
applicability,
114+
|diag| {
115+
diag.span_suggestion_verbose(span_to_remove, "remove this `mut`", String::new(), applicability);
116+
},
100117
);
101118
}
102119
}

tests/ui/unnecessary_mut_passed.fixed

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ mod issue11268 {
4040
struct MyStruct;
4141

4242
impl MyStruct {
43+
fn takes_nothing(&self) {}
4344
fn takes_ref(&self, a: &i32) {}
4445
fn takes_refmut(&self, a: &mut i32) {}
4546
fn takes_ref_ref(&self, a: &&i32) {}
@@ -168,3 +169,22 @@ fn raw_ptrs(my_struct: MyStruct) {
168169
my_struct.takes_raw_mut(&raw mut n);
169170
my_struct.takes_raw_const(a);
170171
}
172+
173+
#[expect(clippy::needless_borrow)]
174+
fn issue15722(mut my_struct: MyStruct) {
175+
(&my_struct).takes_nothing();
176+
//~^ unnecessary_mut_passed
177+
(&my_struct).takes_nothing();
178+
179+
// Only put parens around the argument that used to have it
180+
(&my_struct).takes_ref(&42);
181+
//~^ unnecessary_mut_passed
182+
//~| unnecessary_mut_passed
183+
#[expect(clippy::double_parens)]
184+
(&my_struct).takes_ref((&42));
185+
//~^ unnecessary_mut_passed
186+
//~| unnecessary_mut_passed
187+
#[expect(clippy::double_parens)]
188+
my_struct.takes_ref((&42));
189+
//~^ unnecessary_mut_passed
190+
}

tests/ui/unnecessary_mut_passed.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ mod issue11268 {
4040
struct MyStruct;
4141

4242
impl MyStruct {
43+
fn takes_nothing(&self) {}
4344
fn takes_ref(&self, a: &i32) {}
4445
fn takes_refmut(&self, a: &mut i32) {}
4546
fn takes_ref_ref(&self, a: &&i32) {}
@@ -168,3 +169,22 @@ fn raw_ptrs(my_struct: MyStruct) {
168169
my_struct.takes_raw_mut(&raw mut n);
169170
my_struct.takes_raw_const(a);
170171
}
172+
173+
#[expect(clippy::needless_borrow)]
174+
fn issue15722(mut my_struct: MyStruct) {
175+
(&mut my_struct).takes_nothing();
176+
//~^ unnecessary_mut_passed
177+
(&my_struct).takes_nothing();
178+
179+
// Only put parens around the argument that used to have it
180+
(&mut my_struct).takes_ref(&mut 42);
181+
//~^ unnecessary_mut_passed
182+
//~| unnecessary_mut_passed
183+
#[expect(clippy::double_parens)]
184+
(&mut my_struct).takes_ref((&mut 42));
185+
//~^ unnecessary_mut_passed
186+
//~| unnecessary_mut_passed
187+
#[expect(clippy::double_parens)]
188+
my_struct.takes_ref((&mut 42));
189+
//~^ unnecessary_mut_passed
190+
}
Lines changed: 168 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,77 +1,220 @@
11
error: the function `takes_ref` doesn't need a mutable reference
2-
--> tests/ui/unnecessary_mut_passed.rs:56:15
2+
--> tests/ui/unnecessary_mut_passed.rs:57:15
33
|
44
LL | takes_ref(&mut 42);
5-
| ^^^^^^^ help: remove this `mut`: `&42`
5+
| ^^^^^^^
66
|
77
= note: `-D clippy::unnecessary-mut-passed` implied by `-D warnings`
88
= help: to override `-D warnings` add `#[allow(clippy::unnecessary_mut_passed)]`
9+
help: remove this `mut`
10+
|
11+
LL - takes_ref(&mut 42);
12+
LL + takes_ref(&42);
13+
|
914

1015
error: the function `takes_ref_ref` doesn't need a mutable reference
11-
--> tests/ui/unnecessary_mut_passed.rs:58:19
16+
--> tests/ui/unnecessary_mut_passed.rs:59:19
1217
|
1318
LL | takes_ref_ref(&mut &42);
14-
| ^^^^^^^^ help: remove this `mut`: `&&42`
19+
| ^^^^^^^^
20+
|
21+
help: remove this `mut`
22+
|
23+
LL - takes_ref_ref(&mut &42);
24+
LL + takes_ref_ref(&&42);
25+
|
1526

1627
error: the function `takes_ref_refmut` doesn't need a mutable reference
17-
--> tests/ui/unnecessary_mut_passed.rs:60:22
28+
--> tests/ui/unnecessary_mut_passed.rs:61:22
1829
|
1930
LL | takes_ref_refmut(&mut &mut 42);
20-
| ^^^^^^^^^^^^ help: remove this `mut`: `&&mut 42`
31+
| ^^^^^^^^^^^^
32+
|
33+
help: remove this `mut`
34+
|
35+
LL - takes_ref_refmut(&mut &mut 42);
36+
LL + takes_ref_refmut(&&mut 42);
37+
|
2138

2239
error: the function `takes_raw_const` doesn't need a mutable reference
23-
--> tests/ui/unnecessary_mut_passed.rs:62:21
40+
--> tests/ui/unnecessary_mut_passed.rs:63:21
2441
|
2542
LL | takes_raw_const(&mut 42);
26-
| ^^^^^^^ help: remove this `mut`: `&42`
43+
| ^^^^^^^
44+
|
45+
help: remove this `mut`
46+
|
47+
LL - takes_raw_const(&mut 42);
48+
LL + takes_raw_const(&42);
49+
|
2750

2851
error: the function `as_ptr` doesn't need a mutable reference
29-
--> tests/ui/unnecessary_mut_passed.rs:66:12
52+
--> tests/ui/unnecessary_mut_passed.rs:67:12
3053
|
3154
LL | as_ptr(&mut 42);
32-
| ^^^^^^^ help: remove this `mut`: `&42`
55+
| ^^^^^^^
56+
|
57+
help: remove this `mut`
58+
|
59+
LL - as_ptr(&mut 42);
60+
LL + as_ptr(&42);
61+
|
3362

3463
error: the function `as_ptr` doesn't need a mutable reference
35-
--> tests/ui/unnecessary_mut_passed.rs:69:12
64+
--> tests/ui/unnecessary_mut_passed.rs:70:12
3665
|
3766
LL | as_ptr(&mut &42);
38-
| ^^^^^^^^ help: remove this `mut`: `&&42`
67+
| ^^^^^^^^
68+
|
69+
help: remove this `mut`
70+
|
71+
LL - as_ptr(&mut &42);
72+
LL + as_ptr(&&42);
73+
|
3974

4075
error: the function `as_ptr` doesn't need a mutable reference
41-
--> tests/ui/unnecessary_mut_passed.rs:72:12
76+
--> tests/ui/unnecessary_mut_passed.rs:73:12
4277
|
4378
LL | as_ptr(&mut &mut 42);
44-
| ^^^^^^^^^^^^ help: remove this `mut`: `&&mut 42`
79+
| ^^^^^^^^^^^^
80+
|
81+
help: remove this `mut`
82+
|
83+
LL - as_ptr(&mut &mut 42);
84+
LL + as_ptr(&&mut 42);
85+
|
4586

4687
error: the function `as_ptr` doesn't need a mutable reference
47-
--> tests/ui/unnecessary_mut_passed.rs:75:12
88+
--> tests/ui/unnecessary_mut_passed.rs:76:12
4889
|
4990
LL | as_ptr(&mut 42);
50-
| ^^^^^^^ help: remove this `mut`: `&42`
91+
| ^^^^^^^
92+
|
93+
help: remove this `mut`
94+
|
95+
LL - as_ptr(&mut 42);
96+
LL + as_ptr(&42);
97+
|
5198

5299
error: the method `takes_ref` doesn't need a mutable reference
53-
--> tests/ui/unnecessary_mut_passed.rs:80:25
100+
--> tests/ui/unnecessary_mut_passed.rs:81:25
54101
|
55102
LL | my_struct.takes_ref(&mut 42);
56-
| ^^^^^^^ help: remove this `mut`: `&42`
103+
| ^^^^^^^
104+
|
105+
help: remove this `mut`
106+
|
107+
LL - my_struct.takes_ref(&mut 42);
108+
LL + my_struct.takes_ref(&42);
109+
|
57110

58111
error: the method `takes_ref_ref` doesn't need a mutable reference
59-
--> tests/ui/unnecessary_mut_passed.rs:82:29
112+
--> tests/ui/unnecessary_mut_passed.rs:83:29
60113
|
61114
LL | my_struct.takes_ref_ref(&mut &42);
62-
| ^^^^^^^^ help: remove this `mut`: `&&42`
115+
| ^^^^^^^^
116+
|
117+
help: remove this `mut`
118+
|
119+
LL - my_struct.takes_ref_ref(&mut &42);
120+
LL + my_struct.takes_ref_ref(&&42);
121+
|
63122

64123
error: the method `takes_ref_refmut` doesn't need a mutable reference
65-
--> tests/ui/unnecessary_mut_passed.rs:84:32
124+
--> tests/ui/unnecessary_mut_passed.rs:85:32
66125
|
67126
LL | my_struct.takes_ref_refmut(&mut &mut 42);
68-
| ^^^^^^^^^^^^ help: remove this `mut`: `&&mut 42`
127+
| ^^^^^^^^^^^^
128+
|
129+
help: remove this `mut`
130+
|
131+
LL - my_struct.takes_ref_refmut(&mut &mut 42);
132+
LL + my_struct.takes_ref_refmut(&&mut 42);
133+
|
69134

70135
error: the method `takes_raw_const` doesn't need a mutable reference
71-
--> tests/ui/unnecessary_mut_passed.rs:86:31
136+
--> tests/ui/unnecessary_mut_passed.rs:87:31
72137
|
73138
LL | my_struct.takes_raw_const(&mut 42);
74-
| ^^^^^^^ help: remove this `mut`: `&42`
139+
| ^^^^^^^
140+
|
141+
help: remove this `mut`
142+
|
143+
LL - my_struct.takes_raw_const(&mut 42);
144+
LL + my_struct.takes_raw_const(&42);
145+
|
146+
147+
error: the method `takes_nothing` doesn't need a mutable reference
148+
--> tests/ui/unnecessary_mut_passed.rs:175:5
149+
|
150+
LL | (&mut my_struct).takes_nothing();
151+
| ^^^^^^^^^^^^^^^^
152+
|
153+
help: remove this `mut`
154+
|
155+
LL - (&mut my_struct).takes_nothing();
156+
LL + (&my_struct).takes_nothing();
157+
|
158+
159+
error: the method `takes_ref` doesn't need a mutable reference
160+
--> tests/ui/unnecessary_mut_passed.rs:180:5
161+
|
162+
LL | (&mut my_struct).takes_ref(&mut 42);
163+
| ^^^^^^^^^^^^^^^^
164+
|
165+
help: remove this `mut`
166+
|
167+
LL - (&mut my_struct).takes_ref(&mut 42);
168+
LL + (&my_struct).takes_ref(&mut 42);
169+
|
170+
171+
error: the method `takes_ref` doesn't need a mutable reference
172+
--> tests/ui/unnecessary_mut_passed.rs:180:32
173+
|
174+
LL | (&mut my_struct).takes_ref(&mut 42);
175+
| ^^^^^^^
176+
|
177+
help: remove this `mut`
178+
|
179+
LL - (&mut my_struct).takes_ref(&mut 42);
180+
LL + (&mut my_struct).takes_ref(&42);
181+
|
182+
183+
error: the method `takes_ref` doesn't need a mutable reference
184+
--> tests/ui/unnecessary_mut_passed.rs:184:5
185+
|
186+
LL | (&mut my_struct).takes_ref((&mut 42));
187+
| ^^^^^^^^^^^^^^^^
188+
|
189+
help: remove this `mut`
190+
|
191+
LL - (&mut my_struct).takes_ref((&mut 42));
192+
LL + (&my_struct).takes_ref((&mut 42));
193+
|
194+
195+
error: the method `takes_ref` doesn't need a mutable reference
196+
--> tests/ui/unnecessary_mut_passed.rs:184:32
197+
|
198+
LL | (&mut my_struct).takes_ref((&mut 42));
199+
| ^^^^^^^^^
200+
|
201+
help: remove this `mut`
202+
|
203+
LL - (&mut my_struct).takes_ref((&mut 42));
204+
LL + (&mut my_struct).takes_ref((&42));
205+
|
206+
207+
error: the method `takes_ref` doesn't need a mutable reference
208+
--> tests/ui/unnecessary_mut_passed.rs:188:25
209+
|
210+
LL | my_struct.takes_ref((&mut 42));
211+
| ^^^^^^^^^
212+
|
213+
help: remove this `mut`
214+
|
215+
LL - my_struct.takes_ref((&mut 42));
216+
LL + my_struct.takes_ref((&42));
217+
|
75218

76-
error: aborting due to 12 previous errors
219+
error: aborting due to 18 previous errors
77220

0 commit comments

Comments
 (0)