diff --git a/clippy_lints/src/unnecessary_mut_passed.rs b/clippy_lints/src/unnecessary_mut_passed.rs index eb2d7639e91f..6f6d18f04a3b 100644 --- a/clippy_lints/src/unnecessary_mut_passed.rs +++ b/clippy_lints/src/unnecessary_mut_passed.rs @@ -85,16 +85,30 @@ fn check_arguments<'tcx>( let parameters = type_definition.fn_sig(cx.tcx).skip_binder().inputs(); for (argument, parameter) in iter::zip(arguments, parameters) { if let ty::Ref(_, _, Mutability::Not) | ty::RawPtr(_, Mutability::Not) = parameter.kind() - && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, arg) = argument.kind + && let ExprKind::AddrOf(borrow_kind, Mutability::Mut, arg) = argument.kind { - let applicability = Applicability::MachineApplicable; + emit(cx, name, fn_kind, argument, borrow_kind, arg); + } + } + } +} + +fn emit(cx: &LateContext<'_>, name: &str, fn_kind: &str, argument: &Expr<'_>, borrow_kind: BorrowKind, arg: &Expr<'_>) { + let applicability = Applicability::MachineApplicable; - let span_to_remove = { - let span_until_arg = argument.span.until(arg.span); - if let Some(Some(ref_pos)) = span_until_arg.with_source_text(cx, |src| { + span_lint_and_then( + cx, + UNNECESSARY_MUT_PASSED, + argument.span, + format!("the {fn_kind} `{name}` doesn't need a mutable reference"), + |diag| { + let span_until_arg = argument.span.until(arg.span); + match borrow_kind { + BorrowKind::Ref => { + let span_to_remove = if let Some(Some(ref_pos)) = span_until_arg.with_source_text(cx, |src| { src - // we don't use `strip_prefix` here, because `argument` might be enclosed in parens, in - // which case `&` is no longer the prefix + // we don't use `strip_prefix` here, because `argument` might be enclosed in + // parens, in which case `&` is no longer the prefix .find('&') // just a sanity check, in case some proc-macro messes up the spans .filter(|ref_pos| src[*ref_pos..].contains("mut")) @@ -103,19 +117,47 @@ fn check_arguments<'tcx>( span_until_arg.split_at(lo).1 } else { return; - } - }; + }; + diag.span_suggestion_verbose(span_to_remove, "remove this `mut`", String::new(), applicability); + }, + BorrowKind::Raw => { + let span_to_remove = + if let Some(Some(ref_pos)) = span_until_arg.with_source_text(cx, |src: &str| { + // we don't use `strip_prefix` here, because `argument` might be enclosed in + // parens, and there might be arbitrary whitespace between things + let src_after_addr_raw = src.split_once('&')?.1.split_once("raw")?.1.trim_start(); - span_lint_and_then( - cx, - UNNECESSARY_MUT_PASSED, - argument.span, - format!("the {fn_kind} `{name}` doesn't need a mutable reference"), - |diag| { - diag.span_suggestion_verbose(span_to_remove, "remove this `mut`", String::new(), applicability); - }, - ); + Some(src_after_addr_raw) + // just a sanity check, in case some proc-macro messes up the spans + .filter(|trimmed| trimmed.contains("mut")) + .map(|trimmed| { + // SAFETY: + // - `trimmed` is derived from `src` by trimming characters from the latter's start + // - that also means that `trimmed` > `src` + unsafe { trimmed.as_ptr().offset_from_unsigned(src.as_ptr()) } + }) + }) && let Ok(lo) = u32::try_from(ref_pos) + { + span_until_arg.split_at(lo).1 + } else { + return; + }; + diag.span_suggestion_verbose( + span_to_remove, + "make this a `const` ptr", + // the span points at `&raw mut x` + // ^^^^ + // so we append a space to our suggestion + String::from("const "), + applicability, + ); + }, + BorrowKind::Pin => { + // it's fine to only "check" this after we've emitted the lint -- if the + // reference was an `&pin`, passing it into a function requiring a ptr wouldn't + // have type-checked in the first place + }, } - } - } + }, + ); } diff --git a/tests/ui/unnecessary_mut_passed.fixed b/tests/ui/unnecessary_mut_passed.fixed index 63bbadb01dcb..55680899e0df 100644 --- a/tests/ui/unnecessary_mut_passed.fixed +++ b/tests/ui/unnecessary_mut_passed.fixed @@ -41,6 +41,10 @@ struct MyStruct; impl MyStruct { fn takes_nothing(&self) {} + // XXX: enable the tests for these if `arbitrary_self_types` is extended to support `*const Self` + // + // fn takes_nothing_raw(self: *const Self) {} + // fn takes_nothing_raw_and_raw_const(self: *const Self, a: *const i32) {} fn takes_ref(&self, a: &i32) {} fn takes_refmut(&self, a: &mut i32) {} fn takes_ref_ref(&self, a: &&i32) {} @@ -146,16 +150,24 @@ fn main() { my_struct.takes_raw_mut(a); } -// not supported currently fn raw_ptrs(my_struct: MyStruct) { let mut n = 42; - takes_raw_const(&raw mut n); + takes_raw_const(&raw const n); + //~^ unnecessary_mut_passed + + // bad formatting + #[rustfmt::skip] + #[allow(clippy::double_parens)] + takes_raw_const( & raw const n); + //~^ unnecessary_mut_passed let as_ptr: fn(*const i32) = takes_raw_const; - as_ptr(&raw mut n); + as_ptr(&raw const n); + //~^ unnecessary_mut_passed - my_struct.takes_raw_const(&raw mut n); + my_struct.takes_raw_const(&raw const n); + //~^ unnecessary_mut_passed // No error @@ -187,4 +199,15 @@ fn issue15722(mut my_struct: MyStruct) { #[expect(clippy::double_parens)] my_struct.takes_ref((&42)); //~^ unnecessary_mut_passed + + // XXX: enable these if `arbitrary_self_types` is extended to support `*const Self` + // + // let mut n = 42; + // (&raw mut my_struct).takes_nothing_raw(); + // (&raw const my_struct).takes_nothing_raw(); + // (&raw mut my_struct).takes_nothing_raw_and_raw_const(&raw mut n); + // #[expect(clippy::double_parens)] + // (&raw mut my_struct).takes_nothing_raw_and_raw_const((&raw mut n)); + // #[expect(clippy::double_parens)] + // my_struct.takes_nothing_raw_and_raw_const((&raw mut n)); } diff --git a/tests/ui/unnecessary_mut_passed.rs b/tests/ui/unnecessary_mut_passed.rs index b719ca1871b2..d6e1701a57f1 100644 --- a/tests/ui/unnecessary_mut_passed.rs +++ b/tests/ui/unnecessary_mut_passed.rs @@ -41,6 +41,10 @@ struct MyStruct; impl MyStruct { fn takes_nothing(&self) {} + // XXX: enable the tests for these if `arbitrary_self_types` is extended to support `*const Self` + // + // fn takes_nothing_raw(self: *const Self) {} + // fn takes_nothing_raw_and_raw_const(self: *const Self, a: *const i32) {} fn takes_ref(&self, a: &i32) {} fn takes_refmut(&self, a: &mut i32) {} fn takes_ref_ref(&self, a: &&i32) {} @@ -146,16 +150,24 @@ fn main() { my_struct.takes_raw_mut(a); } -// not supported currently fn raw_ptrs(my_struct: MyStruct) { let mut n = 42; takes_raw_const(&raw mut n); + //~^ unnecessary_mut_passed + + // bad formatting + #[rustfmt::skip] + #[allow(clippy::double_parens)] + takes_raw_const( & raw mut n); + //~^ unnecessary_mut_passed let as_ptr: fn(*const i32) = takes_raw_const; as_ptr(&raw mut n); + //~^ unnecessary_mut_passed my_struct.takes_raw_const(&raw mut n); + //~^ unnecessary_mut_passed // No error @@ -187,4 +199,15 @@ fn issue15722(mut my_struct: MyStruct) { #[expect(clippy::double_parens)] my_struct.takes_ref((&mut 42)); //~^ unnecessary_mut_passed + + // XXX: enable these if `arbitrary_self_types` is extended to support `*const Self` + // + // let mut n = 42; + // (&raw mut my_struct).takes_nothing_raw(); + // (&raw const my_struct).takes_nothing_raw(); + // (&raw mut my_struct).takes_nothing_raw_and_raw_const(&raw mut n); + // #[expect(clippy::double_parens)] + // (&raw mut my_struct).takes_nothing_raw_and_raw_const((&raw mut n)); + // #[expect(clippy::double_parens)] + // my_struct.takes_nothing_raw_and_raw_const((&raw mut n)); } diff --git a/tests/ui/unnecessary_mut_passed.stderr b/tests/ui/unnecessary_mut_passed.stderr index ace11027e3e2..00b132b82583 100644 --- a/tests/ui/unnecessary_mut_passed.stderr +++ b/tests/ui/unnecessary_mut_passed.stderr @@ -1,5 +1,5 @@ error: the function `takes_ref` doesn't need a mutable reference - --> tests/ui/unnecessary_mut_passed.rs:57:15 + --> tests/ui/unnecessary_mut_passed.rs:61:15 | LL | takes_ref(&mut 42); | ^^^^^^^ @@ -13,7 +13,7 @@ LL + takes_ref(&42); | error: the function `takes_ref_ref` doesn't need a mutable reference - --> tests/ui/unnecessary_mut_passed.rs:59:19 + --> tests/ui/unnecessary_mut_passed.rs:63:19 | LL | takes_ref_ref(&mut &42); | ^^^^^^^^ @@ -25,7 +25,7 @@ LL + takes_ref_ref(&&42); | error: the function `takes_ref_refmut` doesn't need a mutable reference - --> tests/ui/unnecessary_mut_passed.rs:61:22 + --> tests/ui/unnecessary_mut_passed.rs:65:22 | LL | takes_ref_refmut(&mut &mut 42); | ^^^^^^^^^^^^ @@ -37,7 +37,7 @@ LL + takes_ref_refmut(&&mut 42); | error: the function `takes_raw_const` doesn't need a mutable reference - --> tests/ui/unnecessary_mut_passed.rs:63:21 + --> tests/ui/unnecessary_mut_passed.rs:67:21 | LL | takes_raw_const(&mut 42); | ^^^^^^^ @@ -49,7 +49,7 @@ LL + takes_raw_const(&42); | error: the function `as_ptr` doesn't need a mutable reference - --> tests/ui/unnecessary_mut_passed.rs:67:12 + --> tests/ui/unnecessary_mut_passed.rs:71:12 | LL | as_ptr(&mut 42); | ^^^^^^^ @@ -61,7 +61,7 @@ LL + as_ptr(&42); | error: the function `as_ptr` doesn't need a mutable reference - --> tests/ui/unnecessary_mut_passed.rs:70:12 + --> tests/ui/unnecessary_mut_passed.rs:74:12 | LL | as_ptr(&mut &42); | ^^^^^^^^ @@ -73,7 +73,7 @@ LL + as_ptr(&&42); | error: the function `as_ptr` doesn't need a mutable reference - --> tests/ui/unnecessary_mut_passed.rs:73:12 + --> tests/ui/unnecessary_mut_passed.rs:77:12 | LL | as_ptr(&mut &mut 42); | ^^^^^^^^^^^^ @@ -85,7 +85,7 @@ LL + as_ptr(&&mut 42); | error: the function `as_ptr` doesn't need a mutable reference - --> tests/ui/unnecessary_mut_passed.rs:76:12 + --> tests/ui/unnecessary_mut_passed.rs:80:12 | LL | as_ptr(&mut 42); | ^^^^^^^ @@ -97,7 +97,7 @@ LL + as_ptr(&42); | error: the method `takes_ref` doesn't need a mutable reference - --> tests/ui/unnecessary_mut_passed.rs:81:25 + --> tests/ui/unnecessary_mut_passed.rs:85:25 | LL | my_struct.takes_ref(&mut 42); | ^^^^^^^ @@ -109,7 +109,7 @@ LL + my_struct.takes_ref(&42); | error: the method `takes_ref_ref` doesn't need a mutable reference - --> tests/ui/unnecessary_mut_passed.rs:83:29 + --> tests/ui/unnecessary_mut_passed.rs:87:29 | LL | my_struct.takes_ref_ref(&mut &42); | ^^^^^^^^ @@ -121,7 +121,7 @@ LL + my_struct.takes_ref_ref(&&42); | error: the method `takes_ref_refmut` doesn't need a mutable reference - --> tests/ui/unnecessary_mut_passed.rs:85:32 + --> tests/ui/unnecessary_mut_passed.rs:89:32 | LL | my_struct.takes_ref_refmut(&mut &mut 42); | ^^^^^^^^^^^^ @@ -133,7 +133,7 @@ LL + my_struct.takes_ref_refmut(&&mut 42); | error: the method `takes_raw_const` doesn't need a mutable reference - --> tests/ui/unnecessary_mut_passed.rs:87:31 + --> tests/ui/unnecessary_mut_passed.rs:91:31 | LL | my_struct.takes_raw_const(&mut 42); | ^^^^^^^ @@ -144,8 +144,56 @@ LL - my_struct.takes_raw_const(&mut 42); LL + my_struct.takes_raw_const(&42); | +error: the function `takes_raw_const` doesn't need a mutable reference + --> tests/ui/unnecessary_mut_passed.rs:156:21 + | +LL | takes_raw_const(&raw mut n); + | ^^^^^^^^^^ + | +help: make this a `const` ptr + | +LL - takes_raw_const(&raw mut n); +LL + takes_raw_const(&raw const n); + | + +error: the function `takes_raw_const` doesn't need a mutable reference + --> tests/ui/unnecessary_mut_passed.rs:162:22 + | +LL | takes_raw_const( & raw mut n); + | ^^^^^^^^^^^^^^^^ + | +help: make this a `const` ptr + | +LL - takes_raw_const( & raw mut n); +LL + takes_raw_const( & raw const n); + | + +error: the function `as_ptr` doesn't need a mutable reference + --> tests/ui/unnecessary_mut_passed.rs:166:12 + | +LL | as_ptr(&raw mut n); + | ^^^^^^^^^^ + | +help: make this a `const` ptr + | +LL - as_ptr(&raw mut n); +LL + as_ptr(&raw const n); + | + +error: the method `takes_raw_const` doesn't need a mutable reference + --> tests/ui/unnecessary_mut_passed.rs:169:31 + | +LL | my_struct.takes_raw_const(&raw mut n); + | ^^^^^^^^^^ + | +help: make this a `const` ptr + | +LL - my_struct.takes_raw_const(&raw mut n); +LL + my_struct.takes_raw_const(&raw const n); + | + error: the method `takes_nothing` doesn't need a mutable reference - --> tests/ui/unnecessary_mut_passed.rs:175:5 + --> tests/ui/unnecessary_mut_passed.rs:187:5 | LL | (&mut my_struct).takes_nothing(); | ^^^^^^^^^^^^^^^^ @@ -157,7 +205,7 @@ LL + (&my_struct).takes_nothing(); | error: the method `takes_ref` doesn't need a mutable reference - --> tests/ui/unnecessary_mut_passed.rs:180:5 + --> tests/ui/unnecessary_mut_passed.rs:192:5 | LL | (&mut my_struct).takes_ref(&mut 42); | ^^^^^^^^^^^^^^^^ @@ -169,7 +217,7 @@ LL + (&my_struct).takes_ref(&mut 42); | error: the method `takes_ref` doesn't need a mutable reference - --> tests/ui/unnecessary_mut_passed.rs:180:32 + --> tests/ui/unnecessary_mut_passed.rs:192:32 | LL | (&mut my_struct).takes_ref(&mut 42); | ^^^^^^^ @@ -181,7 +229,7 @@ LL + (&mut my_struct).takes_ref(&42); | error: the method `takes_ref` doesn't need a mutable reference - --> tests/ui/unnecessary_mut_passed.rs:184:5 + --> tests/ui/unnecessary_mut_passed.rs:196:5 | LL | (&mut my_struct).takes_ref((&mut 42)); | ^^^^^^^^^^^^^^^^ @@ -193,7 +241,7 @@ LL + (&my_struct).takes_ref((&mut 42)); | error: the method `takes_ref` doesn't need a mutable reference - --> tests/ui/unnecessary_mut_passed.rs:184:32 + --> tests/ui/unnecessary_mut_passed.rs:196:32 | LL | (&mut my_struct).takes_ref((&mut 42)); | ^^^^^^^^^ @@ -205,7 +253,7 @@ LL + (&mut my_struct).takes_ref((&42)); | error: the method `takes_ref` doesn't need a mutable reference - --> tests/ui/unnecessary_mut_passed.rs:188:25 + --> tests/ui/unnecessary_mut_passed.rs:200:25 | LL | my_struct.takes_ref((&mut 42)); | ^^^^^^^^^ @@ -216,5 +264,5 @@ LL - my_struct.takes_ref((&mut 42)); LL + my_struct.takes_ref((&42)); | -error: aborting due to 18 previous errors +error: aborting due to 22 previous errors