1 use syntax::ast::{Item, ItemKind, TyKind, Ty};
2 use rustc::lint::{LintPass, EarlyLintPass, LintArray, EarlyContext};
3 use utils::{span_help_and_lint, in_macro};
5 /// **What it does:** Checks for constants with an explicit `'static` lifetime.
7 /// **Why is this bad?** Adding `'static` to every reference can create very complicated types.
9 /// **Known problems:** None.
13 /// const FOO: &'static [(&'static str, &'static str, fn(&Bar) -> bool)] = &[..]
15 /// This code can be rewritten as
17 /// const FOO: &[(&str, &str, fn(&Bar) -> bool)] = &[...]
21 pub CONST_STATIC_LIFETIME,
23 "Using explicit `'static` lifetime for constants when elision rules would allow omitting them."
26 pub struct StaticConst;
28 impl LintPass for StaticConst {
29 fn get_lints(&self) -> LintArray {
30 lint_array!(CONST_STATIC_LIFETIME)
35 // Recursively visit types
36 fn visit_type(&mut self, ty: &Ty, cx: &EarlyContext) {
38 // Be carefull of nested structures (arrays and tuples)
39 TyKind::Array(ref ty, _) => {
41 self.visit_type(&*ty, cx);
43 TyKind::Tup(ref tup) => {
45 self.visit_type(&*tup_ty, cx);
48 // This is what we are looking for !
49 TyKind::Rptr(ref optional_lifetime, ref borrow_type) => {
50 // Match the 'static lifetime
51 if let Some(lifetime) = *optional_lifetime {
52 if let TyKind::Path(_, _) = borrow_type.ty.node {
53 // Verify that the path is a str
54 if lifetime.ident.name == "'static" {
55 span_help_and_lint(cx,
56 CONST_STATIC_LIFETIME,
58 "Constants have by default a `'static` lifetime",
59 "consider removing `'static`");
63 self.visit_type(&*borrow_type.ty, cx);
65 TyKind::Slice(ref ty) => {
66 self.visit_type(ty, cx);
73 impl EarlyLintPass for StaticConst {
74 fn check_item(&mut self, cx: &EarlyContext, item: &Item) {
75 if !in_macro(item.span) {
76 // Match only constants...
77 if let ItemKind::Const(ref var_type, _) = item.node {
78 self.visit_type(var_type, cx);