|
1 | 1 | use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
2 | 2 | use rustc_hir::def::{DefKind, Res};
|
3 | 3 | use rustc_hir::intravisit::{
|
4 |
| - walk_fn_decl, walk_generic_param, walk_generics, walk_param_bound, walk_ty, NestedVisitorMap, Visitor, |
| 4 | + walk_fn_decl, walk_generic_param, walk_generics, walk_param_bound, walk_trait_ref, walk_ty, NestedVisitorMap, |
| 5 | + Visitor, |
5 | 6 | };
|
6 | 7 | use rustc_hir::FnRetTy::Return;
|
7 | 8 | use rustc_hir::{
|
8 | 9 | BodyId, FnDecl, GenericArg, GenericBound, GenericParam, GenericParamKind, Generics, ImplItem, ImplItemKind, Item,
|
9 |
| - ItemKind, Lifetime, LifetimeName, ParamName, QPath, TraitBoundModifier, TraitFn, TraitItem, TraitItemKind, Ty, |
10 |
| - TyKind, WhereClause, WherePredicate, |
| 10 | + ItemKind, Lifetime, LifetimeName, ParamName, QPath, TraitBoundModifier, TraitFn, TraitItem, TraitItemKind, |
| 11 | + TraitRef, Ty, TyKind, WhereClause, WherePredicate, |
11 | 12 | };
|
12 | 13 | use rustc_lint::{LateContext, LateLintPass};
|
13 | 14 | use rustc_middle::hir::map::Map;
|
14 | 15 | use rustc_session::{declare_lint_pass, declare_tool_lint};
|
15 | 16 | use rustc_span::source_map::Span;
|
16 | 17 | use rustc_span::symbol::{kw, Symbol};
|
17 | 18 |
|
18 |
| -use crate::utils::{in_macro, last_path_segment, span_lint, trait_ref_of_method}; |
| 19 | +use crate::utils::paths; |
| 20 | +use crate::utils::{get_trait_def_id, in_macro, last_path_segment, span_lint, trait_ref_of_method}; |
19 | 21 |
|
20 | 22 | declare_clippy_lint! {
|
21 | 23 | /// **What it does:** Checks for lifetime annotations which can be removed by
|
@@ -127,6 +129,14 @@ fn check_fn_inner<'tcx>(
|
127 | 129 | return;
|
128 | 130 | }
|
129 | 131 |
|
| 132 | + // fn pointers and closure trait bounds are also lifetime elision sites. This lint does not |
| 133 | + // support nested elision sites in a fn item. |
| 134 | + if FnPointerOrClosureTraitBoundFinder::find_in_generics(cx, generics) |
| 135 | + || FnPointerOrClosureTraitBoundFinder::find_in_fn_decl(cx, decl) |
| 136 | + { |
| 137 | + return; |
| 138 | + } |
| 139 | + |
130 | 140 | let mut bounds_lts = Vec::new();
|
131 | 141 | let types = generics
|
132 | 142 | .params
|
@@ -523,3 +533,54 @@ impl<'tcx> Visitor<'tcx> for BodyLifetimeChecker {
|
523 | 533 | NestedVisitorMap::None
|
524 | 534 | }
|
525 | 535 | }
|
| 536 | + |
| 537 | +const CLOSURE_TRAIT_BOUNDS: [&[&str]; 3] = [&paths::FN, &paths::FN_MUT, &paths::FN_ONCE]; |
| 538 | + |
| 539 | +struct FnPointerOrClosureTraitBoundFinder<'a, 'tcx> { |
| 540 | + cx: &'a LateContext<'tcx>, |
| 541 | + found: bool, |
| 542 | +} |
| 543 | + |
| 544 | +impl<'a, 'tcx> FnPointerOrClosureTraitBoundFinder<'a, 'tcx> { |
| 545 | + fn find_in_generics(cx: &'a LateContext<'tcx>, generics: &'tcx Generics<'tcx>) -> bool { |
| 546 | + let mut finder = Self { cx, found: false }; |
| 547 | + finder.visit_generics(generics); |
| 548 | + finder.found |
| 549 | + } |
| 550 | + |
| 551 | + fn find_in_fn_decl(cx: &'a LateContext<'tcx>, generics: &'tcx FnDecl<'tcx>) -> bool { |
| 552 | + let mut finder = Self { cx, found: false }; |
| 553 | + finder.visit_fn_decl(generics); |
| 554 | + finder.found |
| 555 | + } |
| 556 | +} |
| 557 | + |
| 558 | +impl<'a, 'tcx> Visitor<'tcx> for FnPointerOrClosureTraitBoundFinder<'a, 'tcx> { |
| 559 | + type Map = Map<'tcx>; |
| 560 | + fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> { |
| 561 | + NestedVisitorMap::None |
| 562 | + } |
| 563 | + |
| 564 | + fn visit_trait_ref(&mut self, tref: &'tcx TraitRef<'tcx>) { |
| 565 | + if CLOSURE_TRAIT_BOUNDS |
| 566 | + .iter() |
| 567 | + .any(|trait_path| tref.trait_def_id() == get_trait_def_id(self.cx, trait_path)) |
| 568 | + { |
| 569 | + self.found = true; |
| 570 | + } |
| 571 | + walk_trait_ref(self, tref); |
| 572 | + } |
| 573 | + |
| 574 | + fn visit_ty(&mut self, ty: &'tcx Ty<'tcx>) { |
| 575 | + match ty.kind { |
| 576 | + TyKind::BareFn(..) => self.found = true, |
| 577 | + TyKind::OpaqueDef(item_id, _) => { |
| 578 | + let map = self.cx.tcx.hir(); |
| 579 | + let item = map.expect_item(item_id.id); |
| 580 | + self.visit_item(item); |
| 581 | + }, |
| 582 | + _ => (), |
| 583 | + } |
| 584 | + walk_ty(self, ty); |
| 585 | + } |
| 586 | +} |
0 commit comments