Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion clippy_lints/src/needless_pass_by_ref_mut.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use super::needless_pass_by_value::requires_exact_signature;
use clippy_utils::diagnostics::span_lint_hir_and_then;
use clippy_utils::source::snippet;
use clippy_utils::{get_parent_node, is_from_proc_macro, is_self};
use clippy_utils::{get_parent_node, inherits_cfg, is_from_proc_macro, is_self};
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
use rustc_errors::Applicability;
use rustc_hir::intravisit::{walk_qpath, FnKind, Visitor};
Expand Down Expand Up @@ -192,10 +192,12 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> {
let show_semver_warning =
self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(*fn_def_id);

let mut is_cfged = None;
for input in unused {
// If the argument is never used mutably, we emit the warning.
let sp = input.span;
if let rustc_hir::TyKind::Ref(_, inner_ty) = input.kind {
let is_cfged = is_cfged.get_or_insert_with(|| inherits_cfg(cx.tcx, *fn_def_id));
span_lint_hir_and_then(
cx,
NEEDLESS_PASS_BY_REF_MUT,
Expand All @@ -212,6 +214,9 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> {
if show_semver_warning {
diag.warn("changing this function will impact semver compatibility");
}
if *is_cfged {
diag.note("this is cfg-gated and may require further changes");
}
},
);
}
Expand Down
11 changes: 11 additions & 0 deletions clippy_utils/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2451,6 +2451,17 @@ pub fn is_in_cfg_test(tcx: TyCtxt<'_>, id: hir::HirId) -> bool {
.any(is_cfg_test)
}

/// Checks if the item of any of its parents has `#[cfg(...)]` attribute applied.
pub fn inherits_cfg(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
let hir = tcx.hir();

tcx.has_attr(def_id, sym::cfg)
|| hir
.parent_iter(hir.local_def_id_to_hir_id(def_id))
.flat_map(|(parent_id, _)| hir.attrs(parent_id))
.any(|attr| attr.has_name(sym::cfg))
}

/// Checks whether item either has `test` attribute applied, or
/// is a module with `test` in its name.
///
Expand Down
36 changes: 24 additions & 12 deletions tests/ui/needless_pass_by_ref_mut.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@

use std::ptr::NonNull;

// Should only warn for `s`.
fn foo(s: &mut Vec<u32>, b: &u32, x: &mut u32) {
//~^ ERROR: this argument is a mutable reference, but not used mutably
*x += *b + s.len() as u32;
}

Expand All @@ -28,8 +28,8 @@ fn foo5(s: &mut Vec<u32>) {
foo2(s);
}

// Should warn.
fn foo6(s: &mut Vec<u32>) {
//~^ ERROR: this argument is a mutable reference, but not used mutably
non_mut_ref(s);
}

Expand All @@ -41,13 +41,13 @@ impl Bar {
// Should not warn on `&mut self`.
fn bar(&mut self) {}

// Should warn about `vec`
fn mushroom(&self, vec: &mut Vec<i32>) -> usize {
//~^ ERROR: this argument is a mutable reference, but not used mutably
vec.len()
}

// Should warn about `vec` (and not `self`).
fn badger(&mut self, vec: &mut Vec<i32>) -> usize {
//~^ ERROR: this argument is a mutable reference, but not used mutably
vec.len()
}
}
Expand Down Expand Up @@ -123,36 +123,36 @@ async fn f7(x: &mut i32, y: i32, z: &mut i32, a: i32) {
*z += 1;
}

// Should warn.
async fn a1(x: &mut i32) {
//~^ ERROR: this argument is a mutable reference, but not used mutably
println!("{:?}", x);
}
// Should warn.
async fn a2(x: &mut i32, y: String) {
//~^ ERROR: this argument is a mutable reference, but not used mutably
println!("{:?}", x);
}
// Should warn.
async fn a3(x: &mut i32, y: String, z: String) {
//~^ ERROR: this argument is a mutable reference, but not used mutably
println!("{:?}", x);
}
// Should warn.
async fn a4(x: &mut i32, y: i32) {
//~^ ERROR: this argument is a mutable reference, but not used mutably
println!("{:?}", x);
}
// Should warn.
async fn a5(x: i32, y: &mut i32) {
//~^ ERROR: this argument is a mutable reference, but not used mutably
println!("{:?}", x);
}
// Should warn.
async fn a6(x: i32, y: &mut i32) {
//~^ ERROR: this argument is a mutable reference, but not used mutably
println!("{:?}", x);
}
// Should warn.
async fn a7(x: i32, y: i32, z: &mut i32) {
//~^ ERROR: this argument is a mutable reference, but not used mutably
println!("{:?}", z);
}
// Should warn.
async fn a8(x: i32, a: &mut i32, y: i32, z: &mut i32) {
//~^ ERROR: this argument is a mutable reference, but not used mutably
println!("{:?}", z);
}

Expand Down Expand Up @@ -184,6 +184,18 @@ fn used_as_path(s: &mut u32) {}
#[expect(clippy::needless_pass_by_ref_mut)]
fn lint_attr(s: &mut u32) {}

#[cfg(not(feature = "a"))]
fn cfg_warn(s: &mut u32) {}
//~^ ERROR: this argument is a mutable reference, but not used mutably
//~| NOTE: this is cfg-gated and may require further changes

#[cfg(not(feature = "a"))]
mod foo {
fn cfg_warn(s: &mut u32) {}
//~^ ERROR: this argument is a mutable reference, but not used mutably
//~| NOTE: this is cfg-gated and may require further changes
}

fn main() {
let mut u = 0;
let mut v = vec![0];
Expand Down
44 changes: 30 additions & 14 deletions tests/ui/needless_pass_by_ref_mut.stderr
Original file line number Diff line number Diff line change
@@ -1,82 +1,98 @@
error: this argument is a mutable reference, but not used mutably
--> $DIR/needless_pass_by_ref_mut.rs:7:11
--> $DIR/needless_pass_by_ref_mut.rs:6:11
|
LL | fn foo(s: &mut Vec<u32>, b: &u32, x: &mut u32) {
| ^^^^^^^^^^^^^ help: consider changing to: `&Vec<u32>`
|
= note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings`

error: this argument is a mutable reference, but not used mutably
--> $DIR/needless_pass_by_ref_mut.rs:32:12
--> $DIR/needless_pass_by_ref_mut.rs:31:12
|
LL | fn foo6(s: &mut Vec<u32>) {
| ^^^^^^^^^^^^^ help: consider changing to: `&Vec<u32>`

error: this argument is a mutable reference, but not used mutably
--> $DIR/needless_pass_by_ref_mut.rs:45:29
--> $DIR/needless_pass_by_ref_mut.rs:44:29
|
LL | fn mushroom(&self, vec: &mut Vec<i32>) -> usize {
| ^^^^^^^^^^^^^ help: consider changing to: `&Vec<i32>`

error: this argument is a mutable reference, but not used mutably
--> $DIR/needless_pass_by_ref_mut.rs:50:31
--> $DIR/needless_pass_by_ref_mut.rs:49:31
|
LL | fn badger(&mut self, vec: &mut Vec<i32>) -> usize {
| ^^^^^^^^^^^^^ help: consider changing to: `&Vec<i32>`

error: this argument is a mutable reference, but not used mutably
--> $DIR/needless_pass_by_ref_mut.rs:127:16
--> $DIR/needless_pass_by_ref_mut.rs:126:16
|
LL | async fn a1(x: &mut i32) {
| ^^^^^^^^ help: consider changing to: `&i32`

error: this argument is a mutable reference, but not used mutably
--> $DIR/needless_pass_by_ref_mut.rs:131:16
--> $DIR/needless_pass_by_ref_mut.rs:130:16
|
LL | async fn a2(x: &mut i32, y: String) {
| ^^^^^^^^ help: consider changing to: `&i32`

error: this argument is a mutable reference, but not used mutably
--> $DIR/needless_pass_by_ref_mut.rs:135:16
--> $DIR/needless_pass_by_ref_mut.rs:134:16
|
LL | async fn a3(x: &mut i32, y: String, z: String) {
| ^^^^^^^^ help: consider changing to: `&i32`

error: this argument is a mutable reference, but not used mutably
--> $DIR/needless_pass_by_ref_mut.rs:139:16
--> $DIR/needless_pass_by_ref_mut.rs:138:16
|
LL | async fn a4(x: &mut i32, y: i32) {
| ^^^^^^^^ help: consider changing to: `&i32`

error: this argument is a mutable reference, but not used mutably
--> $DIR/needless_pass_by_ref_mut.rs:143:24
--> $DIR/needless_pass_by_ref_mut.rs:142:24
|
LL | async fn a5(x: i32, y: &mut i32) {
| ^^^^^^^^ help: consider changing to: `&i32`

error: this argument is a mutable reference, but not used mutably
--> $DIR/needless_pass_by_ref_mut.rs:147:24
--> $DIR/needless_pass_by_ref_mut.rs:146:24
|
LL | async fn a6(x: i32, y: &mut i32) {
| ^^^^^^^^ help: consider changing to: `&i32`

error: this argument is a mutable reference, but not used mutably
--> $DIR/needless_pass_by_ref_mut.rs:151:32
--> $DIR/needless_pass_by_ref_mut.rs:150:32
|
LL | async fn a7(x: i32, y: i32, z: &mut i32) {
| ^^^^^^^^ help: consider changing to: `&i32`

error: this argument is a mutable reference, but not used mutably
--> $DIR/needless_pass_by_ref_mut.rs:155:24
--> $DIR/needless_pass_by_ref_mut.rs:154:24
|
LL | async fn a8(x: i32, a: &mut i32, y: i32, z: &mut i32) {
| ^^^^^^^^ help: consider changing to: `&i32`

error: this argument is a mutable reference, but not used mutably
--> $DIR/needless_pass_by_ref_mut.rs:155:45
--> $DIR/needless_pass_by_ref_mut.rs:154:45
|
LL | async fn a8(x: i32, a: &mut i32, y: i32, z: &mut i32) {
| ^^^^^^^^ help: consider changing to: `&i32`

error: aborting due to 13 previous errors
error: this argument is a mutable reference, but not used mutably
--> $DIR/needless_pass_by_ref_mut.rs:188:16
|
LL | fn cfg_warn(s: &mut u32) {}
| ^^^^^^^^ help: consider changing to: `&u32`
|
= note: this is cfg-gated and may require further changes

error: this argument is a mutable reference, but not used mutably
--> $DIR/needless_pass_by_ref_mut.rs:194:20
|
LL | fn cfg_warn(s: &mut u32) {}
| ^^^^^^^^ help: consider changing to: `&u32`
|
= note: this is cfg-gated and may require further changes

error: aborting due to 15 previous errors