]> git.lizzy.rs Git - rust.git/blob - clippy_lints/src/redundant_static_lifetimes.rs
Auto merge of #6924 - mgacek8:issue6727_copy_types, r=llogiq
[rust.git] / clippy_lints / src / redundant_static_lifetimes.rs
1 use clippy_utils::diagnostics::span_lint_and_then;
2 use clippy_utils::meets_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_semver::RustcVersion;
8 use rustc_session::{declare_tool_lint, impl_lint_pass};
9
10 const REDUNDANT_STATIC_LIFETIMES_MSRV: RustcVersion = RustcVersion::new(1, 17, 0);
11
12 declare_clippy_lint! {
13     /// **What it does:** Checks for constants and statics with an explicit `'static` lifetime.
14     ///
15     /// **Why is this bad?** Adding `'static` to every reference can create very
16     /// complicated types.
17     ///
18     /// **Known problems:** None.
19     ///
20     /// **Example:**
21     /// ```ignore
22     /// const FOO: &'static [(&'static str, &'static str, fn(&Bar) -> bool)] =
23     /// &[...]
24     /// static FOO: &'static [(&'static str, &'static str, fn(&Bar) -> bool)] =
25     /// &[...]
26     /// ```
27     /// This code can be rewritten as
28     /// ```ignore
29     ///  const FOO: &[(&str, &str, fn(&Bar) -> bool)] = &[...]
30     ///  static FOO: &[(&str, &str, fn(&Bar) -> bool)] = &[...]
31     /// ```
32     pub REDUNDANT_STATIC_LIFETIMES,
33     style,
34     "Using explicit `'static` lifetime for constants or statics when elision rules would allow omitting them."
35 }
36
37 pub struct RedundantStaticLifetimes {
38     msrv: Option<RustcVersion>,
39 }
40
41 impl RedundantStaticLifetimes {
42     #[must_use]
43     pub fn new(msrv: Option<RustcVersion>) -> Self {
44         Self { msrv }
45     }
46 }
47
48 impl_lint_pass!(RedundantStaticLifetimes => [REDUNDANT_STATIC_LIFETIMES]);
49
50 impl RedundantStaticLifetimes {
51     // Recursively visit types
52     fn visit_type(&mut self, ty: &Ty, cx: &EarlyContext<'_>, reason: &str) {
53         match ty.kind {
54             // Be careful of nested structures (arrays and tuples)
55             TyKind::Array(ref ty, _) => {
56                 self.visit_type(&*ty, cx, reason);
57             },
58             TyKind::Tup(ref tup) => {
59                 for tup_ty in tup {
60                     self.visit_type(&*tup_ty, cx, reason);
61                 }
62             },
63             // This is what we are looking for !
64             TyKind::Rptr(ref optional_lifetime, ref borrow_type) => {
65                 // Match the 'static lifetime
66                 if let Some(lifetime) = *optional_lifetime {
67                     match borrow_type.ty.kind {
68                         TyKind::Path(..) | TyKind::Slice(..) | TyKind::Array(..) | TyKind::Tup(..) => {
69                             if lifetime.ident.name == rustc_span::symbol::kw::StaticLifetime {
70                                 let snip = snippet(cx, borrow_type.ty.span, "<type>");
71                                 let sugg = format!("&{}", snip);
72                                 span_lint_and_then(
73                                     cx,
74                                     REDUNDANT_STATIC_LIFETIMES,
75                                     lifetime.ident.span,
76                                     reason,
77                                     |diag| {
78                                         diag.span_suggestion(
79                                             ty.span,
80                                             "consider removing `'static`",
81                                             sugg,
82                                             Applicability::MachineApplicable, //snippet
83                                         );
84                                     },
85                                 );
86                             }
87                         },
88                         _ => {},
89                     }
90                 }
91                 self.visit_type(&*borrow_type.ty, cx, reason);
92             },
93             TyKind::Slice(ref ty) => {
94                 self.visit_type(ty, cx, reason);
95             },
96             _ => {},
97         }
98     }
99 }
100
101 impl EarlyLintPass for RedundantStaticLifetimes {
102     fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
103         if !meets_msrv(self.msrv.as_ref(), &REDUNDANT_STATIC_LIFETIMES_MSRV) {
104             return;
105         }
106
107         if !item.span.from_expansion() {
108             if let ItemKind::Const(_, ref var_type, _) = item.kind {
109                 self.visit_type(var_type, cx, "constants have by default a `'static` lifetime");
110                 // Don't check associated consts because `'static` cannot be elided on those (issue
111                 // #2438)
112             }
113
114             if let ItemKind::Static(ref var_type, _, _) = item.kind {
115                 self.visit_type(var_type, cx, "statics have by default a `'static` lifetime");
116             }
117         }
118     }
119
120     extract_msrv_attr!(EarlyContext);
121 }