1- use crate :: redundant_static_lifetime:: RedundantStaticLifetime ;
2- use crate :: utils:: in_macro_or_desugar;
1+ use crate :: utils:: { in_macro_or_desugar, snippet, span_lint_and_then} ;
32use rustc:: lint:: { EarlyContext , EarlyLintPass , LintArray , LintPass } ;
43use rustc:: { declare_lint_pass, declare_tool_lint} ;
4+ use rustc_errors:: Applicability ;
55use syntax:: ast:: * ;
66
77declare_clippy_lint ! {
8- /// **What it does:** Checks for constants with an explicit `'static` lifetime.
8+ /// **What it does:** Checks for constants and statics with an explicit `'static` lifetime.
99 ///
1010 /// **Why is this bad?** Adding `'static` to every reference can create very
1111 /// complicated types.
@@ -16,36 +16,77 @@ declare_clippy_lint! {
1616 /// ```ignore
1717 /// const FOO: &'static [(&'static str, &'static str, fn(&Bar) -> bool)] =
1818 /// &[...]
19+ /// static FOO: &'static [(&'static str, &'static str, fn(&Bar) -> bool)] =
20+ /// &[...]
1921 /// ```
2022 /// This code can be rewritten as
2123 /// ```ignore
2224 /// const FOO: &[(&str, &str, fn(&Bar) -> bool)] = &[...]
25+ /// static FOO: &[(&str, &str, fn(&Bar) -> bool)] = &[...]
2326 /// ```
2427 pub CONST_STATIC_LIFETIME ,
2528 style,
26- "Using explicit `'static` lifetime for constants when elision rules would allow omitting them."
29+ "Using explicit `'static` lifetime for constants or statics when elision rules would allow omitting them."
2730}
2831
2932declare_lint_pass ! ( StaticConst => [ CONST_STATIC_LIFETIME ] ) ;
3033
3134impl StaticConst {
3235 // Recursively visit types
33- fn visit_type ( & mut self , ty : & Ty , cx : & EarlyContext < ' _ > ) {
34- let mut rsl =
35- RedundantStaticLifetime :: new ( CONST_STATIC_LIFETIME , "Constants have by default a `'static` lifetime" ) ;
36- rsl. visit_type ( ty, cx)
36+ pub fn visit_type ( & mut self , ty : & Ty , cx : & EarlyContext < ' _ > , reason : & str ) {
37+ match ty. node {
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 . node {
52+ TyKind :: Path ( ..) | TyKind :: Slice ( ..) | TyKind :: Array ( ..) | TyKind :: Tup ( ..) => {
53+ if lifetime. ident . name == syntax:: symbol:: kw:: StaticLifetime {
54+ let snip = snippet ( cx, borrow_type. ty . span , "<type>" ) ;
55+ let sugg = format ! ( "&{}" , snip) ;
56+ span_lint_and_then ( cx, CONST_STATIC_LIFETIME , lifetime. ident . span , reason, |db| {
57+ db. span_suggestion (
58+ ty. span ,
59+ "consider removing `'static`" ,
60+ sugg,
61+ Applicability :: MachineApplicable , //snippet
62+ ) ;
63+ } ) ;
64+ }
65+ } ,
66+ _ => { } ,
67+ }
68+ }
69+ self . visit_type ( & * borrow_type. ty , cx, reason) ;
70+ } ,
71+ TyKind :: Slice ( ref ty) => {
72+ self . visit_type ( ty, cx, reason) ;
73+ } ,
74+ _ => { } ,
75+ }
3776 }
3877}
3978
4079impl EarlyLintPass for StaticConst {
4180 fn check_item ( & mut self , cx : & EarlyContext < ' _ > , item : & Item ) {
4281 if !in_macro_or_desugar ( item. span ) {
43- // Match only constants...
4482 if let ItemKind :: Const ( ref var_type, _) = item. node {
45- self . visit_type ( var_type, cx) ;
83+ self . visit_type ( var_type, cx, "Constants have by default a `'static` lifetime" ) ;
84+ // Don't check associated consts because `'static` cannot be elided on those (issue #2438)
85+ }
86+
87+ if let ItemKind :: Static ( ref var_type, _, _) = item. node {
88+ self . visit_type ( var_type, cx, "Statics have by default a `'static` lifetime" ) ;
4689 }
4790 }
4891 }
49-
50- // Don't check associated consts because `'static` cannot be elided on those (issue #2438)
5192}
0 commit comments