diff --git a/CHANGELOG.md b/CHANGELOG.md index 8e31e8f0d981..e31388150f20 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4226,6 +4226,7 @@ Released 2018-09-13 [`get_first`]: https://rust-lang.github.io/rust-clippy/master/index.html#get_first [`get_last_with_len`]: https://rust-lang.github.io/rust-clippy/master/index.html#get_last_with_len [`get_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#get_unwrap +[`hidden_static_lifetime`]: https://rust-lang.github.io/rust-clippy/master/index.html#hidden_static_lifetime [`identity_conversion`]: https://rust-lang.github.io/rust-clippy/master/index.html#identity_conversion [`identity_op`]: https://rust-lang.github.io/rust-clippy/master/index.html#identity_op [`if_let_mutex`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_let_mutex diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 91ca73633f06..23d4585511bb 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -178,6 +178,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::from_raw_with_void_ptr::FROM_RAW_WITH_VOID_PTR_INFO, crate::from_str_radix_10::FROM_STR_RADIX_10_INFO, crate::functions::DOUBLE_MUST_USE_INFO, + crate::functions::HIDDEN_STATIC_LIFETIME_INFO, crate::functions::MISNAMED_GETTERS_INFO, crate::functions::MUST_USE_CANDIDATE_INFO, crate::functions::MUST_USE_UNIT_INFO, diff --git a/clippy_lints/src/functions/hidden_static_lifetime.rs b/clippy_lints/src/functions/hidden_static_lifetime.rs new file mode 100644 index 000000000000..3c21a8fe1f4c --- /dev/null +++ b/clippy_lints/src/functions/hidden_static_lifetime.rs @@ -0,0 +1,235 @@ +use crate::rustc_lint::LintContext; +use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; +use rustc_hir::{ + intravisit::{FnKind, Visitor}, + BareFnTy, FnDecl, FnRetTy, GenericArg, GenericArgs, GenericBound, GenericParam, GenericParamKind, Generics, + Lifetime, LifetimeParamKind, MutTy, ParamName, PolyTraitRef, QPath, Ty, TyKind, TypeBindingKind, WherePredicate, +}; +use rustc_lint::LateContext; +use rustc_middle::lint::in_external_macro; +use rustc_span::{symbol::Ident, Span}; + +use super::HIDDEN_STATIC_LIFETIME; + +struct V<'a> { + // (Lifetime, Bounded typ) + lifetimes: Vec<&'a GenericParam<'a>>, +} + +impl<'a> Visitor<'_> for V<'a> { + /// Remove all mutable lifetimes that aren't for T: 'static + fn visit_where_predicate(&mut self, predicate: &WherePredicate<'_>) { + if let WherePredicate::BoundPredicate(pred) = predicate { + for bound in pred.bounds { + // Check (for each lifetime) that the type they're associated with is 'static. + continue; + } + } + } + + fn visit_ty(&mut self, ty: &Ty<'_>) { + let mut outer_continue: bool; + let mut outer_break = false; + let mut i = 0; + while i < self.lifetimes.len() { + outer_continue = false; + let lifetime = self.lifetimes[i]; + + // Check references + + let mut final_ty = ty; + let mut behind_mut_ref = false; + while let TyKind::Ref(lt, mut_ty) = &final_ty.kind { + if mut_ty.mutbl.is_mut() { + behind_mut_ref = true; + }; + + if lt.ident.name == lifetime.name.ident().name || behind_mut_ref { + if self.lifetimes.is_empty() { + outer_continue = true; + continue; + } + + self.lifetimes.remove(i); + outer_continue = true; + + } + final_ty = mut_ty.ty; + } + + if outer_continue { + continue; + } else if outer_break { + break; + } + + // Now final_ty is equal to ty.peel_refs() + // Check Paths: + + if let TyKind::Path(QPath::Resolved(_, path)) = final_ty.kind { + for segment in path.segments { + for argument in segment.args().args { + if let GenericArg::Lifetime(lt) = argument && lt.ident.name == lifetime.name.ident().name { + self.lifetimes.remove(i); + outer_continue = true; + continue; + }; + } + if outer_continue { + break; + } + } + }; + + if outer_continue { + continue; + } + i += 1; + } + } + + fn visit_fn_ret_ty<'v>(&mut self, ret_ty: &'v FnRetTy<'v>) { + if let FnRetTy::Return(ty) = ret_ty { + let mut i = 0; + while i < self.lifetimes.len() { + dbg!(self.lifetimes[i].name.ident().as_str()); + if ty_uses_lifetime(ty, &self.lifetimes[i], &self) { + self.lifetimes.remove(i); + } + i += 1; + } + } + } +} + +pub(super) fn check_fn<'tcx>(cx: &LateContext<'_>, kind: FnKind<'tcx>, decl: &'tcx FnDecl<'_>, span: Span) { + if !in_external_macro(cx.sess(), span) && + let FnKind::ItemFn(_, generics, _) = kind { + let mut visitor = V { + lifetimes: Vec::new() + }; + + // Fill visitor.lifetimes with function's lifetimes + + for generic in generics.params { + if let GenericParamKind::Lifetime { .. } = generic.kind { + visitor.lifetimes.push(generic); + }; + }; + + for input in decl.inputs { + visitor.visit_ty(input); + } + + for predicate in generics.predicates { + visitor.visit_where_predicate(predicate); + } + visitor.visit_fn_ret_ty(&decl.output); + + for generic in visitor.lifetimes { + span_lint_and_help(cx, + HIDDEN_STATIC_LIFETIME, + generic.span, + "this lifetime can be changed to `'static`", + None, + &format!("try removing the lifetime parameter `{}` and changing references to `'static`", generic.name.ident().as_str())); + } + }; +} + +fn ty_uses_lifetime(ty: &Ty<'_>, generic: &GenericParam, v: &V<'_>) -> bool { + fn check_ty(ty: &Ty<'_>, generic: &GenericParam, v: &V<'_>) -> bool { + if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind { + for segment in path.segments { + if let Some(GenericArgs { args, .. }) = segment.args { + for arg in args.iter() { + if let GenericArg::Lifetime(lifetime) = arg { + if lifetime.ident.name == generic.name.ident().name { + // generic is used + return true; + } + } else if let GenericArg::Type(ty) = arg { + return classify_ty(ty, generic, v); + } + } + } + } + } + false + } + + #[inline] + fn barefn_uses_lifetime(barefn: &BareFnTy<'_>, generic: &GenericParam, v: &V<'_>) -> bool { + // let mut visitor = V { + // lifetimes: v.lifetimes.clone(), + // }; + + // for input in barefn.decl.inputs { + // visitor.visit_ty(input); + // } + + // visitor.visit_fn_ret_ty(&barefn.decl.output); + // !visitor.lifetimes.contains(&generic) + true + } + + #[inline] + fn tuple_uses_lifetime(tuple: &[Ty<'_>], generic: &GenericParam, v: &V<'_>) -> bool { + tuple.iter().any(|ty| classify_ty(ty, generic, v)) + } + + fn opaquedef_uses_lifetime(args: &[GenericArg<'_>], generic: &GenericParam, v: &V<'_>) -> bool { + for arg in args.iter() { + if let GenericArg::Lifetime(lifetime) = arg { + if lifetime.ident.name == generic.name.ident().name { + // generic is used + return true; + } + } else if let GenericArg::Type(ty) = arg { + return classify_ty(ty, generic, v); + } + } + false + } + + #[inline] + fn traitobject_uses_lifetime(lifetime: &Lifetime, traits: &[PolyTraitRef<'_>], generic: &GenericParam<'_>) -> bool { + if lifetime.ident.name == generic.name.ident().name { + return false; + } + for PolyTraitRef { + bound_generic_params, .. + } in traits + { + if bound_generic_params + .iter() + .any(|param| param.name.ident().name == generic.name.ident().name) + { + return true; + }; + } + false + } + + #[inline] + fn classify_ty(ty: &Ty<'_>, generic: &GenericParam, v: &V<'_>) -> bool { + match &ty.kind { + TyKind::Slice(ty) | TyKind::Array(ty, _) => check_ty(ty, generic, v), + TyKind::Ptr(mut_ty) => check_ty(mut_ty.ty, generic, v), + TyKind::BareFn(barefnty) => { + barefn_uses_lifetime(barefnty, generic, v)}, + TyKind::Tup(tuple) => tuple_uses_lifetime(tuple, generic, v), + TyKind::Path(_) => check_ty(ty, generic, v), + TyKind::OpaqueDef(_, genericargs, _) => opaquedef_uses_lifetime(genericargs, generic, v), + TyKind::TraitObject(poly_trait_ref, lifetime, _) => + traitobject_uses_lifetime(lifetime, poly_trait_ref, generic), + TyKind::Typeof(_) // This is unused for now, this needs revising when Typeof is used. + | TyKind::Err + | TyKind::Never + | TyKind::Ref(_, _) + | TyKind::Infer => true, + } + } + + return classify_ty(ty.peel_refs(), &generic, v); +} diff --git a/clippy_lints/src/functions/hidden_static_lifetime_old.rs b/clippy_lints/src/functions/hidden_static_lifetime_old.rs new file mode 100644 index 000000000000..5ee181d4343e --- /dev/null +++ b/clippy_lints/src/functions/hidden_static_lifetime_old.rs @@ -0,0 +1,212 @@ +use crate::rustc_lint::LintContext; +use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; +use rustc_hir::{ + intravisit::{FnKind, Visitor}, + BareFnTy, FnDecl, FnRetTy, GenericArg, GenericArgs, GenericBound, GenericParam, GenericParamKind, Generics, + Lifetime, LifetimeParamKind, MutTy, ParamName, PolyTraitRef, QPath, Ty, TyKind, TypeBindingKind, WherePredicate, +}; +use rustc_lint::LateContext; +use rustc_middle::lint::in_external_macro; +use rustc_span::Span; + +use super::HIDDEN_STATIC_LIFETIME; + +// As a summary: +// +// A lifetime can only be changed if: +// * Used in immutable references. +// * Not behind a mutable reference. +// * Not used in function types +// +// NOTE: Struct's fields follow the same rules as types + +pub(super) fn check_fn<'tcx>(cx: &LateContext<'_>, kind: FnKind<'tcx>, decl: &'tcx FnDecl<'_>, span: Span) { + if !in_external_macro(cx.sess(), span) && + let FnKind::ItemFn(_, generics, _) = kind { + + let mut v = FuncVisitor { + ret_ty: &decl.output, + inputs: decl.inputs, + predicates: &generics.predicates, + lifetime_is_used: false + }; + + for param in generics.params { + if let GenericParamKind::Lifetime { kind } = param.kind && kind != LifetimeParamKind::Elided { + v.visit_generic_param(param); + if !v.lifetime_is_used { + span_lint(cx, HIDDEN_STATIC_LIFETIME, param.span, "hi"); + }; + } + }; + } +} + +struct FuncVisitor<'a> { + ret_ty: &'a FnRetTy<'a>, + inputs: &'a [Ty<'a>], + predicates: &'a [WherePredicate<'a>], + lifetime_is_used: bool, +} + +impl<'v> Visitor<'_> for FuncVisitor<'v> { + fn visit_generic_param(&mut self, param: &GenericParam<'_>) { + // Check inputs + for input in self.inputs { + if ref_uses_lifetime(input, param) || check_path(input, param) { + dbg!("@@@@@@@@@@@@@@@@@@@@@@@@"); + self.lifetime_is_used = true; + return; + }; + } + + // Check return + if let FnRetTy::Return(ret_ty) = self.ret_ty { + if ref_uses_lifetime(ret_ty, param) || check_path(ret_ty, param) { + dbg!("============================"); + self.lifetime_is_used = true; + return; + }; + }; + + // Check predicates + + for predicate in self.predicates { + for bound in predicate.bounds() { + if let GenericBound::Outlives(lifetime) = bound && + lifetime.ident.name == param.name.ident().name { + self.lifetime_is_used = true; + return; + } + } + } + } +} + +fn ref_uses_lifetime(mut ty: &Ty<'_>, lifetime: &GenericParam<'_>) -> bool { + while let TyKind::Ref(lt_ref, mut_ty) = &ty.kind { + if lt_ref.ident.name == lifetime.name.ident().name && mut_ty.mutbl.is_not() { + return true; + } else { + ty = mut_ty.ty; + } + } + false +} + +fn check_path(ty: &Ty<'_>, lifetime: &GenericParam<'_>) -> bool { + if let TyKind::Path(QPath::Resolved(_, path)) = ty.peel_refs().kind { + for segment in path.segments { + for arg in segment.args().args { + if let GenericArg::Lifetime(lt_arg) = arg { + if lt_arg.ident.name == lifetime.name.ident().name { + return true; + }; + } else if let &GenericArg::Type(ty) = arg { + dbg!("!!!!!!!!!!!!!!!!!!!!!!!!!"); + return check_all_types(ty, lifetime); + }; + } + } + }; + false +} + +fn check_all_types(ty: &Ty<'_>, lifetime: &GenericParam<'_>) -> bool { + fn ty_uses_lifetime(ty: &Ty<'_>, generic: &GenericParam<'_>) -> bool { + if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind { + for segment in path.segments { + if let Some(GenericArgs { args, .. }) = segment.args { + for arg in args.iter() { + if let GenericArg::Lifetime(lifetime) = arg { + if lifetime.ident.name == generic.name.ident().name { + // generic is used + return true; + } + } else if let GenericArg::Type(ty) = arg { + return classify_ty(ty, generic); + } + } + } + } + } + false + } + + #[inline] + fn barefn_uses_lifetime(barefn: &BareFnTy<'_>, generic: &GenericParam<'_>) -> bool { + // Check inputs + for input in barefn.decl.inputs { + if ref_uses_lifetime(input, generic) || check_path(input, generic) { + return false; + }; + } + + // Check return + if let FnRetTy::Return(ret_ty) = barefn.decl.output { + if check_path(ret_ty, generic) { + return false; + }; + }; + true + } + + #[inline] + fn tuple_uses_lifetime(tuple: &[Ty<'_>], generic: &GenericParam<'_>) -> bool { + tuple.iter().any(|ty| classify_ty(ty, generic)) + } + + fn opaquedef_uses_lifetime(args: &[GenericArg<'_>], generic: &GenericParam<'_>) -> bool { + for arg in args.iter() { + if let GenericArg::Lifetime(lifetime) = arg { + if lifetime.ident.name == generic.name.ident().name { + // generic is used + return true; + } + } else if let GenericArg::Type(ty) = arg { + return classify_ty(ty, generic); + } + } + false + } + + #[inline] + fn traitobject_uses_lifetime(lifetime: &Lifetime, traits: &[PolyTraitRef<'_>], generic: &GenericParam<'_>) -> bool { + if lifetime.ident.name == generic.name.ident().name { + return true; + } + for PolyTraitRef { + bound_generic_params, .. + } in traits + { + if bound_generic_params.iter().any(|param| param.def_id == generic.def_id) { + return true; + }; + } + false + } + + #[inline] + fn classify_ty(ty: &Ty<'_>, generic: &GenericParam<'_>) -> bool { + match &ty.kind { + TyKind::Slice(ty) | TyKind::Array(ty, _) => ty_uses_lifetime(ty, generic), + TyKind::Ptr(mut_ty) => ty_uses_lifetime(mut_ty.ty, generic), + TyKind::BareFn(barefnty) => barefn_uses_lifetime(barefnty, generic), + TyKind::Tup(tuple) => tuple_uses_lifetime(tuple, generic), + TyKind::Path(_) => ty_uses_lifetime(ty, generic), + TyKind::OpaqueDef(_, genericargs, _) => opaquedef_uses_lifetime(genericargs, generic), + TyKind::TraitObject(poly_trait_ref, lifetime, _) => + traitobject_uses_lifetime(lifetime, poly_trait_ref, generic), + TyKind::Typeof(_) // This is unused for now, this needs revising when Typeof is used. + | TyKind::Err + | TyKind::Never => false, + TyKind::Ref(_, MutTy { ty, ..}) => ref_uses_lifetime(ty, generic), + TyKind::Infer => true, + } + } + + // Separate refs from ty. + + // Now final_ty is equivalent to ty.peel_refs + return classify_ty(ty.peel_refs(), lifetime); +} diff --git a/clippy_lints/src/functions/mod.rs b/clippy_lints/src/functions/mod.rs index 9dbce3f889be..cc3c7a2a7da0 100644 --- a/clippy_lints/src/functions/mod.rs +++ b/clippy_lints/src/functions/mod.rs @@ -1,3 +1,4 @@ +mod hidden_static_lifetime; mod misnamed_getters; mod must_use; mod not_unsafe_ptr_arg_deref; @@ -326,6 +327,25 @@ declare_clippy_lint! { "getter method returning the wrong field" } +declare_clippy_lint! { + /// ### What it does + /// Detects generic lifetimes that the compiler will always resolve to be `'static`. + /// ### Why is this bad? + /// The introduction of a lifetime parameter that can only resolve to `'static` adds unnecesary complexity. + /// ### Example + /// ```rust + /// fn foo<'a>() -> &'a str { "bar" } + /// ``` + /// Use instead: + /// ```rust + /// fn foo() -> &'static str { "bar" } + /// ``` + #[clippy::version = "1.68.0"] + pub HIDDEN_STATIC_LIFETIME, + pedantic, + "`'a` lifetime isn't clear to be `'static`" +} + #[derive(Copy, Clone)] pub struct Functions { too_many_arguments_threshold: u64, @@ -353,6 +373,7 @@ impl_lint_pass!(Functions => [ RESULT_UNIT_ERR, RESULT_LARGE_ERR, MISNAMED_GETTERS, + HIDDEN_STATIC_LIFETIME, ]); impl<'tcx> LateLintPass<'tcx> for Functions { @@ -369,6 +390,7 @@ impl<'tcx> LateLintPass<'tcx> for Functions { too_many_lines::check_fn(cx, kind, span, body, self.too_many_lines_threshold); not_unsafe_ptr_arg_deref::check_fn(cx, kind, decl, body, hir_id); misnamed_getters::check_fn(cx, kind, decl, body, span, hir_id); + hidden_static_lifetime::check_fn(cx, kind, decl, span); } fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) { diff --git a/tests/ui/hidden_static_lifetime.rs b/tests/ui/hidden_static_lifetime.rs new file mode 100644 index 000000000000..2ba5c938271f --- /dev/null +++ b/tests/ui/hidden_static_lifetime.rs @@ -0,0 +1,131 @@ +#![allow(unused)] +#![warn(clippy::hidden_static_lifetime)] +#![allow(clippy::needless_lifetimes)] + +struct S<'s> { + s: &'s u32, +} + +mod module { + pub struct S<'s> { + s: &'s u32, + } +} + +struct SMut<'a>(&'a mut i32); +struct STuple<'a>(&'a i32); +struct SGeneric(T); +struct SRef<'a, T: 'a>(&'a T); +struct Both<'a, 'b, T> { + owned: T, + borrow: &'a T, + mut_borrow: &'b mut T, +} + +// ============= Should warn ============= + +fn a<'a>() -> &'a str { + "" +} + +// Valid +fn o<'o, T>() -> &'o mut T +where + T: 'static, +{ + unsafe { std::ptr::null::<&mut T>().read() } +} + +// Only 'm1 +fn n<'m1, 'm2, T>() -> &'m1 fn(&'m2 T) { + unsafe { std::ptr::null::<&'m1 fn(&'m2 T)>().read() } +} + +// Only 's1 +fn s<'s1, 's2>() -> &'s1 STuple<'s2> { + unsafe { std::ptr::null::<&STuple<'s2>>().read() } +} + +fn q<'q>() -> STuple<'q> { + STuple(&1) +} + +// Only 'r1 +fn r<'r1, 'r2>() -> &'r1 SMut<'r2> { + unsafe { std::ptr::null::<&SMut<'r2>>().read() } +} + +// ============= Should not warn ============= +fn b<'b>(_: &'b str) -> &'b str { + "" +} +fn d<'d>(_: &'d str) {} +fn e<'e>(_: &'e str) -> &'e str { + "" +} + +fn h<'h>() -> S<'h> { + S { s: &1 } +} + +fn f<'f, F>(_: F) -> F +where + F: 'f, +{ + todo!() +} +fn g<'g>(_: S<'g>) -> S<'g> { + S { s: &1 } +} + +fn i() -> S<'static> { + S { s: &1 } +} + +fn j<'j>(s: &module::S<'j>) -> S<'j> { + S { s: &1 } +} + +// Invalid +fn k<'k1, 'k2, T>() -> &'k1 mut &'k2 T { + unsafe { std::ptr::null::<&mut &T>().read() } +} + +// Invalid +fn m<'m, T>() -> fn(&'m T) { + unsafe { std::ptr::null::().read() } +} + +// Valid +fn l<'l, T>() -> &'l mut T +where + T: 'static, +{ + unsafe { std::ptr::null::<&mut T>().read() } +} + +fn p<'p>() -> SMut<'p> { + unsafe { std::ptr::null::>().read() } +} + +fn t<'t1, 't2>() -> SGeneric<&'t1 mut SRef<'t2, u32>> { + unsafe { std::ptr::null::>>().read() } +} + +fn u<'u1, 'u2>() -> &'u1 Both<'u1, 'u2, &'u1 str> { + unsafe { std::ptr::null::<&Both<'u1, 'u2, &'u1 str>>().read() } +} + +fn v<'v1, 'v2, 'v3>() -> &'v1 Both<'v1, 'v2, &'v3 str> { + unsafe { std::ptr::null::<&Both<'v1, 'v2, &'v3 str>>().read() } +} + +fn w<'w1, 'w2>() -> &'w1 Both<'w1, 'w2, &'static str> { + unsafe { std::ptr::null::<&Both<'w1, 'w2, &'static str>>().read() } +} + +fn x<'x>() -> SRef<'x, fn(SGeneric>)> { + unsafe { std::ptr::null::>)>>().read() } +} + +fn main() {} diff --git a/tests/ui/hidden_static_lifetime.stderr b/tests/ui/hidden_static_lifetime.stderr new file mode 100644 index 000000000000..75dade5898d2 --- /dev/null +++ b/tests/ui/hidden_static_lifetime.stderr @@ -0,0 +1,51 @@ +error: this lifetime can be changed to `'static` + --> $DIR/hidden_static_lifetime.rs:27:6 + | +LL | fn a<'a>() -> &'a str { + | ^^ + | + = help: try removing the lifetime parameter `'a` and changing references to `'static` + = note: `-D clippy::hidden-static-lifetime` implied by `-D warnings` + +error: this lifetime can be changed to `'static` + --> $DIR/hidden_static_lifetime.rs:32:6 + | +LL | fn o<'o, T>() -> &'o mut T + | ^^ + | + = help: try removing the lifetime parameter `'o` and changing references to `'static` + +error: this lifetime can be changed to `'static` + --> $DIR/hidden_static_lifetime.rs:40:6 + | +LL | fn n<'m1, 'm2, T>() -> &'m1 fn(&'m2 T) { + | ^^^ + | + = help: try removing the lifetime parameter `'m1` and changing references to `'static` + +error: this lifetime can be changed to `'static` + --> $DIR/hidden_static_lifetime.rs:45:6 + | +LL | fn s<'s1, 's2>() -> &'s1 STuple<'s2> { + | ^^^ + | + = help: try removing the lifetime parameter `'s1` and changing references to `'static` + +error: this lifetime can be changed to `'static` + --> $DIR/hidden_static_lifetime.rs:54:6 + | +LL | fn r<'r1, 'r2>() -> &'r1 SMut<'r2> { + | ^^^ + | + = help: try removing the lifetime parameter `'r1` and changing references to `'static` + +error: this lifetime can be changed to `'static` + --> $DIR/hidden_static_lifetime.rs:100:6 + | +LL | fn l<'l, T>() -> &'l mut T + | ^^ + | + = help: try removing the lifetime parameter `'l` and changing references to `'static` + +error: aborting due to 6 previous errors + diff --git a/tests/ui/unknown_clippy_lints.fixed b/tests/ui/unknown_clippy_lints.fixed index 4249ff8a958d..524d9171bd4a 100644 --- a/tests/ui/unknown_clippy_lints.fixed +++ b/tests/ui/unknown_clippy_lints.fixed @@ -14,5 +14,5 @@ // Shouldn't suggest removed/deprecated clippy lint name(`unused_collect`) #[warn(clippy::unused_self)] // Shouldn't suggest renamed clippy lint name(`const_static_lifetime`) -#[warn(clippy::redundant_static_lifetimes)] +#[warn(clippy::hidden_static_lifetime)] fn main() {} diff --git a/tests/ui/unknown_clippy_lints.stderr b/tests/ui/unknown_clippy_lints.stderr index 421bf5ffa9a7..ba0f09e38ad1 100644 --- a/tests/ui/unknown_clippy_lints.stderr +++ b/tests/ui/unknown_clippy_lints.stderr @@ -46,7 +46,7 @@ error: unknown lint: `clippy::const_static_lifetim` --> $DIR/unknown_clippy_lints.rs:17:8 | LL | #[warn(clippy::const_static_lifetim)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: did you mean: `clippy::redundant_static_lifetimes` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: did you mean: `clippy::hidden_static_lifetime` error: aborting due to 8 previous errors