]> git.lizzy.rs Git - rust.git/blob - src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs
Rollup merge of #105837 - compiler-errors:issue-105728, r=estebank
[rust.git] / src / tools / clippy / clippy_lints / src / redundant_static_lifetimes.rs
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};
8
9 declare_clippy_lint! {
10     /// ### What it does
11     /// Checks for constants and statics with an explicit `'static` lifetime.
12     ///
13     /// ### Why is this bad?
14     /// Adding `'static` to every reference can create very
15     /// complicated types.
16     ///
17     /// ### Example
18     /// ```ignore
19     /// const FOO: &'static [(&'static str, &'static str, fn(&Bar) -> bool)] =
20     /// &[...]
21     /// static FOO: &'static [(&'static str, &'static str, fn(&Bar) -> bool)] =
22     /// &[...]
23     /// ```
24     /// This code can be rewritten as
25     /// ```ignore
26     ///  const FOO: &[(&str, &str, fn(&Bar) -> bool)] = &[...]
27     ///  static FOO: &[(&str, &str, fn(&Bar) -> bool)] = &[...]
28     /// ```
29     #[clippy::version = "1.37.0"]
30     pub REDUNDANT_STATIC_LIFETIMES,
31     style,
32     "Using explicit `'static` lifetime for constants or statics when elision rules would allow omitting them."
33 }
34
35 pub struct RedundantStaticLifetimes {
36     msrv: Msrv,
37 }
38
39 impl RedundantStaticLifetimes {
40     #[must_use]
41     pub fn new(msrv: Msrv) -> Self {
42         Self { msrv }
43     }
44 }
45
46 impl_lint_pass!(RedundantStaticLifetimes => [REDUNDANT_STATIC_LIFETIMES]);
47
48 impl RedundantStaticLifetimes {
49     // Recursively visit types
50     fn visit_type(ty: &Ty, cx: &EarlyContext<'_>, reason: &str) {
51         match ty.kind {
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);
55             },
56             TyKind::Tup(ref tup) => {
57                 for tup_ty in tup {
58                     Self::visit_type(tup_ty, cx, reason);
59                 }
60             },
61             // This is what we are looking for !
62             TyKind::Rptr(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());
70                                 span_lint_and_then(
71                                     cx,
72                                     REDUNDANT_STATIC_LIFETIMES,
73                                     lifetime.ident.span,
74                                     reason,
75                                     |diag| {
76                                         diag.span_suggestion(
77                                             ty.span,
78                                             "consider removing `'static`",
79                                             sugg,
80                                             Applicability::MachineApplicable, //snippet
81                                         );
82                                     },
83                                 );
84                             }
85                         },
86                         _ => {},
87                     }
88                 }
89                 Self::visit_type(&borrow_type.ty, cx, reason);
90             },
91             _ => {},
92         }
93     }
94 }
95
96 impl EarlyLintPass for RedundantStaticLifetimes {
97     fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
98         if !self.msrv.meets(msrvs::STATIC_IN_CONST) {
99             return;
100         }
101
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
106                 // #2438)
107             }
108
109             if let ItemKind::Static(ref var_type, _, _) = item.kind {
110                 Self::visit_type(var_type, cx, "statics have by default a `'static` lifetime");
111             }
112         }
113     }
114
115     extract_msrv_attr!(EarlyContext);
116 }