add notes for immutable inputs

This commit is contained in:
Andre Bogus 2017-02-12 13:53:30 +01:00
parent ad01fa9b57
commit 36b8554cf1
4 changed files with 32 additions and 47 deletions

View file

@ -15,6 +15,7 @@
#![allow(needless_lifetimes)]
extern crate syntax;
extern crate syntax_pos;
#[macro_use]
extern crate rustc;
extern crate rustc_data_structures;

View file

@ -5,7 +5,9 @@ use rustc::hir::map::NodeItem;
use rustc::lint::*;
use rustc::ty;
use syntax::ast::NodeId;
use utils::{match_path, match_type, paths, span_lint};
use syntax::codemap::Span;
use syntax_pos::MultiSpan;
use utils::{match_path, match_type, paths, span_lint, span_lint_and_then};
/// **What it does:** This lint checks for function arguments of type `&String` or `&Vec` unless
/// the references are mutable.
@ -132,29 +134,31 @@ fn check_fn(cx: &LateContext, decl: &FnDecl, fn_id: NodeId) {
}
if let FunctionRetTy::Return(ref ty) = decl.output {
if let Some((out, MutMutable)) = get_rptr_lm(ty) {
if let Some(MutImmutable) =
decl.inputs
.iter()
.filter_map(|ty| get_rptr_lm(ty))
.filter(|&(lt, _)| lt.name == out.name)
.fold(None, |x, (_, m)| match (x, m) {
(Some(MutMutable), _) |
(_, MutMutable) => Some(MutMutable),
(_, m) => Some(m),
}) {
span_lint(cx,
MUT_FROM_REF,
ty.span,
"this function takes an immutable ref to return a mutable one");
if let Some((out, MutMutable, _)) = get_rptr_lm(ty) {
let mut immutables = vec![];
for (_, ref mutbl, ref argspan) in decl.inputs
.iter()
.filter_map(|ty| get_rptr_lm(ty))
.filter(|&(lt, _, _)| lt.name == out.name) {
if *mutbl == MutMutable { return; }
immutables.push(*argspan);
}
if immutables.is_empty() { return; }
span_lint_and_then(cx,
MUT_FROM_REF,
ty.span,
"mutable borrow from immutable input(s)",
|db| {
let ms = MultiSpan::from_spans(immutables);
db.span_note(ms, "immutable borrow here");
});
}
}
}
fn get_rptr_lm(ty: &Ty) -> Option<(&Lifetime, Mutability)> {
fn get_rptr_lm(ty: &Ty) -> Option<(&Lifetime, Mutability, Span)> {
if let Ty_::TyRptr(ref lt, ref m) = ty.node {
Some((lt, m.mutbl))
Some((lt, m.mutbl, ty.span))
} else {
None
}

View file

@ -29,6 +29,10 @@ fn fail_lifetime<'a>(x: &'a u32, y: &mut u32) -> &'a mut u32 {
unimplemented!()
}
fn fail_double<'a>(x: &'a u32, y: &'a u32, z: &'b mut u32) -> &'a mut u32 {
unimplemented!()
}
// this is OK, because the result borrows y
fn works<'a>(x: &u32, y: &'a mut u32) -> &'a mut u32 {
unimplemented!()

View file

@ -1,32 +1,8 @@
error: this function takes an immutable ref to return a mutable one
--> $DIR/mut_from_ref.rs:9:39
|
9 | fn this_wont_hurt_a_bit(&self) -> &mut Foo {
| ^^^^^^^^
|
note: lint level defined here
--> $DIR/mut_from_ref.rs:4:9
|
4 | #![deny(mut_from_ref)]
| ^^^^^^^^^^^^
error: this function takes an immutable ref to return a mutable one
--> $DIR/mut_from_ref.rs:15:25
error[E0261]: use of undeclared lifetime name `'b`
--> $DIR/mut_from_ref.rs:32:48
|
15 | fn ouch(x: &Foo) -> &mut Foo;
| ^^^^^^^^
32 | fn fail_double<'a>(x: &'a u32, y: &'a u32, z: &'b mut u32) -> &'a mut u32 {
| ^^ undeclared lifetime
error: this function takes an immutable ref to return a mutable one
--> $DIR/mut_from_ref.rs:24:21
|
24 | fn fail(x: &u32) -> &mut u16 {
| ^^^^^^^^
error: this function takes an immutable ref to return a mutable one
--> $DIR/mut_from_ref.rs:28:50
|
28 | fn fail_lifetime<'a>(x: &'a u32, y: &mut u32) -> &'a mut u32 {
| ^^^^^^^^^^^
error: aborting due to 4 previous errors
error: aborting due to previous error