Add lint for unused lifetimes (fixes #459)

This commit is contained in:
Manish Goregaokar 2015-12-07 03:06:22 +05:30
parent c4e9982dd7
commit c7b87a06d2
5 changed files with 80 additions and 5 deletions

View file

@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your Rust code.
[Jump to usage instructions](#usage) [Jump to usage instructions](#usage)
##Lints ##Lints
There are 81 lints included in this crate: There are 82 lints included in this crate:
name | default | meaning name | default | meaning
---------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ ---------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@ -84,6 +84,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_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 [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_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 [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_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 [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

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

View file

@ -2,9 +2,9 @@ use rustc_front::hir::*;
use reexport::*; use reexport::*;
use rustc::lint::*; use rustc::lint::*;
use syntax::codemap::Span; 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 rustc::middle::def::Def::{DefTy, DefTrait, DefStruct};
use std::collections::HashSet; use std::collections::{HashSet, HashMap};
use utils::{in_external_macro, span_lint}; 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 \ "using explicit lifetimes for references in function arguments when elision rules \
would allow omitting them"); would allow omitting them");
declare_lint!(pub UNUSED_LIFETIMES, Warn,
"unused lifetimes in function definitions");
#[derive(Copy,Clone)] #[derive(Copy,Clone)]
pub struct LifetimePass; pub struct LifetimePass;
impl LintPass for LifetimePass { impl LintPass for LifetimePass {
fn get_lints(&self) -> LintArray { 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, span_lint(cx, NEEDLESS_LIFETIMES, span,
"explicit lifetimes given in parameter types where they could be elided"); "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>, 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 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)] #![plugin(clippy)]
#![deny(needless_lifetimes)] #![deny(needless_lifetimes)]
#![allow(dead_code)] #![allow(dead_code, unused_lifetimes)]
fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) { } fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) { }
//~^ERROR explicit lifetimes given //~^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() {
}