Skip to content

Commit 9b09257

Browse files
committed
Add lint for statics with explicit static lifetime.
1 parent c0dbd34 commit 9b09257

File tree

6 files changed

+230
-1
lines changed

6 files changed

+230
-1
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1087,6 +1087,7 @@ All notable changes to this project will be documented in this file.
10871087
[`single_match`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_match
10881088
[`single_match_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_match_else
10891089
[`slow_vector_initialization`]: https://rust-lang.github.io/rust-clippy/master/index.html#slow_vector_initialization
1090+
[`static_static_lifetime`]: https://rust-lang.github.io/rust-clippy/master/index.html#static_static_lifetime
10901091
[`str_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#str_to_string
10911092
[`string_add`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_add
10921093
[`string_add_assign`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_add_assign

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code.
99

10-
[There are 304 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
10+
[There are 305 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
1111

1212
We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you:
1313

clippy_lints/src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,7 @@ pub mod returns;
255255
pub mod serde_api;
256256
pub mod shadow;
257257
pub mod slow_vector_initialization;
258+
pub mod static_static_lifetime;
258259
pub mod strings;
259260
pub mod suspicious_trait_impl;
260261
pub mod swap;
@@ -553,6 +554,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) {
553554
reg.register_late_lint_pass(box identity_conversion::IdentityConversion::default());
554555
reg.register_late_lint_pass(box types::ImplicitHasher);
555556
reg.register_early_lint_pass(box const_static_lifetime::StaticConst);
557+
reg.register_early_lint_pass(box static_static_lifetime::StaticStatic);
556558
reg.register_late_lint_pass(box fallible_impl_from::FallibleImplFrom);
557559
reg.register_late_lint_pass(box replace_consts::ReplaceConsts);
558560
reg.register_late_lint_pass(box types::UnitArg);
@@ -841,6 +843,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) {
841843
returns::UNUSED_UNIT,
842844
serde_api::SERDE_API_MISUSE,
843845
slow_vector_initialization::SLOW_VECTOR_INITIALIZATION,
846+
static_static_lifetime::STATIC_STATIC_LIFETIME,
844847
strings::STRING_LIT_AS_BYTES,
845848
suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL,
846849
suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL,
@@ -959,6 +962,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) {
959962
returns::LET_AND_RETURN,
960963
returns::NEEDLESS_RETURN,
961964
returns::UNUSED_UNIT,
965+
static_static_lifetime::STATIC_STATIC_LIFETIME,
962966
strings::STRING_LIT_AS_BYTES,
963967
types::FN_TO_NUMERIC_CAST,
964968
types::FN_TO_NUMERIC_CAST_WITH_TRUNCATION,
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
use crate::utils::{in_macro_or_desugar, snippet, span_lint_and_then};
2+
use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass};
3+
use rustc::{declare_lint_pass, declare_tool_lint};
4+
use rustc_errors::Applicability;
5+
use syntax::ast::*;
6+
7+
declare_clippy_lint! {
8+
/// **What it does:** Checks for statics with an explicit `'static` lifetime.
9+
///
10+
/// **Why is this bad?** Adding `'static` to every reference can create very
11+
/// complicated types.
12+
///
13+
/// **Known problems:** None.
14+
///
15+
/// **Example:**
16+
/// ```ignore
17+
/// static FOO: &'static [(&'static str, &'static str, fn(&Bar) -> bool)] =
18+
/// &[...]
19+
/// ```
20+
/// This code can be rewritten as
21+
/// ```ignore
22+
/// static FOO: &[(&str, &str, fn(&Bar) -> bool)] = &[...]
23+
/// ```
24+
pub STATIC_STATIC_LIFETIME,
25+
style,
26+
"Using explicit `'static` lifetime for statics when elision rules would allow omitting them."
27+
}
28+
29+
declare_lint_pass!(StaticStatic => [STATIC_STATIC_LIFETIME]);
30+
31+
impl StaticStatic {
32+
// Recursively visit types
33+
fn visit_type(&mut self, ty: &Ty, cx: &EarlyContext<'_>) {
34+
match ty.node {
35+
// Be careful of nested structures (arrays and tuples)
36+
TyKind::Array(ref ty, _) => {
37+
self.visit_type(&*ty, cx);
38+
},
39+
TyKind::Tup(ref tup) => {
40+
for tup_ty in tup {
41+
self.visit_type(&*tup_ty, cx);
42+
}
43+
},
44+
// This is what we are looking for !
45+
TyKind::Rptr(ref optional_lifetime, ref borrow_type) => {
46+
// Match the 'static lifetime
47+
if let Some(lifetime) = *optional_lifetime {
48+
match borrow_type.ty.node {
49+
TyKind::Path(..) | TyKind::Slice(..) | TyKind::Array(..) | TyKind::Tup(..) => {
50+
if lifetime.ident.name == syntax::symbol::kw::StaticLifetime {
51+
let snip = snippet(cx, borrow_type.ty.span, "<type>");
52+
let sugg = format!("&{}", snip);
53+
span_lint_and_then(
54+
cx,
55+
STATIC_STATIC_LIFETIME,
56+
lifetime.ident.span,
57+
"Statics have by default a `'static` lifetime",
58+
|db| {
59+
db.span_suggestion(
60+
ty.span,
61+
"consider removing `'static`",
62+
sugg,
63+
Applicability::MachineApplicable, //snippet
64+
);
65+
},
66+
);
67+
}
68+
},
69+
_ => {},
70+
}
71+
}
72+
self.visit_type(&*borrow_type.ty, cx);
73+
},
74+
TyKind::Slice(ref ty) => {
75+
self.visit_type(ty, cx);
76+
},
77+
_ => {},
78+
}
79+
}
80+
}
81+
82+
impl EarlyLintPass for StaticStatic {
83+
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
84+
if !in_macro_or_desugar(item.span) {
85+
// Match only statics...
86+
if let ItemKind::Static(ref var_type, _, _) = item.node {
87+
self.visit_type(var_type, cx);
88+
}
89+
}
90+
}
91+
92+
// Don't check associated consts because `'static` cannot be elided on those (issue #2438)
93+
}

tests/ui/static_static_lifetime.rs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
#[derive(Debug)]
2+
struct Foo {}
3+
4+
static VAR_ONE: &'static str = "Test static #1"; // ERROR Consider removing 'static.
5+
6+
static VAR_TWO: &str = "Test static #2"; // This line should not raise a warning.
7+
8+
static VAR_THREE: &[&'static str] = &["one", "two"]; // ERROR Consider removing 'static
9+
10+
static VAR_FOUR: (&str, (&str, &'static str), &'static str) = ("on", ("th", "th"), "on"); // ERROR Consider removing 'static
11+
12+
static VAR_FIVE: &'static [&[&'static str]] = &[&["test"], &["other one"]]; // ERROR Consider removing 'static
13+
14+
static VAR_SIX: &'static u8 = &5;
15+
16+
static VAR_SEVEN: &[&(&str, &'static [&'static str])] = &[&("one", &["other one"])];
17+
18+
static VAR_HEIGHT: &'static Foo = &Foo {};
19+
20+
static VAR_SLICE: &'static [u8] = b"Test static #3"; // ERROR Consider removing 'static.
21+
22+
static VAR_TUPLE: &'static (u8, u8) = &(1, 2); // ERROR Consider removing 'static.
23+
24+
static VAR_ARRAY: &'static [u8; 1] = b"T"; // ERROR Consider removing 'static.
25+
26+
fn main() {
27+
let false_positive: &'static str = "test";
28+
println!("{}", VAR_ONE);
29+
println!("{}", VAR_TWO);
30+
println!("{:?}", VAR_THREE);
31+
println!("{:?}", VAR_FOUR);
32+
println!("{:?}", VAR_FIVE);
33+
println!("{:?}", VAR_SIX);
34+
println!("{:?}", VAR_SEVEN);
35+
println!("{:?}", VAR_HEIGHT);
36+
println!("{}", false_positive);
37+
}
38+
39+
// trait Bar {
40+
// static TRAIT_VAR: &'static str;
41+
// }
42+
43+
// impl Foo {
44+
// static IMPL_VAR: &'static str = "var";
45+
// }
46+
47+
// impl Bar for Foo {
48+
// static TRAIT_VAR: &'static str = "foo";
49+
// }
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
error: Statics have by default a `'static` lifetime
2+
--> $DIR/static_static_lifetime.rs:4:18
3+
|
4+
LL | static VAR_ONE: &'static str = "Test static #1"; // ERROR Consider removing 'static.
5+
| -^^^^^^^---- help: consider removing `'static`: `&str`
6+
|
7+
= note: `-D clippy::static-static-lifetime` implied by `-D warnings`
8+
9+
error: Statics have by default a `'static` lifetime
10+
--> $DIR/static_static_lifetime.rs:8:22
11+
|
12+
LL | static VAR_THREE: &[&'static str] = &["one", "two"]; // ERROR Consider removing 'static
13+
| -^^^^^^^---- help: consider removing `'static`: `&str`
14+
15+
error: Statics have by default a `'static` lifetime
16+
--> $DIR/static_static_lifetime.rs:10:33
17+
|
18+
LL | static VAR_FOUR: (&str, (&str, &'static str), &'static str) = ("on", ("th", "th"), "on"); // ERROR Consider removing 'static
19+
| -^^^^^^^---- help: consider removing `'static`: `&str`
20+
21+
error: Statics have by default a `'static` lifetime
22+
--> $DIR/static_static_lifetime.rs:10:48
23+
|
24+
LL | static VAR_FOUR: (&str, (&str, &'static str), &'static str) = ("on", ("th", "th"), "on"); // ERROR Consider removing 'static
25+
| -^^^^^^^---- help: consider removing `'static`: `&str`
26+
27+
error: Statics have by default a `'static` lifetime
28+
--> $DIR/static_static_lifetime.rs:12:19
29+
|
30+
LL | static VAR_FIVE: &'static [&[&'static str]] = &[&["test"], &["other one"]]; // ERROR Consider removing 'static
31+
| -^^^^^^^------------------ help: consider removing `'static`: `&[&[&'static str]]`
32+
33+
error: Statics have by default a `'static` lifetime
34+
--> $DIR/static_static_lifetime.rs:12:31
35+
|
36+
LL | static VAR_FIVE: &'static [&[&'static str]] = &[&["test"], &["other one"]]; // ERROR Consider removing 'static
37+
| -^^^^^^^---- help: consider removing `'static`: `&str`
38+
39+
error: Statics have by default a `'static` lifetime
40+
--> $DIR/static_static_lifetime.rs:14:18
41+
|
42+
LL | static VAR_SIX: &'static u8 = &5;
43+
| -^^^^^^^--- help: consider removing `'static`: `&u8`
44+
45+
error: Statics have by default a `'static` lifetime
46+
--> $DIR/static_static_lifetime.rs:16:30
47+
|
48+
LL | static VAR_SEVEN: &[&(&str, &'static [&'static str])] = &[&("one", &["other one"])];
49+
| -^^^^^^^--------------- help: consider removing `'static`: `&[&'static str]`
50+
51+
error: Statics have by default a `'static` lifetime
52+
--> $DIR/static_static_lifetime.rs:16:40
53+
|
54+
LL | static VAR_SEVEN: &[&(&str, &'static [&'static str])] = &[&("one", &["other one"])];
55+
| -^^^^^^^---- help: consider removing `'static`: `&str`
56+
57+
error: Statics have by default a `'static` lifetime
58+
--> $DIR/static_static_lifetime.rs:18:21
59+
|
60+
LL | static VAR_HEIGHT: &'static Foo = &Foo {};
61+
| -^^^^^^^---- help: consider removing `'static`: `&Foo`
62+
63+
error: Statics have by default a `'static` lifetime
64+
--> $DIR/static_static_lifetime.rs:20:20
65+
|
66+
LL | static VAR_SLICE: &'static [u8] = b"Test static #3"; // ERROR Consider removing 'static.
67+
| -^^^^^^^----- help: consider removing `'static`: `&[u8]`
68+
69+
error: Statics have by default a `'static` lifetime
70+
--> $DIR/static_static_lifetime.rs:22:20
71+
|
72+
LL | static VAR_TUPLE: &'static (u8, u8) = &(1, 2); // ERROR Consider removing 'static.
73+
| -^^^^^^^--------- help: consider removing `'static`: `&(u8, u8)`
74+
75+
error: Statics have by default a `'static` lifetime
76+
--> $DIR/static_static_lifetime.rs:24:20
77+
|
78+
LL | static VAR_ARRAY: &'static [u8; 1] = b"T"; // ERROR Consider removing 'static.
79+
| -^^^^^^^-------- help: consider removing `'static`: `&[u8; 1]`
80+
81+
error: aborting due to 13 previous errors
82+

0 commit comments

Comments
 (0)