rust-clippy/src/mut_reference.rs

78 lines
3.1 KiB
Rust
Raw Normal View History

2015-09-29 11:11:19 +00:00
use rustc::lint::*;
use rustc::ty::{TypeAndMut, TypeVariants, MethodCall, TyS};
use rustc::hir::*;
use syntax::ptr::P;
2016-02-24 16:38:57 +00:00
use utils::span_lint;
2015-09-29 11:11:19 +00:00
/// **What it does:** This lint detects giving a mutable reference to a function that only requires an immutable reference.
///
/// **Why is this bad?** The immutable reference rules out all other references to the value. Also the code misleads about the intent of the call site.
///
/// **Known problems:** None
///
/// **Example** `my_vec.push(&mut value)`
2015-09-29 11:11:19 +00:00
declare_lint! {
pub UNNECESSARY_MUT_PASSED,
Warn,
"an argument is passed as a mutable reference although the function/method only demands an \
2015-09-29 11:11:19 +00:00
immutable reference"
}
#[derive(Copy,Clone)]
pub struct UnnecessaryMutPassed;
impl LintPass for UnnecessaryMutPassed {
fn get_lints(&self) -> LintArray {
lint_array!(UNNECESSARY_MUT_PASSED)
}
}
impl LateLintPass for UnnecessaryMutPassed {
fn check_expr(&mut self, cx: &LateContext, e: &Expr) {
let borrowed_table = cx.tcx.tables.borrow();
match e.node {
ExprCall(ref fn_expr, ref arguments) => {
2016-02-01 10:28:39 +00:00
let function_type = borrowed_table.node_types
.get(&fn_expr.id)
.expect("A function with an unknown type is called. \
If this happened, the compiler would have \
aborted the compilation long ago");
if let ExprPath(_, ref path) = fn_expr.node {
2016-04-26 15:05:39 +00:00
check_arguments(cx, arguments, function_type, &path.to_string());
2016-02-01 10:28:39 +00:00
}
}
ExprMethodCall(ref name, _, ref arguments) => {
let method_call = MethodCall::expr(e.id);
2016-02-01 10:28:39 +00:00
let method_type = borrowed_table.method_map.get(&method_call).expect("This should never happen.");
2016-04-26 15:05:39 +00:00
check_arguments(cx, arguments, method_type.ty, &name.node.as_str())
}
2016-04-14 18:14:03 +00:00
_ => (),
2015-09-29 11:11:19 +00:00
}
}
}
fn check_arguments(cx: &LateContext, arguments: &[P<Expr>], type_definition: &TyS, name: &str) {
match type_definition.sty {
2016-04-14 18:14:03 +00:00
TypeVariants::TyFnDef(_, _, ref fn_type) |
TypeVariants::TyFnPtr(ref fn_type) => {
let parameters = &fn_type.sig.skip_binder().inputs;
for (argument, parameter) in arguments.iter().zip(parameters.iter()) {
match parameter.sty {
2016-04-14 18:14:03 +00:00
TypeVariants::TyRef(_, TypeAndMut { mutbl: MutImmutable, .. }) |
TypeVariants::TyRawPtr(TypeAndMut { mutbl: MutImmutable, .. }) => {
if let ExprAddrOf(MutMutable, _) = argument.node {
span_lint(cx,
UNNECESSARY_MUT_PASSED,
argument.span,
&format!("The function/method \"{}\" doesn't need a mutable reference", name));
}
}
2016-04-14 18:14:03 +00:00
_ => (),
}
}
}
_ => (),
}
}