Merge pull request #483 from Manishearth/bored

Add lint for unused lifetimes (fixes #459)
This commit is contained in:
llogiq 2015-12-07 21:47:10 +01:00
commit 3260b501a2
5 changed files with 79 additions and 4 deletions

View File

@ -85,6 +85,7 @@ name
[unstable_as_mut_slice](https://github.com/Manishearth/rust-clippy/wiki#unstable_as_mut_slice) | warn | as_mut_slice is not stable and can be replaced by &mut v[..]see https://github.com/rust-lang/rust/issues/27729
[unstable_as_slice](https://github.com/Manishearth/rust-clippy/wiki#unstable_as_slice) | warn | as_slice is not stable and can be replaced by & v[..]see https://github.com/rust-lang/rust/issues/27729
[unused_collect](https://github.com/Manishearth/rust-clippy/wiki#unused_collect) | warn | `collect()`ing an iterator without using the result; this is usually better written as a for loop
[unused_lifetimes](https://github.com/Manishearth/rust-clippy/wiki#unused_lifetimes) | warn | unused lifetimes in function definitions
[useless_transmute](https://github.com/Manishearth/rust-clippy/wiki#useless_transmute) | warn | transmutes that have the same to and from types
[while_let_loop](https://github.com/Manishearth/rust-clippy/wiki#while_let_loop) | warn | `loop { if let { ... } else break }` can be written as a `while let` loop
[while_let_on_iterator](https://github.com/Manishearth/rust-clippy/wiki#while_let_on_iterator) | warn | using a while-let loop instead of a for loop on an iterator

View File

@ -156,6 +156,7 @@ pub fn plugin_registrar(reg: &mut Registry) {
len_zero::LEN_WITHOUT_IS_EMPTY,
len_zero::LEN_ZERO,
lifetimes::NEEDLESS_LIFETIMES,
lifetimes::UNUSED_LIFETIMES,
loops::EMPTY_LOOP,
loops::EXPLICIT_COUNTER_LOOP,
loops::EXPLICIT_ITER_LOOP,

View File

@ -2,9 +2,9 @@ use rustc_front::hir::*;
use reexport::*;
use rustc::lint::*;
use syntax::codemap::Span;
use rustc_front::intravisit::{Visitor, walk_ty, walk_ty_param_bound};
use rustc_front::intravisit::{Visitor, walk_ty, walk_ty_param_bound, walk_fn_decl};
use rustc::middle::def::Def::{DefTy, DefTrait, DefStruct};
use std::collections::HashSet;
use std::collections::{HashSet, HashMap};
use utils::{in_external_macro, span_lint};
@ -12,12 +12,15 @@ declare_lint!(pub NEEDLESS_LIFETIMES, Warn,
"using explicit lifetimes for references in function arguments when elision rules \
would allow omitting them");
declare_lint!(pub UNUSED_LIFETIMES, Warn,
"unused lifetimes in function definitions");
#[derive(Copy,Clone)]
pub struct LifetimePass;
impl LintPass for LifetimePass {
fn get_lints(&self) -> LintArray {
lint_array!(NEEDLESS_LIFETIMES)
lint_array!(NEEDLESS_LIFETIMES, UNUSED_LIFETIMES)
}
}
@ -61,6 +64,7 @@ fn check_fn_inner(cx: &LateContext, decl: &FnDecl, slf: Option<&ExplicitSelf>,
span_lint(cx, NEEDLESS_LIFETIMES, span,
"explicit lifetimes given in parameter types where they could be elided");
}
report_extra_lifetimes(cx, decl, &generics.lifetimes);
}
fn could_use_elision(cx: &LateContext, func: &FnDecl, slf: Option<&ExplicitSelf>,
@ -263,3 +267,24 @@ fn has_where_lifetimes(cx: &LateContext, where_clause: &WhereClause) -> bool {
}
false
}
struct LifetimeChecker(HashMap<Name, Span>);
impl<'v> Visitor<'v> for LifetimeChecker {
// for lifetimes as parameters of generics
fn visit_lifetime(&mut self, lifetime: &'v Lifetime) {
self.0.remove(&lifetime.name);
}
}
fn report_extra_lifetimes(cx: &LateContext, func: &FnDecl,
named_lts: &[LifetimeDef]) {
let hs = named_lts.iter().map(|lt| (lt.lifetime.name, lt.lifetime.span)).collect();
let mut checker = LifetimeChecker(hs);
walk_fn_decl(&mut checker, func);
for (_, v) in checker.0 {
span_lint(cx, UNUSED_LIFETIMES, v,
"this lifetime isn't used in the function definition");
}
}

View File

@ -2,7 +2,7 @@
#![plugin(clippy)]
#![deny(needless_lifetimes)]
#![allow(dead_code)]
#![allow(dead_code, unused_lifetimes)]
fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) { }
//~^ERROR explicit lifetimes given

View File

@ -0,0 +1,48 @@
#![feature(plugin)]
#![plugin(clippy)]
#![allow(unused, dead_code, needless_lifetimes)]
#![deny(unused_lifetimes)]
fn empty() {
}
fn used_lt<'a>(x: &'a u8) {
}
fn unused_lt<'a>(x: u8) { //~ ERROR this lifetime
}
fn unused_lt_transitive<'a, 'b: 'a>(x: &'b u8) { //~ ERROR this lifetime
// 'a is useless here since it's not directly bound
}
fn lt_return<'a, 'b: 'a>(x: &'b u8) -> &'a u8 {
panic!()
}
fn lt_return_only<'a>() -> &'a u8 {
panic!()
}
fn unused_lt_blergh<'a>(x: Option<Box<Send+'a>>) {
}
trait Foo<'a> {
fn x(&self, a: &'a u8);
}
impl<'a> Foo<'a> for u8 {
fn x(&self, a: &'a u8) {
}
}
fn main() {
}