Skip to content

Commit 51200cb

Browse files
committed
Auto merge of #11647 - flip1995:needless-pass-by-ref-mut-pub-api, r=xFrednet
Honor `avoid-breaking-exported-api` in `needless_pass_by_ref_mut` Until now, the lint only emitted a warning, when breaking public API. Now it doesn't lint at all when the config value is not set to `false`, bringing it in line with the other lints using this config value. Also ensures that this config value is documented in the lint. changelog: none (I don't think a changelog is necessary, since this lint is in `nursery`) --- Fixes #11374 cc `@GuillaumeGomez` Marking as draft: Does this lint even break public API? If I change a function signature from `fn foo(x: &mut T)` to `fn foo(x: &T)`, I can still call it with `foo(&mut x)`. The only "breaking" thing is that the `clippy::unnecessary_mut_passed` lint will complain that `&mut` at the callsite is not necessary, possibly trickling down to the crate user having to remote a `mut` from a variable. [Playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=058165a7663902e84af1d23e35c10d66). Are there examples where this actually breaks public API, that I'm missing?
2 parents 6e6683b + 125c778 commit 51200cb

11 files changed

+85
-54
lines changed

clippy_config/src/conf.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,7 @@ define_Conf! {
263263
/// arithmetic-side-effects-allowed-unary = ["SomeType", "AnotherType"]
264264
/// ```
265265
(arithmetic_side_effects_allowed_unary: FxHashSet<String> = <_>::default()),
266-
/// Lint: ENUM_VARIANT_NAMES, LARGE_TYPES_PASSED_BY_VALUE, TRIVIALLY_COPY_PASS_BY_REF, UNNECESSARY_WRAPS, UNUSED_SELF, UPPER_CASE_ACRONYMS, WRONG_SELF_CONVENTION, BOX_COLLECTION, REDUNDANT_ALLOCATION, RC_BUFFER, VEC_BOX, OPTION_OPTION, LINKEDLIST, RC_MUTEX, UNNECESSARY_BOX_RETURNS, SINGLE_CALL_FN.
266+
/// Lint: ENUM_VARIANT_NAMES, LARGE_TYPES_PASSED_BY_VALUE, TRIVIALLY_COPY_PASS_BY_REF, UNNECESSARY_WRAPS, UNUSED_SELF, UPPER_CASE_ACRONYMS, WRONG_SELF_CONVENTION, BOX_COLLECTION, REDUNDANT_ALLOCATION, RC_BUFFER, VEC_BOX, OPTION_OPTION, LINKEDLIST, RC_MUTEX, UNNECESSARY_BOX_RETURNS, SINGLE_CALL_FN, NEEDLESS_PASS_BY_REF_MUT.
267267
///
268268
/// Suppress lints whenever the suggested change would cause breakage for other crates.
269269
(avoid_breaking_exported_api: bool = true),

clippy_lints/src/needless_pass_by_ref_mut.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ declare_clippy_lint! {
2727
/// Check if a `&mut` function argument is actually used mutably.
2828
///
2929
/// Be careful if the function is publicly reexported as it would break compatibility with
30-
/// users of this function.
30+
/// users of this function, when the users pass this function as an argument.
3131
///
3232
/// ### Why is this bad?
3333
/// Less `mut` means less fights with the borrow checker. It can also lead to more
@@ -138,6 +138,10 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> {
138138
return;
139139
}
140140

141+
if self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(fn_def_id) {
142+
return;
143+
}
144+
141145
let hir_id = cx.tcx.local_def_id_to_hir_id(fn_def_id);
142146
let is_async = match kind {
143147
FnKind::ItemFn(.., header) => {
@@ -262,9 +266,6 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> {
262266
.iter()
263267
.filter(|(def_id, _)| !self.used_fn_def_ids.contains(def_id))
264268
{
265-
let show_semver_warning =
266-
self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(*fn_def_id);
267-
268269
let mut is_cfged = None;
269270
for input in unused {
270271
// If the argument is never used mutably, we emit the warning.
@@ -284,7 +285,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> {
284285
format!("&{}", snippet(cx, cx.tcx.hir().span(inner_ty.ty.hir_id), "_"),),
285286
Applicability::Unspecified,
286287
);
287-
if show_semver_warning {
288+
if cx.effective_visibilities.is_exported(*fn_def_id) {
288289
diag.warn("changing this function will impact semver compatibility");
289290
}
290291
if *is_cfged {
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
avoid-breaking-exported-api = false
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#![warn(clippy::needless_pass_by_ref_mut)]
2+
#![allow(clippy::ptr_arg)]
3+
4+
// Should warn
5+
pub fn pub_foo(s: &Vec<u32>, b: &u32, x: &mut u32) {
6+
//~^ ERROR: this argument is a mutable reference, but not used mutably
7+
*x += *b + s.len() as u32;
8+
}
9+
10+
fn main() {}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#![warn(clippy::needless_pass_by_ref_mut)]
2+
#![allow(clippy::ptr_arg)]
3+
4+
// Should warn
5+
pub fn pub_foo(s: &mut Vec<u32>, b: &u32, x: &mut u32) {
6+
//~^ ERROR: this argument is a mutable reference, but not used mutably
7+
*x += *b + s.len() as u32;
8+
}
9+
10+
fn main() {}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
error: this argument is a mutable reference, but not used mutably
2+
--> tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.rs:5:19
3+
|
4+
LL | pub fn pub_foo(s: &mut Vec<u32>, b: &u32, x: &mut u32) {
5+
| ^^^^^^^^^^^^^ help: consider changing to: `&Vec<u32>`
6+
|
7+
= warning: changing this function will impact semver compatibility
8+
= note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings`
9+
= help: to override `-D warnings` add `#[allow(clippy::needless_pass_by_ref_mut)]`
10+
11+
error: aborting due to 1 previous error
12+

tests/ui/needless_pass_by_ref_mut.rs

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -232,43 +232,48 @@ async fn async_vec2(b: &mut Vec<bool>) {
232232
}
233233
fn non_mut(n: &str) {}
234234
//Should warn
235-
pub async fn call_in_closure1(n: &mut str) {
235+
async fn call_in_closure1(n: &mut str) {
236236
(|| non_mut(n))()
237237
}
238238
fn str_mut(str: &mut String) -> bool {
239239
str.pop().is_some()
240240
}
241241
//Should not warn
242-
pub async fn call_in_closure2(str: &mut String) {
242+
async fn call_in_closure2(str: &mut String) {
243243
(|| str_mut(str))();
244244
}
245245

246246
// Should not warn.
247-
pub async fn closure(n: &mut usize) -> impl '_ + FnMut() {
247+
async fn closure(n: &mut usize) -> impl '_ + FnMut() {
248248
|| {
249249
*n += 1;
250250
}
251251
}
252252

253253
// Should warn.
254-
pub fn closure2(n: &mut usize) -> impl '_ + FnMut() -> usize {
254+
fn closure2(n: &mut usize) -> impl '_ + FnMut() -> usize {
255255
//~^ ERROR: this argument is a mutable reference, but not used mutably
256256
|| *n + 1
257257
}
258258

259259
// Should not warn.
260-
pub async fn closure3(n: &mut usize) {
260+
async fn closure3(n: &mut usize) {
261261
(|| *n += 1)();
262262
}
263263

264264
// Should warn.
265-
pub async fn closure4(n: &mut usize) {
265+
async fn closure4(n: &mut usize) {
266266
//~^ ERROR: this argument is a mutable reference, but not used mutably
267267
(|| {
268268
let _x = *n + 1;
269269
})();
270270
}
271271

272+
// Should not warn: pub
273+
pub fn pub_foo(s: &mut Vec<u32>, b: &u32, x: &mut u32) {
274+
*x += *b + s.len() as u32;
275+
}
276+
272277
// Should not warn.
273278
async fn _f(v: &mut Vec<()>) {
274279
let x = || v.pop();
@@ -365,4 +370,5 @@ fn main() {
365370
used_as_path;
366371
let _: fn(&mut u32) = passed_as_local;
367372
let _ = if v[0] == 0 { ty_unify_1 } else { ty_unify_2 };
373+
pub_foo(&mut v, &0, &mut u);
368374
}

tests/ui/needless_pass_by_ref_mut.stderr

Lines changed: 23 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -108,109 +108,103 @@ LL | async fn inner_async3(x: &mut i32, y: &mut u32) {
108108
| ^^^^^^^^ help: consider changing to: `&i32`
109109

110110
error: this argument is a mutable reference, but not used mutably
111-
--> tests/ui/needless_pass_by_ref_mut.rs:235:34
111+
--> tests/ui/needless_pass_by_ref_mut.rs:235:30
112112
|
113-
LL | pub async fn call_in_closure1(n: &mut str) {
114-
| ^^^^^^^^ help: consider changing to: `&str`
115-
|
116-
= warning: changing this function will impact semver compatibility
113+
LL | async fn call_in_closure1(n: &mut str) {
114+
| ^^^^^^^^ help: consider changing to: `&str`
117115

118116
error: this argument is a mutable reference, but not used mutably
119-
--> tests/ui/needless_pass_by_ref_mut.rs:254:20
120-
|
121-
LL | pub fn closure2(n: &mut usize) -> impl '_ + FnMut() -> usize {
122-
| ^^^^^^^^^^ help: consider changing to: `&usize`
117+
--> tests/ui/needless_pass_by_ref_mut.rs:254:16
123118
|
124-
= warning: changing this function will impact semver compatibility
119+
LL | fn closure2(n: &mut usize) -> impl '_ + FnMut() -> usize {
120+
| ^^^^^^^^^^ help: consider changing to: `&usize`
125121

126122
error: this argument is a mutable reference, but not used mutably
127-
--> tests/ui/needless_pass_by_ref_mut.rs:265:26
128-
|
129-
LL | pub async fn closure4(n: &mut usize) {
130-
| ^^^^^^^^^^ help: consider changing to: `&usize`
123+
--> tests/ui/needless_pass_by_ref_mut.rs:265:22
131124
|
132-
= warning: changing this function will impact semver compatibility
125+
LL | async fn closure4(n: &mut usize) {
126+
| ^^^^^^^^^^ help: consider changing to: `&usize`
133127

134128
error: this argument is a mutable reference, but not used mutably
135-
--> tests/ui/needless_pass_by_ref_mut.rs:314:12
129+
--> tests/ui/needless_pass_by_ref_mut.rs:319:12
136130
|
137131
LL | fn bar(&mut self) {}
138132
| ^^^^^^^^^ help: consider changing to: `&self`
139133

140134
error: this argument is a mutable reference, but not used mutably
141-
--> tests/ui/needless_pass_by_ref_mut.rs:316:18
135+
--> tests/ui/needless_pass_by_ref_mut.rs:321:18
142136
|
143137
LL | async fn foo(&mut self, u: &mut i32, v: &mut u32) {
144138
| ^^^^^^^^^ help: consider changing to: `&self`
145139

146140
error: this argument is a mutable reference, but not used mutably
147-
--> tests/ui/needless_pass_by_ref_mut.rs:316:45
141+
--> tests/ui/needless_pass_by_ref_mut.rs:321:45
148142
|
149143
LL | async fn foo(&mut self, u: &mut i32, v: &mut u32) {
150144
| ^^^^^^^^ help: consider changing to: `&u32`
151145

152146
error: this argument is a mutable reference, but not used mutably
153-
--> tests/ui/needless_pass_by_ref_mut.rs:324:46
147+
--> tests/ui/needless_pass_by_ref_mut.rs:329:46
154148
|
155149
LL | async fn foo2(&mut self, u: &mut i32, v: &mut u32) {
156150
| ^^^^^^^^ help: consider changing to: `&u32`
157151

158152
error: this argument is a mutable reference, but not used mutably
159-
--> tests/ui/needless_pass_by_ref_mut.rs:340:18
153+
--> tests/ui/needless_pass_by_ref_mut.rs:345:18
160154
|
161155
LL | fn _empty_tup(x: &mut (())) {}
162156
| ^^^^^^^^^ help: consider changing to: `&()`
163157

164158
error: this argument is a mutable reference, but not used mutably
165-
--> tests/ui/needless_pass_by_ref_mut.rs:341:19
159+
--> tests/ui/needless_pass_by_ref_mut.rs:346:19
166160
|
167161
LL | fn _single_tup(x: &mut ((i32,))) {}
168162
| ^^^^^^^^^^^^^ help: consider changing to: `&(i32,)`
169163

170164
error: this argument is a mutable reference, but not used mutably
171-
--> tests/ui/needless_pass_by_ref_mut.rs:342:18
165+
--> tests/ui/needless_pass_by_ref_mut.rs:347:18
172166
|
173167
LL | fn _multi_tup(x: &mut ((i32, u32))) {}
174168
| ^^^^^^^^^^^^^^^^^ help: consider changing to: `&(i32, u32)`
175169

176170
error: this argument is a mutable reference, but not used mutably
177-
--> tests/ui/needless_pass_by_ref_mut.rs:343:11
171+
--> tests/ui/needless_pass_by_ref_mut.rs:348:11
178172
|
179173
LL | fn _fn(x: &mut (fn())) {}
180174
| ^^^^^^^^^^^ help: consider changing to: `&fn()`
181175

182176
error: this argument is a mutable reference, but not used mutably
183-
--> tests/ui/needless_pass_by_ref_mut.rs:345:23
177+
--> tests/ui/needless_pass_by_ref_mut.rs:350:23
184178
|
185179
LL | fn _extern_rust_fn(x: &mut extern "Rust" fn()) {}
186180
| ^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&extern "Rust" fn()`
187181

188182
error: this argument is a mutable reference, but not used mutably
189-
--> tests/ui/needless_pass_by_ref_mut.rs:346:20
183+
--> tests/ui/needless_pass_by_ref_mut.rs:351:20
190184
|
191185
LL | fn _extern_c_fn(x: &mut extern "C" fn()) {}
192186
| ^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&extern "C" fn()`
193187

194188
error: this argument is a mutable reference, but not used mutably
195-
--> tests/ui/needless_pass_by_ref_mut.rs:347:18
189+
--> tests/ui/needless_pass_by_ref_mut.rs:352:18
196190
|
197191
LL | fn _unsafe_fn(x: &mut unsafe fn()) {}
198192
| ^^^^^^^^^^^^^^^^ help: consider changing to: `&unsafe fn()`
199193

200194
error: this argument is a mutable reference, but not used mutably
201-
--> tests/ui/needless_pass_by_ref_mut.rs:348:25
195+
--> tests/ui/needless_pass_by_ref_mut.rs:353:25
202196
|
203197
LL | fn _unsafe_extern_fn(x: &mut unsafe extern "C" fn()) {}
204198
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&unsafe extern "C" fn()`
205199

206200
error: this argument is a mutable reference, but not used mutably
207-
--> tests/ui/needless_pass_by_ref_mut.rs:349:20
201+
--> tests/ui/needless_pass_by_ref_mut.rs:354:20
208202
|
209203
LL | fn _fn_with_arg(x: &mut unsafe extern "C" fn(i32)) {}
210204
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&unsafe extern "C" fn(i32)`
211205

212206
error: this argument is a mutable reference, but not used mutably
213-
--> tests/ui/needless_pass_by_ref_mut.rs:350:20
207+
--> tests/ui/needless_pass_by_ref_mut.rs:355:20
214208
|
215209
LL | fn _fn_with_ret(x: &mut unsafe extern "C" fn() -> (i32)) {}
216210
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&unsafe extern "C" fn() -> (i32)`

tests/ui/needless_pass_by_ref_mut2.fixed

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,15 @@
55
#![allow(clippy::redundant_closure_call)]
66
#![warn(clippy::needless_pass_by_ref_mut)]
77

8-
pub async fn inner_async3(x: &i32, y: &mut u32) {
8+
async fn inner_async3(x: &i32, y: &mut u32) {
99
//~^ ERROR: this argument is a mutable reference, but not used mutably
1010
async {
1111
*y += 1;
1212
}
1313
.await;
1414
}
1515

16-
pub async fn inner_async4(u: &mut i32, v: &u32) {
16+
async fn inner_async4(u: &mut i32, v: &u32) {
1717
//~^ ERROR: this argument is a mutable reference, but not used mutably
1818
async {
1919
*u += 1;

tests/ui/needless_pass_by_ref_mut2.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,15 @@
55
#![allow(clippy::redundant_closure_call)]
66
#![warn(clippy::needless_pass_by_ref_mut)]
77

8-
pub async fn inner_async3(x: &mut i32, y: &mut u32) {
8+
async fn inner_async3(x: &mut i32, y: &mut u32) {
99
//~^ ERROR: this argument is a mutable reference, but not used mutably
1010
async {
1111
*y += 1;
1212
}
1313
.await;
1414
}
1515

16-
pub async fn inner_async4(u: &mut i32, v: &mut u32) {
16+
async fn inner_async4(u: &mut i32, v: &mut u32) {
1717
//~^ ERROR: this argument is a mutable reference, but not used mutably
1818
async {
1919
*u += 1;
Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,17 @@
11
error: this argument is a mutable reference, but not used mutably
2-
--> tests/ui/needless_pass_by_ref_mut2.rs:8:30
2+
--> tests/ui/needless_pass_by_ref_mut2.rs:8:26
33
|
4-
LL | pub async fn inner_async3(x: &mut i32, y: &mut u32) {
5-
| ^^^^^^^^ help: consider changing to: `&i32`
4+
LL | async fn inner_async3(x: &mut i32, y: &mut u32) {
5+
| ^^^^^^^^ help: consider changing to: `&i32`
66
|
7-
= warning: changing this function will impact semver compatibility
87
= note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings`
98
= help: to override `-D warnings` add `#[allow(clippy::needless_pass_by_ref_mut)]`
109

1110
error: this argument is a mutable reference, but not used mutably
12-
--> tests/ui/needless_pass_by_ref_mut2.rs:16:43
11+
--> tests/ui/needless_pass_by_ref_mut2.rs:16:39
1312
|
14-
LL | pub async fn inner_async4(u: &mut i32, v: &mut u32) {
15-
| ^^^^^^^^ help: consider changing to: `&u32`
16-
|
17-
= warning: changing this function will impact semver compatibility
13+
LL | async fn inner_async4(u: &mut i32, v: &mut u32) {
14+
| ^^^^^^^^ help: consider changing to: `&u32`
1815

1916
error: aborting due to 2 previous errors
2017

0 commit comments

Comments
 (0)