about summary refs log tree commit diff
diff options
context:
space:
mode:
authorkrk <keremkat@gmail.com>2019-06-01 12:10:15 +0200
committerflip1995 <hello@philkrones.com>2019-06-14 09:41:46 +0200
commit16bd4796e998f7ef3c7eaecc60bf03349fdbb859 (patch)
tree7c3b208f1bc66430967664d91752c2a4f043cdcc
parentbd39cea01ce5c539fa109f9ab576f5cf8cf329dc (diff)
downloadrust-16bd4796e998f7ef3c7eaecc60bf03349fdbb859.tar.gz
rust-16bd4796e998f7ef3c7eaecc60bf03349fdbb859.zip
Add lint for statics with explicit static lifetime.
-rw-r--r--CHANGELOG.md1
-rw-r--r--clippy_lints/src/lib.rs4
-rw-r--r--clippy_lints/src/static_static_lifetime.rs93
-rw-r--r--tests/ui/static_static_lifetime.rs49
-rw-r--r--tests/ui/static_static_lifetime.stderr82
5 files changed, 229 insertions, 0 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5f34d24cd47..03c8be124c3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1088,6 +1088,7 @@ All notable changes to this project will be documented in this file.
 [`single_match`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_match
 [`single_match_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_match_else
 [`slow_vector_initialization`]: https://rust-lang.github.io/rust-clippy/master/index.html#slow_vector_initialization
+[`static_static_lifetime`]: https://rust-lang.github.io/rust-clippy/master/index.html#static_static_lifetime
 [`str_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#str_to_string
 [`string_add`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_add
 [`string_add_assign`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_add_assign
diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs
index 2bec5cb2d01..0b1c7685969 100644
--- a/clippy_lints/src/lib.rs
+++ b/clippy_lints/src/lib.rs
@@ -256,6 +256,7 @@ pub mod returns;
 pub mod serde_api;
 pub mod shadow;
 pub mod slow_vector_initialization;
+pub mod static_static_lifetime;
 pub mod strings;
 pub mod suspicious_trait_impl;
 pub mod swap;
@@ -554,6 +555,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) {
     reg.register_late_lint_pass(box identity_conversion::IdentityConversion::default());
     reg.register_late_lint_pass(box types::ImplicitHasher);
     reg.register_early_lint_pass(box const_static_lifetime::StaticConst);
+    reg.register_early_lint_pass(box static_static_lifetime::StaticStatic);
     reg.register_late_lint_pass(box fallible_impl_from::FallibleImplFrom);
     reg.register_late_lint_pass(box replace_consts::ReplaceConsts);
     reg.register_late_lint_pass(box types::UnitArg);
@@ -844,6 +846,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) {
         returns::UNUSED_UNIT,
         serde_api::SERDE_API_MISUSE,
         slow_vector_initialization::SLOW_VECTOR_INITIALIZATION,
+        static_static_lifetime::STATIC_STATIC_LIFETIME,
         strings::STRING_LIT_AS_BYTES,
         suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL,
         suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL,
@@ -962,6 +965,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) {
         returns::LET_AND_RETURN,
         returns::NEEDLESS_RETURN,
         returns::UNUSED_UNIT,
+        static_static_lifetime::STATIC_STATIC_LIFETIME,
         strings::STRING_LIT_AS_BYTES,
         types::FN_TO_NUMERIC_CAST,
         types::FN_TO_NUMERIC_CAST_WITH_TRUNCATION,
diff --git a/clippy_lints/src/static_static_lifetime.rs b/clippy_lints/src/static_static_lifetime.rs
new file mode 100644
index 00000000000..338d9e76602
--- /dev/null
+++ b/clippy_lints/src/static_static_lifetime.rs
@@ -0,0 +1,93 @@
+use crate::utils::{in_macro_or_desugar, snippet, span_lint_and_then};
+use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass};
+use rustc::{declare_lint_pass, declare_tool_lint};
+use rustc_errors::Applicability;
+use syntax::ast::*;
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for statics with an explicit `'static` lifetime.
+    ///
+    /// **Why is this bad?** Adding `'static` to every reference can create very
+    /// complicated types.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```ignore
+    /// static FOO: &'static [(&'static str, &'static str, fn(&Bar) -> bool)] =
+    /// &[...]
+    /// ```
+    /// This code can be rewritten as
+    /// ```ignore
+    ///  static FOO: &[(&str, &str, fn(&Bar) -> bool)] = &[...]
+    /// ```
+    pub STATIC_STATIC_LIFETIME,
+    style,
+    "Using explicit `'static` lifetime for statics when elision rules would allow omitting them."
+}
+
+declare_lint_pass!(StaticStatic => [STATIC_STATIC_LIFETIME]);
+
+impl StaticStatic {
+    // Recursively visit types
+    fn visit_type(&mut self, ty: &Ty, cx: &EarlyContext<'_>) {
+        match ty.node {
+            // Be careful of nested structures (arrays and tuples)
+            TyKind::Array(ref ty, _) => {
+                self.visit_type(&*ty, cx);
+            },
+            TyKind::Tup(ref tup) => {
+                for tup_ty in tup {
+                    self.visit_type(&*tup_ty, cx);
+                }
+            },
+            // This is what we are looking for !
+            TyKind::Rptr(ref optional_lifetime, ref borrow_type) => {
+                // Match the 'static lifetime
+                if let Some(lifetime) = *optional_lifetime {
+                    match borrow_type.ty.node {
+                        TyKind::Path(..) | TyKind::Slice(..) | TyKind::Array(..) | TyKind::Tup(..) => {
+                            if lifetime.ident.name == syntax::symbol::kw::StaticLifetime {
+                                let snip = snippet(cx, borrow_type.ty.span, "<type>");
+                                let sugg = format!("&{}", snip);
+                                span_lint_and_then(
+                                    cx,
+                                    STATIC_STATIC_LIFETIME,
+                                    lifetime.ident.span,
+                                    "Statics have by default a `'static` lifetime",
+                                    |db| {
+                                        db.span_suggestion(
+                                            ty.span,
+                                            "consider removing `'static`",
+                                            sugg,
+                                            Applicability::MachineApplicable, //snippet
+                                        );
+                                    },
+                                );
+                            }
+                        },
+                        _ => {},
+                    }
+                }
+                self.visit_type(&*borrow_type.ty, cx);
+            },
+            TyKind::Slice(ref ty) => {
+                self.visit_type(ty, cx);
+            },
+            _ => {},
+        }
+    }
+}
+
+impl EarlyLintPass for StaticStatic {
+    fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
+        if !in_macro_or_desugar(item.span) {
+            // Match only statics...
+            if let ItemKind::Static(ref var_type, _, _) = item.node {
+                self.visit_type(var_type, cx);
+            }
+        }
+    }
+
+    // Don't check associated consts because `'static` cannot be elided on those (issue #2438)
+}
diff --git a/tests/ui/static_static_lifetime.rs b/tests/ui/static_static_lifetime.rs
new file mode 100644
index 00000000000..04fecbfaeb2
--- /dev/null
+++ b/tests/ui/static_static_lifetime.rs
@@ -0,0 +1,49 @@
+#[derive(Debug)]
+struct Foo {}
+
+static VAR_ONE: &'static str = "Test static #1"; // ERROR Consider removing 'static.
+
+static VAR_TWO: &str = "Test static #2"; // This line should not raise a warning.
+
+static VAR_THREE: &[&'static str] = &["one", "two"]; // ERROR Consider removing 'static
+
+static VAR_FOUR: (&str, (&str, &'static str), &'static str) = ("on", ("th", "th"), "on"); // ERROR Consider removing 'static
+
+static VAR_FIVE: &'static [&[&'static str]] = &[&["test"], &["other one"]]; // ERROR Consider removing 'static
+
+static VAR_SIX: &'static u8 = &5;
+
+static VAR_SEVEN: &[&(&str, &'static [&'static str])] = &[&("one", &["other one"])];
+
+static VAR_HEIGHT: &'static Foo = &Foo {};
+
+static VAR_SLICE: &'static [u8] = b"Test static #3"; // ERROR Consider removing 'static.
+
+static VAR_TUPLE: &'static (u8, u8) = &(1, 2); // ERROR Consider removing 'static.
+
+static VAR_ARRAY: &'static [u8; 1] = b"T"; // ERROR Consider removing 'static.
+
+fn main() {
+    let false_positive: &'static str = "test";
+    println!("{}", VAR_ONE);
+    println!("{}", VAR_TWO);
+    println!("{:?}", VAR_THREE);
+    println!("{:?}", VAR_FOUR);
+    println!("{:?}", VAR_FIVE);
+    println!("{:?}", VAR_SIX);
+    println!("{:?}", VAR_SEVEN);
+    println!("{:?}", VAR_HEIGHT);
+    println!("{}", false_positive);
+}
+
+// trait Bar {
+//     static TRAIT_VAR: &'static str;
+// }
+
+// impl Foo {
+//     static IMPL_VAR: &'static str = "var";
+// }
+
+// impl Bar for Foo {
+//     static TRAIT_VAR: &'static str = "foo";
+// }
diff --git a/tests/ui/static_static_lifetime.stderr b/tests/ui/static_static_lifetime.stderr
new file mode 100644
index 00000000000..c4111b1f13c
--- /dev/null
+++ b/tests/ui/static_static_lifetime.stderr
@@ -0,0 +1,82 @@
+error: Statics have by default a `'static` lifetime
+  --> $DIR/static_static_lifetime.rs:4:18
+   |
+LL | static VAR_ONE: &'static str = "Test static #1"; // ERROR Consider removing 'static.
+   |                 -^^^^^^^---- help: consider removing `'static`: `&str`
+   |
+   = note: `-D clippy::static-static-lifetime` implied by `-D warnings`
+
+error: Statics have by default a `'static` lifetime
+  --> $DIR/static_static_lifetime.rs:8:22
+   |
+LL | static VAR_THREE: &[&'static str] = &["one", "two"]; // ERROR Consider removing 'static
+   |                     -^^^^^^^---- help: consider removing `'static`: `&str`
+
+error: Statics have by default a `'static` lifetime
+  --> $DIR/static_static_lifetime.rs:10:33
+   |
+LL | static VAR_FOUR: (&str, (&str, &'static str), &'static str) = ("on", ("th", "th"), "on"); // ERROR Consider removing 'static
+   |                                -^^^^^^^---- help: consider removing `'static`: `&str`
+
+error: Statics have by default a `'static` lifetime
+  --> $DIR/static_static_lifetime.rs:10:48
+   |
+LL | static VAR_FOUR: (&str, (&str, &'static str), &'static str) = ("on", ("th", "th"), "on"); // ERROR Consider removing 'static
+   |                                               -^^^^^^^---- help: consider removing `'static`: `&str`
+
+error: Statics have by default a `'static` lifetime
+  --> $DIR/static_static_lifetime.rs:12:19
+   |
+LL | static VAR_FIVE: &'static [&[&'static str]] = &[&["test"], &["other one"]]; // ERROR Consider removing 'static
+   |                  -^^^^^^^------------------ help: consider removing `'static`: `&[&[&'static str]]`
+
+error: Statics have by default a `'static` lifetime
+  --> $DIR/static_static_lifetime.rs:12:31
+   |
+LL | static VAR_FIVE: &'static [&[&'static str]] = &[&["test"], &["other one"]]; // ERROR Consider removing 'static
+   |                              -^^^^^^^---- help: consider removing `'static`: `&str`
+
+error: Statics have by default a `'static` lifetime
+  --> $DIR/static_static_lifetime.rs:14:18
+   |
+LL | static VAR_SIX: &'static u8 = &5;
+   |                 -^^^^^^^--- help: consider removing `'static`: `&u8`
+
+error: Statics have by default a `'static` lifetime
+  --> $DIR/static_static_lifetime.rs:16:30
+   |
+LL | static VAR_SEVEN: &[&(&str, &'static [&'static str])] = &[&("one", &["other one"])];
+   |                             -^^^^^^^--------------- help: consider removing `'static`: `&[&'static str]`
+
+error: Statics have by default a `'static` lifetime
+  --> $DIR/static_static_lifetime.rs:16:40
+   |
+LL | static VAR_SEVEN: &[&(&str, &'static [&'static str])] = &[&("one", &["other one"])];
+   |                                       -^^^^^^^---- help: consider removing `'static`: `&str`
+
+error: Statics have by default a `'static` lifetime
+  --> $DIR/static_static_lifetime.rs:18:21
+   |
+LL | static VAR_HEIGHT: &'static Foo = &Foo {};
+   |                    -^^^^^^^---- help: consider removing `'static`: `&Foo`
+
+error: Statics have by default a `'static` lifetime
+  --> $DIR/static_static_lifetime.rs:20:20
+   |
+LL | static VAR_SLICE: &'static [u8] = b"Test static #3"; // ERROR Consider removing 'static.
+   |                   -^^^^^^^----- help: consider removing `'static`: `&[u8]`
+
+error: Statics have by default a `'static` lifetime
+  --> $DIR/static_static_lifetime.rs:22:20
+   |
+LL | static VAR_TUPLE: &'static (u8, u8) = &(1, 2); // ERROR Consider removing 'static.
+   |                   -^^^^^^^--------- help: consider removing `'static`: `&(u8, u8)`
+
+error: Statics have by default a `'static` lifetime
+  --> $DIR/static_static_lifetime.rs:24:20
+   |
+LL | static VAR_ARRAY: &'static [u8; 1] = b"T"; // ERROR Consider removing 'static.
+   |                   -^^^^^^^-------- help: consider removing `'static`: `&[u8; 1]`
+
+error: aborting due to 13 previous errors
+