From c7b87a06d20a13e9fdf86d34f200ad4e444cb5b8 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Mon, 7 Dec 2015 03:06:22 +0530 Subject: [PATCH] Add lint for unused lifetimes (fixes #459) --- README.md | 3 ++- src/lib.rs | 1 + src/lifetimes.rs | 31 ++++++++++++++++++--- tests/compile-fail/lifetimes.rs | 2 +- tests/compile-fail/unused_lt.rs | 48 +++++++++++++++++++++++++++++++++ 5 files changed, 80 insertions(+), 5 deletions(-) create mode 100644 tests/compile-fail/unused_lt.rs diff --git a/README.md b/README.md index e19ab474c5e..8fdaf1206f9 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your Rust code. [Jump to usage instructions](#usage) ##Lints -There are 81 lints included in this crate: +There are 82 lints included in this crate: 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_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 diff --git a/src/lib.rs b/src/lib.rs index 9ead05b93b2..3faa0427c39 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -154,6 +154,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, diff --git a/src/lifetimes.rs b/src/lifetimes.rs index 16ba43766e0..e9591ab6ddc 100644 --- a/src/lifetimes.rs +++ b/src/lifetimes.rs @@ -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); + +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"); + } +} diff --git a/tests/compile-fail/lifetimes.rs b/tests/compile-fail/lifetimes.rs index 040c3554e89..4d454a738d9 100644 --- a/tests/compile-fail/lifetimes.rs +++ b/tests/compile-fail/lifetimes.rs @@ -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 diff --git a/tests/compile-fail/unused_lt.rs b/tests/compile-fail/unused_lt.rs new file mode 100644 index 00000000000..d4babdfc4fd --- /dev/null +++ b/tests/compile-fail/unused_lt.rs @@ -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>) { + +} + + +trait Foo<'a> { + fn x(&self, a: &'a u8); +} + +impl<'a> Foo<'a> for u8 { + fn x(&self, a: &'a u8) { + + } +} +fn main() { + +}