1 use crate::utils::{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_session::{declare_lint_pass, declare_tool_lint};
8 /// **What it does:** Checks for constants and statics with an explicit `'static` lifetime.
10 /// **Why is this bad?** Adding `'static` to every reference can create very
11 /// complicated types.
13 /// **Known problems:** None.
17 /// const FOO: &'static [(&'static str, &'static str, fn(&Bar) -> bool)] =
19 /// static FOO: &'static [(&'static str, &'static str, fn(&Bar) -> bool)] =
22 /// This code can be rewritten as
24 /// const FOO: &[(&str, &str, fn(&Bar) -> bool)] = &[...]
25 /// static FOO: &[(&str, &str, fn(&Bar) -> bool)] = &[...]
27 pub REDUNDANT_STATIC_LIFETIMES,
29 "Using explicit `'static` lifetime for constants or statics when elision rules would allow omitting them."
32 declare_lint_pass!(RedundantStaticLifetimes => [REDUNDANT_STATIC_LIFETIMES]);
34 impl RedundantStaticLifetimes {
35 // Recursively visit types
36 fn visit_type(&mut self, ty: &Ty, cx: &EarlyContext<'_>, reason: &str) {
38 // Be careful of nested structures (arrays and tuples)
39 TyKind::Array(ref ty, _) => {
40 self.visit_type(&*ty, cx, reason);
42 TyKind::Tup(ref tup) => {
44 self.visit_type(&*tup_ty, cx, reason);
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.kind {
52 TyKind::Path(..) | TyKind::Slice(..) | TyKind::Array(..) | TyKind::Tup(..) => {
53 if lifetime.ident.name == rustc_span::symbol::kw::StaticLifetime {
54 let snip = snippet(cx, borrow_type.ty.span, "<type>");
55 let sugg = format!("&{}", snip);
58 REDUNDANT_STATIC_LIFETIMES,
64 "consider removing `'static`",
66 Applicability::MachineApplicable, //snippet
75 self.visit_type(&*borrow_type.ty, cx, reason);
77 TyKind::Slice(ref ty) => {
78 self.visit_type(ty, cx, reason);
85 impl EarlyLintPass for RedundantStaticLifetimes {
86 fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
87 if !item.span.from_expansion() {
88 if let ItemKind::Const(_, ref var_type, _) = item.kind {
89 self.visit_type(var_type, cx, "Constants have by default a `'static` lifetime");
90 // Don't check associated consts because `'static` cannot be elided on those (issue
94 if let ItemKind::Static(ref var_type, _, _) = item.kind {
95 self.visit_type(var_type, cx, "Statics have by default a `'static` lifetime");