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