]>
Commit | Line | Data |
---|---|---|
cdc7bbd5 | 1 | use clippy_utils::diagnostics::span_lint_and_then; |
6522a427 | 2 | use clippy_utils::msrvs::{self, Msrv}; |
cdc7bbd5 | 3 | use clippy_utils::source::snippet; |
f20569fa XL |
4 | use rustc_ast::ast::{Item, ItemKind, Ty, TyKind}; |
5 | use rustc_errors::Applicability; | |
6 | use rustc_lint::{EarlyContext, EarlyLintPass}; | |
f20569fa XL |
7 | use rustc_session::{declare_tool_lint, impl_lint_pass}; |
8 | ||
f20569fa | 9 | declare_clippy_lint! { |
94222f64 XL |
10 | /// ### What it does |
11 | /// Checks for constants and statics with an explicit `'static` lifetime. | |
f20569fa | 12 | /// |
94222f64 XL |
13 | /// ### Why is this bad? |
14 | /// Adding `'static` to every reference can create very | |
f20569fa XL |
15 | /// complicated types. |
16 | /// | |
94222f64 | 17 | /// ### Example |
f20569fa XL |
18 | /// ```ignore |
19 | /// const FOO: &'static [(&'static str, &'static str, fn(&Bar) -> bool)] = | |
20 | /// &[...] | |
21 | /// static FOO: &'static [(&'static str, &'static str, fn(&Bar) -> bool)] = | |
22 | /// &[...] | |
23 | /// ``` | |
24 | /// This code can be rewritten as | |
25 | /// ```ignore | |
26 | /// const FOO: &[(&str, &str, fn(&Bar) -> bool)] = &[...] | |
27 | /// static FOO: &[(&str, &str, fn(&Bar) -> bool)] = &[...] | |
28 | /// ``` | |
a2a8927a | 29 | #[clippy::version = "1.37.0"] |
f20569fa XL |
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 { | |
6522a427 | 36 | msrv: Msrv, |
f20569fa XL |
37 | } |
38 | ||
39 | impl RedundantStaticLifetimes { | |
40 | #[must_use] | |
6522a427 | 41 | pub fn new(msrv: Msrv) -> Self { |
f20569fa XL |
42 | Self { msrv } |
43 | } | |
44 | } | |
45 | ||
46 | impl_lint_pass!(RedundantStaticLifetimes => [REDUNDANT_STATIC_LIFETIMES]); | |
47 | ||
48 | impl RedundantStaticLifetimes { | |
49 | // Recursively visit types | |
f2b60f7d | 50 | fn visit_type(ty: &Ty, cx: &EarlyContext<'_>, reason: &str) { |
f20569fa XL |
51 | match ty.kind { |
52 | // Be careful of nested structures (arrays and tuples) | |
923072b8 | 53 | TyKind::Array(ref ty, _) | TyKind::Slice(ref ty) => { |
f2b60f7d | 54 | Self::visit_type(ty, cx, reason); |
f20569fa XL |
55 | }, |
56 | TyKind::Tup(ref tup) => { | |
57 | for tup_ty in tup { | |
f2b60f7d | 58 | Self::visit_type(tup_ty, cx, reason); |
f20569fa XL |
59 | } |
60 | }, | |
61 | // This is what we are looking for ! | |
6522a427 | 62 | TyKind::Ref(ref optional_lifetime, ref borrow_type) => { |
f20569fa XL |
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>"); | |
6522a427 | 69 | let sugg = format!("&{}{snip}", borrow_type.mutbl.prefix_str()); |
f20569fa XL |
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 | } | |
f2b60f7d | 89 | Self::visit_type(&borrow_type.ty, cx, reason); |
f20569fa | 90 | }, |
f20569fa XL |
91 | _ => {}, |
92 | } | |
93 | } | |
94 | } | |
95 | ||
96 | impl EarlyLintPass for RedundantStaticLifetimes { | |
97 | fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { | |
6522a427 | 98 | if !self.msrv.meets(msrvs::STATIC_IN_CONST) { |
f20569fa XL |
99 | return; |
100 | } | |
101 | ||
102 | if !item.span.from_expansion() { | |
103 | if let ItemKind::Const(_, ref var_type, _) = item.kind { | |
f2b60f7d | 104 | Self::visit_type(var_type, cx, "constants have by default a `'static` lifetime"); |
f20569fa XL |
105 | // Don't check associated consts because `'static` cannot be elided on those (issue |
106 | // #2438) | |
107 | } | |
108 | ||
109 | if let ItemKind::Static(ref var_type, _, _) = item.kind { | |
f2b60f7d | 110 | Self::visit_type(var_type, cx, "statics have by default a `'static` lifetime"); |
f20569fa XL |
111 | } |
112 | } | |
113 | } | |
114 | ||
115 | extract_msrv_attr!(EarlyContext); | |
116 | } |