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)] #![allow(needless_lifetimes)]
extern crate syntax; extern crate syntax;
extern crate syntax_pos;
#[macro_use] #[macro_use]
extern crate rustc; extern crate rustc;
extern crate rustc_data_structures; extern crate rustc_data_structures;

View File

@@ -5,7 +5,9 @@ use rustc::hir::map::NodeItem;
use rustc::lint::*; use rustc::lint::*;
use rustc::ty; use rustc::ty;
use syntax::ast::NodeId; 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 /// **What it does:** This lint checks for function arguments of type `&String` or `&Vec` unless
/// the references are mutable. /// 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 FunctionRetTy::Return(ref ty) = decl.output {
if let Some((out, MutMutable)) = get_rptr_lm(ty) { if let Some((out, MutMutable, _)) = get_rptr_lm(ty) {
if let Some(MutImmutable) = let mut immutables = vec![];
decl.inputs for (_, ref mutbl, ref argspan) in decl.inputs
.iter() .iter()
.filter_map(|ty| get_rptr_lm(ty)) .filter_map(|ty| get_rptr_lm(ty))
.filter(|&(lt, _)| lt.name == out.name) .filter(|&(lt, _, _)| lt.name == out.name) {
.fold(None, |x, (_, m)| match (x, m) { if *mutbl == MutMutable { return; }
(Some(MutMutable), _) | immutables.push(*argspan);
(_, 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 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 { if let Ty_::TyRptr(ref lt, ref m) = ty.node {
Some((lt, m.mutbl)) Some((lt, m.mutbl, ty.span))
} else { } else {
None None
} }

View File

@@ -29,6 +29,10 @@ fn fail_lifetime<'a>(x: &'a u32, y: &mut u32) -> &'a mut u32 {
unimplemented!() 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 // this is OK, because the result borrows y
fn works<'a>(x: &u32, y: &'a mut u32) -> &'a mut u32 { fn works<'a>(x: &u32, y: &'a mut u32) -> &'a mut u32 {
unimplemented!() unimplemented!()

View File

@@ -1,32 +1,8 @@
error: this function takes an immutable ref to return a mutable one error[E0261]: use of undeclared lifetime name `'b`
--> $DIR/mut_from_ref.rs:9:39 --> $DIR/mut_from_ref.rs:32:48
|
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
| |
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 error: aborting due to previous error
--> $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