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