]> git.lizzy.rs Git - rust.git/blobdiff - clippy_lints/src/lifetimes.rs
Rustup to https://github.com/rust-lang/rust/pull/60740
[rust.git] / clippy_lints / src / lifetimes.rs
index 5b04b829453b98ef1ed518ff5be74a0229553d00..4f27d38c12fe408fe066ed85bf66f746d18812fd 100644 (file)
@@ -1,65 +1,63 @@
-use crate::reexport::*;
 use matches::matches;
-use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass, in_external_macro, LintContext};
-use rustc::{declare_tool_lint, lint_array};
-use rustc::hir::def::Def;
-use rustc::hir::*;
+use rustc::hir::def::{DefKind, Res};
 use rustc::hir::intravisit::*;
+use rustc::hir::*;
+use rustc::lint::{in_external_macro, LateContext, LateLintPass, LintArray, LintContext, LintPass};
+use rustc::{declare_lint_pass, declare_tool_lint};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use syntax::source_map::Span;
+use syntax::symbol::kw;
+
+use crate::reexport::*;
 use crate::utils::{last_path_segment, span_lint};
-use syntax::symbol::keywords;
-
-/// **What it does:** Checks for lifetime annotations which can be removed by
-/// relying on lifetime elision.
-///
-/// **Why is this bad?** The additional lifetimes make the code look more
-/// complicated, while there is nothing out of the ordinary going on. Removing
-/// them leads to more readable code.
-///
-/// **Known problems:** Potential false negatives: we bail out if the function
-/// has a `where` clause where lifetimes are mentioned.
-///
-/// **Example:**
-/// ```rust
-/// fn in_and_out<'a>(x: &'a u8, y: u8) -> &'a u8 { x }
-/// ```
+
 declare_clippy_lint! {
+    /// **What it does:** Checks for lifetime annotations which can be removed by
+    /// relying on lifetime elision.
+    ///
+    /// **Why is this bad?** The additional lifetimes make the code look more
+    /// complicated, while there is nothing out of the ordinary going on. Removing
+    /// them leads to more readable code.
+    ///
+    /// **Known problems:** Potential false negatives: we bail out if the function
+    /// has a `where` clause where lifetimes are mentioned.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// fn in_and_out<'a>(x: &'a u8, y: u8) -> &'a u8 {
+    ///     x
+    /// }
+    /// ```
     pub NEEDLESS_LIFETIMES,
     complexity,
     "using explicit lifetimes for references in function arguments when elision rules \
      would allow omitting them"
 }
 
-/// **What it does:** Checks for lifetimes in generics that are never used
-/// anywhere else.
-///
-/// **Why is this bad?** The additional lifetimes make the code look more
-/// complicated, while there is nothing out of the ordinary going on. Removing
-/// them leads to more readable code.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// fn unused_lifetime<'a>(x: u8) { .. }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for lifetimes in generics that are never used
+    /// anywhere else.
+    ///
+    /// **Why is this bad?** The additional lifetimes make the code look more
+    /// complicated, while there is nothing out of the ordinary going on. Removing
+    /// them leads to more readable code.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// fn unused_lifetime<'a>(x: u8) {
+    ///     ..
+    /// }
+    /// ```
     pub EXTRA_UNUSED_LIFETIMES,
     complexity,
     "unused lifetimes in function definitions"
 }
 
-#[derive(Copy, Clone)]
-pub struct LifetimePass;
+declare_lint_pass!(Lifetimes => [NEEDLESS_LIFETIMES, EXTRA_UNUSED_LIFETIMES]);
 
-impl LintPass for LifetimePass {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(NEEDLESS_LIFETIMES, EXTRA_UNUSED_LIFETIMES)
-    }
-}
-
-impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LifetimePass {
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Lifetimes {
     fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) {
         if let ItemKind::Fn(ref decl, _, ref generics, id) = item.node {
             check_fn_inner(cx, decl, Some(id), generics, item.span);
@@ -103,9 +101,9 @@ fn check_fn_inner<'a, 'tcx>(
     }
 
     let mut bounds_lts = Vec::new();
-    let types = generics.params.iter().filter_map(|param| match param.kind {
-        GenericParamKind::Type { .. } => Some(param),
-        GenericParamKind::Lifetime { .. } => None,
+    let types = generics.params.iter().filter(|param| match param.kind {
+        GenericParamKind::Type { .. } => true,
+        _ => false,
     });
     for typ in types {
         for bound in &typ.bounds {
@@ -125,7 +123,7 @@ fn check_fn_inner<'a, 'tcx>(
                 if let Some(ref params) = *params {
                     let lifetimes = params.args.iter().filter_map(|arg| match arg {
                         GenericArg::Lifetime(lt) => Some(lt),
-                        GenericArg::Type(_) => None,
+                        _ => None,
                     });
                     for bound in lifetimes {
                         if bound.name != LifetimeName::Static && !bound.is_elided() {
@@ -142,7 +140,8 @@ fn check_fn_inner<'a, 'tcx>(
             cx,
             NEEDLESS_LIFETIMES,
             span,
-            "explicit lifetimes given in parameter types where they could be elided",
+            "explicit lifetimes given in parameter types where they could be elided \
+             (or replaced with `'_` if needed by type declaration)",
         );
     }
     report_extra_lifetimes(cx, decl, generics);
@@ -190,7 +189,7 @@ fn could_use_elision<'a, 'tcx: 'a>(
         let mut checker = BodyLifetimeChecker {
             lifetimes_used_in_body: false,
         };
-        checker.visit_expr(&cx.tcx.hir.body(body_id).value);
+        checker.visit_expr(&cx.tcx.hir().body(body_id).value);
         if checker.lifetimes_used_in_body {
             return false;
         }
@@ -210,9 +209,7 @@ fn could_use_elision<'a, 'tcx: 'a>(
         // no output lifetimes, check distinctness of input lifetimes
 
         // only unnamed and static, ok
-        let unnamed_and_static = input_lts
-            .iter()
-            .all(|lt| *lt == RefLt::Unnamed || *lt == RefLt::Static);
+        let unnamed_and_static = input_lts.iter().all(|lt| *lt == RefLt::Unnamed || *lt == RefLt::Static);
         if unnamed_and_static {
             return false;
         }
@@ -309,17 +306,18 @@ fn collect_anonymous_lifetimes(&mut self, qpath: &QPath, ty: &Ty) {
             if !last_path_segment.parenthesized
                 && !last_path_segment.args.iter().any(|arg| match arg {
                     GenericArg::Lifetime(_) => true,
-                    GenericArg::Type(_) => false,
-                }) {
-                let hir_id = self.cx.tcx.hir.node_to_hir_id(ty.id);
-                match self.cx.tables.qpath_def(qpath, hir_id) {
-                    Def::TyAlias(def_id) | Def::Struct(def_id) => {
+                    _ => false,
+                })
+            {
+                let hir_id = ty.hir_id;
+                match self.cx.tables.qpath_res(qpath, hir_id) {
+                    Res::Def(DefKind::TyAlias, def_id) | Res::Def(DefKind::Struct, def_id) => {
                         let generics = self.cx.tcx.generics_of(def_id);
                         for _ in generics.params.as_slice() {
                             self.record(&None);
                         }
                     },
-                    Def::Trait(def_id) => {
+                    Res::Def(DefKind::Trait, def_id) => {
                         let trait_def = self.cx.tcx.trait_def(def_id);
                         for _ in &self.cx.tcx.generics_of(trait_def.def_id).params {
                             self.record(&None);
@@ -344,24 +342,21 @@ fn visit_ty(&mut self, ty: &'tcx Ty) {
                 self.record(&None);
             },
             TyKind::Path(ref path) => {
-                if let QPath::Resolved(_, ref path) = *path {
-                    if let Def::Existential(def_id) = path.def {
-                        let node_id = self.cx.tcx.hir.as_local_node_id(def_id).unwrap();
-                        if let ItemKind::Existential(ref exist_ty) = self.cx.tcx.hir.expect_item(node_id).node {
-                            for bound in &exist_ty.bounds {
-                                if let GenericBound::Outlives(_) = *bound {
-                                    self.record(&None);
-                                }
-                            }
-                        } else {
-                            unreachable!()
+                self.collect_anonymous_lifetimes(path, ty);
+            },
+            TyKind::Def(item, _) => {
+                let map = self.cx.tcx.hir();
+                if let ItemKind::Existential(ref exist_ty) = map.expect_item(map.hir_to_node_id(item.id)).node {
+                    for bound in &exist_ty.bounds {
+                        if let GenericBound::Outlives(_) = *bound {
+                            self.record(&None);
                         }
-                        walk_ty(self, ty);
-                        return;
                     }
+                } else {
+                    unreachable!()
                 }
-                self.collect_anonymous_lifetimes(path, ty);
-            }
+                walk_ty(self, ty);
+            },
             TyKind::TraitObject(ref bounds, ref lt) => {
                 if !lt.is_elided() {
                     self.abort = true;
@@ -380,7 +375,7 @@ fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
     }
 }
 
-/// Are any lifetimes mentioned in the `where` clause? If yes, we don't try to
+/// Are any lifetimes mentioned in the `where` clause? If so, we don't try to
 /// reason about elision.
 fn has_where_lifetimes<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, where_clause: &'tcx WhereClause) -> bool {
     for predicate in &where_clause.predicates {
@@ -403,9 +398,11 @@ fn has_where_lifetimes<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, where_clause: &
                 // and check that all lifetimes are allowed
                 match visitor.into_vec() {
                     None => return false,
-                    Some(lts) => for lt in lts {
-                        if !allowed_lts.contains(&lt) {
-                            return true;
+                    Some(lts) => {
+                        for lt in lts {
+                            if !allowed_lts.contains(&lt) {
+                                return true;
+                            }
                         }
                     },
                 }
@@ -449,7 +446,9 @@ fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
 }
 
 fn report_extra_lifetimes<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, func: &'tcx FnDecl, generics: &'tcx Generics) {
-    let hs = generics.params.iter()
+    let hs = generics
+        .params
+        .iter()
         .filter_map(|par| match par.kind {
             GenericParamKind::Lifetime { .. } => Some((par.name.ident().name, par.span)),
             _ => None,
@@ -461,7 +460,12 @@ fn report_extra_lifetimes<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, func: &'tcx
     walk_fn_decl(&mut checker, func);
 
     for &v in checker.map.values() {
-        span_lint(cx, EXTRA_UNUSED_LIFETIMES, v, "this lifetime isn't used in the function definition");
+        span_lint(
+            cx,
+            EXTRA_UNUSED_LIFETIMES,
+            v,
+            "this lifetime isn't used in the function definition",
+        );
     }
 }
 
@@ -472,7 +476,9 @@ struct BodyLifetimeChecker {
 impl<'tcx> Visitor<'tcx> for BodyLifetimeChecker {
     // for lifetimes as parameters of generics
     fn visit_lifetime(&mut self, lifetime: &'tcx Lifetime) {
-        if lifetime.name.ident().name != keywords::Invalid.name() && lifetime.name.ident().name != "'static" {
+        if lifetime.name.ident().name != kw::Invalid
+            && lifetime.name.ident().name != kw::StaticLifetime
+        {
             self.lifetimes_used_in_body = true;
         }
     }