1 use clippy_utils
::diagnostics
::span_lint_and_then
;
2 use clippy_utils
::msrvs
::{self, Msrv}
;
3 use clippy_utils
::source
::snippet
;
4 use rustc_ast
::ast
::{Item, ItemKind, Ty, TyKind}
;
5 use rustc_errors
::Applicability
;
6 use rustc_lint
::{EarlyContext, EarlyLintPass}
;
7 use rustc_session
::{declare_tool_lint, impl_lint_pass}
;
11 /// Checks for constants and statics with an explicit `'static` lifetime.
13 /// ### Why is this bad?
14 /// Adding `'static` to every reference can create very
15 /// complicated types.
19 /// const FOO: &'static [(&'static str, &'static str, fn(&Bar) -> bool)] =
21 /// static FOO: &'static [(&'static str, &'static str, fn(&Bar) -> bool)] =
24 /// This code can be rewritten as
26 /// const FOO: &[(&str, &str, fn(&Bar) -> bool)] = &[...]
27 /// static FOO: &[(&str, &str, fn(&Bar) -> bool)] = &[...]
29 #[clippy::version = "1.37.0"]
30 pub REDUNDANT_STATIC_LIFETIMES
,
32 "Using explicit `'static` lifetime for constants or statics when elision rules would allow omitting them."
35 pub struct RedundantStaticLifetimes
{
39 impl RedundantStaticLifetimes
{
41 pub fn new(msrv
: Msrv
) -> Self {
46 impl_lint_pass
!(RedundantStaticLifetimes
=> [REDUNDANT_STATIC_LIFETIMES
]);
48 impl RedundantStaticLifetimes
{
49 // Recursively visit types
50 fn visit_type(ty
: &Ty
, cx
: &EarlyContext
<'_
>, reason
: &str) {
52 // Be careful of nested structures (arrays and tuples)
53 TyKind
::Array(ref ty
, _
) | TyKind
::Slice(ref ty
) => {
54 Self::visit_type(ty
, cx
, reason
);
56 TyKind
::Tup(ref tup
) => {
58 Self::visit_type(tup_ty
, cx
, reason
);
61 // This is what we are looking for !
62 TyKind
::Ref(ref optional_lifetime
, ref borrow_type
) => {
63 // Match the 'static lifetime
64 if let Some(lifetime
) = *optional_lifetime
{
65 match borrow_type
.ty
.kind
{
66 TyKind
::Path(..) | TyKind
::Slice(..) | TyKind
::Array(..) | TyKind
::Tup(..) => {
67 if lifetime
.ident
.name
== rustc_span
::symbol
::kw
::StaticLifetime
{
68 let snip
= snippet(cx
, borrow_type
.ty
.span
, "<type>");
69 let sugg
= format
!("&{}{snip}", borrow_type
.mutbl
.prefix_str());
72 REDUNDANT_STATIC_LIFETIMES
,
78 "consider removing `'static`",
80 Applicability
::MachineApplicable
, //snippet
89 Self::visit_type(&borrow_type
.ty
, cx
, reason
);
96 impl EarlyLintPass
for RedundantStaticLifetimes
{
97 fn check_item(&mut self, cx
: &EarlyContext
<'_
>, item
: &Item
) {
98 if !self.msrv
.meets(msrvs
::STATIC_IN_CONST
) {
102 if !item
.span
.from_expansion() {
103 if let ItemKind
::Const(_
, ref var_type
, _
) = item
.kind
{
104 Self::visit_type(var_type
, cx
, "constants have by default a `'static` lifetime");
105 // Don't check associated consts because `'static` cannot be elided on those (issue
109 if let ItemKind
::Static(ref var_type
, _
, _
) = item
.kind
{
110 Self::visit_type(var_type
, cx
, "statics have by default a `'static` lifetime");
115 extract_msrv_attr
!(EarlyContext
);