diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 5563b8094f01..89178290e1a2 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -535,7 +535,6 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[ crate::multiple_unsafe_ops_per_block::MULTIPLE_UNSAFE_OPS_PER_BLOCK_INFO, crate::mut_key::MUTABLE_KEY_TYPE_INFO, crate::mut_mut::MUT_MUT_INFO, - crate::mut_reference::UNNECESSARY_MUT_PASSED_INFO, crate::mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL_INFO, crate::mutex_atomic::MUTEX_ATOMIC_INFO, crate::mutex_atomic::MUTEX_INTEGER_INFO, @@ -752,6 +751,7 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[ crate::unnecessary_box_returns::UNNECESSARY_BOX_RETURNS_INFO, crate::unnecessary_literal_bound::UNNECESSARY_LITERAL_BOUND_INFO, crate::unnecessary_map_on_constructor::UNNECESSARY_MAP_ON_CONSTRUCTOR_INFO, + crate::unnecessary_mut_passed::UNNECESSARY_MUT_PASSED_INFO, crate::unnecessary_owned_empty_strings::UNNECESSARY_OWNED_EMPTY_STRINGS_INFO, crate::unnecessary_self_imports::UNNECESSARY_SELF_IMPORTS_INFO, crate::unnecessary_semicolon::UNNECESSARY_SEMICOLON_INFO, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index c56fa257b068..1d6c83669154 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -253,7 +253,6 @@ mod multiple_bound_locations; mod multiple_unsafe_ops_per_block; mod mut_key; mod mut_mut; -mod mut_reference; mod mutable_debug_assertion; mod mutex_atomic; mod needless_arbitrary_self_type; @@ -375,6 +374,7 @@ mod unit_types; mod unnecessary_box_returns; mod unnecessary_literal_bound; mod unnecessary_map_on_constructor; +mod unnecessary_mut_passed; mod unnecessary_owned_empty_strings; mod unnecessary_self_imports; mod unnecessary_semicolon; @@ -483,7 +483,7 @@ pub fn register_lint_passes(store: &mut rustc_lint::LintStore, conf: &'static Co store.register_late_pass(|_| Box::new(misc::LintPass)); store.register_late_pass(|_| Box::new(eta_reduction::EtaReduction)); store.register_late_pass(|_| Box::new(mut_mut::MutMut)); - store.register_late_pass(|_| Box::new(mut_reference::UnnecessaryMutPassed)); + store.register_late_pass(|_| Box::new(unnecessary_mut_passed::UnnecessaryMutPassed)); store.register_late_pass(|_| Box::>::default()); store.register_late_pass(|_| Box::new(len_zero::LenZero)); store.register_late_pass(move |_| Box::new(attrs::Attributes::new(conf))); diff --git a/clippy_lints/src/mut_reference.rs b/clippy_lints/src/unnecessary_mut_passed.rs similarity index 72% rename from clippy_lints/src/mut_reference.rs rename to clippy_lints/src/unnecessary_mut_passed.rs index ec93ef97cfaf..eb2d7639e91f 100644 --- a/clippy_lints/src/mut_reference.rs +++ b/clippy_lints/src/unnecessary_mut_passed.rs @@ -1,5 +1,5 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::sugg::Sugg; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::source::SpanRangeExt; use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability}; use rustc_lint::{LateContext, LateLintPass}; @@ -87,16 +87,33 @@ fn check_arguments<'tcx>( if let ty::Ref(_, _, Mutability::Not) | ty::RawPtr(_, Mutability::Not) = parameter.kind() && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, arg) = argument.kind { - let mut applicability = Applicability::MachineApplicable; - let sugg = Sugg::hir_with_applicability(cx, arg, "_", &mut applicability).addr(); - span_lint_and_sugg( + 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| { + src + // 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")) + }) && let Ok(lo) = u32::try_from(ref_pos + '&'.len_utf8()) + { + span_until_arg.split_at(lo).1 + } else { + return; + } + }; + + span_lint_and_then( cx, UNNECESSARY_MUT_PASSED, argument.span, format!("the {fn_kind} `{name}` doesn't need a mutable reference"), - "remove this `mut`", - sugg.to_string(), - applicability, + |diag| { + diag.span_suggestion_verbose(span_to_remove, "remove this `mut`", String::new(), applicability); + }, ); } } diff --git a/tests/ui/mut_reference.stderr b/tests/ui/mut_reference.stderr deleted file mode 100644 index 5ecfaa37416b..000000000000 --- a/tests/ui/mut_reference.stderr +++ /dev/null @@ -1,77 +0,0 @@ -error: the function `takes_ref` doesn't need a mutable reference - --> tests/ui/mut_reference.rs:56:15 - | -LL | takes_ref(&mut 42); - | ^^^^^^^ help: remove this `mut`: `&42` - | - = note: `-D clippy::unnecessary-mut-passed` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::unnecessary_mut_passed)]` - -error: the function `takes_ref_ref` doesn't need a mutable reference - --> tests/ui/mut_reference.rs:58:19 - | -LL | takes_ref_ref(&mut &42); - | ^^^^^^^^ help: remove this `mut`: `&&42` - -error: the function `takes_ref_refmut` doesn't need a mutable reference - --> tests/ui/mut_reference.rs:60:22 - | -LL | takes_ref_refmut(&mut &mut 42); - | ^^^^^^^^^^^^ help: remove this `mut`: `&&mut 42` - -error: the function `takes_raw_const` doesn't need a mutable reference - --> tests/ui/mut_reference.rs:62:21 - | -LL | takes_raw_const(&mut 42); - | ^^^^^^^ help: remove this `mut`: `&42` - -error: the function `as_ptr` doesn't need a mutable reference - --> tests/ui/mut_reference.rs:66:12 - | -LL | as_ptr(&mut 42); - | ^^^^^^^ help: remove this `mut`: `&42` - -error: the function `as_ptr` doesn't need a mutable reference - --> tests/ui/mut_reference.rs:69:12 - | -LL | as_ptr(&mut &42); - | ^^^^^^^^ help: remove this `mut`: `&&42` - -error: the function `as_ptr` doesn't need a mutable reference - --> tests/ui/mut_reference.rs:72:12 - | -LL | as_ptr(&mut &mut 42); - | ^^^^^^^^^^^^ help: remove this `mut`: `&&mut 42` - -error: the function `as_ptr` doesn't need a mutable reference - --> tests/ui/mut_reference.rs:75:12 - | -LL | as_ptr(&mut 42); - | ^^^^^^^ help: remove this `mut`: `&42` - -error: the method `takes_ref` doesn't need a mutable reference - --> tests/ui/mut_reference.rs:80:25 - | -LL | my_struct.takes_ref(&mut 42); - | ^^^^^^^ help: remove this `mut`: `&42` - -error: the method `takes_ref_ref` doesn't need a mutable reference - --> tests/ui/mut_reference.rs:82:29 - | -LL | my_struct.takes_ref_ref(&mut &42); - | ^^^^^^^^ help: remove this `mut`: `&&42` - -error: the method `takes_ref_refmut` doesn't need a mutable reference - --> tests/ui/mut_reference.rs:84:32 - | -LL | my_struct.takes_ref_refmut(&mut &mut 42); - | ^^^^^^^^^^^^ help: remove this `mut`: `&&mut 42` - -error: the method `takes_raw_const` doesn't need a mutable reference - --> tests/ui/mut_reference.rs:86:31 - | -LL | my_struct.takes_raw_const(&mut 42); - | ^^^^^^^ help: remove this `mut`: `&42` - -error: aborting due to 12 previous errors - diff --git a/tests/ui/mut_reference.fixed b/tests/ui/unnecessary_mut_passed.fixed similarity index 87% rename from tests/ui/mut_reference.fixed rename to tests/ui/unnecessary_mut_passed.fixed index 03d854099e64..63bbadb01dcb 100644 --- a/tests/ui/mut_reference.fixed +++ b/tests/ui/unnecessary_mut_passed.fixed @@ -40,6 +40,7 @@ mod issue11268 { struct MyStruct; impl MyStruct { + fn takes_nothing(&self) {} fn takes_ref(&self, a: &i32) {} fn takes_refmut(&self, a: &mut i32) {} fn takes_ref_ref(&self, a: &&i32) {} @@ -168,3 +169,22 @@ fn raw_ptrs(my_struct: MyStruct) { my_struct.takes_raw_mut(&raw mut n); my_struct.takes_raw_const(a); } + +#[expect(clippy::needless_borrow)] +fn issue15722(mut my_struct: MyStruct) { + (&my_struct).takes_nothing(); + //~^ unnecessary_mut_passed + (&my_struct).takes_nothing(); + + // Only put parens around the argument that used to have it + (&my_struct).takes_ref(&42); + //~^ unnecessary_mut_passed + //~| unnecessary_mut_passed + #[expect(clippy::double_parens)] + (&my_struct).takes_ref((&42)); + //~^ unnecessary_mut_passed + //~| unnecessary_mut_passed + #[expect(clippy::double_parens)] + my_struct.takes_ref((&42)); + //~^ unnecessary_mut_passed +} diff --git a/tests/ui/mut_reference.rs b/tests/ui/unnecessary_mut_passed.rs similarity index 87% rename from tests/ui/mut_reference.rs rename to tests/ui/unnecessary_mut_passed.rs index 80e3f5069277..b719ca1871b2 100644 --- a/tests/ui/mut_reference.rs +++ b/tests/ui/unnecessary_mut_passed.rs @@ -40,6 +40,7 @@ mod issue11268 { struct MyStruct; impl MyStruct { + fn takes_nothing(&self) {} fn takes_ref(&self, a: &i32) {} fn takes_refmut(&self, a: &mut i32) {} fn takes_ref_ref(&self, a: &&i32) {} @@ -168,3 +169,22 @@ fn raw_ptrs(my_struct: MyStruct) { my_struct.takes_raw_mut(&raw mut n); my_struct.takes_raw_const(a); } + +#[expect(clippy::needless_borrow)] +fn issue15722(mut my_struct: MyStruct) { + (&mut my_struct).takes_nothing(); + //~^ unnecessary_mut_passed + (&my_struct).takes_nothing(); + + // Only put parens around the argument that used to have it + (&mut my_struct).takes_ref(&mut 42); + //~^ unnecessary_mut_passed + //~| unnecessary_mut_passed + #[expect(clippy::double_parens)] + (&mut my_struct).takes_ref((&mut 42)); + //~^ unnecessary_mut_passed + //~| unnecessary_mut_passed + #[expect(clippy::double_parens)] + my_struct.takes_ref((&mut 42)); + //~^ unnecessary_mut_passed +} diff --git a/tests/ui/unnecessary_mut_passed.stderr b/tests/ui/unnecessary_mut_passed.stderr new file mode 100644 index 000000000000..ace11027e3e2 --- /dev/null +++ b/tests/ui/unnecessary_mut_passed.stderr @@ -0,0 +1,220 @@ +error: the function `takes_ref` doesn't need a mutable reference + --> tests/ui/unnecessary_mut_passed.rs:57:15 + | +LL | takes_ref(&mut 42); + | ^^^^^^^ + | + = note: `-D clippy::unnecessary-mut-passed` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unnecessary_mut_passed)]` +help: remove this `mut` + | +LL - takes_ref(&mut 42); +LL + takes_ref(&42); + | + +error: the function `takes_ref_ref` doesn't need a mutable reference + --> tests/ui/unnecessary_mut_passed.rs:59:19 + | +LL | takes_ref_ref(&mut &42); + | ^^^^^^^^ + | +help: remove this `mut` + | +LL - takes_ref_ref(&mut &42); +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 + | +LL | takes_ref_refmut(&mut &mut 42); + | ^^^^^^^^^^^^ + | +help: remove this `mut` + | +LL - takes_ref_refmut(&mut &mut 42); +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 + | +LL | takes_raw_const(&mut 42); + | ^^^^^^^ + | +help: remove this `mut` + | +LL - takes_raw_const(&mut 42); +LL + takes_raw_const(&42); + | + +error: the function `as_ptr` doesn't need a mutable reference + --> tests/ui/unnecessary_mut_passed.rs:67:12 + | +LL | as_ptr(&mut 42); + | ^^^^^^^ + | +help: remove this `mut` + | +LL - as_ptr(&mut 42); +LL + as_ptr(&42); + | + +error: the function `as_ptr` doesn't need a mutable reference + --> tests/ui/unnecessary_mut_passed.rs:70:12 + | +LL | as_ptr(&mut &42); + | ^^^^^^^^ + | +help: remove this `mut` + | +LL - as_ptr(&mut &42); +LL + as_ptr(&&42); + | + +error: the function `as_ptr` doesn't need a mutable reference + --> tests/ui/unnecessary_mut_passed.rs:73:12 + | +LL | as_ptr(&mut &mut 42); + | ^^^^^^^^^^^^ + | +help: remove this `mut` + | +LL - as_ptr(&mut &mut 42); +LL + as_ptr(&&mut 42); + | + +error: the function `as_ptr` doesn't need a mutable reference + --> tests/ui/unnecessary_mut_passed.rs:76:12 + | +LL | as_ptr(&mut 42); + | ^^^^^^^ + | +help: remove this `mut` + | +LL - as_ptr(&mut 42); +LL + as_ptr(&42); + | + +error: the method `takes_ref` doesn't need a mutable reference + --> tests/ui/unnecessary_mut_passed.rs:81:25 + | +LL | my_struct.takes_ref(&mut 42); + | ^^^^^^^ + | +help: remove this `mut` + | +LL - my_struct.takes_ref(&mut 42); +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 + | +LL | my_struct.takes_ref_ref(&mut &42); + | ^^^^^^^^ + | +help: remove this `mut` + | +LL - my_struct.takes_ref_ref(&mut &42); +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 + | +LL | my_struct.takes_ref_refmut(&mut &mut 42); + | ^^^^^^^^^^^^ + | +help: remove this `mut` + | +LL - my_struct.takes_ref_refmut(&mut &mut 42); +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 + | +LL | my_struct.takes_raw_const(&mut 42); + | ^^^^^^^ + | +help: remove this `mut` + | +LL - my_struct.takes_raw_const(&mut 42); +LL + my_struct.takes_raw_const(&42); + | + +error: the method `takes_nothing` doesn't need a mutable reference + --> tests/ui/unnecessary_mut_passed.rs:175:5 + | +LL | (&mut my_struct).takes_nothing(); + | ^^^^^^^^^^^^^^^^ + | +help: remove this `mut` + | +LL - (&mut my_struct).takes_nothing(); +LL + (&my_struct).takes_nothing(); + | + +error: the method `takes_ref` doesn't need a mutable reference + --> tests/ui/unnecessary_mut_passed.rs:180:5 + | +LL | (&mut my_struct).takes_ref(&mut 42); + | ^^^^^^^^^^^^^^^^ + | +help: remove this `mut` + | +LL - (&mut my_struct).takes_ref(&mut 42); +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 + | +LL | (&mut my_struct).takes_ref(&mut 42); + | ^^^^^^^ + | +help: remove this `mut` + | +LL - (&mut my_struct).takes_ref(&mut 42); +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 + | +LL | (&mut my_struct).takes_ref((&mut 42)); + | ^^^^^^^^^^^^^^^^ + | +help: remove this `mut` + | +LL - (&mut my_struct).takes_ref((&mut 42)); +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 + | +LL | (&mut my_struct).takes_ref((&mut 42)); + | ^^^^^^^^^ + | +help: remove this `mut` + | +LL - (&mut my_struct).takes_ref((&mut 42)); +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 + | +LL | my_struct.takes_ref((&mut 42)); + | ^^^^^^^^^ + | +help: remove this `mut` + | +LL - my_struct.takes_ref((&mut 42)); +LL + my_struct.takes_ref((&42)); + | + +error: aborting due to 18 previous errors +