Auto merge of #13286 - smoelius:elidable-impl-lifetimes, r=Alexendoo
Extend `needless_lifetimes` to suggest eliding `impl` lifetimes
Example:
```
error: the following explicit lifetimes could be elided: 'a
--> tests/ui/needless_lifetimes.rs:332:10
|
LL | impl<'a> Foo for Baz<'a> {}
| ^^ ^^
|
help: elide the lifetimes
|
LL - impl<'a> Foo for Baz<'a> {}
LL + impl Foo for Baz<'_> {}
```
The main change is in how `impl` lifetime uses are tracked. Previously, a hashmap was created, and lifetimes were removed from the hashmap as their uses were discovered. However, the uses are needed to generate elision suggestions. So, now, uses are added to the hashmap as they are discovered.
The PR is currently organized as six commits, which I think are self-explanatory:
- Extend `needless_lifetimes` to suggest eliding `impl` lifetimes
- Reorder functions _[not strictly necessary, but IMHO, the code is better structured as a result]_
- Fix lifetime tests
- Fix non-lifetime tests
- Fix `clippy_lints` and `clippy_utils`
- Fix typo in `needless_lifetimes` test
r? `@Alexendoo` (I think you are `needless_lifetimes`' primary author? Sorry if I have this wrong.)
---
changelog: Extend `needless_lifetimes` to suggest eliding `impl` lifetimes
This commit is contained in:
commit
db1bda3df1
115 changed files with 796 additions and 618 deletions
|
|
@ -205,7 +205,7 @@ struct Hir2Qmm<'a, 'tcx, 'v> {
|
|||
cx: &'a LateContext<'tcx>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx, 'v> Hir2Qmm<'a, 'tcx, 'v> {
|
||||
impl<'v> Hir2Qmm<'_, '_, 'v> {
|
||||
fn extract(&mut self, op: BinOpKind, a: &[&'v Expr<'_>], mut v: Vec<Bool>) -> Result<Vec<Bool>, String> {
|
||||
for a in a {
|
||||
if let ExprKind::Binary(binop, lhs, rhs) = &a.kind {
|
||||
|
|
@ -292,7 +292,7 @@ struct SuggestContext<'a, 'tcx, 'v> {
|
|||
output: String,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx, 'v> SuggestContext<'a, 'tcx, 'v> {
|
||||
impl SuggestContext<'_, '_, '_> {
|
||||
fn recurse(&mut self, suggestion: &Bool) -> Option<()> {
|
||||
use quine_mc_cluskey::Bool::{And, False, Not, Or, Term, True};
|
||||
match suggestion {
|
||||
|
|
@ -475,7 +475,7 @@ fn terminal_stats(b: &Bool) -> Stats {
|
|||
stats
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> {
|
||||
impl<'tcx> NonminimalBoolVisitor<'_, 'tcx> {
|
||||
fn bool_expr(&self, e: &'tcx Expr<'_>) {
|
||||
let mut h2q = Hir2Qmm {
|
||||
terminals: Vec::new(),
|
||||
|
|
@ -582,7 +582,7 @@ impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for NonminimalBoolVisitor<'a, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for NonminimalBoolVisitor<'_, 'tcx> {
|
||||
fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
|
||||
if !e.span.from_expansion() {
|
||||
match &e.kind {
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ fn is_local_vec_expn(cx: &LateContext<'_>, expr: &Expr<'_>, ref_expr: &Expr<'_>)
|
|||
#[derive(Default)]
|
||||
struct InferVisitor(bool);
|
||||
|
||||
impl<'tcx> Visitor<'tcx> for InferVisitor {
|
||||
impl Visitor<'_> for InferVisitor {
|
||||
fn visit_ty(&mut self, t: &Ty<'_>) {
|
||||
self.0 |= matches!(t.kind, TyKind::Infer | TyKind::OpaqueDef(..) | TyKind::TraitObject(..));
|
||||
if !self.0 {
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ impl CheckedConversions {
|
|||
|
||||
impl_lint_pass!(CheckedConversions => [CHECKED_CONVERSIONS]);
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for CheckedConversions {
|
||||
impl LateLintPass<'_> for CheckedConversions {
|
||||
fn check_expr(&mut self, cx: &LateContext<'_>, item: &Expr<'_>) {
|
||||
if let ExprKind::Binary(op, lhs, rhs) = item.kind
|
||||
&& let (lt1, gt1, op2) = match op.node {
|
||||
|
|
|
|||
|
|
@ -119,7 +119,7 @@ impl<'a, 'tcx> NumericFallbackVisitor<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for NumericFallbackVisitor<'_, 'tcx> {
|
||||
fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
|
||||
match &expr.kind {
|
||||
ExprKind::Block(
|
||||
|
|
|
|||
|
|
@ -970,7 +970,7 @@ impl<'a, 'tcx> FindPanicUnwrap<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for FindPanicUnwrap<'a, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for FindPanicUnwrap<'_, 'tcx> {
|
||||
type NestedFilter = nested_filter::OnlyBodies;
|
||||
|
||||
fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ declare_clippy_lint! {
|
|||
|
||||
declare_lint_pass!(EmptyEnum => [EMPTY_ENUM]);
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for EmptyEnum {
|
||||
impl LateLintPass<'_> for EmptyEnum {
|
||||
fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
|
||||
if let ItemKind::Enum(..) = item.kind
|
||||
// Only suggest the `never_type` if the feature is enabled
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@ fn is_argument(tcx: TyCtxt<'_>, id: HirId) -> bool {
|
|||
matches!(tcx.parent_hir_node(id), Node::Param(_))
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> {
|
||||
impl<'tcx> Delegate<'tcx> for EscapeDelegate<'_, 'tcx> {
|
||||
fn consume(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId) {
|
||||
if cmt.place.projections.is_empty() {
|
||||
if let PlaceBase::Local(lid) = cmt.place.base {
|
||||
|
|
@ -188,7 +188,7 @@ impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> {
|
|||
fn fake_read(&mut self, _: &PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> EscapeDelegate<'a, 'tcx> {
|
||||
impl<'tcx> EscapeDelegate<'_, 'tcx> {
|
||||
fn is_large_box(&self, ty: Ty<'tcx>) -> bool {
|
||||
// Large types need to be boxed to avoid stack overflows.
|
||||
if let Some(boxed_ty) = ty.boxed_ty() {
|
||||
|
|
|
|||
|
|
@ -135,7 +135,7 @@ impl NestingVisitor<'_, '_> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'conf, 'cx> Visitor<'_> for NestingVisitor<'conf, 'cx> {
|
||||
impl Visitor<'_> for NestingVisitor<'_, '_> {
|
||||
fn visit_block(&mut self, block: &Block) {
|
||||
if block.span.from_expansion() {
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -193,7 +193,7 @@ fn bound_to_trait_def_id(bound: &GenericBound<'_>) -> Option<LocalDefId> {
|
|||
bound.trait_ref()?.trait_def_id()?.as_local()
|
||||
}
|
||||
|
||||
impl<'cx, 'tcx> Visitor<'tcx> for TypeWalker<'cx, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for TypeWalker<'_, 'tcx> {
|
||||
type NestedFilter = nested_filter::OnlyBodies;
|
||||
|
||||
fn visit_ty(&mut self, t: &'tcx Ty<'tcx>) {
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ fn lint_impl_body(cx: &LateContext<'_>, impl_span: Span, impl_items: &[hir::Impl
|
|||
result: Vec<Span>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for FindPanicUnwrap<'a, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for FindPanicUnwrap<'_, 'tcx> {
|
||||
fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
|
||||
if let Some(macro_call) = root_macro_call_first_node(self.lcx, expr) {
|
||||
if is_panic(self.lcx, macro_call.def_id) {
|
||||
|
|
|
|||
|
|
@ -219,7 +219,7 @@ struct FormatArgsExpr<'a, 'tcx> {
|
|||
ignore_mixed: bool,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> FormatArgsExpr<'a, 'tcx> {
|
||||
impl FormatArgsExpr<'_, '_> {
|
||||
fn check_templates(&self) {
|
||||
for piece in &self.format_args.template {
|
||||
if let FormatArgsPiece::Placeholder(placeholder) = piece
|
||||
|
|
|
|||
|
|
@ -148,7 +148,7 @@ struct FormatImplExpr<'a, 'tcx> {
|
|||
format_trait_impl: FormatTraitNames,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> FormatImplExpr<'a, 'tcx> {
|
||||
impl FormatImplExpr<'_, '_> {
|
||||
fn check_to_string_in_display(&self) {
|
||||
if self.format_trait_impl.name == sym::Display
|
||||
&& let ExprKind::MethodCall(path, self_arg, ..) = self.expr.kind
|
||||
|
|
|
|||
|
|
@ -126,7 +126,7 @@ struct SelfFinder<'a, 'tcx> {
|
|||
invalid: bool,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for SelfFinder<'a, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for SelfFinder<'_, 'tcx> {
|
||||
type NestedFilter = OnlyBodies;
|
||||
|
||||
fn nested_visit_map(&mut self) -> Self::Map {
|
||||
|
|
|
|||
|
|
@ -281,7 +281,7 @@ impl<'a, 'tcx> ImplicitHasherTypeVisitor<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for ImplicitHasherTypeVisitor<'a, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for ImplicitHasherTypeVisitor<'_, 'tcx> {
|
||||
fn visit_ty(&mut self, t: &'tcx hir::Ty<'_>) {
|
||||
if let Some(target) = ImplicitHasherType::new(self.cx, t) {
|
||||
self.found.push(target);
|
||||
|
|
@ -318,7 +318,7 @@ impl<'a, 'b, 'tcx> ImplicitHasherConstructorVisitor<'a, 'b, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b, 'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'a, 'b, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'_, '_, 'tcx> {
|
||||
type NestedFilter = nested_filter::OnlyBodies;
|
||||
|
||||
fn visit_body(&mut self, body: &Body<'tcx>) {
|
||||
|
|
|
|||
|
|
@ -226,7 +226,7 @@ struct SliceIndexLintingVisitor<'a, 'tcx> {
|
|||
max_suggested_slice: u64,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for SliceIndexLintingVisitor<'a, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for SliceIndexLintingVisitor<'_, 'tcx> {
|
||||
type NestedFilter = nested_filter::OnlyBodies;
|
||||
|
||||
fn nested_visit_map(&mut self) -> Self::Map {
|
||||
|
|
|
|||
|
|
@ -6,12 +6,12 @@ use rustc_errors::Applicability;
|
|||
use rustc_hir::FnRetTy::Return;
|
||||
use rustc_hir::intravisit::nested_filter::{self as hir_nested_filter, NestedFilter};
|
||||
use rustc_hir::intravisit::{
|
||||
Visitor, walk_fn_decl, walk_generic_param, walk_generics, walk_impl_item_ref, walk_item, walk_param_bound,
|
||||
walk_poly_trait_ref, walk_trait_ref, walk_ty,
|
||||
Visitor, walk_fn_decl, walk_generic_args, walk_generics, walk_impl_item_ref, walk_item, walk_param_bound,
|
||||
walk_poly_trait_ref, walk_trait_ref, walk_ty, walk_where_predicate,
|
||||
};
|
||||
use rustc_hir::{
|
||||
BareFnTy, BodyId, FnDecl, FnSig, GenericArg, GenericBound, GenericParam, GenericParamKind, Generics, Impl,
|
||||
ImplItem, ImplItemKind, Item, ItemKind, Lifetime, LifetimeName, LifetimeParamKind, Node, PolyTraitRef,
|
||||
BareFnTy, BodyId, FnDecl, FnSig, GenericArg, GenericArgs, GenericBound, GenericParam, GenericParamKind, Generics,
|
||||
Impl, ImplItem, ImplItemKind, Item, ItemKind, Lifetime, LifetimeName, LifetimeParamKind, Node, PolyTraitRef,
|
||||
PredicateOrigin, TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WherePredicate, lang_items,
|
||||
};
|
||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||
|
|
@ -21,7 +21,7 @@ use rustc_middle::lint::in_external_macro;
|
|||
use rustc_session::declare_lint_pass;
|
||||
use rustc_span::Span;
|
||||
use rustc_span::def_id::LocalDefId;
|
||||
use rustc_span::symbol::{Ident, Symbol, kw};
|
||||
use rustc_span::symbol::{Ident, kw};
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
declare_clippy_lint! {
|
||||
|
|
@ -191,45 +191,10 @@ fn check_fn_inner<'tcx>(
|
|||
if usages.iter().any(|usage| !usage.ident.span.eq_ctxt(span)) {
|
||||
return;
|
||||
}
|
||||
|
||||
let lts = elidable_lts
|
||||
.iter()
|
||||
// In principle, the result of the call to `Node::ident` could be `unwrap`ped, as `DefId` should refer to a
|
||||
// `Node::GenericParam`.
|
||||
.filter_map(|&def_id| cx.tcx.hir_node_by_def_id(def_id).ident())
|
||||
.map(|ident| ident.to_string())
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ");
|
||||
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
NEEDLESS_LIFETIMES,
|
||||
elidable_lts
|
||||
.iter()
|
||||
.map(|<| cx.tcx.def_span(lt))
|
||||
.chain(usages.iter().filter_map(|usage| {
|
||||
if let LifetimeName::Param(def_id) = usage.res
|
||||
&& elidable_lts.contains(&def_id)
|
||||
{
|
||||
return Some(usage.ident.span);
|
||||
}
|
||||
|
||||
None
|
||||
}))
|
||||
.collect_vec(),
|
||||
format!("the following explicit lifetimes could be elided: {lts}"),
|
||||
|diag| {
|
||||
if sig.header.is_async() {
|
||||
// async functions have usages whose spans point at the lifetime declaration which messes up
|
||||
// suggestions
|
||||
return;
|
||||
};
|
||||
|
||||
if let Some(suggestions) = elision_suggestions(cx, generics, &elidable_lts, &usages) {
|
||||
diag.multipart_suggestion("elide the lifetimes", suggestions, Applicability::MachineApplicable);
|
||||
}
|
||||
},
|
||||
);
|
||||
// async functions have usages whose spans point at the lifetime declaration which messes up
|
||||
// suggestions
|
||||
let include_suggestions = !sig.header.is_async();
|
||||
report_elidable_lifetimes(cx, generics, &elidable_lts, &usages, include_suggestions);
|
||||
}
|
||||
|
||||
if report_extra_lifetimes {
|
||||
|
|
@ -237,97 +202,6 @@ fn check_fn_inner<'tcx>(
|
|||
}
|
||||
}
|
||||
|
||||
fn elision_suggestions(
|
||||
cx: &LateContext<'_>,
|
||||
generics: &Generics<'_>,
|
||||
elidable_lts: &[LocalDefId],
|
||||
usages: &[Lifetime],
|
||||
) -> Option<Vec<(Span, String)>> {
|
||||
let explicit_params = generics
|
||||
.params
|
||||
.iter()
|
||||
.filter(|param| !param.is_elided_lifetime() && !param.is_impl_trait())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let mut suggestions = if elidable_lts.len() == explicit_params.len() {
|
||||
// if all the params are elided remove the whole generic block
|
||||
//
|
||||
// fn x<'a>() {}
|
||||
// ^^^^
|
||||
vec![(generics.span, String::new())]
|
||||
} else {
|
||||
elidable_lts
|
||||
.iter()
|
||||
.map(|&id| {
|
||||
let pos = explicit_params.iter().position(|param| param.def_id == id)?;
|
||||
let param = explicit_params.get(pos)?;
|
||||
|
||||
let span = if let Some(next) = explicit_params.get(pos + 1) {
|
||||
// fn x<'prev, 'a, 'next>() {}
|
||||
// ^^^^
|
||||
param.span.until(next.span)
|
||||
} else {
|
||||
// `pos` should be at least 1 here, because the param in position 0 would either have a `next`
|
||||
// param or would have taken the `elidable_lts.len() == explicit_params.len()` branch.
|
||||
let prev = explicit_params.get(pos - 1)?;
|
||||
|
||||
// fn x<'prev, 'a>() {}
|
||||
// ^^^^
|
||||
param.span.with_lo(prev.span.hi())
|
||||
};
|
||||
|
||||
Some((span, String::new()))
|
||||
})
|
||||
.collect::<Option<Vec<_>>>()?
|
||||
};
|
||||
|
||||
suggestions.extend(
|
||||
usages
|
||||
.iter()
|
||||
.filter(|usage| named_lifetime(usage).map_or(false, |id| elidable_lts.contains(&id)))
|
||||
.map(|usage| {
|
||||
match cx.tcx.parent_hir_node(usage.hir_id) {
|
||||
Node::Ty(Ty {
|
||||
kind: TyKind::Ref(..), ..
|
||||
}) => {
|
||||
// expand `&'a T` to `&'a T`
|
||||
// ^^ ^^^
|
||||
let span = cx.sess().source_map().span_extend_while_whitespace(usage.ident.span);
|
||||
|
||||
(span, String::new())
|
||||
},
|
||||
// `T<'a>` and `impl Foo + 'a` should be replaced by `'_`
|
||||
_ => (usage.ident.span, String::from("'_")),
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
Some(suggestions)
|
||||
}
|
||||
|
||||
// elision doesn't work for explicit self types, see rust-lang/rust#69064
|
||||
fn explicit_self_type<'tcx>(cx: &LateContext<'tcx>, func: &FnDecl<'tcx>, ident: Option<Ident>) -> bool {
|
||||
if let Some(ident) = ident
|
||||
&& ident.name == kw::SelfLower
|
||||
&& !func.implicit_self.has_implicit_self()
|
||||
&& let Some(self_ty) = func.inputs.first()
|
||||
{
|
||||
let mut visitor = RefVisitor::new(cx);
|
||||
visitor.visit_ty(self_ty);
|
||||
|
||||
!visitor.all_lts().is_empty()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn named_lifetime(lt: &Lifetime) -> Option<LocalDefId> {
|
||||
match lt.res {
|
||||
LifetimeName::Param(id) if !lt.is_anonymous() => Some(id),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn could_use_elision<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
func: &'tcx FnDecl<'_>,
|
||||
|
|
@ -450,6 +324,22 @@ fn allowed_lts_from(named_generics: &[GenericParam<'_>]) -> FxHashSet<LocalDefId
|
|||
.collect()
|
||||
}
|
||||
|
||||
// elision doesn't work for explicit self types, see rust-lang/rust#69064
|
||||
fn explicit_self_type<'tcx>(cx: &LateContext<'tcx>, func: &FnDecl<'tcx>, ident: Option<Ident>) -> bool {
|
||||
if let Some(ident) = ident
|
||||
&& ident.name == kw::SelfLower
|
||||
&& !func.implicit_self.has_implicit_self()
|
||||
&& let Some(self_ty) = func.inputs.first()
|
||||
{
|
||||
let mut visitor = RefVisitor::new(cx);
|
||||
visitor.visit_ty(self_ty);
|
||||
|
||||
!visitor.all_lts().is_empty()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// Number of times each named lifetime occurs in the given slice. Returns a vector to preserve
|
||||
/// relative order.
|
||||
#[must_use]
|
||||
|
|
@ -470,6 +360,13 @@ fn named_lifetime_occurrences(lts: &[Lifetime]) -> Vec<(LocalDefId, usize)> {
|
|||
occurrences
|
||||
}
|
||||
|
||||
fn named_lifetime(lt: &Lifetime) -> Option<LocalDefId> {
|
||||
match lt.res {
|
||||
LifetimeName::Param(id) if !lt.is_anonymous() => Some(id),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
struct RefVisitor<'a, 'tcx> {
|
||||
cx: &'a LateContext<'tcx>,
|
||||
lts: Vec<Lifetime>,
|
||||
|
|
@ -500,7 +397,7 @@ impl<'a, 'tcx> RefVisitor<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for RefVisitor<'_, 'tcx> {
|
||||
// for lifetimes as parameters of generics
|
||||
fn visit_lifetime(&mut self, lifetime: &'tcx Lifetime) {
|
||||
self.lts.push(*lifetime);
|
||||
|
|
@ -594,23 +491,43 @@ fn has_where_lifetimes<'tcx>(cx: &LateContext<'tcx>, generics: &'tcx Generics<'_
|
|||
false
|
||||
}
|
||||
|
||||
struct Usage {
|
||||
lifetime: Lifetime,
|
||||
in_where_predicate: bool,
|
||||
in_generics_arg: bool,
|
||||
}
|
||||
|
||||
struct LifetimeChecker<'cx, 'tcx, F> {
|
||||
cx: &'cx LateContext<'tcx>,
|
||||
map: FxHashMap<Symbol, Span>,
|
||||
map: FxHashMap<LocalDefId, Vec<Usage>>,
|
||||
where_predicate_depth: usize,
|
||||
generic_args_depth: usize,
|
||||
phantom: std::marker::PhantomData<F>,
|
||||
}
|
||||
|
||||
impl<'cx, 'tcx, F> LifetimeChecker<'cx, 'tcx, F> {
|
||||
fn new(cx: &'cx LateContext<'tcx>, map: FxHashMap<Symbol, Span>) -> LifetimeChecker<'cx, 'tcx, F> {
|
||||
fn new(cx: &'cx LateContext<'tcx>, generics: &'tcx Generics<'_>) -> LifetimeChecker<'cx, 'tcx, F> {
|
||||
let map = generics
|
||||
.params
|
||||
.iter()
|
||||
.filter_map(|par| match par.kind {
|
||||
GenericParamKind::Lifetime {
|
||||
kind: LifetimeParamKind::Explicit,
|
||||
} => Some((par.def_id, Vec::new())),
|
||||
_ => None,
|
||||
})
|
||||
.collect();
|
||||
Self {
|
||||
cx,
|
||||
map,
|
||||
where_predicate_depth: 0,
|
||||
generic_args_depth: 0,
|
||||
phantom: std::marker::PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'cx, 'tcx, F> Visitor<'tcx> for LifetimeChecker<'cx, 'tcx, F>
|
||||
impl<'tcx, F> Visitor<'tcx> for LifetimeChecker<'_, 'tcx, F>
|
||||
where
|
||||
F: NestedFilter<'tcx>,
|
||||
{
|
||||
|
|
@ -619,18 +536,27 @@ where
|
|||
|
||||
// for lifetimes as parameters of generics
|
||||
fn visit_lifetime(&mut self, lifetime: &'tcx Lifetime) {
|
||||
self.map.remove(&lifetime.ident.name);
|
||||
if let LifetimeName::Param(def_id) = lifetime.res
|
||||
&& let Some(usages) = self.map.get_mut(&def_id)
|
||||
{
|
||||
usages.push(Usage {
|
||||
lifetime: *lifetime,
|
||||
in_where_predicate: self.where_predicate_depth != 0,
|
||||
in_generics_arg: self.generic_args_depth != 0,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_generic_param(&mut self, param: &'tcx GenericParam<'_>) {
|
||||
// don't actually visit `<'a>` or `<'a: 'b>`
|
||||
// we've already visited the `'a` declarations and
|
||||
// don't want to spuriously remove them
|
||||
// `'b` in `'a: 'b` is useless unless used elsewhere in
|
||||
// a non-lifetime bound
|
||||
if let GenericParamKind::Type { .. } = param.kind {
|
||||
walk_generic_param(self, param);
|
||||
}
|
||||
fn visit_where_predicate(&mut self, predicate: &'tcx WherePredicate<'tcx>) {
|
||||
self.where_predicate_depth += 1;
|
||||
walk_where_predicate(self, predicate);
|
||||
self.where_predicate_depth -= 1;
|
||||
}
|
||||
|
||||
fn visit_generic_args(&mut self, generic_args: &'tcx GenericArgs<'tcx>) -> Self::Result {
|
||||
self.generic_args_depth += 1;
|
||||
walk_generic_args(self, generic_args);
|
||||
self.generic_args_depth -= 1;
|
||||
}
|
||||
|
||||
fn nested_visit_map(&mut self) -> Self::Map {
|
||||
|
|
@ -639,44 +565,28 @@ where
|
|||
}
|
||||
|
||||
fn report_extra_lifetimes<'tcx>(cx: &LateContext<'tcx>, func: &'tcx FnDecl<'_>, generics: &'tcx Generics<'_>) {
|
||||
let hs = generics
|
||||
.params
|
||||
.iter()
|
||||
.filter_map(|par| match par.kind {
|
||||
GenericParamKind::Lifetime {
|
||||
kind: LifetimeParamKind::Explicit,
|
||||
} => Some((par.name.ident().name, par.span)),
|
||||
_ => None,
|
||||
})
|
||||
.collect();
|
||||
let mut checker = LifetimeChecker::<hir_nested_filter::None>::new(cx, hs);
|
||||
let mut checker = LifetimeChecker::<hir_nested_filter::None>::new(cx, generics);
|
||||
|
||||
walk_generics(&mut checker, generics);
|
||||
walk_fn_decl(&mut checker, func);
|
||||
|
||||
for &v in checker.map.values() {
|
||||
span_lint(
|
||||
cx,
|
||||
EXTRA_UNUSED_LIFETIMES,
|
||||
v,
|
||||
"this lifetime isn't used in the function definition",
|
||||
);
|
||||
for (def_id, usages) in checker.map {
|
||||
if usages
|
||||
.iter()
|
||||
.all(|usage| usage.in_where_predicate && !usage.in_generics_arg)
|
||||
{
|
||||
span_lint(
|
||||
cx,
|
||||
EXTRA_UNUSED_LIFETIMES,
|
||||
cx.tcx.def_span(def_id),
|
||||
"this lifetime isn't used in the function definition",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn report_extra_impl_lifetimes<'tcx>(cx: &LateContext<'tcx>, impl_: &'tcx Impl<'_>) {
|
||||
let hs = impl_
|
||||
.generics
|
||||
.params
|
||||
.iter()
|
||||
.filter_map(|par| match par.kind {
|
||||
GenericParamKind::Lifetime {
|
||||
kind: LifetimeParamKind::Explicit,
|
||||
} => Some((par.name.ident().name, par.span)),
|
||||
_ => None,
|
||||
})
|
||||
.collect();
|
||||
let mut checker = LifetimeChecker::<middle_nested_filter::All>::new(cx, hs);
|
||||
let mut checker = LifetimeChecker::<middle_nested_filter::All>::new(cx, impl_.generics);
|
||||
|
||||
walk_generics(&mut checker, impl_.generics);
|
||||
if let Some(ref trait_ref) = impl_.of_trait {
|
||||
|
|
@ -687,9 +597,176 @@ fn report_extra_impl_lifetimes<'tcx>(cx: &LateContext<'tcx>, impl_: &'tcx Impl<'
|
|||
walk_impl_item_ref(&mut checker, item);
|
||||
}
|
||||
|
||||
for &v in checker.map.values() {
|
||||
span_lint(cx, EXTRA_UNUSED_LIFETIMES, v, "this lifetime isn't used in the impl");
|
||||
for (&def_id, usages) in &checker.map {
|
||||
if usages
|
||||
.iter()
|
||||
.all(|usage| usage.in_where_predicate && !usage.in_generics_arg)
|
||||
{
|
||||
span_lint(
|
||||
cx,
|
||||
EXTRA_UNUSED_LIFETIMES,
|
||||
cx.tcx.def_span(def_id),
|
||||
"this lifetime isn't used in the impl",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
report_elidable_impl_lifetimes(cx, impl_, &checker.map);
|
||||
}
|
||||
|
||||
// An `impl` lifetime is elidable if it satisfies the following conditions:
|
||||
// - It is used exactly once.
|
||||
// - That single use is not in `GenericArgs` in a `WherePredicate`. (Note that `GenericArgs` are
|
||||
// different from `GenericParam`s.)
|
||||
fn report_elidable_impl_lifetimes<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
impl_: &'tcx Impl<'_>,
|
||||
map: &FxHashMap<LocalDefId, Vec<Usage>>,
|
||||
) {
|
||||
let single_usages = map
|
||||
.iter()
|
||||
.filter_map(|(def_id, usages)| {
|
||||
if let [
|
||||
Usage {
|
||||
lifetime,
|
||||
in_where_predicate: false,
|
||||
..
|
||||
}
|
||||
| Usage {
|
||||
lifetime,
|
||||
in_generics_arg: false,
|
||||
..
|
||||
},
|
||||
] = usages.as_slice()
|
||||
{
|
||||
Some((def_id, lifetime))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if single_usages.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let (elidable_lts, usages): (Vec<_>, Vec<_>) = single_usages.into_iter().unzip();
|
||||
|
||||
report_elidable_lifetimes(cx, impl_.generics, &elidable_lts, &usages, true);
|
||||
}
|
||||
|
||||
/// Generate diagnostic messages for elidable lifetimes.
|
||||
fn report_elidable_lifetimes(
|
||||
cx: &LateContext<'_>,
|
||||
generics: &Generics<'_>,
|
||||
elidable_lts: &[LocalDefId],
|
||||
usages: &[Lifetime],
|
||||
include_suggestions: bool,
|
||||
) {
|
||||
let lts = elidable_lts
|
||||
.iter()
|
||||
// In principle, the result of the call to `Node::ident` could be `unwrap`ped, as `DefId` should refer to a
|
||||
// `Node::GenericParam`.
|
||||
.filter_map(|&def_id| cx.tcx.hir_node_by_def_id(def_id).ident())
|
||||
.map(|ident| ident.to_string())
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ");
|
||||
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
NEEDLESS_LIFETIMES,
|
||||
elidable_lts
|
||||
.iter()
|
||||
.map(|<| cx.tcx.def_span(lt))
|
||||
.chain(usages.iter().filter_map(|usage| {
|
||||
if let LifetimeName::Param(def_id) = usage.res
|
||||
&& elidable_lts.contains(&def_id)
|
||||
{
|
||||
return Some(usage.ident.span);
|
||||
}
|
||||
|
||||
None
|
||||
}))
|
||||
.collect_vec(),
|
||||
format!("the following explicit lifetimes could be elided: {lts}"),
|
||||
|diag| {
|
||||
if !include_suggestions {
|
||||
return;
|
||||
};
|
||||
|
||||
if let Some(suggestions) = elision_suggestions(cx, generics, elidable_lts, usages) {
|
||||
diag.multipart_suggestion("elide the lifetimes", suggestions, Applicability::MachineApplicable);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
fn elision_suggestions(
|
||||
cx: &LateContext<'_>,
|
||||
generics: &Generics<'_>,
|
||||
elidable_lts: &[LocalDefId],
|
||||
usages: &[Lifetime],
|
||||
) -> Option<Vec<(Span, String)>> {
|
||||
let explicit_params = generics
|
||||
.params
|
||||
.iter()
|
||||
.filter(|param| !param.is_elided_lifetime() && !param.is_impl_trait())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let mut suggestions = if elidable_lts.len() == explicit_params.len() {
|
||||
// if all the params are elided remove the whole generic block
|
||||
//
|
||||
// fn x<'a>() {}
|
||||
// ^^^^
|
||||
vec![(generics.span, String::new())]
|
||||
} else {
|
||||
elidable_lts
|
||||
.iter()
|
||||
.map(|&id| {
|
||||
let pos = explicit_params.iter().position(|param| param.def_id == id)?;
|
||||
let param = explicit_params.get(pos)?;
|
||||
|
||||
let span = if let Some(next) = explicit_params.get(pos + 1) {
|
||||
// fn x<'prev, 'a, 'next>() {}
|
||||
// ^^^^
|
||||
param.span.until(next.span)
|
||||
} else {
|
||||
// `pos` should be at least 1 here, because the param in position 0 would either have a `next`
|
||||
// param or would have taken the `elidable_lts.len() == explicit_params.len()` branch.
|
||||
let prev = explicit_params.get(pos - 1)?;
|
||||
|
||||
// fn x<'prev, 'a>() {}
|
||||
// ^^^^
|
||||
param.span.with_lo(prev.span.hi())
|
||||
};
|
||||
|
||||
Some((span, String::new()))
|
||||
})
|
||||
.collect::<Option<Vec<_>>>()?
|
||||
};
|
||||
|
||||
suggestions.extend(
|
||||
usages
|
||||
.iter()
|
||||
.filter(|usage| named_lifetime(usage).map_or(false, |id| elidable_lts.contains(&id)))
|
||||
.map(|usage| {
|
||||
match cx.tcx.parent_hir_node(usage.hir_id) {
|
||||
Node::Ty(Ty {
|
||||
kind: TyKind::Ref(..), ..
|
||||
}) => {
|
||||
// expand `&'a T` to `&'a T`
|
||||
// ^^ ^^^
|
||||
let span = cx.sess().source_map().span_extend_while_whitespace(usage.ident.span);
|
||||
|
||||
(span, String::new())
|
||||
},
|
||||
// `T<'a>` and `impl Foo + 'a` should be replaced by `'_`
|
||||
_ => (usage.ident.span, String::from("'_")),
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
Some(suggestions)
|
||||
}
|
||||
|
||||
struct BodyLifetimeChecker;
|
||||
|
|
|
|||
|
|
@ -209,7 +209,7 @@ fn build_manual_memcpy_suggestion<'tcx>(
|
|||
#[derive(Clone)]
|
||||
struct MinifyingSugg<'a>(Sugg<'a>);
|
||||
|
||||
impl<'a> Display for MinifyingSugg<'a> {
|
||||
impl Display for MinifyingSugg<'_> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
self.0.fmt(f)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -241,7 +241,7 @@ struct VarVisitor<'a, 'tcx> {
|
|||
prefer_mutable: bool,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> VarVisitor<'a, 'tcx> {
|
||||
impl<'tcx> VarVisitor<'_, 'tcx> {
|
||||
fn check(&mut self, idx: &'tcx Expr<'_>, seqexpr: &'tcx Expr<'_>, expr: &'tcx Expr<'_>) -> bool {
|
||||
if let ExprKind::Path(ref seqpath) = seqexpr.kind
|
||||
// the indexed container is referenced by a name
|
||||
|
|
@ -292,7 +292,7 @@ impl<'a, 'tcx> VarVisitor<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for VarVisitor<'_, 'tcx> {
|
||||
fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
|
||||
if let ExprKind::MethodCall(meth, args_0, [args_1, ..], _) = &expr.kind
|
||||
// a range index op
|
||||
|
|
|
|||
|
|
@ -123,7 +123,7 @@ impl<'a, 'tcx> SameItemPushVisitor<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for SameItemPushVisitor<'a, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for SameItemPushVisitor<'_, 'tcx> {
|
||||
fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
|
||||
match &expr.kind {
|
||||
// Non-determinism may occur ... don't give a lint
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ impl<'a, 'tcx> IncrementVisitor<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for IncrementVisitor<'a, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for IncrementVisitor<'_, 'tcx> {
|
||||
fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
|
||||
// If node is a variable
|
||||
if let Some(def_id) = path_to_local(expr) {
|
||||
|
|
@ -138,7 +138,7 @@ impl<'a, 'tcx> InitializeVisitor<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for InitializeVisitor<'a, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for InitializeVisitor<'_, 'tcx> {
|
||||
type NestedFilter = nested_filter::OnlyBodies;
|
||||
|
||||
fn visit_local(&mut self, l: &'tcx LetStmt<'_>) {
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ struct VarCollectorVisitor<'a, 'tcx> {
|
|||
skip: bool,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> VarCollectorVisitor<'a, 'tcx> {
|
||||
impl<'tcx> VarCollectorVisitor<'_, 'tcx> {
|
||||
fn insert_def_id(&mut self, ex: &'tcx Expr<'_>) {
|
||||
if let ExprKind::Path(ref qpath) = ex.kind
|
||||
&& let QPath::Resolved(None, _) = *qpath
|
||||
|
|
@ -103,7 +103,7 @@ impl<'a, 'tcx> VarCollectorVisitor<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for VarCollectorVisitor<'a, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for VarCollectorVisitor<'_, 'tcx> {
|
||||
fn visit_expr(&mut self, ex: &'tcx Expr<'_>) {
|
||||
match ex.kind {
|
||||
ExprKind::Path(_) => self.insert_def_id(ex),
|
||||
|
|
|
|||
|
|
@ -283,7 +283,7 @@ fn needs_mutable_borrow(cx: &LateContext<'_>, iter_expr: &IterExpr, loop_expr: &
|
|||
found_local: bool,
|
||||
used_after: bool,
|
||||
}
|
||||
impl<'a, 'b, 'tcx> Visitor<'tcx> for NestedLoopVisitor<'a, 'b, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for NestedLoopVisitor<'_, '_, 'tcx> {
|
||||
type NestedFilter = OnlyBodies;
|
||||
fn nested_visit_map(&mut self) -> Self::Map {
|
||||
self.cx.tcx.hir()
|
||||
|
|
|
|||
|
|
@ -149,7 +149,7 @@ fn is_public_macro(cx: &LateContext<'_>, def_id: LocalDefId) -> bool {
|
|||
&& !cx.tcx.is_doc_hidden(def_id)
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for BodyVisitor<'a, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for BodyVisitor<'_, 'tcx> {
|
||||
fn visit_stmt(&mut self, s: &'tcx Stmt<'tcx>) {
|
||||
let from_expn = s.span.from_expansion();
|
||||
if from_expn {
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ impl MacroUseImports {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for MacroUseImports {
|
||||
impl LateLintPass<'_> for MacroUseImports {
|
||||
fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
|
||||
if cx.sess().opts.edition >= Edition::Edition2018
|
||||
&& let hir::ItemKind::Use(path, _kind) = &item.kind
|
||||
|
|
|
|||
|
|
@ -741,7 +741,7 @@ enum MaybeBorrowedStmtKind<'a> {
|
|||
Owned(StmtKind<'a>),
|
||||
}
|
||||
|
||||
impl<'a> Clone for MaybeBorrowedStmtKind<'a> {
|
||||
impl Clone for MaybeBorrowedStmtKind<'_> {
|
||||
fn clone(&self) -> Self {
|
||||
match self {
|
||||
Self::Borrowed(t) => Self::Borrowed(t),
|
||||
|
|
|
|||
|
|
@ -203,7 +203,7 @@ fn find_stripping<'tcx>(
|
|||
results: Vec<Span>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for StrippingFinder<'a, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for StrippingFinder<'_, 'tcx> {
|
||||
fn visit_expr(&mut self, ex: &'tcx Expr<'_>) {
|
||||
if is_ref_str(self.cx, ex)
|
||||
&& let unref = peel_ref(ex)
|
||||
|
|
|
|||
|
|
@ -251,7 +251,7 @@ fn lint_map_unit_fn(
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for MapUnit {
|
||||
impl LateLintPass<'_> for MapUnit {
|
||||
fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &hir::Stmt<'_>) {
|
||||
if let hir::StmtKind::Semi(expr) = stmt.kind
|
||||
&& !stmt.span.from_expansion()
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ struct MatchExprVisitor<'a, 'tcx> {
|
|||
case_method: Option<CaseMethod>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for MatchExprVisitor<'a, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for MatchExprVisitor<'_, 'tcx> {
|
||||
fn visit_expr(&mut self, ex: &'tcx Expr<'_>) {
|
||||
match ex.kind {
|
||||
ExprKind::MethodCall(segment, receiver, [], _) if self.case_altered(segment.ident.as_str(), receiver) => {},
|
||||
|
|
@ -49,7 +49,7 @@ impl<'a, 'tcx> Visitor<'tcx> for MatchExprVisitor<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> MatchExprVisitor<'a, 'tcx> {
|
||||
impl MatchExprVisitor<'_, '_> {
|
||||
fn case_altered(&mut self, segment_ident: &str, receiver: &Expr<'_>) -> bool {
|
||||
if let Some(case_method) = get_case_method(segment_ident) {
|
||||
let ty = self.cx.typeck_results().expr_ty(receiver).peel_refs();
|
||||
|
|
|
|||
|
|
@ -96,13 +96,13 @@ where
|
|||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
struct RangeBound<'a, T>(T, BoundKind, &'a SpannedRange<T>);
|
||||
|
||||
impl<'a, T: Copy + Ord> PartialOrd for RangeBound<'a, T> {
|
||||
impl<T: Copy + Ord> PartialOrd for RangeBound<'_, T> {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Copy + Ord> Ord for RangeBound<'a, T> {
|
||||
impl<T: Copy + Ord> Ord for RangeBound<'_, T> {
|
||||
fn cmp(&self, RangeBound(other_value, other_kind, _): &Self) -> Ordering {
|
||||
let RangeBound(self_value, self_kind, _) = *self;
|
||||
(self_value, self_kind).cmp(&(*other_value, *other_kind))
|
||||
|
|
|
|||
|
|
@ -424,7 +424,7 @@ fn ty_has_erased_regions(ty: Ty<'_>) -> bool {
|
|||
ty.visit_with(&mut V).is_break()
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for SigDropHelper<'a, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for SigDropHelper<'_, 'tcx> {
|
||||
fn visit_expr(&mut self, ex: &'tcx Expr<'_>) {
|
||||
// We've emitted a lint on some neighborhood expression. That lint will suggest to move out the
|
||||
// _parent_ expression (not the expression itself). Since we decide to move out the parent
|
||||
|
|
@ -495,7 +495,7 @@ fn has_significant_drop_in_arms<'tcx>(cx: &LateContext<'tcx>, arms: &[&'tcx Expr
|
|||
helper.found_sig_drop_spans
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for ArmSigDropHelper<'a, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for ArmSigDropHelper<'_, 'tcx> {
|
||||
fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) {
|
||||
if self.sig_drop_checker.is_sig_drop_expr(ex) {
|
||||
self.found_sig_drop_spans.insert(ex.span);
|
||||
|
|
|
|||
|
|
@ -441,7 +441,7 @@ struct UsedCountVisitor<'a, 'tcx> {
|
|||
count: usize,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for UsedCountVisitor<'a, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for UsedCountVisitor<'_, 'tcx> {
|
||||
type NestedFilter = nested_filter::OnlyBodies;
|
||||
|
||||
fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
|
||||
|
|
|
|||
|
|
@ -130,7 +130,7 @@ struct UnwrapVisitor<'a, 'tcx> {
|
|||
identifiers: FxHashSet<HirId>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for UnwrapVisitor<'a, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for UnwrapVisitor<'_, 'tcx> {
|
||||
type NestedFilter = nested_filter::All;
|
||||
|
||||
fn visit_path(&mut self, path: &Path<'tcx>, _: HirId) {
|
||||
|
|
@ -154,7 +154,7 @@ struct ReferenceVisitor<'a, 'tcx> {
|
|||
unwrap_or_span: Span,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for ReferenceVisitor<'a, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for ReferenceVisitor<'_, 'tcx> {
|
||||
type NestedFilter = nested_filter::All;
|
||||
type Result = ControlFlow<()>;
|
||||
fn visit_expr(&mut self, expr: &'tcx rustc_hir::Expr<'_>) -> ControlFlow<()> {
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ struct CloneOrCopyVisitor<'cx, 'tcx> {
|
|||
references_to_binding: Vec<(Span, String)>,
|
||||
}
|
||||
|
||||
impl<'cx, 'tcx> Visitor<'tcx> for CloneOrCopyVisitor<'cx, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for CloneOrCopyVisitor<'_, 'tcx> {
|
||||
type NestedFilter = nested_filter::OnlyBodies;
|
||||
|
||||
fn nested_visit_map(&mut self) -> Self::Map {
|
||||
|
|
@ -123,7 +123,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for CloneOrCopyVisitor<'cx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'cx, 'tcx> CloneOrCopyVisitor<'cx, 'tcx> {
|
||||
impl<'tcx> CloneOrCopyVisitor<'_, 'tcx> {
|
||||
fn is_binding(&self, expr: &Expr<'tcx>) -> bool {
|
||||
self.binding_hir_ids
|
||||
.iter()
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ struct DivergenceVisitor<'a, 'tcx> {
|
|||
cx: &'a LateContext<'tcx>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> DivergenceVisitor<'a, 'tcx> {
|
||||
impl<'tcx> DivergenceVisitor<'_, 'tcx> {
|
||||
fn maybe_walk_expr(&mut self, e: &'tcx Expr<'_>) {
|
||||
match e.kind {
|
||||
ExprKind::Closure(..) | ExprKind::If(..) | ExprKind::Loop(..) => {},
|
||||
|
|
@ -148,7 +148,7 @@ fn stmt_might_diverge(stmt: &Stmt<'_>) -> bool {
|
|||
!matches!(stmt.kind, StmtKind::Item(..))
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for DivergenceVisitor<'a, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for DivergenceVisitor<'_, 'tcx> {
|
||||
fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
|
||||
match e.kind {
|
||||
// fix #10776
|
||||
|
|
@ -321,7 +321,7 @@ struct ReadVisitor<'a, 'tcx> {
|
|||
last_expr: &'tcx Expr<'tcx>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for ReadVisitor<'a, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for ReadVisitor<'_, 'tcx> {
|
||||
fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
|
||||
if expr.hir_id == self.last_expr.hir_id {
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ pub struct MutVisitor<'a, 'tcx> {
|
|||
cx: &'a LateContext<'tcx>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> intravisit::Visitor<'tcx> for MutVisitor<'a, 'tcx> {
|
||||
impl<'tcx> intravisit::Visitor<'tcx> for MutVisitor<'_, 'tcx> {
|
||||
fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) {
|
||||
if in_external_macro(self.cx.sess(), expr.span) {
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ impl<'a, 'tcx> MutArgVisitor<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for MutArgVisitor<'a, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for MutArgVisitor<'_, 'tcx> {
|
||||
type NestedFilter = nested_filter::OnlyBodies;
|
||||
|
||||
fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
|
||||
|
|
|
|||
|
|
@ -133,7 +133,7 @@ struct RetCollector {
|
|||
loop_depth: u16,
|
||||
}
|
||||
|
||||
impl<'tcx> Visitor<'tcx> for RetCollector {
|
||||
impl Visitor<'_> for RetCollector {
|
||||
fn visit_expr(&mut self, expr: &Expr<'_>) {
|
||||
match expr.kind {
|
||||
ExprKind::Ret(..) => {
|
||||
|
|
|
|||
|
|
@ -311,7 +311,7 @@ struct MutablyUsedVariablesCtxt<'tcx> {
|
|||
tcx: TyCtxt<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> MutablyUsedVariablesCtxt<'tcx> {
|
||||
impl MutablyUsedVariablesCtxt<'_> {
|
||||
fn add_mutably_used_var(&mut self, used_id: HirId) {
|
||||
self.mutably_used_vars.insert(used_id);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ struct SimilarNamesLocalVisitor<'a, 'tcx> {
|
|||
single_char_names: Vec<Vec<Ident>>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> SimilarNamesLocalVisitor<'a, 'tcx> {
|
||||
impl SimilarNamesLocalVisitor<'_, '_> {
|
||||
fn check_single_char_names(&self) {
|
||||
if self.single_char_names.last().map(Vec::len) == Some(0) {
|
||||
return;
|
||||
|
|
@ -152,7 +152,7 @@ fn chars_are_similar(a: char, b: char) -> bool {
|
|||
|
||||
struct SimilarNamesNameVisitor<'a, 'tcx, 'b>(&'b mut SimilarNamesLocalVisitor<'a, 'tcx>);
|
||||
|
||||
impl<'a, 'tcx, 'b> Visitor<'tcx> for SimilarNamesNameVisitor<'a, 'tcx, 'b> {
|
||||
impl<'tcx> Visitor<'tcx> for SimilarNamesNameVisitor<'_, 'tcx, '_> {
|
||||
fn visit_pat(&mut self, pat: &'tcx Pat) {
|
||||
match pat.kind {
|
||||
PatKind::Ident(_, ident, _) => {
|
||||
|
|
@ -189,7 +189,7 @@ fn allowed_to_be_similar(interned_name: &str, list: &[&str]) -> bool {
|
|||
.any(|&name| interned_name.starts_with(name) || interned_name.ends_with(name))
|
||||
}
|
||||
|
||||
impl<'a, 'tcx, 'b> SimilarNamesNameVisitor<'a, 'tcx, 'b> {
|
||||
impl SimilarNamesNameVisitor<'_, '_, '_> {
|
||||
fn check_short_ident(&mut self, ident: Ident) {
|
||||
// Ignore shadowing
|
||||
if self
|
||||
|
|
@ -329,7 +329,7 @@ impl<'a, 'tcx, 'b> SimilarNamesNameVisitor<'a, 'tcx, 'b> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b> SimilarNamesLocalVisitor<'a, 'b> {
|
||||
impl SimilarNamesLocalVisitor<'_, '_> {
|
||||
/// ensure scoping rules work
|
||||
fn apply<F: for<'c> Fn(&'c mut Self)>(&mut self, f: F) {
|
||||
let n = self.names.len();
|
||||
|
|
@ -340,7 +340,7 @@ impl<'a, 'b> SimilarNamesLocalVisitor<'a, 'b> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for SimilarNamesLocalVisitor<'a, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for SimilarNamesLocalVisitor<'_, 'tcx> {
|
||||
fn visit_local(&mut self, local: &'tcx Local) {
|
||||
if let Some((init, els)) = &local.kind.init_else_opt() {
|
||||
self.apply(|this| walk_expr(this, init));
|
||||
|
|
|
|||
|
|
@ -159,7 +159,7 @@ struct NonSendField<'tcx> {
|
|||
generic_params: Vec<Ty<'tcx>>,
|
||||
}
|
||||
|
||||
impl<'tcx> NonSendField<'tcx> {
|
||||
impl NonSendField<'_> {
|
||||
fn generic_params_string(&self) -> String {
|
||||
self.generic_params
|
||||
.iter()
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@ pub struct PassByRefOrValue {
|
|||
avoid_breaking_exported_api: bool,
|
||||
}
|
||||
|
||||
impl<'tcx> PassByRefOrValue {
|
||||
impl PassByRefOrValue {
|
||||
pub fn new(tcx: TyCtxt<'_>, conf: &'static Conf) -> Self {
|
||||
let ref_min_size = conf.trivial_copy_size_limit.unwrap_or_else(|| {
|
||||
let bit_width = u64::from(tcx.sess.target.pointer_width);
|
||||
|
|
@ -130,7 +130,7 @@ impl<'tcx> PassByRefOrValue {
|
|||
}
|
||||
}
|
||||
|
||||
fn check_poly_fn(&mut self, cx: &LateContext<'tcx>, def_id: LocalDefId, decl: &FnDecl<'_>, span: Option<Span>) {
|
||||
fn check_poly_fn(&mut self, cx: &LateContext<'_>, def_id: LocalDefId, decl: &FnDecl<'_>, span: Option<Span>) {
|
||||
if self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(def_id) {
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ struct PathbufPushSearcher<'tcx> {
|
|||
err_span: Span,
|
||||
}
|
||||
|
||||
impl<'tcx> PathbufPushSearcher<'tcx> {
|
||||
impl PathbufPushSearcher<'_> {
|
||||
/// Try to generate a suggestion with `PathBuf::from`.
|
||||
/// Returns `None` if the suggestion would be invalid.
|
||||
fn gen_pathbuf_from(&self, cx: &LateContext<'_>) -> Option<String> {
|
||||
|
|
|
|||
|
|
@ -228,7 +228,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall {
|
|||
path: &'tcx hir::Path<'tcx>,
|
||||
count: usize,
|
||||
}
|
||||
impl<'a, 'tcx> Visitor<'tcx> for ClosureUsageCount<'a, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for ClosureUsageCount<'_, 'tcx> {
|
||||
type NestedFilter = nested_filter::OnlyBodies;
|
||||
|
||||
fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
|
||||
|
|
|
|||
|
|
@ -140,7 +140,7 @@ enum RetReplacement<'tcx> {
|
|||
Expr(Cow<'tcx, str>, Applicability),
|
||||
}
|
||||
|
||||
impl<'tcx> RetReplacement<'tcx> {
|
||||
impl RetReplacement<'_> {
|
||||
fn sugg_help(&self) -> &'static str {
|
||||
match self {
|
||||
Self::Empty | Self::Expr(..) => "remove `return`",
|
||||
|
|
@ -158,7 +158,7 @@ impl<'tcx> RetReplacement<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Display for RetReplacement<'tcx> {
|
||||
impl Display for RetReplacement<'_> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::Empty => write!(f, ""),
|
||||
|
|
|
|||
|
|
@ -249,7 +249,7 @@ impl<'ap, 'lc, 'others, 'stmt, 'tcx> StmtsChecker<'ap, 'lc, 'others, 'stmt, 'tcx
|
|||
}
|
||||
}
|
||||
|
||||
impl<'ap, 'lc, 'others, 'stmt, 'tcx> Visitor<'tcx> for StmtsChecker<'ap, 'lc, 'others, 'stmt, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for StmtsChecker<'_, '_, '_, '_, 'tcx> {
|
||||
fn visit_block(&mut self, block: &'tcx hir::Block<'tcx>) {
|
||||
self.ap.curr_block_hir_id = block.hir_id;
|
||||
self.ap.curr_block_span = block.span;
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ struct ImportUsageVisitor {
|
|||
imports_referenced_with_self: Vec<Symbol>,
|
||||
}
|
||||
|
||||
impl<'tcx> Visitor<'tcx> for ImportUsageVisitor {
|
||||
impl Visitor<'_> for ImportUsageVisitor {
|
||||
fn visit_expr(&mut self, expr: &Expr) {
|
||||
if let ExprKind::Path(_, path) = &expr.kind
|
||||
&& path.segments.len() > 1
|
||||
|
|
|
|||
|
|
@ -229,7 +229,7 @@ struct VectorInitializationVisitor<'a, 'tcx> {
|
|||
initialization_found: bool,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> {
|
||||
impl<'tcx> VectorInitializationVisitor<'_, 'tcx> {
|
||||
/// Checks if the given expression is extending a vector with `repeat(0).take(..)`
|
||||
fn search_slow_extend_filling(&mut self, expr: &'tcx Expr<'_>) {
|
||||
if self.initialization_found
|
||||
|
|
@ -299,7 +299,7 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for VectorInitializationVisitor<'a, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for VectorInitializationVisitor<'_, 'tcx> {
|
||||
fn visit_stmt(&mut self, stmt: &'tcx Stmt<'_>) {
|
||||
if self.initialization_found {
|
||||
match stmt.kind {
|
||||
|
|
|
|||
|
|
@ -332,7 +332,7 @@ struct IndexBinding<'a, 'tcx> {
|
|||
applicability: &'a mut Applicability,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> IndexBinding<'a, 'tcx> {
|
||||
impl<'tcx> IndexBinding<'_, 'tcx> {
|
||||
fn snippet_index_bindings(&mut self, exprs: &[&'tcx Expr<'tcx>]) -> String {
|
||||
let mut bindings = FxHashSet::default();
|
||||
for expr in exprs {
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ struct AsyncFnVisitor<'a, 'tcx> {
|
|||
async_depth: usize,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for AsyncFnVisitor<'a, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for AsyncFnVisitor<'_, 'tcx> {
|
||||
type NestedFilter = nested_filter::OnlyBodies;
|
||||
|
||||
fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) {
|
||||
|
|
|
|||
|
|
@ -235,7 +235,7 @@ impl<'tcx> Delegate<'tcx> for MutationVisitor<'tcx> {
|
|||
fn fake_read(&mut self, _: &PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> UnwrappableVariablesVisitor<'a, 'tcx> {
|
||||
impl<'tcx> UnwrappableVariablesVisitor<'_, 'tcx> {
|
||||
fn visit_branch(
|
||||
&mut self,
|
||||
if_expr: &'tcx Expr<'_>,
|
||||
|
|
@ -288,7 +288,7 @@ fn consume_option_as_ref<'tcx>(expr: &'tcx Expr<'tcx>) -> (&'tcx Expr<'tcx>, Opt
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'a, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'_, 'tcx> {
|
||||
type NestedFilter = nested_filter::OnlyBodies;
|
||||
|
||||
fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
|
||||
|
|
|
|||
|
|
@ -280,7 +280,7 @@ struct SkipTyCollector {
|
|||
types_to_skip: Vec<HirId>,
|
||||
}
|
||||
|
||||
impl<'tcx> Visitor<'tcx> for SkipTyCollector {
|
||||
impl Visitor<'_> for SkipTyCollector {
|
||||
fn visit_infer(&mut self, inf: &hir::InferArg) {
|
||||
self.types_to_skip.push(inf.hir_id);
|
||||
|
||||
|
|
|
|||
|
|
@ -270,7 +270,7 @@ struct LintCollector<'a, 'tcx> {
|
|||
cx: &'a LateContext<'tcx>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for LintCollector<'a, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for LintCollector<'_, 'tcx> {
|
||||
type NestedFilter = nested_filter::All;
|
||||
|
||||
fn visit_path(&mut self, path: &Path<'_>, _: HirId) {
|
||||
|
|
|
|||
|
|
@ -118,7 +118,7 @@ enum WaitFinder<'a, 'tcx> {
|
|||
Found(&'a LateContext<'tcx>, HirId),
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for WaitFinder<'a, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for WaitFinder<'_, 'tcx> {
|
||||
type Result = ControlFlow<BreakReason>;
|
||||
|
||||
fn visit_local(&mut self, l: &'tcx LetStmt<'tcx>) -> Self::Result {
|
||||
|
|
@ -300,7 +300,7 @@ struct ExitPointFinder<'a, 'tcx> {
|
|||
|
||||
struct ExitCallFound;
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for ExitPointFinder<'a, 'tcx> {
|
||||
impl<'tcx> Visitor<'tcx> for ExitPointFinder<'_, 'tcx> {
|
||||
type Result = ControlFlow<ExitCallFound>;
|
||||
|
||||
fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) -> Self::Result {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue