]> git.lizzy.rs Git - rust.git/blobdiff - clippy_lints/src/shadow.rs
Last PR adjustments
[rust.git] / clippy_lints / src / shadow.rs
index f6880af0cab28a068709a113ab03b81479db97c3..87f966ced0df121b640a5b301809027ed3dd3cb3 100644 (file)
@@ -5,7 +5,7 @@
 use rustc_hir::def::Res;
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::hir_id::ItemLocalId;
-use rustc_hir::{Block, Body, BodyOwnerKind, Expr, ExprKind, HirId, Node, Pat, PatKind, QPath, UnOp};
+use rustc_hir::{Block, Body, BodyOwnerKind, Expr, ExprKind, HirId, Let, Node, Pat, PatKind, QPath, UnOp};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::{Span, Symbol};
     /// ### Example
     /// ```rust
     /// # let x = 1;
-    /// // Bad
     /// let x = &x;
+    /// ```
     ///
-    /// // Good
+    /// Use instead:
+    /// ```rust
+    /// # let x = 1;
     /// let y = &x; // use different variable name
     /// ```
     #[clippy::version = "pre 1.29.0"]
     /// # let y = 1;
     /// # let z = 2;
     /// let x = y;
-    ///
-    /// // Bad
     /// let x = z; // shadows the earlier binding
+    /// ```
     ///
-    /// // Good
+    /// Use instead:
+    /// ```rust
+    /// # let y = 1;
+    /// # let z = 2;
+    /// let x = y;
     /// let w = z; // use different variable name
     /// ```
     #[clippy::version = "pre 1.29.0"]
 
 #[derive(Default)]
 pub(crate) struct Shadow {
-    bindings: Vec<FxHashMap<Symbol, Vec<ItemLocalId>>>,
+    bindings: Vec<(FxHashMap<Symbol, Vec<ItemLocalId>>, LocalDefId)>,
 }
 
 impl_lint_pass!(Shadow => [SHADOW_SAME, SHADOW_REUSE, SHADOW_UNRELATED]);
 
 impl<'tcx> LateLintPass<'tcx> for Shadow {
     fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) {
-        let (id, ident) = match pat.kind {
-            PatKind::Binding(_, hir_id, ident, _) => (hir_id, ident),
-            _ => return,
-        };
+        let PatKind::Binding(_, id, ident, _) = pat.kind else { return };
 
         if pat.span.desugaring_kind().is_some() {
             return;
@@ -116,7 +118,7 @@ fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) {
 
         let HirId { owner, local_id } = id;
         // get (or insert) the list of items for this owner and symbol
-        let data = self.bindings.last_mut().unwrap();
+        let (ref mut data, scope_owner) = *self.bindings.last_mut().unwrap();
         let items_with_name = data.entry(ident.name).or_default();
 
         // check other bindings with the same name, most recently seen first
@@ -126,7 +128,7 @@ fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) {
                 return;
             }
 
-            if is_shadow(cx, owner, prev, local_id) {
+            if is_shadow(cx, scope_owner, prev, local_id) {
                 let prev_hir_id = HirId { owner, local_id: prev };
                 lint_shadow(cx, pat, prev_hir_id, ident.span);
                 // only lint against the "nearest" shadowed binding
@@ -139,14 +141,18 @@ fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) {
 
     fn check_body(&mut self, cx: &LateContext<'_>, body: &Body<'_>) {
         let hir = cx.tcx.hir();
-        if !matches!(hir.body_owner_kind(hir.body_owner(body.id())), BodyOwnerKind::Closure) {
-            self.bindings.push(FxHashMap::default());
+        let owner_id = hir.body_owner_def_id(body.id());
+        if !matches!(hir.body_owner_kind(owner_id), BodyOwnerKind::Closure) {
+            self.bindings.push((FxHashMap::default(), owner_id));
         }
     }
 
     fn check_body_post(&mut self, cx: &LateContext<'_>, body: &Body<'_>) {
         let hir = cx.tcx.hir();
-        if !matches!(hir.body_owner_kind(hir.body_owner(body.id())), BodyOwnerKind::Closure) {
+        if !matches!(
+            hir.body_owner_kind(hir.body_owner_def_id(body.id())),
+            BodyOwnerKind::Closure
+        ) {
             self.bindings.pop();
         }
     }
@@ -154,9 +160,13 @@ fn check_body_post(&mut self, cx: &LateContext<'_>, body: &Body<'_>) {
 
 fn is_shadow(cx: &LateContext<'_>, owner: LocalDefId, first: ItemLocalId, second: ItemLocalId) -> bool {
     let scope_tree = cx.tcx.region_scope_tree(owner.to_def_id());
-    let first_scope = scope_tree.var_scope(first);
-    let second_scope = scope_tree.var_scope(second);
-    scope_tree.is_subscope_of(second_scope, first_scope)
+    if let Some(first_scope) = scope_tree.var_scope(first) {
+        if let Some(second_scope) = scope_tree.var_scope(second) {
+            return scope_tree.is_subscope_of(second_scope, first_scope);
+        }
+    }
+
+    false
 }
 
 fn lint_shadow(cx: &LateContext<'_>, pat: &Pat<'_>, shadowed: HirId, span: Span) {
@@ -220,14 +230,14 @@ fn is_self_shadow(cx: &LateContext<'_>, pat: &Pat<'_>, mut expr: &Expr<'_>, hir_
     }
 }
 
-/// Finds the "init" expression for a pattern: `let <pat> = <init>;` or
+/// Finds the "init" expression for a pattern: `let <pat> = <init>;` (or `if let`) or
 /// `match <init> { .., <pat> => .., .. }`
 fn find_init<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<&'tcx Expr<'tcx>> {
     for (_, node) in cx.tcx.hir().parent_iter(hir_id) {
         let init = match node {
             Node::Arm(_) | Node::Pat(_) => continue,
             Node::Expr(expr) => match expr.kind {
-                ExprKind::Match(e, _, _) => Some(e),
+                ExprKind::Match(e, _, _) | ExprKind::Let(&Let { init: e, .. }) => Some(e),
                 _ => None,
             },
             Node::Local(local) => local.init,