Skip to content

Commit 99c6ebd

Browse files
committed
unnecessary_mut_passed: add structured suggestion
1 parent 8779679 commit 99c6ebd

File tree

4 files changed

+248
-35
lines changed

4 files changed

+248
-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: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
#![allow(clippy::mut_mut)]
2+
fn takes_ref(a: &i32) {}
3+
fn takes_refmut(a: &mut i32) {}
4+
fn takes_ref_ref(a: &&i32) {}
5+
fn takes_refmut_ref(a: &mut &i32) {}
6+
fn takes_ref_refmut(a: &&mut i32) {}
7+
fn takes_refmut_refmut(a: &mut &mut i32) {}
8+
9+
mod issue11268 {
10+
macro_rules! x {
11+
(1 $f:expr) => {
12+
$f(&mut 1);
13+
};
14+
(2 $f:expr) => {
15+
$f(&mut &1)
16+
};
17+
(3 $f:expr) => {
18+
$f(&mut &mut 1)
19+
};
20+
}
21+
22+
fn f() {
23+
x!(1 super::takes_ref);
24+
x!(1 super::takes_refmut);
25+
x!(2 super::takes_refmut_ref);
26+
x!(3 super::takes_ref_refmut);
27+
x!(3 super::takes_refmut_refmut);
28+
}
29+
}
30+
31+
struct MyStruct;
32+
33+
impl MyStruct {
34+
fn takes_ref(&self, a: &i32) {}
35+
fn takes_refmut(&self, a: &mut i32) {}
36+
fn takes_ref_ref(&self, a: &&i32) {}
37+
fn takes_refmut_ref(&self, a: &mut &i32) {}
38+
fn takes_ref_refmut(&self, a: &&mut i32) {}
39+
fn takes_refmut_refmut(&self, a: &mut &mut i32) {}
40+
}
41+
42+
#[warn(clippy::unnecessary_mut_passed)]
43+
fn main() {
44+
// Functions
45+
takes_ref(&42);
46+
//~^ unnecessary_mut_passed
47+
takes_ref_ref(&&42);
48+
//~^ unnecessary_mut_passed
49+
takes_ref_refmut(&&mut 42);
50+
//~^ unnecessary_mut_passed
51+
52+
let as_ptr: fn(&i32) = takes_ref;
53+
as_ptr(&42);
54+
//~^ unnecessary_mut_passed
55+
let as_ptr: fn(&&i32) = takes_ref_ref;
56+
as_ptr(&&42);
57+
//~^ unnecessary_mut_passed
58+
let as_ptr: fn(&&mut i32) = takes_ref_refmut;
59+
as_ptr(&&mut 42);
60+
//~^ unnecessary_mut_passed
61+
62+
// Methods
63+
let my_struct = MyStruct;
64+
my_struct.takes_ref(&42);
65+
//~^ unnecessary_mut_passed
66+
my_struct.takes_ref_ref(&&42);
67+
//~^ unnecessary_mut_passed
68+
my_struct.takes_ref_refmut(&&mut 42);
69+
//~^ unnecessary_mut_passed
70+
71+
// No error
72+
73+
// Functions
74+
takes_ref(&42);
75+
let as_ptr: fn(&i32) = takes_ref;
76+
as_ptr(&42);
77+
78+
takes_refmut(&mut 42);
79+
let as_ptr: fn(&mut i32) = takes_refmut;
80+
as_ptr(&mut 42);
81+
82+
takes_ref_ref(&&42);
83+
let as_ptr: fn(&&i32) = takes_ref_ref;
84+
as_ptr(&&42);
85+
86+
takes_refmut_ref(&mut &42);
87+
let as_ptr: fn(&mut &i32) = takes_refmut_ref;
88+
as_ptr(&mut &42);
89+
90+
takes_ref_refmut(&&mut 42);
91+
let as_ptr: fn(&&mut i32) = takes_ref_refmut;
92+
as_ptr(&&mut 42);
93+
94+
takes_refmut_refmut(&mut &mut 42);
95+
let as_ptr: fn(&mut &mut i32) = takes_refmut_refmut;
96+
as_ptr(&mut &mut 42);
97+
98+
let a = &mut 42;
99+
let b = &mut &42;
100+
let c = &mut &mut 42;
101+
takes_ref(a);
102+
takes_ref_ref(b);
103+
takes_ref_refmut(c);
104+
105+
// Methods
106+
my_struct.takes_ref(&42);
107+
my_struct.takes_refmut(&mut 42);
108+
my_struct.takes_ref_ref(&&42);
109+
my_struct.takes_refmut_ref(&mut &42);
110+
my_struct.takes_ref_refmut(&&mut 42);
111+
my_struct.takes_refmut_refmut(&mut &mut 42);
112+
my_struct.takes_ref(a);
113+
my_struct.takes_ref_ref(b);
114+
my_struct.takes_ref_refmut(c);
115+
}

tests/ui/mut_reference.rs

Lines changed: 76 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,115 @@
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+
fn takes_ref(a: &i32) {}
3+
fn takes_refmut(a: &mut i32) {}
4+
fn takes_ref_ref(a: &&i32) {}
5+
fn takes_refmut_ref(a: &mut &i32) {}
6+
fn takes_ref_refmut(a: &&mut i32) {}
7+
fn takes_refmut_refmut(a: &mut &mut i32) {}
58

69
mod issue11268 {
710
macro_rules! x {
8-
($f:expr) => {
11+
(1 $f:expr) => {
912
$f(&mut 1);
1013
};
14+
(2 $f:expr) => {
15+
$f(&mut &1)
16+
};
17+
(3 $f:expr) => {
18+
$f(&mut &mut 1)
19+
};
1120
}
1221

1322
fn f() {
14-
x!(super::takes_an_immutable_reference);
15-
x!(super::takes_a_mutable_reference);
23+
x!(1 super::takes_ref);
24+
x!(1 super::takes_refmut);
25+
x!(2 super::takes_refmut_ref);
26+
x!(3 super::takes_ref_refmut);
27+
x!(3 super::takes_refmut_refmut);
1628
}
1729
}
1830

1931
struct MyStruct;
2032

2133
impl MyStruct {
22-
fn takes_an_immutable_reference(&self, a: &i32) {}
23-
24-
fn takes_a_mutable_reference(&self, a: &mut i32) {}
34+
fn takes_ref(&self, a: &i32) {}
35+
fn takes_refmut(&self, a: &mut i32) {}
36+
fn takes_ref_ref(&self, a: &&i32) {}
37+
fn takes_refmut_ref(&self, a: &mut &i32) {}
38+
fn takes_ref_refmut(&self, a: &&mut i32) {}
39+
fn takes_refmut_refmut(&self, a: &mut &mut i32) {}
2540
}
2641

2742
#[warn(clippy::unnecessary_mut_passed)]
2843
fn main() {
2944
// Functions
30-
takes_an_immutable_reference(&mut 42);
45+
takes_ref(&mut 42);
46+
//~^ unnecessary_mut_passed
47+
takes_ref_ref(&mut &42);
48+
//~^ unnecessary_mut_passed
49+
takes_ref_refmut(&mut &mut 42);
3150
//~^ unnecessary_mut_passed
3251

33-
let as_ptr: fn(&i32) = takes_an_immutable_reference;
52+
let as_ptr: fn(&i32) = takes_ref;
3453
as_ptr(&mut 42);
3554
//~^ unnecessary_mut_passed
55+
let as_ptr: fn(&&i32) = takes_ref_ref;
56+
as_ptr(&mut &42);
57+
//~^ unnecessary_mut_passed
58+
let as_ptr: fn(&&mut i32) = takes_ref_refmut;
59+
as_ptr(&mut &mut 42);
60+
//~^ unnecessary_mut_passed
3661

3762
// Methods
3863
let my_struct = MyStruct;
39-
my_struct.takes_an_immutable_reference(&mut 42);
64+
my_struct.takes_ref(&mut 42);
65+
//~^ unnecessary_mut_passed
66+
my_struct.takes_ref_ref(&mut &42);
67+
//~^ unnecessary_mut_passed
68+
my_struct.takes_ref_refmut(&mut &mut 42);
4069
//~^ unnecessary_mut_passed
4170

4271
// No error
4372

4473
// Functions
45-
takes_an_immutable_reference(&42);
46-
let as_ptr: fn(&i32) = takes_an_immutable_reference;
74+
takes_ref(&42);
75+
let as_ptr: fn(&i32) = takes_ref;
4776
as_ptr(&42);
4877

49-
takes_a_mutable_reference(&mut 42);
50-
let as_ptr: fn(&mut i32) = takes_a_mutable_reference;
78+
takes_refmut(&mut 42);
79+
let as_ptr: fn(&mut i32) = takes_refmut;
5180
as_ptr(&mut 42);
5281

82+
takes_ref_ref(&&42);
83+
let as_ptr: fn(&&i32) = takes_ref_ref;
84+
as_ptr(&&42);
85+
86+
takes_refmut_ref(&mut &42);
87+
let as_ptr: fn(&mut &i32) = takes_refmut_ref;
88+
as_ptr(&mut &42);
89+
90+
takes_ref_refmut(&&mut 42);
91+
let as_ptr: fn(&&mut i32) = takes_ref_refmut;
92+
as_ptr(&&mut 42);
93+
94+
takes_refmut_refmut(&mut &mut 42);
95+
let as_ptr: fn(&mut &mut i32) = takes_refmut_refmut;
96+
as_ptr(&mut &mut 42);
97+
5398
let a = &mut 42;
54-
takes_an_immutable_reference(a);
99+
let b = &mut &42;
100+
let c = &mut &mut 42;
101+
takes_ref(a);
102+
takes_ref_ref(b);
103+
takes_ref_refmut(c);
55104

56105
// 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);
106+
my_struct.takes_ref(&42);
107+
my_struct.takes_refmut(&mut 42);
108+
my_struct.takes_ref_ref(&&42);
109+
my_struct.takes_refmut_ref(&mut &42);
110+
my_struct.takes_ref_refmut(&&mut 42);
111+
my_struct.takes_refmut_refmut(&mut &mut 42);
112+
my_struct.takes_ref(a);
113+
my_struct.takes_ref_ref(b);
114+
my_struct.takes_ref_refmut(c);
60115
}

tests/ui/mut_reference.stderr

Lines changed: 47 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,59 @@
1-
error: the function `takes_an_immutable_reference` doesn't need a mutable reference
2-
--> tests/ui/mut_reference.rs:30:34
1+
error: the function `takes_ref` doesn't need a mutable reference
2+
--> tests/ui/mut_reference.rs:45:15
33
|
4-
LL | takes_an_immutable_reference(&mut 42);
5-
| ^^^^^^^
4+
LL | takes_ref(&mut 42);
5+
| ^^^^^^^ help: remove this `mut`: `&42`
66
|
77
= note: `-D clippy::unnecessary-mut-passed` implied by `-D warnings`
88
= help: to override `-D warnings` add `#[allow(clippy::unnecessary_mut_passed)]`
99

10+
error: the function `takes_ref_ref` doesn't need a mutable reference
11+
--> tests/ui/mut_reference.rs:47:19
12+
|
13+
LL | takes_ref_ref(&mut &42);
14+
| ^^^^^^^^ help: remove this `mut`: `&&42`
15+
16+
error: the function `takes_ref_refmut` doesn't need a mutable reference
17+
--> tests/ui/mut_reference.rs:49:22
18+
|
19+
LL | takes_ref_refmut(&mut &mut 42);
20+
| ^^^^^^^^^^^^ help: remove this `mut`: `&&mut 42`
21+
1022
error: the function `as_ptr` doesn't need a mutable reference
11-
--> tests/ui/mut_reference.rs:34:12
23+
--> tests/ui/mut_reference.rs:53:12
1224
|
1325
LL | as_ptr(&mut 42);
14-
| ^^^^^^^
26+
| ^^^^^^^ help: remove this `mut`: `&42`
27+
28+
error: the function `as_ptr` doesn't need a mutable reference
29+
--> tests/ui/mut_reference.rs:56:12
30+
|
31+
LL | as_ptr(&mut &42);
32+
| ^^^^^^^^ help: remove this `mut`: `&&42`
33+
34+
error: the function `as_ptr` doesn't need a mutable reference
35+
--> tests/ui/mut_reference.rs:59:12
36+
|
37+
LL | as_ptr(&mut &mut 42);
38+
| ^^^^^^^^^^^^ help: remove this `mut`: `&&mut 42`
39+
40+
error: the method `takes_ref` doesn't need a mutable reference
41+
--> tests/ui/mut_reference.rs:64:25
42+
|
43+
LL | my_struct.takes_ref(&mut 42);
44+
| ^^^^^^^ help: remove this `mut`: `&42`
45+
46+
error: the method `takes_ref_ref` doesn't need a mutable reference
47+
--> tests/ui/mut_reference.rs:66:29
48+
|
49+
LL | my_struct.takes_ref_ref(&mut &42);
50+
| ^^^^^^^^ help: remove this `mut`: `&&42`
1551

16-
error: the method `takes_an_immutable_reference` doesn't need a mutable reference
17-
--> tests/ui/mut_reference.rs:39:44
52+
error: the method `takes_ref_refmut` doesn't need a mutable reference
53+
--> tests/ui/mut_reference.rs:68:32
1854
|
19-
LL | my_struct.takes_an_immutable_reference(&mut 42);
20-
| ^^^^^^^
55+
LL | my_struct.takes_ref_refmut(&mut &mut 42);
56+
| ^^^^^^^^^^^^ help: remove this `mut`: `&&mut 42`
2157

22-
error: aborting due to 3 previous errors
58+
error: aborting due to 9 previous errors
2359

0 commit comments

Comments
 (0)