about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md1
-rw-r--r--clippy_lints/src/declared_lints.rs1
-rw-r--r--clippy_lints/src/lib.rs2
-rw-r--r--clippy_lints/src/redundant_locals.rs103
-rw-r--r--tests/ui/option_if_let_else.fixed3
-rw-r--r--tests/ui/option_if_let_else.rs3
-rw-r--r--tests/ui/option_if_let_else.stderr46
-rw-r--r--tests/ui/redundant_locals.rs111
-rw-r--r--tests/ui/redundant_locals.stderr136
-rw-r--r--tests/ui/shadow.rs2
-rw-r--r--tests/ui/swap.fixed3
-rw-r--r--tests/ui/swap.rs3
-rw-r--r--tests/ui/swap.stderr34
13 files changed, 403 insertions, 45 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index fe879712130..2b53f1df7c0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5190,6 +5190,7 @@ Released 2018-09-13
 [`redundant_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_else
 [`redundant_feature_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_feature_names
 [`redundant_field_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_field_names
+[`redundant_locals`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_locals
 [`redundant_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_pattern
 [`redundant_pattern_matching`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_pattern_matching
 [`redundant_pub_crate`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_pub_crate
diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs
index 830714ce7b0..e92d9fa7f63 100644
--- a/clippy_lints/src/declared_lints.rs
+++ b/clippy_lints/src/declared_lints.rs
@@ -561,6 +561,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::redundant_closure_call::REDUNDANT_CLOSURE_CALL_INFO,
     crate::redundant_else::REDUNDANT_ELSE_INFO,
     crate::redundant_field_names::REDUNDANT_FIELD_NAMES_INFO,
+    crate::redundant_locals::REDUNDANT_LOCALS_INFO,
     crate::redundant_pub_crate::REDUNDANT_PUB_CRATE_INFO,
     crate::redundant_slicing::DEREF_BY_SLICING_INFO,
     crate::redundant_slicing::REDUNDANT_SLICING_INFO,
diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs
index 0fa5c2f1828..ca2f5191cdf 100644
--- a/clippy_lints/src/lib.rs
+++ b/clippy_lints/src/lib.rs
@@ -275,6 +275,7 @@ mod redundant_clone;
 mod redundant_closure_call;
 mod redundant_else;
 mod redundant_field_names;
+mod redundant_locals;
 mod redundant_pub_crate;
 mod redundant_slicing;
 mod redundant_static_lifetimes;
@@ -1091,6 +1092,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
             absolute_paths_allowed_crates: absolute_paths_allowed_crates.clone(),
         })
     });
+    store.register_late_pass(|_| Box::new(redundant_locals::RedundantLocals));
     // add lints here, do not remove this comment, it's used in `new_lint`
 }
 
diff --git a/clippy_lints/src/redundant_locals.rs b/clippy_lints/src/redundant_locals.rs
new file mode 100644
index 00000000000..140ae837a17
--- /dev/null
+++ b/clippy_lints/src/redundant_locals.rs
@@ -0,0 +1,103 @@
+use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::is_from_proc_macro;
+use clippy_utils::ty::needs_ordered_drop;
+use rustc_hir::def::Res;
+use rustc_hir::{BindingAnnotation, ByRef, Expr, ExprKind, HirId, Local, Node, Pat, PatKind, QPath};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_middle::lint::in_external_macro;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::symbol::Ident;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for redundant redefinitions of local bindings.
+    ///
+    /// ### Why is this bad?
+    /// Redundant redefinitions of local bindings do not change behavior and are likely to be unintended.
+    ///
+    /// Note that although these bindings do not affect your code's meaning, they _may_ affect `rustc`'s stack allocation.
+    ///
+    /// ### Example
+    /// ```rust
+    /// let a = 0;
+    /// let a = a;
+    ///
+    /// fn foo(b: i32) {
+    ///    let b = b;
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// let a = 0;
+    /// // no redefinition with the same name
+    ///
+    /// fn foo(b: i32) {
+    ///   // no redefinition with the same name
+    /// }
+    /// ```
+    #[clippy::version = "1.72.0"]
+    pub REDUNDANT_LOCALS,
+    correctness,
+    "redundant redefinition of a local binding"
+}
+declare_lint_pass!(RedundantLocals => [REDUNDANT_LOCALS]);
+
+impl<'tcx> LateLintPass<'tcx> for RedundantLocals {
+    fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'tcx>) {
+        if_chain! {
+            // the pattern is a single by-value binding
+            if let PatKind::Binding(BindingAnnotation(ByRef::No, mutability), _, ident, None) = local.pat.kind;
+            // the binding is not type-ascribed
+            if local.ty.is_none();
+            // the expression is a resolved path
+            if let Some(expr) = local.init;
+            if let ExprKind::Path(qpath @ QPath::Resolved(None, path)) = expr.kind;
+            // the path is a single segment equal to the local's name
+            if let [last_segment] = path.segments;
+            if last_segment.ident == ident;
+            // resolve the path to its defining binding pattern
+            if let Res::Local(binding_id) = cx.qpath_res(&qpath, expr.hir_id);
+            if let Node::Pat(binding_pat) = cx.tcx.hir().get(binding_id);
+            // the previous binding has the same mutability
+            if find_binding(binding_pat, ident).unwrap().1 == mutability;
+            // the local does not affect the code's drop behavior
+            if !affects_drop_behavior(cx, binding_id, local.hir_id, expr);
+            // the local is user-controlled
+            if !in_external_macro(cx.sess(), local.span);
+            if !is_from_proc_macro(cx, expr);
+            then {
+                span_lint_and_help(
+                    cx,
+                    REDUNDANT_LOCALS,
+                    vec![binding_pat.span, local.span],
+                    "redundant redefinition of a binding",
+                    None,
+                    &format!("remove the redefinition of `{ident}`"),
+                );
+            }
+        }
+    }
+}
+
+/// Find the annotation of a binding introduced by a pattern, or `None` if it's not introduced.
+fn find_binding(pat: &Pat<'_>, name: Ident) -> Option<BindingAnnotation> {
+    let mut ret = None;
+
+    pat.each_binding_or_first(&mut |annotation, _, _, ident| {
+        if ident == name {
+            ret = Some(annotation);
+        }
+    });
+
+    ret
+}
+
+/// Check if a rebinding of a local affects the code's drop behavior.
+fn affects_drop_behavior<'tcx>(cx: &LateContext<'tcx>, bind: HirId, rebind: HirId, rebind_expr: &Expr<'tcx>) -> bool {
+    let hir = cx.tcx.hir();
+
+    // the rebinding is in a different scope than the original binding
+    // and the type of the binding cares about drop order
+    hir.get_enclosing_scope(bind) != hir.get_enclosing_scope(rebind)
+        && needs_ordered_drop(cx, cx.typeck_results().expr_ty(rebind_expr))
+}
diff --git a/tests/ui/option_if_let_else.fixed b/tests/ui/option_if_let_else.fixed
index 8e59e4375d2..6fee3cce619 100644
--- a/tests/ui/option_if_let_else.fixed
+++ b/tests/ui/option_if_let_else.fixed
@@ -5,7 +5,8 @@
     clippy::redundant_closure,
     clippy::ref_option_ref,
     clippy::equatable_if_let,
-    clippy::let_unit_value
+    clippy::let_unit_value,
+    clippy::redundant_locals
 )]
 
 fn bad1(string: Option<&str>) -> (bool, &str) {
diff --git a/tests/ui/option_if_let_else.rs b/tests/ui/option_if_let_else.rs
index e72edf2a8e3..4b3cf948a1b 100644
--- a/tests/ui/option_if_let_else.rs
+++ b/tests/ui/option_if_let_else.rs
@@ -5,7 +5,8 @@
     clippy::redundant_closure,
     clippy::ref_option_ref,
     clippy::equatable_if_let,
-    clippy::let_unit_value
+    clippy::let_unit_value,
+    clippy::redundant_locals
 )]
 
 fn bad1(string: Option<&str>) -> (bool, &str) {
diff --git a/tests/ui/option_if_let_else.stderr b/tests/ui/option_if_let_else.stderr
index aa2da217400..350f0f07e13 100644
--- a/tests/ui/option_if_let_else.stderr
+++ b/tests/ui/option_if_let_else.stderr
@@ -1,5 +1,5 @@
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:12:5
+  --> $DIR/option_if_let_else.rs:13:5
    |
 LL | /     if let Some(x) = string {
 LL | |         (true, x)
@@ -11,19 +11,19 @@ LL | |     }
    = note: `-D clippy::option-if-let-else` implied by `-D warnings`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:30:13
+  --> $DIR/option_if_let_else.rs:31:13
    |
 LL |     let _ = if let Some(s) = *string { s.len() } else { 0 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `string.map_or(0, |s| s.len())`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:31:13
+  --> $DIR/option_if_let_else.rs:32:13
    |
 LL |     let _ = if let Some(s) = &num { s } else { &0 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.as_ref().map_or(&0, |s| s)`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:32:13
+  --> $DIR/option_if_let_else.rs:33:13
    |
 LL |       let _ = if let Some(s) = &mut num {
    |  _____________^
@@ -43,13 +43,13 @@ LL ~     });
    |
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:38:13
+  --> $DIR/option_if_let_else.rs:39:13
    |
 LL |     let _ = if let Some(ref s) = num { s } else { &0 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.as_ref().map_or(&0, |s| s)`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:39:13
+  --> $DIR/option_if_let_else.rs:40:13
    |
 LL |       let _ = if let Some(mut s) = num {
    |  _____________^
@@ -69,7 +69,7 @@ LL ~     });
    |
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:45:13
+  --> $DIR/option_if_let_else.rs:46:13
    |
 LL |       let _ = if let Some(ref mut s) = num {
    |  _____________^
@@ -89,7 +89,7 @@ LL ~     });
    |
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:54:5
+  --> $DIR/option_if_let_else.rs:55:5
    |
 LL | /     if let Some(x) = arg {
 LL | |         let y = x * x;
@@ -108,7 +108,7 @@ LL +     })
    |
 
 error: use Option::map_or_else instead of an if let/else
-  --> $DIR/option_if_let_else.rs:67:13
+  --> $DIR/option_if_let_else.rs:68:13
    |
 LL |       let _ = if let Some(x) = arg {
    |  _____________^
@@ -120,7 +120,7 @@ LL | |     };
    | |_____^ help: try: `arg.map_or_else(|| side_effect(), |x| x)`
 
 error: use Option::map_or_else instead of an if let/else
-  --> $DIR/option_if_let_else.rs:76:13
+  --> $DIR/option_if_let_else.rs:77:13
    |
 LL |       let _ = if let Some(x) = arg {
    |  _____________^
@@ -143,7 +143,7 @@ LL ~     }, |x| x * x * x * x);
    |
 
 error: use Option::map_or_else instead of an if let/else
-  --> $DIR/option_if_let_else.rs:109:13
+  --> $DIR/option_if_let_else.rs:110:13
    |
 LL | /             if let Some(idx) = s.find('.') {
 LL | |                 vec![s[..idx].to_string(), s[idx..].to_string()]
@@ -153,7 +153,7 @@ LL | |             }
    | |_____________^ help: try: `s.find('.').map_or_else(|| vec![s.to_string()], |idx| vec![s[..idx].to_string(), s[idx..].to_string()])`
 
 error: use Option::map_or_else instead of an if let/else
-  --> $DIR/option_if_let_else.rs:120:5
+  --> $DIR/option_if_let_else.rs:121:5
    |
 LL | /     if let Ok(binding) = variable {
 LL | |         println!("Ok {binding}");
@@ -172,13 +172,13 @@ LL +     })
    |
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:142:13
+  --> $DIR/option_if_let_else.rs:143:13
    |
 LL |     let _ = if let Some(x) = optional { x + 2 } else { 5 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `optional.map_or(5, |x| x + 2)`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:152:13
+  --> $DIR/option_if_let_else.rs:153:13
    |
 LL |       let _ = if let Some(x) = Some(0) {
    |  _____________^
@@ -200,13 +200,13 @@ LL ~         });
    |
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:180:13
+  --> $DIR/option_if_let_else.rs:181:13
    |
 LL |     let _ = if let Some(x) = Some(0) { s.len() + x } else { s.len() };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(0).map_or(s.len(), |x| s.len() + x)`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:184:13
+  --> $DIR/option_if_let_else.rs:185:13
    |
 LL |       let _ = if let Some(x) = Some(0) {
    |  _____________^
@@ -226,7 +226,7 @@ LL ~     });
    |
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:223:13
+  --> $DIR/option_if_let_else.rs:224:13
    |
 LL |       let _ = match s {
    |  _____________^
@@ -236,7 +236,7 @@ LL | |     };
    | |_____^ help: try: `s.map_or(1, |string| string.len())`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:227:13
+  --> $DIR/option_if_let_else.rs:228:13
    |
 LL |       let _ = match Some(10) {
    |  _____________^
@@ -246,7 +246,7 @@ LL | |     };
    | |_____^ help: try: `Some(10).map_or(5, |a| a + 1)`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:233:13
+  --> $DIR/option_if_let_else.rs:234:13
    |
 LL |       let _ = match res {
    |  _____________^
@@ -256,7 +256,7 @@ LL | |     };
    | |_____^ help: try: `res.map_or(1, |a| a + 1)`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:237:13
+  --> $DIR/option_if_let_else.rs:238:13
    |
 LL |       let _ = match res {
    |  _____________^
@@ -266,13 +266,13 @@ LL | |     };
    | |_____^ help: try: `res.map_or(1, |a| a + 1)`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:241:13
+  --> $DIR/option_if_let_else.rs:242:13
    |
 LL |     let _ = if let Ok(a) = res { a + 1 } else { 5 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `res.map_or(5, |a| a + 1)`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:258:9
+  --> $DIR/option_if_let_else.rs:259:9
    |
 LL | /         match initial {
 LL | |             Some(value) => do_something(value),
@@ -281,7 +281,7 @@ LL | |         }
    | |_________^ help: try: `initial.as_ref().map_or({}, |value| do_something(value))`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:265:9
+  --> $DIR/option_if_let_else.rs:266:9
    |
 LL | /         match initial {
 LL | |             Some(value) => do_something2(value),
diff --git a/tests/ui/redundant_locals.rs b/tests/ui/redundant_locals.rs
new file mode 100644
index 00000000000..e74c78a50b6
--- /dev/null
+++ b/tests/ui/redundant_locals.rs
@@ -0,0 +1,111 @@
+//@aux-build:proc_macros.rs:proc-macro
+#![allow(unused, clippy::no_effect, clippy::needless_pass_by_ref_mut)]
+#![warn(clippy::redundant_locals)]
+
+extern crate proc_macros;
+use proc_macros::{external, with_span};
+
+fn main() {}
+
+fn immutable() {
+    let x = 1;
+    let x = x;
+}
+
+fn mutable() {
+    let mut x = 1;
+    let mut x = x;
+}
+
+fn upgraded_mutability() {
+    let x = 1;
+    let mut x = x;
+}
+
+fn downgraded_mutability() {
+    let mut x = 1;
+    let x = x;
+}
+
+fn coercion(par: &mut i32) {
+    let par: &i32 = par;
+
+    let x: &mut i32 = &mut 1;
+    let x: &i32 = x;
+}
+
+fn parameter(x: i32) {
+    let x = x;
+}
+
+fn many() {
+    let x = 1;
+    let x = x;
+    let x = x;
+    let x = x;
+    let x = x;
+}
+
+fn interleaved() {
+    let a = 1;
+    let b = 2;
+    let a = a;
+    let b = b;
+}
+
+fn block() {
+    {
+        let x = 1;
+        let x = x;
+    }
+}
+
+fn closure() {
+    || {
+        let x = 1;
+        let x = x;
+    };
+    |x: i32| {
+        let x = x;
+    };
+}
+
+fn consequential_drop_order() {
+    use std::sync::Mutex;
+
+    let mutex = Mutex::new(1);
+    let guard = mutex.lock().unwrap();
+
+    {
+        let guard = guard;
+    }
+}
+
+fn inconsequential_drop_order() {
+    let x = 1;
+
+    {
+        let x = x;
+    }
+}
+
+fn macros() {
+    macro_rules! rebind {
+        ($x:ident) => {
+            let $x = 1;
+            let $x = $x;
+        };
+    }
+
+    rebind!(x);
+
+    external! {
+        let x = 1;
+        let x = x;
+    }
+    with_span! {
+        span
+        let x = 1;
+        let x = x;
+    }
+}
diff --git a/tests/ui/redundant_locals.stderr b/tests/ui/redundant_locals.stderr
new file mode 100644
index 00000000000..df07dd2f453
--- /dev/null
+++ b/tests/ui/redundant_locals.stderr
@@ -0,0 +1,136 @@
+error: redundant redefinition of a binding
+  --> $DIR/redundant_locals.rs:11:9
+   |
+LL |     let x = 1;
+   |         ^
+LL |     let x = x;
+   |     ^^^^^^^^^^
+   |
+   = help: remove the redefinition of `x`
+   = note: `-D clippy::redundant-locals` implied by `-D warnings`
+
+error: redundant redefinition of a binding
+  --> $DIR/redundant_locals.rs:16:9
+   |
+LL |     let mut x = 1;
+   |         ^^^^^
+LL |     let mut x = x;
+   |     ^^^^^^^^^^^^^^
+   |
+   = help: remove the redefinition of `x`
+
+error: redundant redefinition of a binding
+  --> $DIR/redundant_locals.rs:37:14
+   |
+LL | fn parameter(x: i32) {
+   |              ^
+LL |     let x = x;
+   |     ^^^^^^^^^^
+   |
+   = help: remove the redefinition of `x`
+
+error: redundant redefinition of a binding
+  --> $DIR/redundant_locals.rs:42:9
+   |
+LL |     let x = 1;
+   |         ^
+LL |     let x = x;
+   |     ^^^^^^^^^^
+   |
+   = help: remove the redefinition of `x`
+
+error: redundant redefinition of a binding
+  --> $DIR/redundant_locals.rs:43:9
+   |
+LL |     let x = x;
+   |         ^
+LL |     let x = x;
+   |     ^^^^^^^^^^
+   |
+   = help: remove the redefinition of `x`
+
+error: redundant redefinition of a binding
+  --> $DIR/redundant_locals.rs:44:9
+   |
+LL |     let x = x;
+   |         ^
+LL |     let x = x;
+   |     ^^^^^^^^^^
+   |
+   = help: remove the redefinition of `x`
+
+error: redundant redefinition of a binding
+  --> $DIR/redundant_locals.rs:45:9
+   |
+LL |     let x = x;
+   |         ^
+LL |     let x = x;
+   |     ^^^^^^^^^^
+   |
+   = help: remove the redefinition of `x`
+
+error: redundant redefinition of a binding
+  --> $DIR/redundant_locals.rs:50:9
+   |
+LL |     let a = 1;
+   |         ^
+LL |     let b = 2;
+LL |     let a = a;
+   |     ^^^^^^^^^^
+   |
+   = help: remove the redefinition of `a`
+
+error: redundant redefinition of a binding
+  --> $DIR/redundant_locals.rs:51:9
+   |
+LL |     let b = 2;
+   |         ^
+LL |     let a = a;
+LL |     let b = b;
+   |     ^^^^^^^^^^
+   |
+   = help: remove the redefinition of `b`
+
+error: redundant redefinition of a binding
+  --> $DIR/redundant_locals.rs:58:13
+   |
+LL |         let x = 1;
+   |             ^
+LL |         let x = x;
+   |         ^^^^^^^^^^
+   |
+   = help: remove the redefinition of `x`
+
+error: redundant redefinition of a binding
+  --> $DIR/redundant_locals.rs:65:13
+   |
+LL |         let x = 1;
+   |             ^
+LL |         let x = x;
+   |         ^^^^^^^^^^
+   |
+   = help: remove the redefinition of `x`
+
+error: redundant redefinition of a binding
+  --> $DIR/redundant_locals.rs:68:6
+   |
+LL |     |x: i32| {
+   |      ^
+LL |         let x = x;
+   |         ^^^^^^^^^^
+   |
+   = help: remove the redefinition of `x`
+
+error: redundant redefinition of a binding
+  --> $DIR/redundant_locals.rs:85:9
+   |
+LL |     let x = 1;
+   |         ^
+...
+LL |         let x = x;
+   |         ^^^^^^^^^^
+   |
+   = help: remove the redefinition of `x`
+
+error: aborting due to 13 previous errors
+
diff --git a/tests/ui/shadow.rs b/tests/ui/shadow.rs
index 9be8c5e59d0..4d22b7d2ad0 100644
--- a/tests/ui/shadow.rs
+++ b/tests/ui/shadow.rs
@@ -1,7 +1,7 @@
 //@aux-build:proc_macro_derive.rs:proc-macro
 
 #![warn(clippy::shadow_same, clippy::shadow_reuse, clippy::shadow_unrelated)]
-#![allow(clippy::let_unit_value, clippy::needless_if)]
+#![allow(clippy::let_unit_value, clippy::needless_if, clippy::redundant_locals)]
 
 extern crate proc_macro_derive;
 
diff --git a/tests/ui/swap.fixed b/tests/ui/swap.fixed
index 22f904e3fd9..7b74a83b6df 100644
--- a/tests/ui/swap.fixed
+++ b/tests/ui/swap.fixed
@@ -11,7 +11,8 @@
     unused_assignments,
     unused_variables,
     clippy::let_and_return,
-    clippy::useless_vec
+    clippy::useless_vec,
+    clippy::redundant_locals
 )]
 
 struct Foo(u32);
diff --git a/tests/ui/swap.rs b/tests/ui/swap.rs
index ada64f89e6d..93855cd7b5c 100644
--- a/tests/ui/swap.rs
+++ b/tests/ui/swap.rs
@@ -11,7 +11,8 @@
     unused_assignments,
     unused_variables,
     clippy::let_and_return,
-    clippy::useless_vec
+    clippy::useless_vec,
+    clippy::redundant_locals
 )]
 
 struct Foo(u32);
diff --git a/tests/ui/swap.stderr b/tests/ui/swap.stderr
index a3b9c2b744c..1097b29bba0 100644
--- a/tests/ui/swap.stderr
+++ b/tests/ui/swap.stderr
@@ -1,5 +1,5 @@
 error: this looks like you are swapping `bar.a` and `bar.b` manually
-  --> $DIR/swap.rs:28:5
+  --> $DIR/swap.rs:29:5
    |
 LL | /     let temp = bar.a;
 LL | |     bar.a = bar.b;
@@ -10,7 +10,7 @@ LL | |     bar.b = temp;
    = note: `-D clippy::manual-swap` implied by `-D warnings`
 
 error: this looks like you are swapping elements of `foo` manually
-  --> $DIR/swap.rs:40:5
+  --> $DIR/swap.rs:41:5
    |
 LL | /     let temp = foo[0];
 LL | |     foo[0] = foo[1];
@@ -18,7 +18,7 @@ LL | |     foo[1] = temp;
    | |__________________^ help: try: `foo.swap(0, 1);`
 
 error: this looks like you are swapping elements of `foo` manually
-  --> $DIR/swap.rs:49:5
+  --> $DIR/swap.rs:50:5
    |
 LL | /     let temp = foo[0];
 LL | |     foo[0] = foo[1];
@@ -26,7 +26,7 @@ LL | |     foo[1] = temp;
    | |__________________^ help: try: `foo.swap(0, 1);`
 
 error: this looks like you are swapping elements of `foo` manually
-  --> $DIR/swap.rs:68:5
+  --> $DIR/swap.rs:69:5
    |
 LL | /     let temp = foo[0];
 LL | |     foo[0] = foo[1];
@@ -34,7 +34,7 @@ LL | |     foo[1] = temp;
    | |__________________^ help: try: `foo.swap(0, 1);`
 
 error: this looks like you are swapping `a` and `b` manually
-  --> $DIR/swap.rs:79:5
+  --> $DIR/swap.rs:80:5
    |
 LL | /     a ^= b;
 LL | |     b ^= a;
@@ -42,7 +42,7 @@ LL | |     a ^= b;
    | |___________^ help: try: `std::mem::swap(&mut a, &mut b);`
 
 error: this looks like you are swapping `bar.a` and `bar.b` manually
-  --> $DIR/swap.rs:87:5
+  --> $DIR/swap.rs:88:5
    |
 LL | /     bar.a ^= bar.b;
 LL | |     bar.b ^= bar.a;
@@ -50,7 +50,7 @@ LL | |     bar.a ^= bar.b;
    | |___________________^ help: try: `std::mem::swap(&mut bar.a, &mut bar.b);`
 
 error: this looks like you are swapping elements of `foo` manually
-  --> $DIR/swap.rs:95:5
+  --> $DIR/swap.rs:96:5
    |
 LL | /     foo[0] ^= foo[1];
 LL | |     foo[1] ^= foo[0];
@@ -58,7 +58,7 @@ LL | |     foo[0] ^= foo[1];
    | |_____________________^ help: try: `foo.swap(0, 1);`
 
 error: this looks like you are swapping `foo[0][1]` and `bar[1][0]` manually
-  --> $DIR/swap.rs:124:5
+  --> $DIR/swap.rs:125:5
    |
 LL | /     let temp = foo[0][1];
 LL | |     foo[0][1] = bar[1][0];
@@ -68,7 +68,7 @@ LL | |     bar[1][0] = temp;
    = note: or maybe you should use `std::mem::replace`?
 
 error: this looks like you are swapping `a` and `b` manually
-  --> $DIR/swap.rs:138:7
+  --> $DIR/swap.rs:139:7
    |
 LL |       ; let t = a;
    |  _______^
@@ -79,7 +79,7 @@ LL | |     b = t;
    = note: or maybe you should use `std::mem::replace`?
 
 error: this looks like you are swapping `c.0` and `a` manually
-  --> $DIR/swap.rs:147:7
+  --> $DIR/swap.rs:148:7
    |
 LL |       ; let t = c.0;
    |  _______^
@@ -90,7 +90,7 @@ LL | |     a = t;
    = note: or maybe you should use `std::mem::replace`?
 
 error: this looks like you are swapping `b` and `a` manually
-  --> $DIR/swap.rs:173:5
+  --> $DIR/swap.rs:174:5
    |
 LL | /     let t = b;
 LL | |     b = a;
@@ -100,7 +100,7 @@ LL | |     a = t;
    = note: or maybe you should use `std::mem::replace`?
 
 error: this looks like you are trying to swap `a` and `b`
-  --> $DIR/swap.rs:135:5
+  --> $DIR/swap.rs:136:5
    |
 LL | /     a = b;
 LL | |     b = a;
@@ -110,7 +110,7 @@ LL | |     b = a;
    = note: `-D clippy::almost-swapped` implied by `-D warnings`
 
 error: this looks like you are trying to swap `c.0` and `a`
-  --> $DIR/swap.rs:144:5
+  --> $DIR/swap.rs:145:5
    |
 LL | /     c.0 = a;
 LL | |     a = c.0;
@@ -119,7 +119,7 @@ LL | |     a = c.0;
    = note: or maybe you should use `std::mem::replace`?
 
 error: this looks like you are trying to swap `a` and `b`
-  --> $DIR/swap.rs:151:5
+  --> $DIR/swap.rs:152:5
    |
 LL | /     let a = b;
 LL | |     let b = a;
@@ -128,7 +128,7 @@ LL | |     let b = a;
    = note: or maybe you should use `std::mem::replace`?
 
 error: this looks like you are trying to swap `d` and `c`
-  --> $DIR/swap.rs:156:5
+  --> $DIR/swap.rs:157:5
    |
 LL | /     d = c;
 LL | |     c = d;
@@ -137,7 +137,7 @@ LL | |     c = d;
    = note: or maybe you should use `std::mem::replace`?
 
 error: this looks like you are trying to swap `a` and `b`
-  --> $DIR/swap.rs:160:5
+  --> $DIR/swap.rs:161:5
    |
 LL | /     let a = b;
 LL | |     b = a;
@@ -146,7 +146,7 @@ LL | |     b = a;
    = note: or maybe you should use `std::mem::replace`?
 
 error: this looks like you are swapping `s.0.x` and `s.0.y` manually
-  --> $DIR/swap.rs:208:5
+  --> $DIR/swap.rs:209:5
    |
 LL | /     let t = s.0.x;
 LL | |     s.0.x = s.0.y;