Skip to content

Commit b35c04f

Browse files
committed
Extend extra_unused_lifetimes to handle impl lifetimes
1 parent ed22428 commit b35c04f

File tree

7 files changed

+97
-12
lines changed

7 files changed

+97
-12
lines changed

clippy_lints/src/lifetimes.rs

Lines changed: 58 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,19 @@
11
use clippy_utils::diagnostics::span_lint;
22
use clippy_utils::trait_ref_of_method;
33
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
4+
use rustc_hir::intravisit::nested_filter::{self as hir_nested_filter, NestedFilter};
45
use rustc_hir::intravisit::{
5-
walk_fn_decl, walk_generic_param, walk_generics, walk_item, walk_param_bound, walk_poly_trait_ref, walk_ty, Visitor,
6+
walk_fn_decl, walk_generic_param, walk_generics, walk_impl_item_ref, walk_item, walk_param_bound,
7+
walk_poly_trait_ref, walk_trait_ref, walk_ty, Visitor,
68
};
79
use rustc_hir::FnRetTy::Return;
810
use rustc_hir::{
9-
BareFnTy, BodyId, FnDecl, GenericArg, GenericBound, GenericParam, GenericParamKind, Generics, ImplItem,
11+
BareFnTy, BodyId, FnDecl, GenericArg, GenericBound, GenericParam, GenericParamKind, Generics, Impl, ImplItem,
1012
ImplItemKind, Item, ItemKind, LangItem, Lifetime, LifetimeName, ParamName, PolyTraitRef, TraitBoundModifier,
1113
TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WhereClause, WherePredicate,
1214
};
1315
use rustc_lint::{LateContext, LateLintPass};
16+
use rustc_middle::hir::nested_filter as mir_nested_filter;
1417
use rustc_session::{declare_lint_pass, declare_tool_lint};
1518
use rustc_span::source_map::Span;
1619
use rustc_span::symbol::{kw, Ident, Symbol};
@@ -84,6 +87,8 @@ impl<'tcx> LateLintPass<'tcx> for Lifetimes {
8487
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
8588
if let ItemKind::Fn(ref sig, ref generics, id) = item.kind {
8689
check_fn_inner(cx, sig.decl, Some(id), None, generics, item.span, true);
90+
} else if let ItemKind::Impl(ref impl_) = item.kind {
91+
report_extra_impl_lifetimes(cx, impl_);
8792
}
8893
}
8994

@@ -194,8 +199,7 @@ fn explicit_self_type<'tcx>(cx: &LateContext<'tcx>, func: &FnDecl<'tcx>, ident:
194199
visitor.visit_ty(self_ty);
195200

196201
!visitor.all_lts().is_empty()
197-
}
198-
else {
202+
} else {
199203
false
200204
}
201205
}
@@ -481,11 +485,29 @@ fn has_where_lifetimes<'tcx>(cx: &LateContext<'tcx>, where_clause: &'tcx WhereCl
481485
false
482486
}
483487

484-
struct LifetimeChecker {
488+
struct LifetimeChecker<'cx, 'tcx, F> {
489+
cx: &'cx LateContext<'tcx>,
485490
map: FxHashMap<Symbol, Span>,
491+
phantom: std::marker::PhantomData<F>,
486492
}
487493

488-
impl<'tcx> Visitor<'tcx> for LifetimeChecker {
494+
impl<'cx, 'tcx, F> LifetimeChecker<'cx, 'tcx, F> {
495+
fn new(cx: &'cx LateContext<'tcx>, map: FxHashMap<Symbol, Span>) -> LifetimeChecker<'cx, 'tcx, F> {
496+
Self {
497+
cx,
498+
map,
499+
phantom: std::marker::PhantomData,
500+
}
501+
}
502+
}
503+
504+
impl<'cx, 'tcx, F> Visitor<'tcx> for LifetimeChecker<'cx, 'tcx, F>
505+
where
506+
F: NestedFilter<'tcx>,
507+
{
508+
type Map = rustc_middle::hir::map::Map<'tcx>;
509+
type NestedFilter = F;
510+
489511
// for lifetimes as parameters of generics
490512
fn visit_lifetime(&mut self, lifetime: &'tcx Lifetime) {
491513
self.map.remove(&lifetime.name.ident().name);
@@ -501,6 +523,10 @@ impl<'tcx> Visitor<'tcx> for LifetimeChecker {
501523
walk_generic_param(self, param);
502524
}
503525
}
526+
527+
fn nested_visit_map(&mut self) -> Self::Map {
528+
self.cx.tcx.hir()
529+
}
504530
}
505531

506532
fn report_extra_lifetimes<'tcx>(cx: &LateContext<'tcx>, func: &'tcx FnDecl<'_>, generics: &'tcx Generics<'_>) {
@@ -512,7 +538,7 @@ fn report_extra_lifetimes<'tcx>(cx: &LateContext<'tcx>, func: &'tcx FnDecl<'_>,
512538
_ => None,
513539
})
514540
.collect();
515-
let mut checker = LifetimeChecker { map: hs };
541+
let mut checker = LifetimeChecker::<hir_nested_filter::None>::new(cx, hs);
516542

517543
walk_generics(&mut checker, generics);
518544
walk_fn_decl(&mut checker, func);
@@ -527,6 +553,31 @@ fn report_extra_lifetimes<'tcx>(cx: &LateContext<'tcx>, func: &'tcx FnDecl<'_>,
527553
}
528554
}
529555

556+
fn report_extra_impl_lifetimes<'tcx>(cx: &LateContext<'tcx>, impl_: &'tcx Impl<'_>) {
557+
let hs = impl_
558+
.generics
559+
.params
560+
.iter()
561+
.filter_map(|par| match par.kind {
562+
GenericParamKind::Lifetime { .. } => Some((par.name.ident().name, par.span)),
563+
_ => None,
564+
})
565+
.collect();
566+
let mut checker = LifetimeChecker::<mir_nested_filter::All>::new(cx, hs);
567+
568+
if let Some(ref trait_ref) = impl_.of_trait {
569+
walk_trait_ref(&mut checker, trait_ref);
570+
}
571+
walk_ty(&mut checker, impl_.self_ty);
572+
for item in impl_.items {
573+
walk_impl_item_ref(&mut checker, item);
574+
}
575+
576+
for &v in checker.map.values() {
577+
span_lint(cx, EXTRA_UNUSED_LIFETIMES, v, "this lifetime isn't used in the impl");
578+
}
579+
}
580+
530581
struct BodyLifetimeChecker {
531582
lifetimes_used_in_body: bool,
532583
}

tests/ui/crashes/ice-2865.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#[allow(dead_code)]
1+
#![allow(dead_code, clippy::extra_unused_lifetimes)]
22

33
/// Test for https://github.com/rust-lang/rust-clippy/issues/2865
44

tests/ui/crashes/ice-3151.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/// Test for https://github.com/rust-lang/rust-clippy/issues/2865
1+
/// Test for https://github.com/rust-lang/rust-clippy/issues/3151
22
33
#[derive(Clone)]
44
pub struct HashMap<V, S> {

tests/ui/extra_unused_lifetimes.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,4 +72,20 @@ mod issue4291 {
7272
}
7373
}
7474

75+
mod issue6437 {
76+
pub struct Scalar;
77+
78+
impl<'a> std::ops::AddAssign<&Scalar> for &mut Scalar {
79+
fn add_assign(&mut self, _rhs: &Scalar) {
80+
unimplemented!();
81+
}
82+
}
83+
84+
impl<'b> Scalar {
85+
pub fn something<'c>() -> Self {
86+
Self
87+
}
88+
}
89+
}
90+
7591
fn main() {}

tests/ui/extra_unused_lifetimes.stderr

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,23 @@ error: this lifetime isn't used in the function definition
2424
LL | fn unused_lt<'a>(x: u8) {}
2525
| ^^
2626

27-
error: aborting due to 4 previous errors
27+
error: this lifetime isn't used in the impl
28+
--> $DIR/extra_unused_lifetimes.rs:78:10
29+
|
30+
LL | impl<'a> std::ops::AddAssign<&Scalar> for &mut Scalar {
31+
| ^^
32+
33+
error: this lifetime isn't used in the impl
34+
--> $DIR/extra_unused_lifetimes.rs:84:10
35+
|
36+
LL | impl<'b> Scalar {
37+
| ^^
38+
39+
error: this lifetime isn't used in the function definition
40+
--> $DIR/extra_unused_lifetimes.rs:85:26
41+
|
42+
LL | pub fn something<'c>() -> Self {
43+
| ^^
44+
45+
error: aborting due to 7 previous errors
2846

tests/ui/impl.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#![allow(dead_code)]
1+
#![allow(dead_code, clippy::extra_unused_lifetimes)]
22
#![warn(clippy::multiple_inherent_impl)]
33

44
struct MyStruct;

tests/ui/new_without_default.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#![allow(dead_code, clippy::missing_safety_doc)]
1+
#![allow(dead_code, clippy::missing_safety_doc, clippy::extra_unused_lifetimes)]
22
#![warn(clippy::new_without_default)]
33

44
pub struct Foo;

0 commit comments

Comments
 (0)