]> git.lizzy.rs Git - rust.git/blob - clippy_lints/src/const_static_lifetime.rs
Auto merge of #3985 - phansch:move_some_cast_tests, r=flip1995
[rust.git] / clippy_lints / src / const_static_lifetime.rs
1 use crate::utils::{in_macro, snippet, span_lint_and_then};
2 use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass};
3 use rustc::{declare_lint_pass, declare_tool_lint};
4 use rustc_errors::Applicability;
5 use syntax::ast::*;
6
7 declare_clippy_lint! {
8     /// **What it does:** Checks for constants 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     /// ```
20     /// This code can be rewritten as
21     /// ```ignore
22     ///  const FOO: &[(&str, &str, fn(&Bar) -> bool)] = &[...]
23     /// ```
24     pub CONST_STATIC_LIFETIME,
25     style,
26     "Using explicit `'static` lifetime for constants when elision rules would allow omitting them."
27 }
28
29 declare_lint_pass!(StaticConst => [CONST_STATIC_LIFETIME]);
30
31 impl StaticConst {
32     // Recursively visit types
33     fn visit_type(&mut self, ty: &Ty, cx: &EarlyContext<'_>) {
34         match ty.node {
35             // Be careful of nested structures (arrays and tuples)
36             TyKind::Array(ref ty, _) => {
37                 self.visit_type(&*ty, cx);
38             },
39             TyKind::Tup(ref tup) => {
40                 for tup_ty in tup {
41                     self.visit_type(&*tup_ty, cx);
42                 }
43             },
44             // This is what we are looking for !
45             TyKind::Rptr(ref optional_lifetime, ref borrow_type) => {
46                 // Match the 'static lifetime
47                 if let Some(lifetime) = *optional_lifetime {
48                     match borrow_type.ty.node {
49                         TyKind::Path(..) | TyKind::Slice(..) | TyKind::Array(..) | TyKind::Tup(..) => {
50                             if lifetime.ident.name == "'static" {
51                                 let snip = snippet(cx, borrow_type.ty.span, "<type>");
52                                 let sugg = format!("&{}", snip);
53                                 span_lint_and_then(
54                                     cx,
55                                     CONST_STATIC_LIFETIME,
56                                     lifetime.ident.span,
57                                     "Constants have by default a `'static` lifetime",
58                                     |db| {
59                                         db.span_suggestion(
60                                             ty.span,
61                                             "consider removing `'static`",
62                                             sugg,
63                                             Applicability::MachineApplicable, //snippet
64                                         );
65                                     },
66                                 );
67                             }
68                         },
69                         _ => {},
70                     }
71                 }
72                 self.visit_type(&*borrow_type.ty, cx);
73             },
74             TyKind::Slice(ref ty) => {
75                 self.visit_type(ty, cx);
76             },
77             _ => {},
78         }
79     }
80 }
81
82 impl EarlyLintPass for StaticConst {
83     fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
84         if !in_macro(item.span) {
85             // Match only constants...
86             if let ItemKind::Const(ref var_type, _) = item.node {
87                 self.visit_type(var_type, cx);
88             }
89         }
90     }
91
92     // Don't check associated consts because `'static` cannot be elided on those (issue #2438)
93 }