-use crate::utils::paths;
-use crate::utils::{get_trait_def_id, in_macro, span_lint, trait_ref_of_method};
+use clippy_utils::diagnostics::span_lint;
+use clippy_utils::{in_macro, trait_ref_of_method};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir::intravisit::{
walk_fn_decl, walk_generic_param, walk_generics, walk_item, walk_param_bound, walk_poly_trait_ref, walk_ty,
use rustc_hir::FnRetTy::Return;
use rustc_hir::{
BareFnTy, BodyId, FnDecl, GenericArg, GenericBound, GenericParam, GenericParamKind, Generics, ImplItem,
- ImplItemKind, Item, ItemKind, Lifetime, LifetimeName, ParamName, PolyTraitRef, TraitBoundModifier, TraitFn,
- TraitItem, TraitItemKind, Ty, TyKind, WhereClause, WherePredicate,
+ ImplItemKind, Item, ItemKind, LangItem, Lifetime, LifetimeName, ParamName, PolyTraitRef, TraitBoundModifier,
+ TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WhereClause, WherePredicate,
};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::hir::map::Map;
use rustc_span::symbol::{kw, Symbol};
declare_clippy_lint! {
- /// **What it does:** Checks for lifetime annotations which can be removed by
+ /// ### What it does
+ /// Checks for lifetime annotations which can be removed by
/// relying on lifetime elision.
///
- /// **Why is this bad?** The additional lifetimes make the code look more
+ /// ### Why is this bad?
+ /// The additional lifetimes make the code look more
/// complicated, while there is nothing out of the ordinary going on. Removing
/// them leads to more readable code.
///
- /// **Known problems:**
+ /// ### Known problems
/// - We bail out if the function has a `where` clause where lifetimes
/// are mentioned due to potenial false positives.
/// - Lifetime bounds such as `impl Foo + 'a` and `T: 'a` must be elided with the
/// placeholder notation `'_` because the fully elided notation leaves the type bound to `'static`.
///
- /// **Example:**
+ /// ### Example
/// ```rust
/// // Bad: unnecessary lifetime annotations
/// fn in_and_out<'a>(x: &'a u8, y: u8) -> &'a u8 {
}
declare_clippy_lint! {
- /// **What it does:** Checks for lifetimes in generics that are never used
+ /// ### What it does
+ /// Checks for lifetimes in generics that are never used
/// anywhere else.
///
- /// **Why is this bad?** The additional lifetimes make the code look more
+ /// ### Why is this bad?
+ /// The additional lifetimes make the code look more
/// complicated, while there is nothing out of the ordinary going on. Removing
/// them leads to more readable code.
///
- /// **Known problems:** None.
- ///
- /// **Example:**
+ /// ### Example
/// ```rust
/// // Bad: unnecessary lifetimes
/// fn unused_lifetime<'a>(x: u8) {
impl<'tcx> LateLintPass<'tcx> for Lifetimes {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
if let ItemKind::Fn(ref sig, ref generics, id) = item.kind {
- check_fn_inner(cx, &sig.decl, Some(id), generics, item.span, true);
+ check_fn_inner(cx, sig.decl, Some(id), generics, item.span, true);
}
}
fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) {
if let ImplItemKind::Fn(ref sig, id) = item.kind {
- let report_extra_lifetimes = trait_ref_of_method(cx, item.hir_id).is_none();
+ let report_extra_lifetimes = trait_ref_of_method(cx, item.hir_id()).is_none();
check_fn_inner(
cx,
- &sig.decl,
+ sig.decl,
Some(id),
&item.generics,
item.span,
TraitFn::Required(_) => None,
TraitFn::Provided(id) => Some(id),
};
- check_fn_inner(cx, &sig.decl, body, &item.generics, item.span, true);
+ check_fn_inner(cx, sig.decl, body, &item.generics, item.span, true);
}
}
}
.last()
.expect("a path must have at least one segment")
.args;
- if let Some(ref params) = *params {
+ if let Some(params) = *params {
let lifetimes = params.args.iter().filter_map(|arg| match arg {
GenericArg::Lifetime(lt) => Some(lt),
_ => None,
}
}
}
- if could_use_elision(cx, decl, body, &generics.params) {
+ if could_use_elision(cx, decl, body, generics.params) {
span_lint(
cx,
NEEDLESS_LIFETIMES,
input_visitor.visit_ty(arg);
}
// extract lifetimes in output type
- if let Return(ref ty) = func.output {
+ if let Return(ty) = func.output {
output_visitor.visit_ty(ty);
}
for lt in named_generics {
- input_visitor.visit_generic_param(lt)
+ input_visitor.visit_generic_param(lt);
}
if input_visitor.abort() || output_visitor.abort() {
lts.iter().collect::<FxHashSet<_>>().len()
}
-const CLOSURE_TRAIT_BOUNDS: [&[&str]; 3] = [&paths::FN, &paths::FN_MUT, &paths::FN_ONCE];
+const CLOSURE_TRAIT_BOUNDS: [LangItem; 3] = [LangItem::Fn, LangItem::FnMut, LangItem::FnOnce];
/// A visitor usable for `rustc_front::visit::walk_ty()`.
struct RefVisitor<'a, 'tcx> {
fn visit_poly_trait_ref(&mut self, poly_tref: &'tcx PolyTraitRef<'tcx>, tbm: TraitBoundModifier) {
let trait_ref = &poly_tref.trait_ref;
- if CLOSURE_TRAIT_BOUNDS
- .iter()
- .any(|trait_path| trait_ref.trait_def_id() == get_trait_def_id(self.cx, trait_path))
- {
+ if CLOSURE_TRAIT_BOUNDS.iter().any(|&item| {
+ self.cx
+ .tcx
+ .lang_items()
+ .require(item)
+ .map_or(false, |id| Some(id) == trait_ref.trait_def_id())
+ }) {
let mut sub_visitor = RefVisitor::new(self.cx);
sub_visitor.visit_trait_ref(trait_ref);
self.nested_elision_site_lts.append(&mut sub_visitor.all_lts());
match ty.kind {
TyKind::OpaqueDef(item, _) => {
let map = self.cx.tcx.hir();
- let item = map.expect_item(item.id);
+ let item = map.item(item);
walk_item(self, item);
walk_ty(self, ty);
},
self.nested_elision_site_lts.append(&mut sub_visitor.all_lts());
return;
},
- TyKind::TraitObject(bounds, ref lt) => {
+ TyKind::TraitObject(bounds, ref lt, _) => {
if !lt.is_elided() {
self.unelided_trait_object_lifetime = true;
}
// a predicate like F: Trait or F: for<'a> Trait<'a>
let mut visitor = RefVisitor::new(cx);
// walk the type F, it may not contain LT refs
- walk_ty(&mut visitor, &pred.bounded_ty);
+ walk_ty(&mut visitor, pred.bounded_ty);
if !visitor.all_lts().is_empty() {
return true;
}
// if the bounds define new lifetimes, they are fine to occur
- let allowed_lts = allowed_lts_from(&pred.bound_generic_params);
+ let allowed_lts = allowed_lts_from(pred.bound_generic_params);
// now walk the bounds
for bound in pred.bounds.iter() {
walk_param_bound(&mut visitor, bound);
},
WherePredicate::EqPredicate(ref pred) => {
let mut visitor = RefVisitor::new(cx);
- walk_ty(&mut visitor, &pred.lhs_ty);
- walk_ty(&mut visitor, &pred.rhs_ty);
+ walk_ty(&mut visitor, pred.lhs_ty);
+ walk_ty(&mut visitor, pred.rhs_ty);
if !visitor.lts.is_empty() {
return true;
}
// `'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)
+ walk_generic_param(self, param);
}
}
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
// for lifetimes as parameters of generics
fn visit_lifetime(&mut self, lifetime: &'tcx Lifetime) {
- if lifetime.name.ident().name != kw::Invalid && lifetime.name.ident().name != kw::StaticLifetime {
+ if lifetime.name.ident().name != kw::Empty && lifetime.name.ident().name != kw::StaticLifetime {
self.lifetimes_used_in_body = true;
}
}