]>
Commit | Line | Data |
---|---|---|
2c00a5a8 | 1 | use syntax::ast::*; |
abe05a73 | 2 | use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass}; |
2c00a5a8 | 3 | use utils::{in_macro, snippet, span_lint_and_then}; |
abe05a73 XL |
4 | |
5 | /// **What it does:** Checks for constants with an explicit `'static` lifetime. | |
6 | /// | |
7 | /// **Why is this bad?** Adding `'static` to every reference can create very | |
8 | /// complicated types. | |
9 | /// | |
10 | /// **Known problems:** None. | |
11 | /// | |
12 | /// **Example:** | |
13 | /// ```rust | |
14 | /// const FOO: &'static [(&'static str, &'static str, fn(&Bar) -> bool)] = | |
15 | /// &[...] | |
16 | /// ``` | |
17 | /// This code can be rewritten as | |
18 | /// ```rust | |
19 | /// const FOO: &[(&str, &str, fn(&Bar) -> bool)] = &[...] | |
20 | /// ``` | |
abe05a73 XL |
21 | declare_lint! { |
22 | pub CONST_STATIC_LIFETIME, | |
23 | Warn, | |
24 | "Using explicit `'static` lifetime for constants when elision rules would allow omitting them." | |
25 | } | |
26 | ||
27 | pub struct StaticConst; | |
28 | ||
29 | impl LintPass for StaticConst { | |
30 | fn get_lints(&self) -> LintArray { | |
31 | lint_array!(CONST_STATIC_LIFETIME) | |
32 | } | |
33 | } | |
34 | ||
35 | impl StaticConst { | |
36 | // Recursively visit types | |
37 | fn visit_type(&mut self, ty: &Ty, cx: &EarlyContext) { | |
38 | match ty.node { | |
39 | // Be careful of nested structures (arrays and tuples) | |
40 | TyKind::Array(ref ty, _) => { | |
41 | self.visit_type(&*ty, cx); | |
42 | }, | |
43 | TyKind::Tup(ref tup) => for tup_ty in tup { | |
44 | self.visit_type(&*tup_ty, cx); | |
45 | }, | |
46 | // This is what we are looking for ! | |
47 | TyKind::Rptr(ref optional_lifetime, ref borrow_type) => { | |
48 | // Match the 'static lifetime | |
49 | if let Some(lifetime) = *optional_lifetime { | |
ff7c6d11 XL |
50 | match borrow_type.ty.node { |
51 | TyKind::Path(..) | TyKind::Slice(..) | TyKind::Array(..) | | |
52 | TyKind::Tup(..) => { | |
53 | if lifetime.ident.name == "'static" { | |
2c00a5a8 XL |
54 | let snip = snippet(cx, borrow_type.ty.span, "<type>"); |
55 | let sugg = format!("&{}", snip); | |
ff7c6d11 XL |
56 | span_lint_and_then( |
57 | cx, | |
58 | CONST_STATIC_LIFETIME, | |
59 | lifetime.span, | |
60 | "Constants have by default a `'static` lifetime", | |
61 | |db| { | |
2c00a5a8 | 62 | db.span_suggestion(ty.span, "consider removing `'static`", sugg); |
ff7c6d11 XL |
63 | }, |
64 | ); | |
65 | } | |
abe05a73 | 66 | } |
ff7c6d11 | 67 | _ => {} |
abe05a73 XL |
68 | } |
69 | } | |
70 | self.visit_type(&*borrow_type.ty, cx); | |
71 | }, | |
72 | TyKind::Slice(ref ty) => { | |
73 | self.visit_type(ty, cx); | |
74 | }, | |
75 | _ => {}, | |
76 | } | |
77 | } | |
78 | } | |
79 | ||
80 | impl EarlyLintPass for StaticConst { | |
81 | fn check_item(&mut self, cx: &EarlyContext, item: &Item) { | |
82 | if !in_macro(item.span) { | |
83 | // Match only constants... | |
84 | if let ItemKind::Const(ref var_type, _) = item.node { | |
85 | self.visit_type(var_type, cx); | |
86 | } | |
87 | } | |
88 | } | |
2c00a5a8 XL |
89 | |
90 | fn check_trait_item(&mut self, cx: &EarlyContext, item: &TraitItem) { | |
91 | if !in_macro(item.span) { | |
92 | // Match only constants... | |
93 | if let TraitItemKind::Const(ref var_type, _) = item.node { | |
94 | self.visit_type(var_type, cx); | |
95 | } | |
96 | } | |
97 | } | |
98 | ||
99 | fn check_impl_item(&mut self, cx: &EarlyContext, item: &ImplItem) { | |
100 | if !in_macro(item.span) { | |
101 | // Match only constants... | |
102 | if let ImplItemKind::Const(ref var_type, _) = item.node { | |
103 | self.visit_type(var_type, cx); | |
104 | } | |
105 | } | |
106 | } | |
abe05a73 | 107 | } |