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
13 changes: 10 additions & 3 deletions clippy_lints/src/mut_reference.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use clippy_utils::diagnostics::span_lint;
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::sugg::Sugg;
use rustc_errors::Applicability;
use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::{self, Ty};
Expand Down Expand Up @@ -83,13 +85,18 @@ 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, _) = argument.kind
&& let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, arg) = argument.kind
{
span_lint(
let mut applicability = Applicability::MachineApplicable;
let sugg = Sugg::hir_with_applicability(cx, arg, "_", &mut applicability).addr();
span_lint_and_sugg(
cx,
UNNECESSARY_MUT_PASSED,
argument.span,
format!("the {fn_kind} `{name}` doesn't need a mutable reference"),
"remove this `mut`",
sugg.to_string(),
applicability,
);
}
}
Expand Down
170 changes: 170 additions & 0 deletions tests/ui/mut_reference.fixed
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
#![allow(clippy::mut_mut)]

fn takes_ref(a: &i32) {}
fn takes_refmut(a: &mut i32) {}
fn takes_ref_ref(a: &&i32) {}
fn takes_refmut_ref(a: &mut &i32) {}
fn takes_ref_refmut(a: &&mut i32) {}
fn takes_refmut_refmut(a: &mut &mut i32) {}
fn takes_raw_const(a: *const i32) {}
fn takes_raw_mut(a: *mut i32) {}

mod issue11268 {
macro_rules! x {
(1 $f:expr) => {
$f(&mut 1);
};
(2 $f:expr) => {
$f(&mut &1)
};
(3 $f:expr) => {
$f(&mut &mut 1)
};
(4 $f:expr) => {
let mut a = 1;
$f(&raw mut a)
};
}

fn f() {
x!(1 super::takes_ref);
x!(1 super::takes_refmut);
x!(2 super::takes_refmut_ref);
x!(3 super::takes_ref_refmut);
x!(3 super::takes_refmut_refmut);
x!(4 super::takes_raw_const);
x!(4 super::takes_raw_mut);
}
}

struct MyStruct;

impl MyStruct {
fn takes_ref(&self, a: &i32) {}
fn takes_refmut(&self, a: &mut i32) {}
fn takes_ref_ref(&self, a: &&i32) {}
fn takes_refmut_ref(&self, a: &mut &i32) {}
fn takes_ref_refmut(&self, a: &&mut i32) {}
fn takes_refmut_refmut(&self, a: &mut &mut i32) {}
fn takes_raw_const(&self, a: *const i32) {}
fn takes_raw_mut(&self, a: *mut i32) {}
}

#[warn(clippy::unnecessary_mut_passed)]
fn main() {
// Functions
takes_ref(&42);
//~^ unnecessary_mut_passed
takes_ref_ref(&&42);
//~^ unnecessary_mut_passed
takes_ref_refmut(&&mut 42);
//~^ unnecessary_mut_passed
takes_raw_const(&42);
//~^ unnecessary_mut_passed

let as_ptr: fn(&i32) = takes_ref;
as_ptr(&42);
//~^ unnecessary_mut_passed
let as_ptr: fn(&&i32) = takes_ref_ref;
as_ptr(&&42);
//~^ unnecessary_mut_passed
let as_ptr: fn(&&mut i32) = takes_ref_refmut;
as_ptr(&&mut 42);
//~^ unnecessary_mut_passed
let as_ptr: fn(*const i32) = takes_raw_const;
as_ptr(&42);
//~^ unnecessary_mut_passed

// Methods
let my_struct = MyStruct;
my_struct.takes_ref(&42);
//~^ unnecessary_mut_passed
my_struct.takes_ref_ref(&&42);
//~^ unnecessary_mut_passed
my_struct.takes_ref_refmut(&&mut 42);
//~^ unnecessary_mut_passed
my_struct.takes_raw_const(&42);
//~^ unnecessary_mut_passed

// No error

// Functions
takes_ref(&42);
let as_ptr: fn(&i32) = takes_ref;
as_ptr(&42);

takes_refmut(&mut 42);
let as_ptr: fn(&mut i32) = takes_refmut;
as_ptr(&mut 42);

takes_ref_ref(&&42);
let as_ptr: fn(&&i32) = takes_ref_ref;
as_ptr(&&42);

takes_refmut_ref(&mut &42);
let as_ptr: fn(&mut &i32) = takes_refmut_ref;
as_ptr(&mut &42);

takes_ref_refmut(&&mut 42);
let as_ptr: fn(&&mut i32) = takes_ref_refmut;
as_ptr(&&mut 42);

takes_refmut_refmut(&mut &mut 42);
let as_ptr: fn(&mut &mut i32) = takes_refmut_refmut;
as_ptr(&mut &mut 42);

takes_raw_const(&42);
let as_ptr: fn(*const i32) = takes_raw_const;
as_ptr(&42);

takes_raw_mut(&mut 42);
let as_ptr: fn(*mut i32) = takes_raw_mut;
as_ptr(&mut 42);

let a = &mut 42;
let b = &mut &42;
let c = &mut &mut 42;
takes_ref(a);
takes_ref_ref(b);
takes_ref_refmut(c);
takes_raw_const(a);

// Methods
my_struct.takes_ref(&42);
my_struct.takes_refmut(&mut 42);
my_struct.takes_ref_ref(&&42);
my_struct.takes_refmut_ref(&mut &42);
my_struct.takes_ref_refmut(&&mut 42);
my_struct.takes_refmut_refmut(&mut &mut 42);
my_struct.takes_raw_const(&42);
my_struct.takes_raw_mut(&mut 42);
my_struct.takes_ref(a);
my_struct.takes_ref_ref(b);
my_struct.takes_ref_refmut(c);
my_struct.takes_raw_const(a);
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);

let as_ptr: fn(*const i32) = takes_raw_const;
as_ptr(&raw mut n);

my_struct.takes_raw_const(&raw mut n);

// No error

takes_raw_const(&raw const n);
takes_raw_mut(&raw mut n);

let a = &raw mut n;
takes_raw_const(a);

my_struct.takes_raw_const(&raw const n);
my_struct.takes_raw_mut(&raw mut n);
my_struct.takes_raw_const(a);
}
152 changes: 131 additions & 21 deletions tests/ui/mut_reference.rs
Original file line number Diff line number Diff line change
@@ -1,60 +1,170 @@
#![allow(unused_variables, dead_code)]
//@no-rustfix
fn takes_an_immutable_reference(a: &i32) {}
fn takes_a_mutable_reference(a: &mut i32) {}
#![allow(clippy::mut_mut)]

fn takes_ref(a: &i32) {}
fn takes_refmut(a: &mut i32) {}
fn takes_ref_ref(a: &&i32) {}
fn takes_refmut_ref(a: &mut &i32) {}
fn takes_ref_refmut(a: &&mut i32) {}
fn takes_refmut_refmut(a: &mut &mut i32) {}
fn takes_raw_const(a: *const i32) {}
fn takes_raw_mut(a: *mut i32) {}

mod issue11268 {
macro_rules! x {
($f:expr) => {
(1 $f:expr) => {
$f(&mut 1);
};
(2 $f:expr) => {
$f(&mut &1)
};
(3 $f:expr) => {
$f(&mut &mut 1)
};
(4 $f:expr) => {
let mut a = 1;
$f(&raw mut a)
};
}

fn f() {
x!(super::takes_an_immutable_reference);
x!(super::takes_a_mutable_reference);
x!(1 super::takes_ref);
x!(1 super::takes_refmut);
x!(2 super::takes_refmut_ref);
x!(3 super::takes_ref_refmut);
x!(3 super::takes_refmut_refmut);
x!(4 super::takes_raw_const);
x!(4 super::takes_raw_mut);
}
}

struct MyStruct;

impl MyStruct {
fn takes_an_immutable_reference(&self, a: &i32) {}

fn takes_a_mutable_reference(&self, a: &mut i32) {}
fn takes_ref(&self, a: &i32) {}
fn takes_refmut(&self, a: &mut i32) {}
fn takes_ref_ref(&self, a: &&i32) {}
fn takes_refmut_ref(&self, a: &mut &i32) {}
fn takes_ref_refmut(&self, a: &&mut i32) {}
fn takes_refmut_refmut(&self, a: &mut &mut i32) {}
fn takes_raw_const(&self, a: *const i32) {}
fn takes_raw_mut(&self, a: *mut i32) {}
}

#[warn(clippy::unnecessary_mut_passed)]
fn main() {
// Functions
takes_an_immutable_reference(&mut 42);
takes_ref(&mut 42);
//~^ unnecessary_mut_passed
takes_ref_ref(&mut &42);
//~^ unnecessary_mut_passed
takes_ref_refmut(&mut &mut 42);
//~^ unnecessary_mut_passed
takes_raw_const(&mut 42);
//~^ unnecessary_mut_passed

let as_ptr: fn(&i32) = takes_an_immutable_reference;
let as_ptr: fn(&i32) = takes_ref;
as_ptr(&mut 42);
//~^ unnecessary_mut_passed
let as_ptr: fn(&&i32) = takes_ref_ref;
as_ptr(&mut &42);
//~^ unnecessary_mut_passed
let as_ptr: fn(&&mut i32) = takes_ref_refmut;
as_ptr(&mut &mut 42);
//~^ unnecessary_mut_passed
let as_ptr: fn(*const i32) = takes_raw_const;
as_ptr(&mut 42);
//~^ unnecessary_mut_passed

// Methods
let my_struct = MyStruct;
my_struct.takes_an_immutable_reference(&mut 42);
my_struct.takes_ref(&mut 42);
//~^ unnecessary_mut_passed
my_struct.takes_ref_ref(&mut &42);
//~^ unnecessary_mut_passed
my_struct.takes_ref_refmut(&mut &mut 42);
//~^ unnecessary_mut_passed
my_struct.takes_raw_const(&mut 42);
//~^ unnecessary_mut_passed

// No error

// Functions
takes_an_immutable_reference(&42);
let as_ptr: fn(&i32) = takes_an_immutable_reference;
takes_ref(&42);
let as_ptr: fn(&i32) = takes_ref;
as_ptr(&42);

takes_a_mutable_reference(&mut 42);
let as_ptr: fn(&mut i32) = takes_a_mutable_reference;
takes_refmut(&mut 42);
let as_ptr: fn(&mut i32) = takes_refmut;
as_ptr(&mut 42);

takes_ref_ref(&&42);
let as_ptr: fn(&&i32) = takes_ref_ref;
as_ptr(&&42);

takes_refmut_ref(&mut &42);
let as_ptr: fn(&mut &i32) = takes_refmut_ref;
as_ptr(&mut &42);

takes_ref_refmut(&&mut 42);
let as_ptr: fn(&&mut i32) = takes_ref_refmut;
as_ptr(&&mut 42);

takes_refmut_refmut(&mut &mut 42);
let as_ptr: fn(&mut &mut i32) = takes_refmut_refmut;
as_ptr(&mut &mut 42);

takes_raw_const(&42);
let as_ptr: fn(*const i32) = takes_raw_const;
as_ptr(&42);

takes_raw_mut(&mut 42);
let as_ptr: fn(*mut i32) = takes_raw_mut;
as_ptr(&mut 42);

let a = &mut 42;
takes_an_immutable_reference(a);
let b = &mut &42;
let c = &mut &mut 42;
takes_ref(a);
takes_ref_ref(b);
takes_ref_refmut(c);
takes_raw_const(a);

// Methods
my_struct.takes_an_immutable_reference(&42);
my_struct.takes_a_mutable_reference(&mut 42);
my_struct.takes_an_immutable_reference(a);
my_struct.takes_ref(&42);
my_struct.takes_refmut(&mut 42);
my_struct.takes_ref_ref(&&42);
my_struct.takes_refmut_ref(&mut &42);
my_struct.takes_ref_refmut(&&mut 42);
my_struct.takes_refmut_refmut(&mut &mut 42);
my_struct.takes_raw_const(&42);
my_struct.takes_raw_mut(&mut 42);
my_struct.takes_ref(a);
my_struct.takes_ref_ref(b);
my_struct.takes_ref_refmut(c);
my_struct.takes_raw_const(a);
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);

let as_ptr: fn(*const i32) = takes_raw_const;
as_ptr(&raw mut n);

my_struct.takes_raw_const(&raw mut n);

// No error

takes_raw_const(&raw const n);
takes_raw_mut(&raw mut n);

let a = &raw mut n;
takes_raw_const(a);

my_struct.takes_raw_const(&raw const n);
my_struct.takes_raw_mut(&raw mut n);
my_struct.takes_raw_const(a);
}
Loading