Split needless_lifetime '_ suggestions into elidable_lifetime_names (#13960)
Fixes https://github.com/rust-lang/rust-clippy/issues/13514 changelog: Added [`elidable_lifetime_names`] to `pedantic` (Split off from [`needless_lifetime`] for suggestions with `'_`) [#13960](https://github.com/rust-lang/rust-clippy/pull/13960) changelog: Enhancement: [`needless_lifetime`] No longer lints for elidable lifetimes `'_`, use [`elidable_lifetime_names`] to lint these. [#13960](https://github.com/rust-lang/rust-clippy/pull/13960)
This commit is contained in:
commit
f50266a423
14 changed files with 687 additions and 637 deletions
|
|
@ -274,6 +274,7 @@ pub static LINTS: &[&crate::LintInfo] = &[
|
|||
crate::let_underscore::LET_UNDERSCORE_MUST_USE_INFO,
|
||||
crate::let_underscore::LET_UNDERSCORE_UNTYPED_INFO,
|
||||
crate::let_with_type_underscore::LET_WITH_TYPE_UNDERSCORE_INFO,
|
||||
crate::lifetimes::ELIDABLE_LIFETIME_NAMES_INFO,
|
||||
crate::lifetimes::EXTRA_UNUSED_LIFETIMES_INFO,
|
||||
crate::lifetimes::NEEDLESS_LIFETIMES_INFO,
|
||||
crate::lines_filter_map_ok::LINES_FILTER_MAP_OK_INFO,
|
||||
|
|
|
|||
|
|
@ -38,8 +38,8 @@ declare_clippy_lint! {
|
|||
/// them leads to more readable code.
|
||||
///
|
||||
/// ### Known problems
|
||||
/// - We bail out if the function has a `where` clause where lifetimes
|
||||
/// are mentioned due to potential false positives.
|
||||
/// This lint ignores functions with `where` clauses that reference
|
||||
/// lifetimes to prevent false positives.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```no_run
|
||||
|
|
@ -62,6 +62,38 @@ declare_clippy_lint! {
|
|||
would allow omitting them"
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Checks for lifetime annotations which can be replaced with anonymous lifetimes (`'_`).
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// The additional lifetimes can make the code look more complicated.
|
||||
///
|
||||
/// ### Known problems
|
||||
/// This lint ignores functions with `where` clauses that reference
|
||||
/// lifetimes to prevent false positives.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```no_run
|
||||
/// # use std::str::Chars;
|
||||
/// fn f<'a>(x: &'a str) -> Chars<'a> {
|
||||
/// x.chars()
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```no_run
|
||||
/// # use std::str::Chars;
|
||||
/// fn f(x: &str) -> Chars<'_> {
|
||||
/// x.chars()
|
||||
/// }
|
||||
/// ```
|
||||
#[clippy::version = "1.84.0"]
|
||||
pub ELIDABLE_LIFETIME_NAMES,
|
||||
pedantic,
|
||||
"lifetime name that can be replaced with the anonymous lifetime"
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Checks for lifetimes in generics that are never used
|
||||
|
|
@ -104,7 +136,11 @@ impl Lifetimes {
|
|||
}
|
||||
}
|
||||
|
||||
impl_lint_pass!(Lifetimes => [NEEDLESS_LIFETIMES, EXTRA_UNUSED_LIFETIMES]);
|
||||
impl_lint_pass!(Lifetimes => [
|
||||
NEEDLESS_LIFETIMES,
|
||||
ELIDABLE_LIFETIME_NAMES,
|
||||
EXTRA_UNUSED_LIFETIMES,
|
||||
]);
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for Lifetimes {
|
||||
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
|
||||
|
|
@ -746,6 +782,15 @@ fn report_elidable_impl_lifetimes<'tcx>(
|
|||
report_elidable_lifetimes(cx, impl_.generics, &elidable_lts, &usages, true);
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
enum ElidableUsage {
|
||||
/// Used in a ref (`&'a T`), can be removed
|
||||
Ref(Span),
|
||||
/// Used as a generic param (`T<'a>`) or an impl lifetime (`impl T + 'a`), can be replaced
|
||||
/// with `'_`
|
||||
Other(Span),
|
||||
}
|
||||
|
||||
/// Generate diagnostic messages for elidable lifetimes.
|
||||
fn report_elidable_lifetimes(
|
||||
cx: &LateContext<'_>,
|
||||
|
|
@ -763,9 +808,29 @@ fn report_elidable_lifetimes(
|
|||
.collect::<Vec<_>>()
|
||||
.join(", ");
|
||||
|
||||
let elidable_usages: Vec<ElidableUsage> = usages
|
||||
.iter()
|
||||
.filter(|usage| named_lifetime(usage).is_some_and(|id| elidable_lts.contains(&id)))
|
||||
.map(|usage| match cx.tcx.parent_hir_node(usage.hir_id) {
|
||||
Node::Ty(Ty {
|
||||
kind: TyKind::Ref(..), ..
|
||||
}) => ElidableUsage::Ref(usage.ident.span),
|
||||
_ => ElidableUsage::Other(usage.ident.span),
|
||||
})
|
||||
.collect();
|
||||
|
||||
let lint = if elidable_usages
|
||||
.iter()
|
||||
.any(|usage| matches!(usage, ElidableUsage::Other(_)))
|
||||
{
|
||||
ELIDABLE_LIFETIME_NAMES
|
||||
} else {
|
||||
NEEDLESS_LIFETIMES
|
||||
};
|
||||
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
NEEDLESS_LIFETIMES,
|
||||
lint,
|
||||
elidable_lts
|
||||
.iter()
|
||||
.map(|<| cx.tcx.def_span(lt))
|
||||
|
|
@ -785,7 +850,7 @@ fn report_elidable_lifetimes(
|
|||
return;
|
||||
}
|
||||
|
||||
if let Some(suggestions) = elision_suggestions(cx, generics, elidable_lts, usages) {
|
||||
if let Some(suggestions) = elision_suggestions(cx, generics, elidable_lts, &elidable_usages) {
|
||||
diag.multipart_suggestion("elide the lifetimes", suggestions, Applicability::MachineApplicable);
|
||||
}
|
||||
},
|
||||
|
|
@ -796,7 +861,7 @@ fn elision_suggestions(
|
|||
cx: &LateContext<'_>,
|
||||
generics: &Generics<'_>,
|
||||
elidable_lts: &[LocalDefId],
|
||||
usages: &[Lifetime],
|
||||
usages: &[ElidableUsage],
|
||||
) -> Option<Vec<(Span, String)>> {
|
||||
let explicit_params = generics
|
||||
.params
|
||||
|
|
@ -836,26 +901,21 @@ fn elision_suggestions(
|
|||
.collect::<Option<Vec<_>>>()?
|
||||
};
|
||||
|
||||
suggestions.extend(
|
||||
usages
|
||||
.iter()
|
||||
.filter(|usage| named_lifetime(usage).is_some_and(|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);
|
||||
suggestions.extend(usages.iter().map(|&usage| {
|
||||
match usage {
|
||||
ElidableUsage::Ref(span) => {
|
||||
// expand `&'a T` to `&'a T`
|
||||
// ^^ ^^^
|
||||
let span = cx.sess().source_map().span_extend_while_whitespace(span);
|
||||
|
||||
(span, String::new())
|
||||
},
|
||||
// `T<'a>` and `impl Foo + 'a` should be replaced by `'_`
|
||||
_ => (usage.ident.span, String::from("'_")),
|
||||
}
|
||||
}),
|
||||
);
|
||||
(span, String::new())
|
||||
},
|
||||
ElidableUsage::Other(span) => {
|
||||
// `T<'a>` and `impl Foo + 'a` should be replaced by `'_`
|
||||
(span, String::from("'_"))
|
||||
},
|
||||
}
|
||||
}));
|
||||
|
||||
Some(suggestions)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue