about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/clippy.yml2
-rw-r--r--.github/workflows/clippy_bors.yml8
-rw-r--r--.github/workflows/clippy_dev.yml2
-rw-r--r--.github/workflows/deploy.yml4
-rw-r--r--.github/workflows/remark.yml2
-rw-r--r--clippy_dev/Cargo.toml1
-rw-r--r--clippy_dev/src/lib.rs1
-rw-r--r--clippy_dev/src/main.rs33
-rw-r--r--clippy_dev/src/update_lints.rs389
-rw-r--r--clippy_lints/src/attrs.rs13
-rw-r--r--clippy_lints/src/casts/cast_slice_different_sizes.rs110
-rw-r--r--clippy_lints/src/eta_reduction.rs4
-rw-r--r--clippy_lints/src/identity_op.rs82
-rw-r--r--clippy_lints/src/init_numbered_fields.rs2
-rw-r--r--clippy_lints/src/large_include_file.rs2
-rw-r--r--clippy_lints/src/lib.register_all.rs1
-rw-r--r--clippy_lints/src/lib.register_complexity.rs1
-rw-r--r--clippy_lints/src/lib.register_nursery.rs1
-rw-r--r--clippy_lints/src/lib.rs42
-rw-r--r--clippy_lints/src/lifetimes.rs66
-rw-r--r--clippy_lints/src/matches/redundant_pattern_match.rs66
-rw-r--r--clippy_lints/src/needless_late_init.rs48
-rw-r--r--clippy_lints/src/only_used_in_recursion.rs9
-rw-r--r--clippy_lints/src/renamed_lints.rs39
-rw-r--r--clippy_utils/src/ty.rs71
-rw-r--r--tests/ui/cast_slice_different_sizes.rs41
-rw-r--r--tests/ui/cast_slice_different_sizes.stderr73
-rw-r--r--tests/ui/crashes/ice-2865.rs2
-rw-r--r--tests/ui/crashes/ice-3151.rs2
-rw-r--r--tests/ui/deprecated.rs4
-rw-r--r--tests/ui/deprecated.stderr32
-rw-r--r--tests/ui/eta.fixed16
-rw-r--r--tests/ui/eta.rs12
-rw-r--r--tests/ui/eta.stderr14
-rw-r--r--tests/ui/extra_unused_lifetimes.rs42
-rw-r--r--tests/ui/extra_unused_lifetimes.stderr20
-rw-r--r--tests/ui/identity_op.rs30
-rw-r--r--tests/ui/identity_op.stderr92
-rw-r--r--tests/ui/impl.rs2
-rw-r--r--tests/ui/needless_late_init.rs74
-rw-r--r--tests/ui/needless_late_init.stderr81
-rw-r--r--tests/ui/needless_late_init_fixable.fixed8
-rw-r--r--tests/ui/needless_late_init_fixable.rs10
-rw-r--r--tests/ui/needless_late_init_fixable.stderr39
-rw-r--r--tests/ui/new_without_default.rs2
-rw-r--r--tests/ui/numbered_fields.fixed5
-rw-r--r--tests/ui/numbered_fields.rs5
-rw-r--r--tests/ui/rename.fixed89
-rw-r--r--tests/ui/rename.rs89
-rw-r--r--tests/ui/rename.stderr194
-rw-r--r--tests/ui/useless_attribute.fixed6
-rw-r--r--tests/ui/useless_attribute.rs6
-rw-r--r--tests/ui/useless_attribute.stderr2
53 files changed, 1461 insertions, 530 deletions
diff --git a/.github/workflows/clippy.yml b/.github/workflows/clippy.yml
index 4292949a02d..0e27cc927ac 100644
--- a/.github/workflows/clippy.yml
+++ b/.github/workflows/clippy.yml
@@ -37,7 +37,7 @@ jobs:
         github_token: "${{ secrets.github_token }}"
 
     - name: Checkout
-      uses: actions/checkout@v2.3.3
+      uses: actions/checkout@v3.0.2
 
     - name: Install toolchain
       run: rustup show active-toolchain
diff --git a/.github/workflows/clippy_bors.yml b/.github/workflows/clippy_bors.yml
index f571485e6d3..9b3fd3ddfeb 100644
--- a/.github/workflows/clippy_bors.yml
+++ b/.github/workflows/clippy_bors.yml
@@ -25,7 +25,7 @@ jobs:
         github_token: "${{ secrets.github_token }}"
 
     - name: Checkout
-      uses: actions/checkout@v2.3.3
+      uses: actions/checkout@v3.0.2
       with:
         ref: ${{ github.ref }}
 
@@ -88,7 +88,7 @@ jobs:
       if: matrix.host == 'i686-unknown-linux-gnu'
 
     - name: Checkout
-      uses: actions/checkout@v2.3.3
+      uses: actions/checkout@v3.0.2
 
     - name: Install toolchain
       run: rustup show active-toolchain
@@ -154,7 +154,7 @@ jobs:
         github_token: "${{ secrets.github_token }}"
 
     - name: Checkout
-      uses: actions/checkout@v2.3.3
+      uses: actions/checkout@v3.0.2
 
     - name: Install toolchain
       run: rustup show active-toolchain
@@ -212,7 +212,7 @@ jobs:
         github_token: "${{ secrets.github_token }}"
 
     - name: Checkout
-      uses: actions/checkout@v2.3.3
+      uses: actions/checkout@v3.0.2
 
     - name: Install toolchain
       run: rustup show active-toolchain
diff --git a/.github/workflows/clippy_dev.yml b/.github/workflows/clippy_dev.yml
index 5dfab1d2ebc..22051093c9c 100644
--- a/.github/workflows/clippy_dev.yml
+++ b/.github/workflows/clippy_dev.yml
@@ -23,7 +23,7 @@ jobs:
     steps:
     # Setup
     - name: Checkout
-      uses: actions/checkout@v2.3.3
+      uses: actions/checkout@v3.0.2
 
     # Run
     - name: Build
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index b8be730be32..71d71d10359 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -21,10 +21,10 @@ jobs:
     steps:
     # Setup
     - name: Checkout
-      uses: actions/checkout@v2.3.3
+      uses: actions/checkout@v3.0.2
 
     - name: Checkout
-      uses: actions/checkout@v2.3.3
+      uses: actions/checkout@v3.0.2
       with:
         ref: ${{ env.TARGET_BRANCH }}
         path: 'out'
diff --git a/.github/workflows/remark.yml b/.github/workflows/remark.yml
index 56c00544c93..a179bfa7261 100644
--- a/.github/workflows/remark.yml
+++ b/.github/workflows/remark.yml
@@ -16,7 +16,7 @@ jobs:
     steps:
     # Setup
     - name: Checkout
-      uses: actions/checkout@v2.3.3
+      uses: actions/checkout@v3.0.2
 
     - name: Setup Node.js
       uses: actions/setup-node@v1.4.4
diff --git a/clippy_dev/Cargo.toml b/clippy_dev/Cargo.toml
index c2ebba0683c..fe380239fa6 100644
--- a/clippy_dev/Cargo.toml
+++ b/clippy_dev/Cargo.toml
@@ -4,6 +4,7 @@ version = "0.0.1"
 edition = "2021"
 
 [dependencies]
+aho-corasick = "0.7"
 clap = "2.33"
 indoc = "1.0"
 itertools = "0.10.1"
diff --git a/clippy_dev/src/lib.rs b/clippy_dev/src/lib.rs
index 9c6d754b400..81e807cf10c 100644
--- a/clippy_dev/src/lib.rs
+++ b/clippy_dev/src/lib.rs
@@ -1,3 +1,4 @@
+#![feature(let_chains)]
 #![feature(let_else)]
 #![feature(once_cell)]
 #![feature(rustc_private)]
diff --git a/clippy_dev/src/main.rs b/clippy_dev/src/main.rs
index 833b7393ff8..ebf8f38d490 100644
--- a/clippy_dev/src/main.rs
+++ b/clippy_dev/src/main.rs
@@ -19,9 +19,9 @@ fn main() {
             if matches.is_present("print-only") {
                 update_lints::print_lints();
             } else if matches.is_present("check") {
-                update_lints::run(update_lints::UpdateMode::Check);
+                update_lints::update(update_lints::UpdateMode::Check);
             } else {
-                update_lints::run(update_lints::UpdateMode::Change);
+                update_lints::update(update_lints::UpdateMode::Change);
             }
         },
         ("new_lint", Some(matches)) => {
@@ -31,7 +31,7 @@ fn main() {
                 matches.value_of("category"),
                 matches.is_present("msrv"),
             ) {
-                Ok(_) => update_lints::run(update_lints::UpdateMode::Change),
+                Ok(_) => update_lints::update(update_lints::UpdateMode::Change),
                 Err(e) => eprintln!("Unable to create lint: {}", e),
             }
         },
@@ -78,6 +78,12 @@ fn main() {
             let path = matches.value_of("path").unwrap();
             lint::run(path);
         },
+        ("rename_lint", Some(matches)) => {
+            let old_name = matches.value_of("old_name").unwrap();
+            let new_name = matches.value_of("new_name").unwrap_or(old_name);
+            let uplift = matches.is_present("uplift");
+            update_lints::rename(old_name, new_name, uplift);
+        },
         _ => {},
     }
 }
@@ -279,5 +285,26 @@ fn get_clap_config<'a>() -> ArgMatches<'a> {
                         .help("The path to a file or package directory to lint"),
                 ),
         )
+        .subcommand(
+            SubCommand::with_name("rename_lint")
+                .about("Renames the given lint")
+                .arg(
+                    Arg::with_name("old_name")
+                        .index(1)
+                        .required(true)
+                        .help("The name of the lint to rename"),
+                )
+                .arg(
+                    Arg::with_name("new_name")
+                        .index(2)
+                        .required_unless("uplift")
+                        .help("The new name of the lint"),
+                )
+                .arg(
+                    Arg::with_name("uplift")
+                        .long("uplift")
+                        .help("This lint will be uplifted into rustc"),
+                ),
+        )
         .get_matches()
 }
diff --git a/clippy_dev/src/update_lints.rs b/clippy_dev/src/update_lints.rs
index d25e42f2468..1a6a4336da2 100644
--- a/clippy_dev/src/update_lints.rs
+++ b/clippy_dev/src/update_lints.rs
@@ -1,11 +1,13 @@
-use core::fmt::Write;
+use aho_corasick::AhoCorasickBuilder;
+use core::fmt::Write as _;
 use itertools::Itertools;
 use rustc_lexer::{tokenize, unescape, LiteralKind, TokenKind};
-use std::collections::HashMap;
+use std::collections::{HashMap, HashSet};
 use std::ffi::OsStr;
 use std::fs;
-use std::path::Path;
-use walkdir::WalkDir;
+use std::io::{self, Read as _, Seek as _, Write as _};
+use std::path::{Path, PathBuf};
+use walkdir::{DirEntry, WalkDir};
 
 use crate::clippy_project_root;
 
@@ -30,12 +32,19 @@ pub enum UpdateMode {
 /// # Panics
 ///
 /// Panics if a file path could not read from or then written to
-#[allow(clippy::too_many_lines)]
-pub fn run(update_mode: UpdateMode) {
-    let (lints, deprecated_lints) = gather_all();
+pub fn update(update_mode: UpdateMode) {
+    let (lints, deprecated_lints, renamed_lints) = gather_all();
+    generate_lint_files(update_mode, &lints, &deprecated_lints, &renamed_lints);
+}
 
-    let internal_lints = Lint::internal_lints(&lints);
-    let usable_lints = Lint::usable_lints(&lints);
+fn generate_lint_files(
+    update_mode: UpdateMode,
+    lints: &[Lint],
+    deprecated_lints: &[DeprecatedLint],
+    renamed_lints: &[RenamedLint],
+) {
+    let internal_lints = Lint::internal_lints(lints);
+    let usable_lints = Lint::usable_lints(lints);
     let mut sorted_usable_lints = usable_lints.clone();
     sorted_usable_lints.sort_by_key(|lint| lint.name.clone());
 
@@ -87,7 +96,7 @@ pub fn run(update_mode: UpdateMode) {
     process_file(
         "clippy_lints/src/lib.deprecated.rs",
         update_mode,
-        &gen_deprecated(&deprecated_lints),
+        &gen_deprecated(deprecated_lints),
     );
 
     let all_group_lints = usable_lints.iter().filter(|l| {
@@ -107,10 +116,16 @@ pub fn run(update_mode: UpdateMode) {
             &content,
         );
     }
+
+    let content = gen_deprecated_lints_test(deprecated_lints);
+    process_file("tests/ui/deprecated.rs", update_mode, &content);
+
+    let content = gen_renamed_lints_test(renamed_lints);
+    process_file("tests/ui/rename.rs", update_mode, &content);
 }
 
 pub fn print_lints() {
-    let (lint_list, _) = gather_all();
+    let (lint_list, _, _) = gather_all();
     let usable_lints = Lint::usable_lints(&lint_list);
     let usable_lint_count = usable_lints.len();
     let grouped_by_lint_group = Lint::by_lint_group(usable_lints.into_iter());
@@ -128,6 +143,209 @@ pub fn print_lints() {
     println!("there are {} lints", usable_lint_count);
 }
 
+/// Runs the `rename_lint` command.
+///
+/// This does the following:
+/// * Adds an entry to `renamed_lints.rs`.
+/// * Renames all lint attributes to the new name (e.g. `#[allow(clippy::lint_name)]`).
+/// * Renames the lint struct to the new name.
+/// * Renames the module containing the lint struct to the new name if it shares a name with the
+///   lint.
+///
+/// # Panics
+/// Panics for the following conditions:
+/// * If a file path could not read from or then written to
+/// * If either lint name has a prefix
+/// * If `old_name` doesn't name an existing lint.
+/// * If `old_name` names a deprecated or renamed lint.
+#[allow(clippy::too_many_lines)]
+pub fn rename(old_name: &str, new_name: &str, uplift: bool) {
+    if let Some((prefix, _)) = old_name.split_once("::") {
+        panic!("`{}` should not contain the `{}` prefix", old_name, prefix);
+    }
+    if let Some((prefix, _)) = new_name.split_once("::") {
+        panic!("`{}` should not contain the `{}` prefix", new_name, prefix);
+    }
+
+    let (mut lints, deprecated_lints, mut renamed_lints) = gather_all();
+    let mut old_lint_index = None;
+    let mut found_new_name = false;
+    for (i, lint) in lints.iter().enumerate() {
+        if lint.name == old_name {
+            old_lint_index = Some(i);
+        } else if lint.name == new_name {
+            found_new_name = true;
+        }
+    }
+    let old_lint_index = old_lint_index.unwrap_or_else(|| panic!("could not find lint `{}`", old_name));
+
+    let lint = RenamedLint {
+        old_name: format!("clippy::{}", old_name),
+        new_name: if uplift {
+            new_name.into()
+        } else {
+            format!("clippy::{}", new_name)
+        },
+    };
+
+    // Renamed lints and deprecated lints shouldn't have been found in the lint list, but check just in
+    // case.
+    assert!(
+        !renamed_lints.iter().any(|l| lint.old_name == l.old_name),
+        "`{}` has already been renamed",
+        old_name
+    );
+    assert!(
+        !deprecated_lints.iter().any(|l| lint.old_name == l.name),
+        "`{}` has already been deprecated",
+        old_name
+    );
+
+    // Update all lint level attributes. (`clippy::lint_name`)
+    for file in WalkDir::new(clippy_project_root())
+        .into_iter()
+        .map(Result::unwrap)
+        .filter(|f| {
+            let name = f.path().file_name();
+            let ext = f.path().extension();
+            (ext == Some(OsStr::new("rs")) || ext == Some(OsStr::new("fixed")))
+                && name != Some(OsStr::new("rename.rs"))
+                && name != Some(OsStr::new("renamed_lints.rs"))
+        })
+    {
+        rewrite_file(file.path(), |s| {
+            replace_ident_like(s, &[(&lint.old_name, &lint.new_name)])
+        });
+    }
+
+    renamed_lints.push(lint);
+    renamed_lints.sort_by(|lhs, rhs| {
+        lhs.new_name
+            .starts_with("clippy::")
+            .cmp(&rhs.new_name.starts_with("clippy::"))
+            .reverse()
+            .then_with(|| lhs.old_name.cmp(&rhs.old_name))
+    });
+
+    write_file(
+        Path::new("clippy_lints/src/renamed_lints.rs"),
+        &gen_renamed_lints_list(&renamed_lints),
+    );
+
+    if uplift {
+        write_file(Path::new("tests/ui/rename.rs"), &gen_renamed_lints_test(&renamed_lints));
+        println!(
+            "`{}` has be uplifted. All the code inside `clippy_lints` related to it needs to be removed manually.",
+            old_name
+        );
+    } else if found_new_name {
+        write_file(Path::new("tests/ui/rename.rs"), &gen_renamed_lints_test(&renamed_lints));
+        println!(
+            "`{}` is already defined. The old linting code inside `clippy_lints` needs to be updated/removed manually.",
+            new_name
+        );
+    } else {
+        // Rename the lint struct and source files sharing a name with the lint.
+        let lint = &mut lints[old_lint_index];
+        let old_name_upper = old_name.to_uppercase();
+        let new_name_upper = new_name.to_uppercase();
+        lint.name = new_name.into();
+
+        // Rename test files. only rename `.stderr` and `.fixed` files if the new test name doesn't exist.
+        if try_rename_file(
+            Path::new(&format!("tests/ui/{}.rs", old_name)),
+            Path::new(&format!("tests/ui/{}.rs", new_name)),
+        ) {
+            try_rename_file(
+                Path::new(&format!("tests/ui/{}.stderr", old_name)),
+                Path::new(&format!("tests/ui/{}.stderr", new_name)),
+            );
+            try_rename_file(
+                Path::new(&format!("tests/ui/{}.fixed", old_name)),
+                Path::new(&format!("tests/ui/{}.fixed", new_name)),
+            );
+        }
+
+        // Try to rename the file containing the lint if the file name matches the lint's name.
+        let replacements;
+        let replacements = if lint.module == old_name
+            && try_rename_file(
+                Path::new(&format!("clippy_lints/src/{}.rs", old_name)),
+                Path::new(&format!("clippy_lints/src/{}.rs", new_name)),
+            ) {
+            // Edit the module name in the lint list. Note there could be multiple lints.
+            for lint in lints.iter_mut().filter(|l| l.module == old_name) {
+                lint.module = new_name.into();
+            }
+            replacements = [(&*old_name_upper, &*new_name_upper), (old_name, new_name)];
+            replacements.as_slice()
+        } else if !lint.module.contains("::")
+            // Catch cases like `methods/lint_name.rs` where the lint is stored in `methods/mod.rs`
+            && try_rename_file(
+                Path::new(&format!("clippy_lints/src/{}/{}.rs", lint.module, old_name)),
+                Path::new(&format!("clippy_lints/src/{}/{}.rs", lint.module, new_name)),
+            )
+        {
+            // Edit the module name in the lint list. Note there could be multiple lints, or none.
+            let renamed_mod = format!("{}::{}", lint.module, old_name);
+            for lint in lints.iter_mut().filter(|l| l.module == renamed_mod) {
+                lint.module = format!("{}::{}", lint.module, new_name);
+            }
+            replacements = [(&*old_name_upper, &*new_name_upper), (old_name, new_name)];
+            replacements.as_slice()
+        } else {
+            replacements = [(&*old_name_upper, &*new_name_upper), ("", "")];
+            &replacements[0..1]
+        };
+
+        // Don't change `clippy_utils/src/renamed_lints.rs` here as it would try to edit the lint being
+        // renamed.
+        for (_, file) in clippy_lints_src_files().filter(|(rel_path, _)| rel_path != OsStr::new("renamed_lints.rs")) {
+            rewrite_file(file.path(), |s| replace_ident_like(s, replacements));
+        }
+
+        generate_lint_files(UpdateMode::Change, &lints, &deprecated_lints, &renamed_lints);
+        println!("{} has been successfully renamed", old_name);
+    }
+
+    println!("note: `cargo uitest` still needs to be run to update the test results");
+}
+
+/// Replace substrings if they aren't bordered by identifier characters. Returns `None` if there
+/// were no replacements.
+fn replace_ident_like(contents: &str, replacements: &[(&str, &str)]) -> Option<String> {
+    fn is_ident_char(c: u8) -> bool {
+        matches!(c, b'a'..=b'z' | b'A'..=b'Z' | b'0'..=b'9' | b'_')
+    }
+
+    let searcher = AhoCorasickBuilder::new()
+        .dfa(true)
+        .match_kind(aho_corasick::MatchKind::LeftmostLongest)
+        .build_with_size::<u16, _, _>(replacements.iter().map(|&(x, _)| x.as_bytes()))
+        .unwrap();
+
+    let mut result = String::with_capacity(contents.len() + 1024);
+    let mut pos = 0;
+    let mut edited = false;
+    for m in searcher.find_iter(contents) {
+        let (old, new) = replacements[m.pattern()];
+        result.push_str(&contents[pos..m.start()]);
+        result.push_str(
+            if !is_ident_char(contents.as_bytes().get(m.start().wrapping_sub(1)).copied().unwrap_or(0))
+                && !is_ident_char(contents.as_bytes().get(m.end()).copied().unwrap_or(0))
+            {
+                edited = true;
+                new
+            } else {
+                old
+            },
+        );
+        pos = m.end();
+    }
+    result.push_str(&contents[pos..]);
+    edited.then(|| result)
+}
+
 fn round_to_fifty(count: usize) -> usize {
     count / 50 * 50
 }
@@ -210,6 +428,19 @@ impl DeprecatedLint {
     }
 }
 
+struct RenamedLint {
+    old_name: String,
+    new_name: String,
+}
+impl RenamedLint {
+    fn new(old_name: &str, new_name: &str) -> Self {
+        Self {
+            old_name: remove_line_splices(old_name),
+            new_name: remove_line_splices(new_name),
+        }
+    }
+}
+
 /// Generates the code for registering a group
 fn gen_lint_group_list<'a>(group_name: &str, lints: impl Iterator<Item = &'a Lint>) -> String {
     let mut details: Vec<_> = lints.map(|l| (&l.module, l.name.to_uppercase())).collect();
@@ -278,18 +509,55 @@ fn gen_register_lint_list<'a>(
     output
 }
 
+fn gen_deprecated_lints_test(lints: &[DeprecatedLint]) -> String {
+    let mut res: String = GENERATED_FILE_COMMENT.into();
+    for lint in lints {
+        writeln!(res, "#![warn(clippy::{})]", lint.name).unwrap();
+    }
+    res.push_str("\nfn main() {}\n");
+    res
+}
+
+fn gen_renamed_lints_test(lints: &[RenamedLint]) -> String {
+    let mut seen_lints = HashSet::new();
+    let mut res: String = GENERATED_FILE_COMMENT.into();
+    res.push_str("// run-rustfix\n\n");
+    for lint in lints {
+        if seen_lints.insert(&lint.new_name) {
+            writeln!(res, "#![allow({})]", lint.new_name).unwrap();
+        }
+    }
+    seen_lints.clear();
+    for lint in lints {
+        if seen_lints.insert(&lint.old_name) {
+            writeln!(res, "#![warn({})]", lint.old_name).unwrap();
+        }
+    }
+    res.push_str("\nfn main() {}\n");
+    res
+}
+
+fn gen_renamed_lints_list(lints: &[RenamedLint]) -> String {
+    const HEADER: &str = "\
+        // This file is managed by `cargo dev rename_lint`. Prefer using that when possible.\n\n\
+        #[rustfmt::skip]\n\
+        pub static RENAMED_LINTS: &[(&str, &str)] = &[\n";
+
+    let mut res = String::from(HEADER);
+    for lint in lints {
+        writeln!(res, "    (\"{}\", \"{}\"),", lint.old_name, lint.new_name).unwrap();
+    }
+    res.push_str("];\n");
+    res
+}
+
 /// Gathers all lints defined in `clippy_lints/src`
-fn gather_all() -> (Vec<Lint>, Vec<DeprecatedLint>) {
+fn gather_all() -> (Vec<Lint>, Vec<DeprecatedLint>, Vec<RenamedLint>) {
     let mut lints = Vec::with_capacity(1000);
     let mut deprecated_lints = Vec::with_capacity(50);
-    let root_path = clippy_project_root().join("clippy_lints/src");
+    let mut renamed_lints = Vec::with_capacity(50);
 
-    for (rel_path, file) in WalkDir::new(&root_path)
-        .into_iter()
-        .map(Result::unwrap)
-        .filter(|f| f.path().extension() == Some(OsStr::new("rs")))
-        .map(|f| (f.path().strip_prefix(&root_path).unwrap().to_path_buf(), f))
-    {
+    for (rel_path, file) in clippy_lints_src_files() {
         let path = file.path();
         let contents =
             fs::read_to_string(path).unwrap_or_else(|e| panic!("Cannot read from `{}`: {}", path.display(), e));
@@ -307,13 +575,21 @@ fn gather_all() -> (Vec<Lint>, Vec<DeprecatedLint>) {
             module.strip_suffix(".rs").unwrap_or(&module)
         };
 
-        if module == "deprecated_lints" {
-            parse_deprecated_contents(&contents, &mut deprecated_lints);
-        } else {
-            parse_contents(&contents, module, &mut lints);
+        match module {
+            "deprecated_lints" => parse_deprecated_contents(&contents, &mut deprecated_lints),
+            "renamed_lints" => parse_renamed_contents(&contents, &mut renamed_lints),
+            _ => parse_contents(&contents, module, &mut lints),
         }
     }
-    (lints, deprecated_lints)
+    (lints, deprecated_lints, renamed_lints)
+}
+
+fn clippy_lints_src_files() -> impl Iterator<Item = (PathBuf, DirEntry)> {
+    let root_path = clippy_project_root().join("clippy_lints/src");
+    let iter = WalkDir::new(&root_path).into_iter();
+    iter.map(Result::unwrap)
+        .filter(|f| f.path().extension() == Some(OsStr::new("rs")))
+        .map(move |f| (f.path().strip_prefix(&root_path).unwrap().to_path_buf(), f))
 }
 
 macro_rules! match_tokens {
@@ -396,6 +672,25 @@ fn parse_deprecated_contents(contents: &str, lints: &mut Vec<DeprecatedLint>) {
     }
 }
 
+fn parse_renamed_contents(contents: &str, lints: &mut Vec<RenamedLint>) {
+    for line in contents.lines() {
+        let mut offset = 0usize;
+        let mut iter = tokenize(line).map(|t| {
+            let range = offset..offset + t.len;
+            offset = range.end;
+            (t.kind, &line[range])
+        });
+        let (old_name, new_name) = match_tokens!(
+            iter,
+            // ("old_name",
+            Whitespace OpenParen Literal{kind: LiteralKind::Str{..},..}(old_name) Comma
+            // "new_name"),
+            Whitespace Literal{kind: LiteralKind::Str{..},..}(new_name) CloseParen Comma
+        );
+        lints.push(RenamedLint::new(old_name, new_name));
+    }
+}
+
 /// Removes the line splices and surrounding quotes from a string literal
 fn remove_line_splices(s: &str) -> String {
     let s = s
@@ -464,6 +759,52 @@ fn replace_region_in_text<'a>(
     Ok(res)
 }
 
+fn try_rename_file(old_name: &Path, new_name: &Path) -> bool {
+    match fs::OpenOptions::new().create_new(true).write(true).open(new_name) {
+        Ok(file) => drop(file),
+        Err(e) if matches!(e.kind(), io::ErrorKind::AlreadyExists | io::ErrorKind::NotFound) => return false,
+        Err(e) => panic_file(e, new_name, "create"),
+    };
+    match fs::rename(old_name, new_name) {
+        Ok(()) => true,
+        Err(e) => {
+            drop(fs::remove_file(new_name));
+            if e.kind() == io::ErrorKind::NotFound {
+                false
+            } else {
+                panic_file(e, old_name, "rename");
+            }
+        },
+    }
+}
+
+#[allow(clippy::needless_pass_by_value)]
+fn panic_file(error: io::Error, name: &Path, action: &str) -> ! {
+    panic!("failed to {} file `{}`: {}", action, name.display(), error)
+}
+
+fn rewrite_file(path: &Path, f: impl FnOnce(&str) -> Option<String>) {
+    let mut file = fs::OpenOptions::new()
+        .write(true)
+        .read(true)
+        .open(path)
+        .unwrap_or_else(|e| panic_file(e, path, "open"));
+    let mut buf = String::new();
+    file.read_to_string(&mut buf)
+        .unwrap_or_else(|e| panic_file(e, path, "read"));
+    if let Some(new_contents) = f(&buf) {
+        file.rewind().unwrap_or_else(|e| panic_file(e, path, "write"));
+        file.write_all(new_contents.as_bytes())
+            .unwrap_or_else(|e| panic_file(e, path, "write"));
+        file.set_len(new_contents.len() as u64)
+            .unwrap_or_else(|e| panic_file(e, path, "write"));
+    }
+}
+
+fn write_file(path: &Path, contents: &str) {
+    fs::write(path, contents).unwrap_or_else(|e| panic_file(e, path, "write"));
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;
diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs
index d0b03c0a9c2..e880876218e 100644
--- a/clippy_lints/src/attrs.rs
+++ b/clippy_lints/src/attrs.rs
@@ -335,9 +335,6 @@ impl<'tcx> LateLintPass<'tcx> for Attributes {
                     }
                     if let Some(lint_list) = &attr.meta_item_list() {
                         if attr.ident().map_or(false, |ident| is_lint_level(ident.name)) {
-                            // permit `unused_imports`, `deprecated`, `unreachable_pub`,
-                            // `clippy::wildcard_imports`, and `clippy::enum_glob_use` for `use` items
-                            // and `unused_imports` for `extern crate` items with `macro_use`
                             for lint in lint_list {
                                 match item.kind {
                                     ItemKind::Use(..) => {
@@ -345,10 +342,12 @@ impl<'tcx> LateLintPass<'tcx> for Attributes {
                                             || is_word(lint, sym::deprecated)
                                             || is_word(lint, sym!(unreachable_pub))
                                             || is_word(lint, sym!(unused))
-                                            || extract_clippy_lint(lint)
-                                                .map_or(false, |s| s.as_str() == "wildcard_imports")
-                                            || extract_clippy_lint(lint)
-                                                .map_or(false, |s| s.as_str() == "enum_glob_use")
+                                            || extract_clippy_lint(lint).map_or(false, |s| {
+                                                matches!(
+                                                    s.as_str(),
+                                                    "wildcard_imports" | "enum_glob_use" | "redundant_pub_crate",
+                                                )
+                                            })
                                         {
                                             return;
                                         }
diff --git a/clippy_lints/src/casts/cast_slice_different_sizes.rs b/clippy_lints/src/casts/cast_slice_different_sizes.rs
index 3608c1654d5..2238668abca 100644
--- a/clippy_lints/src/casts/cast_slice_different_sizes.rs
+++ b/clippy_lints/src/casts/cast_slice_different_sizes.rs
@@ -1,4 +1,4 @@
-use clippy_utils::{diagnostics::span_lint_and_then, meets_msrv, msrvs, source::snippet_opt};
+use clippy_utils::{diagnostics::span_lint_and_then, meets_msrv, msrvs, source};
 use if_chain::if_chain;
 use rustc_ast::Mutability;
 use rustc_hir::{Expr, ExprKind, Node};
@@ -8,32 +8,7 @@ use rustc_semver::RustcVersion;
 
 use super::CAST_SLICE_DIFFERENT_SIZES;
 
-fn is_child_of_cast(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
-    let map = cx.tcx.hir();
-    if_chain! {
-        if let Some(parent_id) = map.find_parent_node(expr.hir_id);
-        if let Some(parent) = map.find(parent_id);
-        then {
-            let expr = match parent {
-                Node::Block(block) => {
-                    if let Some(parent_expr) = block.expr {
-                        parent_expr
-                    } else {
-                        return false;
-                    }
-                },
-                Node::Expr(expr) => expr,
-                _ => return false,
-            };
-
-            matches!(expr.kind, ExprKind::Cast(..))
-        } else {
-            false
-        }
-    }
-}
-
-pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: &Option<RustcVersion>) {
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, msrv: &Option<RustcVersion>) {
     // suggestion is invalid if `ptr::slice_from_raw_parts` does not exist
     if !meets_msrv(msrv.as_ref(), &msrvs::PTR_SLICE_RAW_PARTS) {
         return;
@@ -45,8 +20,13 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: &Option<RustcVe
         return;
     }
 
-    if let Some((from_slice_ty, to_slice_ty)) = expr_cast_chain_tys(cx, expr) {
-        if let (Ok(from_layout), Ok(to_layout)) = (cx.layout_of(from_slice_ty.ty), cx.layout_of(to_slice_ty.ty)) {
+    if let Some(CastChainInfo {
+        left_cast,
+        start_ty,
+        end_ty,
+    }) = expr_cast_chain_tys(cx, expr)
+    {
+        if let (Ok(from_layout), Ok(to_layout)) = (cx.layout_of(start_ty.ty), cx.layout_of(end_ty.ty)) {
             let from_size = from_layout.size.bytes();
             let to_size = to_layout.size.bytes();
             if from_size != to_size && from_size != 0 && to_size != 0 {
@@ -56,21 +36,20 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: &Option<RustcVe
                     expr.span,
                     &format!(
                         "casting between raw pointers to `[{}]` (element size {}) and `[{}]` (element size {}) does not adjust the count",
-                        from_slice_ty, from_size, to_slice_ty, to_size,
+                        start_ty.ty, from_size, end_ty.ty, to_size,
                     ),
                     |diag| {
-                        let cast_expr = match expr.kind {
-                            ExprKind::Cast(cast_expr, ..) => cast_expr,
-                            _ => unreachable!("expr should be a cast as checked by expr_cast_chain_tys"),
-                        };
-                        let ptr_snippet = snippet_opt(cx, cast_expr.span).unwrap();
+                        let ptr_snippet = source::snippet(cx, left_cast.span, "..");
 
-                        let (mutbl_fn_str, mutbl_ptr_str) = match to_slice_ty.mutbl {
+                        let (mutbl_fn_str, mutbl_ptr_str) = match end_ty.mutbl {
                             Mutability::Mut => ("_mut", "mut"),
                             Mutability::Not => ("", "const"),
                         };
                         let sugg = format!(
-                            "core::ptr::slice_from_raw_parts{mutbl_fn_str}({ptr_snippet} as *{mutbl_ptr_str} {to_slice_ty}, ..)"
+                            "core::ptr::slice_from_raw_parts{mutbl_fn_str}({ptr_snippet} as *{mutbl_ptr_str} {}, ..)",
+                            // get just the ty from the TypeAndMut so that the printed type isn't something like `mut
+                            // T`, extract just the `T`
+                            end_ty.ty
                         );
 
                         diag.span_suggestion(
@@ -86,6 +65,31 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: &Option<RustcVe
     }
 }
 
+fn is_child_of_cast(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+    let map = cx.tcx.hir();
+    if_chain! {
+        if let Some(parent_id) = map.find_parent_node(expr.hir_id);
+        if let Some(parent) = map.find(parent_id);
+        then {
+            let expr = match parent {
+                Node::Block(block) => {
+                    if let Some(parent_expr) = block.expr {
+                        parent_expr
+                    } else {
+                        return false;
+                    }
+                },
+                Node::Expr(expr) => expr,
+                _ => return false,
+            };
+
+            matches!(expr.kind, ExprKind::Cast(..))
+        } else {
+            false
+        }
+    }
+}
+
 /// Returns the type T of the pointed to *const [T] or *mut [T] and the mutability of the slice if
 /// the type is one of those slices
 fn get_raw_slice_ty_mut(ty: Ty<'_>) -> Option<TypeAndMut<'_>> {
@@ -98,18 +102,40 @@ fn get_raw_slice_ty_mut(ty: Ty<'_>) -> Option<TypeAndMut<'_>> {
     }
 }
 
-/// Returns the pair (original ptr T, final ptr U) if the expression is composed of casts
+struct CastChainInfo<'tcx> {
+    /// The left most part of the cast chain, or in other words, the first cast in the chain
+    /// Used for diagnostics
+    left_cast: &'tcx Expr<'tcx>,
+    /// The starting type of the cast chain
+    start_ty: TypeAndMut<'tcx>,
+    /// The final type of the cast chain
+    end_ty: TypeAndMut<'tcx>,
+}
+
+/// Returns a `CastChainInfo` with the left-most cast in the chain and the original ptr T and final
+/// ptr U if the expression is composed of casts.
 /// Returns None if the expr is not a Cast
-fn expr_cast_chain_tys<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> Option<(TypeAndMut<'tcx>, TypeAndMut<'tcx>)> {
+fn expr_cast_chain_tys<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> Option<CastChainInfo<'tcx>> {
     if let ExprKind::Cast(cast_expr, _cast_to_hir_ty) = expr.peel_blocks().kind {
         let cast_to = cx.typeck_results().expr_ty(expr);
         let to_slice_ty = get_raw_slice_ty_mut(cast_to)?;
-        if let Some((inner_from_ty, _inner_to_ty)) = expr_cast_chain_tys(cx, cast_expr) {
-            Some((inner_from_ty, to_slice_ty))
+
+        // If the expression that makes up the source of this cast is itself a cast, recursively
+        // call `expr_cast_chain_tys` and update the end type with the final tartet type.
+        // Otherwise, this cast is not immediately nested, just construct the info for this cast
+        if let Some(prev_info) = expr_cast_chain_tys(cx, cast_expr) {
+            Some(CastChainInfo {
+                end_ty: to_slice_ty,
+                ..prev_info
+            })
         } else {
             let cast_from = cx.typeck_results().expr_ty(cast_expr);
             let from_slice_ty = get_raw_slice_ty_mut(cast_from)?;
-            Some((from_slice_ty, to_slice_ty))
+            Some(CastChainInfo {
+                left_cast: cast_expr,
+                start_ty: from_slice_ty,
+                end_ty: to_slice_ty,
+            })
         }
     } else {
         None
diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs
index c2e32f1d9a2..1b19868e4c7 100644
--- a/clippy_lints/src/eta_reduction.rs
+++ b/clippy_lints/src/eta_reduction.rs
@@ -3,7 +3,7 @@ use clippy_utils::higher::VecArgs;
 use clippy_utils::source::snippet_opt;
 use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::usage::local_used_after_expr;
-use clippy_utils::{higher, path_to_local, path_to_local_id};
+use clippy_utils::{higher, is_adjusted, path_to_local, path_to_local_id};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::def_id::DefId;
@@ -103,6 +103,7 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction {
         let closure_ty = cx.typeck_results().expr_ty(expr);
 
         if_chain!(
+            if !is_adjusted(cx, &body.value);
             if let ExprKind::Call(callee, args) = body.value.kind;
             if let ExprKind::Path(_) = callee.kind;
             if check_inputs(cx, body.params, args);
@@ -144,6 +145,7 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction {
         );
 
         if_chain!(
+            if !is_adjusted(cx, &body.value);
             if let ExprKind::MethodCall(path, args, _) = body.value.kind;
             if check_inputs(cx, body.params, args);
             let method_def_id = cx.typeck_results().type_dependent_def_id(body.value.hir_id).unwrap();
diff --git a/clippy_lints/src/identity_op.rs b/clippy_lints/src/identity_op.rs
index 4d6bef89bea..40cc5cd4bcf 100644
--- a/clippy_lints/src/identity_op.rs
+++ b/clippy_lints/src/identity_op.rs
@@ -1,3 +1,4 @@
+use clippy_utils::get_parent_expr;
 use clippy_utils::source::snippet;
 use rustc_hir::{BinOp, BinOpKind, Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
@@ -22,6 +23,11 @@ declare_clippy_lint! {
     /// # let x = 1;
     /// x / 1 + 0 * 1 - 0 | 0;
     /// ```
+    ///
+    /// ### Known problems
+    /// False negatives: `f(0 + if b { 1 } else { 2 } + 3);` is reducible to
+    /// `f(if b { 1 } else { 2 } + 3);`. But the lint doesn't trigger for the code.
+    /// See [#8724](https://github.com/rust-lang/rust-clippy/issues/8724)
     #[clippy::version = "pre 1.29.0"]
     pub IDENTITY_OP,
     complexity,
@@ -31,36 +37,66 @@ declare_clippy_lint! {
 declare_lint_pass!(IdentityOp => [IDENTITY_OP]);
 
 impl<'tcx> LateLintPass<'tcx> for IdentityOp {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
-        if e.span.from_expansion() {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        if expr.span.from_expansion() {
             return;
         }
-        if let ExprKind::Binary(cmp, left, right) = e.kind {
-            if is_allowed(cx, cmp, left, right) {
-                return;
-            }
-            match cmp.node {
-                BinOpKind::Add | BinOpKind::BitOr | BinOpKind::BitXor => {
-                    check(cx, left, 0, e.span, right.span);
-                    check(cx, right, 0, e.span, left.span);
-                },
-                BinOpKind::Shl | BinOpKind::Shr | BinOpKind::Sub => check(cx, right, 0, e.span, left.span),
-                BinOpKind::Mul => {
-                    check(cx, left, 1, e.span, right.span);
-                    check(cx, right, 1, e.span, left.span);
-                },
-                BinOpKind::Div => check(cx, right, 1, e.span, left.span),
-                BinOpKind::BitAnd => {
-                    check(cx, left, -1, e.span, right.span);
-                    check(cx, right, -1, e.span, left.span);
-                },
-                BinOpKind::Rem => check_remainder(cx, left, right, e.span, left.span),
-                _ => (),
+        if let ExprKind::Binary(cmp, left, right) = &expr.kind {
+            if !is_allowed(cx, *cmp, left, right) {
+                match cmp.node {
+                    BinOpKind::Add | BinOpKind::BitOr | BinOpKind::BitXor => {
+                        if reducible_to_right(cx, expr, right) {
+                            check(cx, left, 0, expr.span, right.span);
+                        }
+                        check(cx, right, 0, expr.span, left.span);
+                    },
+                    BinOpKind::Shl | BinOpKind::Shr | BinOpKind::Sub => {
+                        check(cx, right, 0, expr.span, left.span);
+                    },
+                    BinOpKind::Mul => {
+                        if reducible_to_right(cx, expr, right) {
+                            check(cx, left, 1, expr.span, right.span);
+                        }
+                        check(cx, right, 1, expr.span, left.span);
+                    },
+                    BinOpKind::Div => check(cx, right, 1, expr.span, left.span),
+                    BinOpKind::BitAnd => {
+                        if reducible_to_right(cx, expr, right) {
+                            check(cx, left, -1, expr.span, right.span);
+                        }
+                        check(cx, right, -1, expr.span, left.span);
+                    },
+                    BinOpKind::Rem => {
+                        // Don't call reducible_to_right because N % N is always reducible to 1
+                        check_remainder(cx, left, right, expr.span, left.span);
+                    },
+                    _ => (),
+                }
             }
         }
     }
 }
 
+/// Checks if `left op ..right` can be actually reduced to `right`
+/// e.g. `0 + if b { 1 } else { 2 } + if b { 3 } else { 4 }`
+/// cannot be reduced to `if b { 1 } else { 2 } +  if b { 3 } else { 4 }`
+/// See #8724
+fn reducible_to_right(cx: &LateContext<'_>, binary: &Expr<'_>, right: &Expr<'_>) -> bool {
+    if let ExprKind::If(..) | ExprKind::Match(..) | ExprKind::Block(..) | ExprKind::Loop(..) = right.kind {
+        is_toplevel_binary(cx, binary)
+    } else {
+        true
+    }
+}
+
+fn is_toplevel_binary(cx: &LateContext<'_>, must_be_binary: &Expr<'_>) -> bool {
+    if let Some(parent) = get_parent_expr(cx, must_be_binary) && let ExprKind::Binary(..) = &parent.kind {
+        false
+    } else {
+        true
+    }
+}
+
 fn is_allowed(cx: &LateContext<'_>, cmp: BinOp, left: &Expr<'_>, right: &Expr<'_>) -> bool {
     // This lint applies to integers
     !cx.typeck_results().expr_ty(left).peel_refs().is_integral()
diff --git a/clippy_lints/src/init_numbered_fields.rs b/clippy_lints/src/init_numbered_fields.rs
index 9284e002409..7e1548531f1 100644
--- a/clippy_lints/src/init_numbered_fields.rs
+++ b/clippy_lints/src/init_numbered_fields.rs
@@ -1,6 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_applicability;
 use rustc_errors::Applicability;
+use rustc_hir::def::{DefKind, Res};
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -49,6 +50,7 @@ impl<'tcx> LateLintPass<'tcx> for NumberedFields {
                 && fields
                     .iter()
                     .all(|f| f.ident.as_str().as_bytes().iter().all(u8::is_ascii_digit))
+                && !matches!(cx.qpath_res(path, e.hir_id), Res::Def(DefKind::TyAlias, ..))
             {
                 let expr_spans = fields
                     .iter()
diff --git a/clippy_lints/src/large_include_file.rs b/clippy_lints/src/large_include_file.rs
index 5ed275726c5..8bef13c682d 100644
--- a/clippy_lints/src/large_include_file.rs
+++ b/clippy_lints/src/large_include_file.rs
@@ -19,7 +19,7 @@ declare_clippy_lint! {
     /// ### Example
     /// ```rust,ignore
     /// let included_str = include_str!("very_large_file.txt");
-    /// let included_bytes = include_bytes!("very_large_file.txt);
+    /// let included_bytes = include_bytes!("very_large_file.txt");
     /// ```
     ///
     /// Instead, you can load the file at runtime:
diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs
index a49f8656ba3..e68718f9fdf 100644
--- a/clippy_lints/src/lib.register_all.rs
+++ b/clippy_lints/src/lib.register_all.rs
@@ -248,7 +248,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
     LintId::of(non_expressive_names::JUST_UNDERSCORES_AND_DIGITS),
     LintId::of(non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS),
     LintId::of(octal_escapes::OCTAL_ESCAPES),
-    LintId::of(only_used_in_recursion::ONLY_USED_IN_RECURSION),
     LintId::of(open_options::NONSENSICAL_OPEN_OPTIONS),
     LintId::of(option_env_unwrap::OPTION_ENV_UNWRAP),
     LintId::of(overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL),
diff --git a/clippy_lints/src/lib.register_complexity.rs b/clippy_lints/src/lib.register_complexity.rs
index df646ff5c5f..6f3c433af31 100644
--- a/clippy_lints/src/lib.register_complexity.rs
+++ b/clippy_lints/src/lib.register_complexity.rs
@@ -68,7 +68,6 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec!
     LintId::of(neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD),
     LintId::of(no_effect::NO_EFFECT),
     LintId::of(no_effect::UNNECESSARY_OPERATION),
-    LintId::of(only_used_in_recursion::ONLY_USED_IN_RECURSION),
     LintId::of(overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL),
     LintId::of(partialeq_ne_impl::PARTIALEQ_NE_IMPL),
     LintId::of(precedence::PRECEDENCE),
diff --git a/clippy_lints/src/lib.register_nursery.rs b/clippy_lints/src/lib.register_nursery.rs
index c2fc67afba5..18904a94538 100644
--- a/clippy_lints/src/lib.register_nursery.rs
+++ b/clippy_lints/src/lib.register_nursery.rs
@@ -20,6 +20,7 @@ store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![
     LintId::of(mutex_atomic::MUTEX_INTEGER),
     LintId::of(non_send_fields_in_send_ty::NON_SEND_FIELDS_IN_SEND_TY),
     LintId::of(nonstandard_macro_braces::NONSTANDARD_MACRO_BRACES),
+    LintId::of(only_used_in_recursion::ONLY_USED_IN_RECURSION),
     LintId::of(option_if_let_else::OPTION_IF_LET_ELSE),
     LintId::of(path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE),
     LintId::of(redundant_pub_crate::REDUNDANT_PUB_CRATE),
diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs
index caf48194ad4..3bb821a1482 100644
--- a/clippy_lints/src/lib.rs
+++ b/clippy_lints/src/lib.rs
@@ -163,6 +163,8 @@ mod deprecated_lints;
 #[cfg_attr(feature = "internal", allow(clippy::missing_clippy_version_attribute))]
 mod utils;
 
+mod renamed_lints;
+
 // begin lints modules, do not remove this comment, it’s used in `update_lints`
 mod absurd_extreme_comparisons;
 mod approx_const;
@@ -939,43 +941,9 @@ fn register_removed_non_tool_lints(store: &mut rustc_lint::LintStore) {
 ///
 /// Used in `./src/driver.rs`.
 pub fn register_renamed(ls: &mut rustc_lint::LintStore) {
-    // NOTE: when renaming a lint, add a corresponding test to tests/ui/rename.rs
-    ls.register_renamed("clippy::stutter", "clippy::module_name_repetitions");
-    ls.register_renamed("clippy::new_without_default_derive", "clippy::new_without_default");
-    ls.register_renamed("clippy::cyclomatic_complexity", "clippy::cognitive_complexity");
-    ls.register_renamed("clippy::const_static_lifetime", "clippy::redundant_static_lifetimes");
-    ls.register_renamed("clippy::option_and_then_some", "clippy::bind_instead_of_map");
-    ls.register_renamed("clippy::box_vec", "clippy::box_collection");
-    ls.register_renamed("clippy::block_in_if_condition_expr", "clippy::blocks_in_if_conditions");
-    ls.register_renamed("clippy::block_in_if_condition_stmt", "clippy::blocks_in_if_conditions");
-    ls.register_renamed("clippy::option_map_unwrap_or", "clippy::map_unwrap_or");
-    ls.register_renamed("clippy::option_map_unwrap_or_else", "clippy::map_unwrap_or");
-    ls.register_renamed("clippy::result_map_unwrap_or_else", "clippy::map_unwrap_or");
-    ls.register_renamed("clippy::option_unwrap_used", "clippy::unwrap_used");
-    ls.register_renamed("clippy::result_unwrap_used", "clippy::unwrap_used");
-    ls.register_renamed("clippy::option_expect_used", "clippy::expect_used");
-    ls.register_renamed("clippy::result_expect_used", "clippy::expect_used");
-    ls.register_renamed("clippy::for_loop_over_option", "clippy::for_loops_over_fallibles");
-    ls.register_renamed("clippy::for_loop_over_result", "clippy::for_loops_over_fallibles");
-    ls.register_renamed("clippy::identity_conversion", "clippy::useless_conversion");
-    ls.register_renamed("clippy::zero_width_space", "clippy::invisible_characters");
-    ls.register_renamed("clippy::single_char_push_str", "clippy::single_char_add_str");
-    ls.register_renamed("clippy::if_let_some_result", "clippy::match_result_ok");
-    ls.register_renamed("clippy::disallowed_type", "clippy::disallowed_types");
-    ls.register_renamed("clippy::disallowed_method", "clippy::disallowed_methods");
-    ls.register_renamed("clippy::ref_in_deref", "clippy::needless_borrow");
-    ls.register_renamed("clippy::to_string_in_display", "clippy::recursive_format_impl");
-
-    // uplifted lints
-    ls.register_renamed("clippy::invalid_ref", "invalid_value");
-    ls.register_renamed("clippy::into_iter_on_array", "array_into_iter");
-    ls.register_renamed("clippy::unused_label", "unused_labels");
-    ls.register_renamed("clippy::drop_bounds", "drop_bounds");
-    ls.register_renamed("clippy::temporary_cstring_as_ptr", "temporary_cstring_as_ptr");
-    ls.register_renamed("clippy::panic_params", "non_fmt_panics");
-    ls.register_renamed("clippy::unknown_clippy_lints", "unknown_lints");
-    ls.register_renamed("clippy::invalid_atomic_ordering", "invalid_atomic_ordering");
-    ls.register_renamed("clippy::mem_discriminant_non_enum", "enum_intrinsics_non_enums");
+    for (old_name, new_name) in renamed_lints::RENAMED_LINTS {
+        ls.register_renamed(old_name, new_name);
+    }
 }
 
 // only exists to let the dogfood integration test works.
diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs
index b09c23f31e9..54b80bf3b27 100644
--- a/clippy_lints/src/lifetimes.rs
+++ b/clippy_lints/src/lifetimes.rs
@@ -1,16 +1,19 @@
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::trait_ref_of_method;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_hir::intravisit::nested_filter::{self as hir_nested_filter, NestedFilter};
 use rustc_hir::intravisit::{
-    walk_fn_decl, walk_generic_param, walk_generics, walk_item, walk_param_bound, walk_poly_trait_ref, walk_ty, Visitor,
+    walk_fn_decl, walk_generic_param, walk_generics, walk_impl_item_ref, walk_item, walk_param_bound,
+    walk_poly_trait_ref, walk_trait_ref, walk_ty, Visitor,
 };
 use rustc_hir::FnRetTy::Return;
 use rustc_hir::{
-    BareFnTy, BodyId, FnDecl, GenericArg, GenericBound, GenericParam, GenericParamKind, Generics, ImplItem,
+    BareFnTy, BodyId, FnDecl, GenericArg, GenericBound, GenericParam, GenericParamKind, Generics, Impl, ImplItem,
     ImplItemKind, Item, ItemKind, LangItem, Lifetime, LifetimeName, ParamName, PolyTraitRef, TraitBoundModifier,
     TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WhereClause, WherePredicate,
 };
 use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::hir::nested_filter as middle_nested_filter;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::Span;
 use rustc_span::symbol::{kw, Ident, Symbol};
@@ -84,6 +87,8 @@ impl<'tcx> LateLintPass<'tcx> for Lifetimes {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
         if let ItemKind::Fn(ref sig, ref generics, id) = item.kind {
             check_fn_inner(cx, sig.decl, Some(id), None, generics, item.span, true);
+        } else if let ItemKind::Impl(ref impl_) = item.kind {
+            report_extra_impl_lifetimes(cx, impl_);
         }
     }
 
@@ -194,8 +199,7 @@ fn explicit_self_type<'tcx>(cx: &LateContext<'tcx>, func: &FnDecl<'tcx>, ident:
             visitor.visit_ty(self_ty);
 
             !visitor.all_lts().is_empty()
-        }
-        else {
+        } else {
             false
         }
     }
@@ -481,11 +485,29 @@ fn has_where_lifetimes<'tcx>(cx: &LateContext<'tcx>, where_clause: &'tcx WhereCl
     false
 }
 
-struct LifetimeChecker {
+struct LifetimeChecker<'cx, 'tcx, F> {
+    cx: &'cx LateContext<'tcx>,
     map: FxHashMap<Symbol, Span>,
+    phantom: std::marker::PhantomData<F>,
 }
 
-impl<'tcx> Visitor<'tcx> for LifetimeChecker {
+impl<'cx, 'tcx, F> LifetimeChecker<'cx, 'tcx, F> {
+    fn new(cx: &'cx LateContext<'tcx>, map: FxHashMap<Symbol, Span>) -> LifetimeChecker<'cx, 'tcx, F> {
+        Self {
+            cx,
+            map,
+            phantom: std::marker::PhantomData,
+        }
+    }
+}
+
+impl<'cx, 'tcx, F> Visitor<'tcx> for LifetimeChecker<'cx, 'tcx, F>
+where
+    F: NestedFilter<'tcx>,
+{
+    type Map = rustc_middle::hir::map::Map<'tcx>;
+    type NestedFilter = F;
+
     // for lifetimes as parameters of generics
     fn visit_lifetime(&mut self, lifetime: &'tcx Lifetime) {
         self.map.remove(&lifetime.name.ident().name);
@@ -501,6 +523,10 @@ impl<'tcx> Visitor<'tcx> for LifetimeChecker {
             walk_generic_param(self, param);
         }
     }
+
+    fn nested_visit_map(&mut self) -> Self::Map {
+        self.cx.tcx.hir()
+    }
 }
 
 fn report_extra_lifetimes<'tcx>(cx: &LateContext<'tcx>, func: &'tcx FnDecl<'_>, generics: &'tcx Generics<'_>) {
@@ -512,7 +538,7 @@ fn report_extra_lifetimes<'tcx>(cx: &LateContext<'tcx>, func: &'tcx FnDecl<'_>,
             _ => None,
         })
         .collect();
-    let mut checker = LifetimeChecker { map: hs };
+    let mut checker = LifetimeChecker::<hir_nested_filter::None>::new(cx, hs);
 
     walk_generics(&mut checker, generics);
     walk_fn_decl(&mut checker, func);
@@ -527,6 +553,32 @@ fn report_extra_lifetimes<'tcx>(cx: &LateContext<'tcx>, func: &'tcx FnDecl<'_>,
     }
 }
 
+fn report_extra_impl_lifetimes<'tcx>(cx: &LateContext<'tcx>, impl_: &'tcx Impl<'_>) {
+    let hs = impl_
+        .generics
+        .params
+        .iter()
+        .filter_map(|par| match par.kind {
+            GenericParamKind::Lifetime { .. } => Some((par.name.ident().name, par.span)),
+            _ => None,
+        })
+        .collect();
+    let mut checker = LifetimeChecker::<middle_nested_filter::All>::new(cx, hs);
+
+    walk_generics(&mut checker, &impl_.generics);
+    if let Some(ref trait_ref) = impl_.of_trait {
+        walk_trait_ref(&mut checker, trait_ref);
+    }
+    walk_ty(&mut checker, impl_.self_ty);
+    for item in impl_.items {
+        walk_impl_item_ref(&mut checker, item);
+    }
+
+    for &v in checker.map.values() {
+        span_lint(cx, EXTRA_UNUSED_LIFETIMES, v, "this lifetime isn't used in the impl");
+    }
+}
+
 struct BodyLifetimeChecker {
     lifetimes_used_in_body: bool,
 }
diff --git a/clippy_lints/src/matches/redundant_pattern_match.rs b/clippy_lints/src/matches/redundant_pattern_match.rs
index 777ec9b75bc..a34ed58c9c3 100644
--- a/clippy_lints/src/matches/redundant_pattern_match.rs
+++ b/clippy_lints/src/matches/redundant_pattern_match.rs
@@ -2,17 +2,16 @@ use super::REDUNDANT_PATTERN_MATCHING;
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::snippet;
 use clippy_utils::sugg::Sugg;
-use clippy_utils::ty::{implements_trait, is_type_diagnostic_item, is_type_lang_item, match_type};
+use clippy_utils::ty::needs_ordered_drop;
 use clippy_utils::{higher, match_def_path};
 use clippy_utils::{is_lang_ctor, is_trait_method, paths};
 use if_chain::if_chain;
 use rustc_ast::ast::LitKind;
-use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::Applicability;
 use rustc_hir::LangItem::{OptionNone, PollPending};
 use rustc_hir::{
     intravisit::{walk_expr, Visitor},
-    Arm, Block, Expr, ExprKind, LangItem, Node, Pat, PatKind, QPath, UnOp,
+    Arm, Block, Expr, ExprKind, Node, Pat, PatKind, QPath, UnOp,
 };
 use rustc_lint::LateContext;
 use rustc_middle::ty::{self, subst::GenericArgKind, DefIdTree, Ty};
@@ -32,59 +31,6 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
     }
 }
 
-/// Checks if the drop order for a type matters. Some std types implement drop solely to
-/// deallocate memory. For these types, and composites containing them, changing the drop order
-/// won't result in any observable side effects.
-fn type_needs_ordered_drop<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
-    type_needs_ordered_drop_inner(cx, ty, &mut FxHashSet::default())
-}
-
-fn type_needs_ordered_drop_inner<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, seen: &mut FxHashSet<Ty<'tcx>>) -> bool {
-    if !seen.insert(ty) {
-        return false;
-    }
-    if !ty.needs_drop(cx.tcx, cx.param_env) {
-        false
-    } else if !cx
-        .tcx
-        .lang_items()
-        .drop_trait()
-        .map_or(false, |id| implements_trait(cx, ty, id, &[]))
-    {
-        // This type doesn't implement drop, so no side effects here.
-        // Check if any component type has any.
-        match ty.kind() {
-            ty::Tuple(fields) => fields.iter().any(|ty| type_needs_ordered_drop_inner(cx, ty, seen)),
-            ty::Array(ty, _) => type_needs_ordered_drop_inner(cx, *ty, seen),
-            ty::Adt(adt, subs) => adt
-                .all_fields()
-                .map(|f| f.ty(cx.tcx, subs))
-                .any(|ty| type_needs_ordered_drop_inner(cx, ty, seen)),
-            _ => true,
-        }
-    }
-    // Check for std types which implement drop, but only for memory allocation.
-    else if is_type_diagnostic_item(cx, ty, sym::Vec)
-        || is_type_lang_item(cx, ty, LangItem::OwnedBox)
-        || is_type_diagnostic_item(cx, ty, sym::Rc)
-        || is_type_diagnostic_item(cx, ty, sym::Arc)
-        || is_type_diagnostic_item(cx, ty, sym::cstring_type)
-        || is_type_diagnostic_item(cx, ty, sym::BTreeMap)
-        || is_type_diagnostic_item(cx, ty, sym::LinkedList)
-        || match_type(cx, ty, &paths::WEAK_RC)
-        || match_type(cx, ty, &paths::WEAK_ARC)
-    {
-        // Check all of the generic arguments.
-        if let ty::Adt(_, subs) = ty.kind() {
-            subs.types().any(|ty| type_needs_ordered_drop_inner(cx, ty, seen))
-        } else {
-            true
-        }
-    } else {
-        true
-    }
-}
-
 // Extract the generic arguments out of a type
 fn try_get_generic_ty(ty: Ty<'_>, index: usize) -> Option<Ty<'_>> {
     if_chain! {
@@ -115,7 +61,7 @@ fn temporaries_need_ordered_drop<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<
                 // e.g. In `(String::new(), 0).1` the string is a temporary value.
                 ExprKind::AddrOf(_, _, expr) | ExprKind::Field(expr, _) => {
                     if !matches!(expr.kind, ExprKind::Path(_)) {
-                        if type_needs_ordered_drop(self.cx, self.cx.typeck_results().expr_ty(expr)) {
+                        if needs_ordered_drop(self.cx, self.cx.typeck_results().expr_ty(expr)) {
                             self.res = true;
                         } else {
                             self.visit_expr(expr);
@@ -126,7 +72,7 @@ fn temporaries_need_ordered_drop<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<
                 // e.g. In `(vec![0])[0]` the vector is a temporary value.
                 ExprKind::Index(base, index) => {
                     if !matches!(base.kind, ExprKind::Path(_)) {
-                        if type_needs_ordered_drop(self.cx, self.cx.typeck_results().expr_ty(base)) {
+                        if needs_ordered_drop(self.cx, self.cx.typeck_results().expr_ty(base)) {
                             self.res = true;
                         } else {
                             self.visit_expr(base);
@@ -143,7 +89,7 @@ fn temporaries_need_ordered_drop<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<
                             .typeck_results()
                             .type_dependent_def_id(expr.hir_id)
                             .map_or(false, |id| self.cx.tcx.fn_sig(id).skip_binder().inputs()[0].is_ref());
-                        if self_by_ref && type_needs_ordered_drop(self.cx, self.cx.typeck_results().expr_ty(self_arg)) {
+                        if self_by_ref && needs_ordered_drop(self.cx, self.cx.typeck_results().expr_ty(self_arg)) {
                             self.res = true;
                         } else {
                             self.visit_expr(self_arg);
@@ -243,7 +189,7 @@ fn find_sugg_for_if_let<'tcx>(
     // scrutinee would be, so they have to be considered as well.
     // e.g. in `if let Some(x) = foo.lock().unwrap().baz.as_ref() { .. }` the lock will be held
     // for the duration if body.
-    let needs_drop = type_needs_ordered_drop(cx, check_ty) || temporaries_need_ordered_drop(cx, let_expr);
+    let needs_drop = needs_ordered_drop(cx, check_ty) || temporaries_need_ordered_drop(cx, let_expr);
 
     // check that `while_let_on_iterator` lint does not trigger
     if_chain! {
diff --git a/clippy_lints/src/needless_late_init.rs b/clippy_lints/src/needless_late_init.rs
index bbcf7e9e378..b70871b38be 100644
--- a/clippy_lints/src/needless_late_init.rs
+++ b/clippy_lints/src/needless_late_init.rs
@@ -1,10 +1,14 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::path_to_local;
 use clippy_utils::source::snippet_opt;
-use clippy_utils::visitors::{expr_visitor, is_local_used};
-use rustc_errors::Applicability;
+use clippy_utils::ty::needs_ordered_drop;
+use clippy_utils::visitors::{expr_visitor, expr_visitor_no_bodies, is_local_used};
+use rustc_errors::{Applicability, MultiSpan};
 use rustc_hir::intravisit::Visitor;
-use rustc_hir::{Block, Expr, ExprKind, HirId, Local, LocalSource, MatchSource, Node, Pat, PatKind, Stmt, StmtKind};
+use rustc_hir::{
+    BindingAnnotation, Block, Expr, ExprKind, HirId, Local, LocalSource, MatchSource, Node, Pat, PatKind, Stmt,
+    StmtKind,
+};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::Span;
@@ -73,6 +77,31 @@ fn contains_assign_expr<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'tcx>) ->
     seen
 }
 
+fn contains_let(cond: &Expr<'_>) -> bool {
+    let mut seen = false;
+    expr_visitor_no_bodies(|expr| {
+        if let ExprKind::Let(_) = expr.kind {
+            seen = true;
+        }
+
+        !seen
+    })
+    .visit_expr(cond);
+
+    seen
+}
+
+fn stmt_needs_ordered_drop(cx: &LateContext<'_>, stmt: &Stmt<'_>) -> bool {
+    let StmtKind::Local(local) = stmt.kind else { return false };
+    !local.pat.walk_short(|pat| {
+        if let PatKind::Binding(.., None) = pat.kind {
+            !needs_ordered_drop(cx, cx.typeck_results().pat_ty(pat))
+        } else {
+            true
+        }
+    })
+}
+
 #[derive(Debug)]
 struct LocalAssign {
     lhs_id: HirId,
@@ -187,11 +216,14 @@ fn first_usage<'tcx>(
     local_stmt_id: HirId,
     block: &'tcx Block<'tcx>,
 ) -> Option<Usage<'tcx>> {
+    let significant_drop = needs_ordered_drop(cx, cx.typeck_results().node_type(binding_id));
+
     block
         .stmts
         .iter()
         .skip_while(|stmt| stmt.hir_id != local_stmt_id)
         .skip(1)
+        .take_while(|stmt| !significant_drop || !stmt_needs_ordered_drop(cx, stmt))
         .find(|&stmt| is_local_used(cx, stmt, binding_id))
         .and_then(|stmt| match stmt.kind {
             StmtKind::Expr(expr) => Some(Usage {
@@ -235,11 +267,14 @@ fn check<'tcx>(
     match usage.expr.kind {
         ExprKind::Assign(..) => {
             let assign = LocalAssign::new(cx, usage.expr, binding_id)?;
+            let mut msg_span = MultiSpan::from_spans(vec![local_stmt.span, assign.span]);
+            msg_span.push_span_label(local_stmt.span, "created here");
+            msg_span.push_span_label(assign.span, "initialised here");
 
             span_lint_and_then(
                 cx,
                 NEEDLESS_LATE_INIT,
-                local_stmt.span,
+                msg_span,
                 "unneeded late initialization",
                 |diag| {
                     diag.tool_only_span_suggestion(
@@ -258,7 +293,7 @@ fn check<'tcx>(
                 },
             );
         },
-        ExprKind::If(_, then_expr, Some(else_expr)) => {
+        ExprKind::If(cond, then_expr, Some(else_expr)) if !contains_let(cond) => {
             let (applicability, suggestions) = assignment_suggestions(cx, binding_id, [then_expr, else_expr])?;
 
             span_lint_and_then(
@@ -333,12 +368,11 @@ fn check<'tcx>(
 impl<'tcx> LateLintPass<'tcx> for NeedlessLateInit {
     fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'tcx>) {
         let mut parents = cx.tcx.hir().parent_iter(local.hir_id);
-
         if_chain! {
             if let Local {
                 init: None,
                 pat: &Pat {
-                    kind: PatKind::Binding(_, binding_id, _, None),
+                    kind: PatKind::Binding(BindingAnnotation::Unannotated, binding_id, _, None),
                     ..
                 },
                 source: LocalSource::Normal,
diff --git a/clippy_lints/src/only_used_in_recursion.rs b/clippy_lints/src/only_used_in_recursion.rs
index f946fc11192..beb812793f8 100644
--- a/clippy_lints/src/only_used_in_recursion.rs
+++ b/clippy_lints/src/only_used_in_recursion.rs
@@ -1,6 +1,7 @@
 use std::collections::VecDeque;
 
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::is_lint_allowed;
 use itertools::{izip, Itertools};
 use rustc_ast::{walk_list, Label, Mutability};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
@@ -33,6 +34,9 @@ declare_clippy_lint! {
     /// and the assigned variables are also only in recursion, it is useless.
     ///
     /// ### Known problems
+    /// Too many code paths in the linting code are currently untested and prone to produce false
+    /// positives or are prone to have performance implications.
+    ///
     /// In some cases, this would not catch all useless arguments.
     ///
     /// ```rust
@@ -85,7 +89,7 @@ declare_clippy_lint! {
     /// ```
     #[clippy::version = "1.60.0"]
     pub ONLY_USED_IN_RECURSION,
-    complexity,
+    nursery,
     "arguments that is only used in recursion can be removed"
 }
 declare_lint_pass!(OnlyUsedInRecursion => [ONLY_USED_IN_RECURSION]);
@@ -100,6 +104,9 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion {
         _: Span,
         id: HirId,
     ) {
+        if is_lint_allowed(cx, ONLY_USED_IN_RECURSION, id) {
+            return;
+        }
         if let FnKind::ItemFn(ident, ..) | FnKind::Method(ident, ..) = kind {
             let def_id = id.owner.to_def_id();
             let data = cx.tcx.def_path(def_id).data;
diff --git a/clippy_lints/src/renamed_lints.rs b/clippy_lints/src/renamed_lints.rs
new file mode 100644
index 00000000000..bfc03116fe2
--- /dev/null
+++ b/clippy_lints/src/renamed_lints.rs
@@ -0,0 +1,39 @@
+// This file is managed by `cargo dev rename_lint`. Prefer using that when possible.
+
+#[rustfmt::skip]
+pub static RENAMED_LINTS: &[(&str, &str)] = &[
+    ("clippy::block_in_if_condition_expr", "clippy::blocks_in_if_conditions"),
+    ("clippy::block_in_if_condition_stmt", "clippy::blocks_in_if_conditions"),
+    ("clippy::box_vec", "clippy::box_collection"),
+    ("clippy::const_static_lifetime", "clippy::redundant_static_lifetimes"),
+    ("clippy::cyclomatic_complexity", "clippy::cognitive_complexity"),
+    ("clippy::disallowed_method", "clippy::disallowed_methods"),
+    ("clippy::disallowed_type", "clippy::disallowed_types"),
+    ("clippy::for_loop_over_option", "clippy::for_loops_over_fallibles"),
+    ("clippy::for_loop_over_result", "clippy::for_loops_over_fallibles"),
+    ("clippy::identity_conversion", "clippy::useless_conversion"),
+    ("clippy::if_let_some_result", "clippy::match_result_ok"),
+    ("clippy::new_without_default_derive", "clippy::new_without_default"),
+    ("clippy::option_and_then_some", "clippy::bind_instead_of_map"),
+    ("clippy::option_expect_used", "clippy::expect_used"),
+    ("clippy::option_map_unwrap_or", "clippy::map_unwrap_or"),
+    ("clippy::option_map_unwrap_or_else", "clippy::map_unwrap_or"),
+    ("clippy::option_unwrap_used", "clippy::unwrap_used"),
+    ("clippy::ref_in_deref", "clippy::needless_borrow"),
+    ("clippy::result_expect_used", "clippy::expect_used"),
+    ("clippy::result_map_unwrap_or_else", "clippy::map_unwrap_or"),
+    ("clippy::result_unwrap_used", "clippy::unwrap_used"),
+    ("clippy::single_char_push_str", "clippy::single_char_add_str"),
+    ("clippy::stutter", "clippy::module_name_repetitions"),
+    ("clippy::to_string_in_display", "clippy::recursive_format_impl"),
+    ("clippy::zero_width_space", "clippy::invisible_characters"),
+    ("clippy::drop_bounds", "drop_bounds"),
+    ("clippy::into_iter_on_array", "array_into_iter"),
+    ("clippy::invalid_atomic_ordering", "invalid_atomic_ordering"),
+    ("clippy::invalid_ref", "invalid_value"),
+    ("clippy::mem_discriminant_non_enum", "enum_intrinsics_non_enums"),
+    ("clippy::panic_params", "non_fmt_panics"),
+    ("clippy::temporary_cstring_as_ptr", "temporary_cstring_as_ptr"),
+    ("clippy::unknown_clippy_lints", "unknown_lints"),
+    ("clippy::unused_label", "unused_labels"),
+];
diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs
index e3fc76f4e1a..901e3e5390c 100644
--- a/clippy_utils/src/ty.rs
+++ b/clippy_utils/src/ty.rs
@@ -3,11 +3,11 @@
 #![allow(clippy::module_name_repetitions)]
 
 use rustc_ast::ast::Mutability;
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::def_id::DefId;
-use rustc_hir::{Expr, TyKind, Unsafety};
+use rustc_hir::{Expr, LangItem, TyKind, Unsafety};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::LateContext;
 use rustc_middle::mir::interpret::{ConstValue, Scalar};
@@ -22,7 +22,7 @@ use rustc_trait_selection::infer::InferCtxtExt;
 use rustc_trait_selection::traits::query::normalize::AtExt;
 use std::iter;
 
-use crate::{match_def_path, must_use_attr, path_res};
+use crate::{match_def_path, must_use_attr, path_res, paths};
 
 // Checks if the given type implements copy.
 pub fn is_copy<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
@@ -83,6 +83,20 @@ pub fn get_associated_type<'tcx>(
         })
 }
 
+/// Get the diagnostic name of a type, e.g. `sym::HashMap`. To check if a type
+/// implements a trait marked with a diagnostic item use [`implements_trait`].
+///
+/// For a further exploitation what diagnostic items are see [diagnostic items] in
+/// rustc-dev-guide.
+///
+/// [Diagnostic Items]: https://rustc-dev-guide.rust-lang.org/diagnostics/diagnostic-items.html
+pub fn get_type_diagnostic_name(cx: &LateContext<'_>, ty: Ty<'_>) -> Option<Symbol> {
+    match ty.kind() {
+        ty::Adt(adt, _) => cx.tcx.get_diagnostic_name(adt.did()),
+        _ => None,
+    }
+}
+
 /// Returns true if ty has `iter` or `iter_mut` methods
 pub fn has_iter_method(cx: &LateContext<'_>, probably_ref_ty: Ty<'_>) -> Option<Symbol> {
     // FIXME: instead of this hard-coded list, we should check if `<adt>::iter`
@@ -319,6 +333,57 @@ pub fn match_type(cx: &LateContext<'_>, ty: Ty<'_>, path: &[&str]) -> bool {
     }
 }
 
+/// Checks if the drop order for a type matters. Some std types implement drop solely to
+/// deallocate memory. For these types, and composites containing them, changing the drop order
+/// won't result in any observable side effects.
+pub fn needs_ordered_drop<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
+    fn needs_ordered_drop_inner<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, seen: &mut FxHashSet<Ty<'tcx>>) -> bool {
+        if !seen.insert(ty) {
+            return false;
+        }
+        if !ty.has_significant_drop(cx.tcx, cx.param_env) {
+            false
+        }
+        // Check for std types which implement drop, but only for memory allocation.
+        else if is_type_lang_item(cx, ty, LangItem::OwnedBox)
+            || matches!(
+                get_type_diagnostic_name(cx, ty),
+                Some(sym::HashSet | sym::Rc | sym::Arc | sym::cstring_type)
+            )
+            || match_type(cx, ty, &paths::WEAK_RC)
+            || match_type(cx, ty, &paths::WEAK_ARC)
+        {
+            // Check all of the generic arguments.
+            if let ty::Adt(_, subs) = ty.kind() {
+                subs.types().any(|ty| needs_ordered_drop_inner(cx, ty, seen))
+            } else {
+                true
+            }
+        } else if !cx
+            .tcx
+            .lang_items()
+            .drop_trait()
+            .map_or(false, |id| implements_trait(cx, ty, id, &[]))
+        {
+            // This type doesn't implement drop, so no side effects here.
+            // Check if any component type has any.
+            match ty.kind() {
+                ty::Tuple(fields) => fields.iter().any(|ty| needs_ordered_drop_inner(cx, ty, seen)),
+                ty::Array(ty, _) => needs_ordered_drop_inner(cx, *ty, seen),
+                ty::Adt(adt, subs) => adt
+                    .all_fields()
+                    .map(|f| f.ty(cx.tcx, subs))
+                    .any(|ty| needs_ordered_drop_inner(cx, ty, seen)),
+                _ => true,
+            }
+        } else {
+            true
+        }
+    }
+
+    needs_ordered_drop_inner(cx, ty, &mut FxHashSet::default())
+}
+
 /// Peels off all references on the type. Returns the underlying type and the number of references
 /// removed.
 pub fn peel_mid_ty_refs(ty: Ty<'_>) -> (Ty<'_>, usize) {
diff --git a/tests/ui/cast_slice_different_sizes.rs b/tests/ui/cast_slice_different_sizes.rs
index 57270fcf52b..24d7eb28a19 100644
--- a/tests/ui/cast_slice_different_sizes.rs
+++ b/tests/ui/cast_slice_different_sizes.rs
@@ -39,3 +39,44 @@ fn main() {
     let long_chain_restore =
         r_x as *const [i32] as *const [u32] as *const [u16] as *const [i8] as *const [u8] as *const [u32];
 }
+
+// foo and foo2 should not fire, they're the same size
+fn foo(x: *mut [u8]) -> *mut [u8] {
+    x as *mut [u8]
+}
+
+fn foo2(x: *mut [u8]) -> *mut [u8] {
+    x as *mut _
+}
+
+// Test that casts as part of function returns work
+fn bar(x: *mut [u16]) -> *mut [u8] {
+    x as *mut [u8]
+}
+
+fn uwu(x: *mut [u16]) -> *mut [u8] {
+    x as *mut _
+}
+
+fn bar2(x: *mut [u16]) -> *mut [u8] {
+    x as _
+}
+
+// constify
+fn bar3(x: *mut [u16]) -> *const [u8] {
+    x as _
+}
+
+// unconstify
+fn bar4(x: *const [u16]) -> *mut [u8] {
+    x as _
+}
+
+// function returns plus blocks
+fn blocks(x: *mut [u16]) -> *mut [u8] {
+    ({ x }) as _
+}
+
+fn more_blocks(x: *mut [u16]) -> *mut [u8] {
+    { ({ x }) as _ }
+}
diff --git a/tests/ui/cast_slice_different_sizes.stderr b/tests/ui/cast_slice_different_sizes.stderr
index 993e93c2bf3..40721dcd05d 100644
--- a/tests/ui/cast_slice_different_sizes.stderr
+++ b/tests/ui/cast_slice_different_sizes.stderr
@@ -46,7 +46,76 @@ error: casting between raw pointers to `[i32]` (element size 4) and `[u8]` (elem
   --> $DIR/cast_slice_different_sizes.rs:38:27
    |
 LL |     let long_chain_loss = r_x as *const [i32] as *const [u32] as *const [u16] as *const [i8] as *const [u8];
-   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with `ptr::slice_from_raw_parts`: `core::ptr::slice_from_raw_parts(r_x as *const [i32] as *const [u32] as *const [u16] as *const [i8] as *const u8, ..)`
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with `ptr::slice_from_raw_parts`: `core::ptr::slice_from_raw_parts(r_x as *const [i32] as *const u8, ..)`
 
-error: aborting due to 6 previous errors
+error: casting between raw pointers to `[u16]` (element size 2) and `[u8]` (element size 1) does not adjust the count
+  --> $DIR/cast_slice_different_sizes.rs:53:36
+   |
+LL |   fn bar(x: *mut [u16]) -> *mut [u8] {
+   |  ____________________________________^
+LL | |     x as *mut [u8]
+LL | | }
+   | |_^ help: replace with `ptr::slice_from_raw_parts_mut`: `core::ptr::slice_from_raw_parts_mut(x as *mut u8, ..)`
+
+error: casting between raw pointers to `[u16]` (element size 2) and `[u8]` (element size 1) does not adjust the count
+  --> $DIR/cast_slice_different_sizes.rs:57:36
+   |
+LL |   fn uwu(x: *mut [u16]) -> *mut [u8] {
+   |  ____________________________________^
+LL | |     x as *mut _
+LL | | }
+   | |_^ help: replace with `ptr::slice_from_raw_parts_mut`: `core::ptr::slice_from_raw_parts_mut(x as *mut u8, ..)`
+
+error: casting between raw pointers to `[u16]` (element size 2) and `[u8]` (element size 1) does not adjust the count
+  --> $DIR/cast_slice_different_sizes.rs:61:37
+   |
+LL |   fn bar2(x: *mut [u16]) -> *mut [u8] {
+   |  _____________________________________^
+LL | |     x as _
+LL | | }
+   | |_^ help: replace with `ptr::slice_from_raw_parts_mut`: `core::ptr::slice_from_raw_parts_mut(x as *mut u8, ..)`
+
+error: casting between raw pointers to `[u16]` (element size 2) and `[u8]` (element size 1) does not adjust the count
+  --> $DIR/cast_slice_different_sizes.rs:66:39
+   |
+LL |   fn bar3(x: *mut [u16]) -> *const [u8] {
+   |  _______________________________________^
+LL | |     x as _
+LL | | }
+   | |_^ help: replace with `ptr::slice_from_raw_parts`: `core::ptr::slice_from_raw_parts(x as *const u8, ..)`
+
+error: casting between raw pointers to `[u16]` (element size 2) and `[u8]` (element size 1) does not adjust the count
+  --> $DIR/cast_slice_different_sizes.rs:71:39
+   |
+LL |   fn bar4(x: *const [u16]) -> *mut [u8] {
+   |  _______________________________________^
+LL | |     x as _
+LL | | }
+   | |_^ help: replace with `ptr::slice_from_raw_parts_mut`: `core::ptr::slice_from_raw_parts_mut(x as *mut u8, ..)`
+
+error: casting between raw pointers to `[u16]` (element size 2) and `[u8]` (element size 1) does not adjust the count
+  --> $DIR/cast_slice_different_sizes.rs:76:39
+   |
+LL |   fn blocks(x: *mut [u16]) -> *mut [u8] {
+   |  _______________________________________^
+LL | |     ({ x }) as _
+LL | | }
+   | |_^ help: replace with `ptr::slice_from_raw_parts_mut`: `core::ptr::slice_from_raw_parts_mut(({ x }) as *mut u8, ..)`
+
+error: casting between raw pointers to `[u16]` (element size 2) and `[u8]` (element size 1) does not adjust the count
+  --> $DIR/cast_slice_different_sizes.rs:80:44
+   |
+LL |   fn more_blocks(x: *mut [u16]) -> *mut [u8] {
+   |  ____________________________________________^
+LL | |     { ({ x }) as _ }
+LL | | }
+   | |_^ help: replace with `ptr::slice_from_raw_parts_mut`: `core::ptr::slice_from_raw_parts_mut(({ x }) as *mut u8, ..)`
+
+error: casting between raw pointers to `[u16]` (element size 2) and `[u8]` (element size 1) does not adjust the count
+  --> $DIR/cast_slice_different_sizes.rs:81:5
+   |
+LL |     { ({ x }) as _ }
+   |     ^^^^^^^^^^^^^^^^ help: replace with `ptr::slice_from_raw_parts_mut`: `core::ptr::slice_from_raw_parts_mut(({ x }) as *mut u8, ..)`
+
+error: aborting due to 14 previous errors
 
diff --git a/tests/ui/crashes/ice-2865.rs b/tests/ui/crashes/ice-2865.rs
index 6b1ceb50569..c6298139601 100644
--- a/tests/ui/crashes/ice-2865.rs
+++ b/tests/ui/crashes/ice-2865.rs
@@ -1,4 +1,4 @@
-#[allow(dead_code)]
+#![allow(dead_code, clippy::extra_unused_lifetimes)]
 
 /// Test for https://github.com/rust-lang/rust-clippy/issues/2865
 
diff --git a/tests/ui/crashes/ice-3151.rs b/tests/ui/crashes/ice-3151.rs
index fef4d7db84d..268ba86fc7a 100644
--- a/tests/ui/crashes/ice-3151.rs
+++ b/tests/ui/crashes/ice-3151.rs
@@ -1,4 +1,4 @@
-/// Test for https://github.com/rust-lang/rust-clippy/issues/2865
+/// Test for https://github.com/rust-lang/rust-clippy/issues/3151
 
 #[derive(Clone)]
 pub struct HashMap<V, S> {
diff --git a/tests/ui/deprecated.rs b/tests/ui/deprecated.rs
index 39a2601fee9..07270bd7636 100644
--- a/tests/ui/deprecated.rs
+++ b/tests/ui/deprecated.rs
@@ -1,3 +1,7 @@
+// This file was generated by `cargo dev update_lints`.
+// Use that command to update this file and do not edit by hand.
+// Manual edits will be overwritten.
+
 #![warn(clippy::should_assert_eq)]
 #![warn(clippy::extend_from_slice)]
 #![warn(clippy::range_step_by_zero)]
diff --git a/tests/ui/deprecated.stderr b/tests/ui/deprecated.stderr
index 6095f134d55..0e142ac8f20 100644
--- a/tests/ui/deprecated.stderr
+++ b/tests/ui/deprecated.stderr
@@ -1,5 +1,5 @@
 error: lint `clippy::should_assert_eq` has been removed: `assert!()` will be more flexible with RFC 2011
-  --> $DIR/deprecated.rs:1:9
+  --> $DIR/deprecated.rs:5:9
    |
 LL | #![warn(clippy::should_assert_eq)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -7,91 +7,91 @@ LL | #![warn(clippy::should_assert_eq)]
    = note: `-D renamed-and-removed-lints` implied by `-D warnings`
 
 error: lint `clippy::extend_from_slice` has been removed: `.extend_from_slice(_)` is a faster way to extend a Vec by a slice
-  --> $DIR/deprecated.rs:2:9
+  --> $DIR/deprecated.rs:6:9
    |
 LL | #![warn(clippy::extend_from_slice)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: lint `clippy::range_step_by_zero` has been removed: `iterator.step_by(0)` panics nowadays
-  --> $DIR/deprecated.rs:3:9
+  --> $DIR/deprecated.rs:7:9
    |
 LL | #![warn(clippy::range_step_by_zero)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: lint `clippy::unstable_as_slice` has been removed: `Vec::as_slice` has been stabilized in 1.7
-  --> $DIR/deprecated.rs:4:9
+  --> $DIR/deprecated.rs:8:9
    |
 LL | #![warn(clippy::unstable_as_slice)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: lint `clippy::unstable_as_mut_slice` has been removed: `Vec::as_mut_slice` has been stabilized in 1.7
-  --> $DIR/deprecated.rs:5:9
+  --> $DIR/deprecated.rs:9:9
    |
 LL | #![warn(clippy::unstable_as_mut_slice)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: lint `clippy::misaligned_transmute` has been removed: this lint has been split into cast_ptr_alignment and transmute_ptr_to_ptr
-  --> $DIR/deprecated.rs:6:9
+  --> $DIR/deprecated.rs:10:9
    |
 LL | #![warn(clippy::misaligned_transmute)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: lint `clippy::assign_ops` has been removed: using compound assignment operators (e.g., `+=`) is harmless
-  --> $DIR/deprecated.rs:7:9
+  --> $DIR/deprecated.rs:11:9
    |
 LL | #![warn(clippy::assign_ops)]
    |         ^^^^^^^^^^^^^^^^^^
 
 error: lint `clippy::if_let_redundant_pattern_matching` has been removed: this lint has been changed to redundant_pattern_matching
-  --> $DIR/deprecated.rs:8:9
+  --> $DIR/deprecated.rs:12:9
    |
 LL | #![warn(clippy::if_let_redundant_pattern_matching)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: lint `clippy::unsafe_vector_initialization` has been removed: the replacement suggested by this lint had substantially different behavior
-  --> $DIR/deprecated.rs:9:9
+  --> $DIR/deprecated.rs:13:9
    |
 LL | #![warn(clippy::unsafe_vector_initialization)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: lint `clippy::unused_collect` has been removed: `collect` has been marked as #[must_use] in rustc and that covers all cases of this lint
-  --> $DIR/deprecated.rs:10:9
+  --> $DIR/deprecated.rs:14:9
    |
 LL | #![warn(clippy::unused_collect)]
    |         ^^^^^^^^^^^^^^^^^^^^^^
 
 error: lint `clippy::replace_consts` has been removed: associated-constants `MIN`/`MAX` of integers are preferred to `{min,max}_value()` and module constants
-  --> $DIR/deprecated.rs:11:9
+  --> $DIR/deprecated.rs:15:9
    |
 LL | #![warn(clippy::replace_consts)]
    |         ^^^^^^^^^^^^^^^^^^^^^^
 
 error: lint `clippy::regex_macro` has been removed: the regex! macro has been removed from the regex crate in 2018
-  --> $DIR/deprecated.rs:12:9
+  --> $DIR/deprecated.rs:16:9
    |
 LL | #![warn(clippy::regex_macro)]
    |         ^^^^^^^^^^^^^^^^^^^
 
 error: lint `clippy::find_map` has been removed: this lint has been replaced by `manual_find_map`, a more specific lint
-  --> $DIR/deprecated.rs:13:9
+  --> $DIR/deprecated.rs:17:9
    |
 LL | #![warn(clippy::find_map)]
    |         ^^^^^^^^^^^^^^^^
 
 error: lint `clippy::filter_map` has been removed: this lint has been replaced by `manual_filter_map`, a more specific lint
-  --> $DIR/deprecated.rs:14:9
+  --> $DIR/deprecated.rs:18:9
    |
 LL | #![warn(clippy::filter_map)]
    |         ^^^^^^^^^^^^^^^^^^
 
 error: lint `clippy::pub_enum_variant_names` has been removed: set the `avoid-breaking-exported-api` config option to `false` to enable the `enum_variant_names` lint for public items
-  --> $DIR/deprecated.rs:15:9
+  --> $DIR/deprecated.rs:19:9
    |
 LL | #![warn(clippy::pub_enum_variant_names)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: lint `clippy::wrong_pub_self_convention` has been removed: set the `avoid-breaking-exported-api` config option to `false` to enable the `wrong_self_convention` lint for public items
-  --> $DIR/deprecated.rs:16:9
+  --> $DIR/deprecated.rs:20:9
    |
 LL | #![warn(clippy::wrong_pub_self_convention)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/eta.fixed b/tests/ui/eta.fixed
index 873ed689a5b..6c2272f4dff 100644
--- a/tests/ui/eta.fixed
+++ b/tests/ui/eta.fixed
@@ -37,7 +37,7 @@ fn main() {
     }
 
     // See #815
-    let e = Some(1u8).map(divergent);
+    let e = Some(1u8).map(|a| divergent(a));
     let e = Some(1u8).map(generic);
     let e = Some(1u8).map(generic);
     // See #515
@@ -233,7 +233,7 @@ fn late_bound_lifetimes() {
     {
     }
     map_str(|s| take_asref_path(s));
-    map_str_to_path(std::convert::AsRef::as_ref);
+    map_str_to_path(|s| s.as_ref());
 }
 
 mod type_param_bound {
@@ -279,3 +279,15 @@ mod bind_by_ref {
         Some(A).map(|ref a| B::from(a));
     }
 }
+
+// #7812 False positive on coerced closure
+fn coerced_closure() {
+    fn function_returning_unit<F: FnMut(i32)>(f: F) {}
+    function_returning_unit(|x| std::process::exit(x));
+
+    fn arr() -> &'static [u8; 0] {
+        &[]
+    }
+    fn slice_fn(_: impl FnOnce() -> &'static [u8]) {}
+    slice_fn(|| arr());
+}
diff --git a/tests/ui/eta.rs b/tests/ui/eta.rs
index 4cb58eec94c..a1a9c0dfbf3 100644
--- a/tests/ui/eta.rs
+++ b/tests/ui/eta.rs
@@ -279,3 +279,15 @@ mod bind_by_ref {
         Some(A).map(|ref a| B::from(a));
     }
 }
+
+// #7812 False positive on coerced closure
+fn coerced_closure() {
+    fn function_returning_unit<F: FnMut(i32)>(f: F) {}
+    function_returning_unit(|x| std::process::exit(x));
+
+    fn arr() -> &'static [u8; 0] {
+        &[]
+    }
+    fn slice_fn(_: impl FnOnce() -> &'static [u8]) {}
+    slice_fn(|| arr());
+}
diff --git a/tests/ui/eta.stderr b/tests/ui/eta.stderr
index d1ae889d6f3..bf2e97e744a 100644
--- a/tests/ui/eta.stderr
+++ b/tests/ui/eta.stderr
@@ -25,12 +25,6 @@ LL |     all(&[1, 2, 3], &&2, |x, y| below(x, y)); //is adjusted
    |                          ^^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `below`
 
 error: redundant closure
-  --> $DIR/eta.rs:40:27
-   |
-LL |     let e = Some(1u8).map(|a| divergent(a));
-   |                           ^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `divergent`
-
-error: redundant closure
   --> $DIR/eta.rs:41:27
    |
 LL |     let e = Some(1u8).map(|a| generic(a));
@@ -122,11 +116,5 @@ error: redundant closure
 LL |         Some(1).map(|n| in_loop(n));
    |                     ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `in_loop`
 
-error: redundant closure
-  --> $DIR/eta.rs:236:21
-   |
-LL |     map_str_to_path(|s| s.as_ref());
-   |                     ^^^^^^^^^^^^^^ help: replace the closure with the method itself: `std::convert::AsRef::as_ref`
-
-error: aborting due to 21 previous errors
+error: aborting due to 19 previous errors
 
diff --git a/tests/ui/extra_unused_lifetimes.rs b/tests/ui/extra_unused_lifetimes.rs
index 150acfbfee7..f76127a7105 100644
--- a/tests/ui/extra_unused_lifetimes.rs
+++ b/tests/ui/extra_unused_lifetimes.rs
@@ -72,4 +72,46 @@ mod issue4291 {
     }
 }
 
+mod issue6437 {
+    pub struct Scalar;
+
+    impl<'a> std::ops::AddAssign<&Scalar> for &mut Scalar {
+        fn add_assign(&mut self, _rhs: &Scalar) {
+            unimplemented!();
+        }
+    }
+
+    impl<'b> Scalar {
+        pub fn something<'c>() -> Self {
+            Self
+        }
+    }
+}
+
+// https://github.com/rust-lang/rust-clippy/pull/8737#pullrequestreview-951268213
+mod first_case {
+    use serde::de::Visitor;
+    pub trait Expected {
+        fn fmt(&self, formatter: &mut std::fmt::Formatter);
+    }
+
+    impl<'de, T> Expected for T
+    where
+        T: Visitor<'de>,
+    {
+        fn fmt(&self, formatter: &mut std::fmt::Formatter) {}
+    }
+}
+
+// https://github.com/rust-lang/rust-clippy/pull/8737#pullrequestreview-951268213
+mod second_case {
+    pub trait Source {
+        fn hey();
+    }
+
+    impl<'a, T: Source + ?Sized + 'a> Source for Box<T> {
+        fn hey() {}
+    }
+}
+
 fn main() {}
diff --git a/tests/ui/extra_unused_lifetimes.stderr b/tests/ui/extra_unused_lifetimes.stderr
index ebdb8e74952..68f02c7ad0f 100644
--- a/tests/ui/extra_unused_lifetimes.stderr
+++ b/tests/ui/extra_unused_lifetimes.stderr
@@ -24,5 +24,23 @@ error: this lifetime isn't used in the function definition
 LL |         fn unused_lt<'a>(x: u8) {}
    |                      ^^
 
-error: aborting due to 4 previous errors
+error: this lifetime isn't used in the impl
+  --> $DIR/extra_unused_lifetimes.rs:78:10
+   |
+LL |     impl<'a> std::ops::AddAssign<&Scalar> for &mut Scalar {
+   |          ^^
+
+error: this lifetime isn't used in the impl
+  --> $DIR/extra_unused_lifetimes.rs:84:10
+   |
+LL |     impl<'b> Scalar {
+   |          ^^
+
+error: this lifetime isn't used in the function definition
+  --> $DIR/extra_unused_lifetimes.rs:85:26
+   |
+LL |         pub fn something<'c>() -> Self {
+   |                          ^^
+
+error: aborting due to 7 previous errors
 
diff --git a/tests/ui/identity_op.rs b/tests/ui/identity_op.rs
index 9d39d769635..fec54d00ccb 100644
--- a/tests/ui/identity_op.rs
+++ b/tests/ui/identity_op.rs
@@ -77,4 +77,34 @@ fn main() {
     (x + 1) % 3; // no error
     4 % 3; // no error
     4 % -3; // no error
+
+    // See #8724
+    let a = 0;
+    let b = true;
+    0 + if b { 1 } else { 2 };
+    0 + if b { 1 } else { 2 } + if b { 3 } else { 4 }; // no error
+    0 + match a { 0 => 10, _ => 20 };
+    0 + match a { 0 => 10, _ => 20 } + match a { 0 => 30, _ => 40 }; // no error
+    0 + if b { 1 } else { 2 } + match a { 0 => 30, _ => 40 }; // no error
+    0 + match a { 0 => 10, _ => 20 } + if b { 3 } else { 4 }; // no error
+    
+    0 + if b { 0 + 1 } else { 2 };
+    0 + match a { 0 =>  0 + 10, _ => 20 };
+    0 + if b { 0 + 1 } else { 2 } + match a { 0 => 0 + 30, _ => 40 };
+
+    let _ = 0 + if 0 + 1 > 0 { 1 } else { 2 } + if 0 + 1 > 0 { 3 } else { 4 };
+    let _ = 0 + match 0 + 1 { 0 => 10, _ => 20 } + match 0 + 1  { 0 => 30, _ => 40 };
+
+    0 + if b { 1 } else { 2 } + if b { 3 } else { 4 } + 0;
+    
+    0 + { a } + 3; // no error
+    0 + loop { let mut c = 0; if c == 10 { break c; } c += 1; } + { a * 2 }; // no error
+    
+    fn f(_: i32) {
+        todo!();
+    }
+    f(1 * a + { 8 * 5 });
+    f(0 + if b { 1 } else { 2 } + 3); // no error
+    const _: i32 = { 2 * 4 } + 0 + 3;
+    const _: i32 = 0 + { 1 + 2 * 3 } + 3; // no error
 }
diff --git a/tests/ui/identity_op.stderr b/tests/ui/identity_op.stderr
index e3c156b5429..d8cb65839cb 100644
--- a/tests/ui/identity_op.stderr
+++ b/tests/ui/identity_op.stderr
@@ -108,5 +108,95 @@ error: the operation is ineffective. Consider reducing it to `1`
 LL |     x + 1 % 3;
    |         ^^^^^
 
-error: aborting due to 18 previous errors
+error: the operation is ineffective. Consider reducing it to `if b { 1 } else { 2 }`
+  --> $DIR/identity_op.rs:84:5
+   |
+LL |     0 + if b { 1 } else { 2 };
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: the operation is ineffective. Consider reducing it to `match a { 0 => 10, _ => 20 }`
+  --> $DIR/identity_op.rs:86:5
+   |
+LL |     0 + match a { 0 => 10, _ => 20 };
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: the operation is ineffective. Consider reducing it to `if b { 0 + 1 } else { 2 }`
+  --> $DIR/identity_op.rs:91:5
+   |
+LL |     0 + if b { 0 + 1 } else { 2 };
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: the operation is ineffective. Consider reducing it to `1`
+  --> $DIR/identity_op.rs:91:16
+   |
+LL |     0 + if b { 0 + 1 } else { 2 };
+   |                ^^^^^
+
+error: the operation is ineffective. Consider reducing it to `match a { 0 =>  0 + 10, _ => 20 }`
+  --> $DIR/identity_op.rs:92:5
+   |
+LL |     0 + match a { 0 =>  0 + 10, _ => 20 };
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: the operation is ineffective. Consider reducing it to `10`
+  --> $DIR/identity_op.rs:92:25
+   |
+LL |     0 + match a { 0 =>  0 + 10, _ => 20 };
+   |                         ^^^^^^
+
+error: the operation is ineffective. Consider reducing it to `1`
+  --> $DIR/identity_op.rs:93:16
+   |
+LL |     0 + if b { 0 + 1 } else { 2 } + match a { 0 => 0 + 30, _ => 40 };
+   |                ^^^^^
+
+error: the operation is ineffective. Consider reducing it to `30`
+  --> $DIR/identity_op.rs:93:52
+   |
+LL |     0 + if b { 0 + 1 } else { 2 } + match a { 0 => 0 + 30, _ => 40 };
+   |                                                    ^^^^^^
+
+error: the operation is ineffective. Consider reducing it to `1`
+  --> $DIR/identity_op.rs:95:20
+   |
+LL |     let _ = 0 + if 0 + 1 > 0 { 1 } else { 2 } + if 0 + 1 > 0 { 3 } else { 4 };
+   |                    ^^^^^
+
+error: the operation is ineffective. Consider reducing it to `1`
+  --> $DIR/identity_op.rs:95:52
+   |
+LL |     let _ = 0 + if 0 + 1 > 0 { 1 } else { 2 } + if 0 + 1 > 0 { 3 } else { 4 };
+   |                                                    ^^^^^
+
+error: the operation is ineffective. Consider reducing it to `1`
+  --> $DIR/identity_op.rs:96:23
+   |
+LL |     let _ = 0 + match 0 + 1 { 0 => 10, _ => 20 } + match 0 + 1  { 0 => 30, _ => 40 };
+   |                       ^^^^^
+
+error: the operation is ineffective. Consider reducing it to `1`
+  --> $DIR/identity_op.rs:96:58
+   |
+LL |     let _ = 0 + match 0 + 1 { 0 => 10, _ => 20 } + match 0 + 1  { 0 => 30, _ => 40 };
+   |                                                          ^^^^^
+
+error: the operation is ineffective. Consider reducing it to `0 + if b { 1 } else { 2 } + if b { 3 } else { 4 }`
+  --> $DIR/identity_op.rs:98:5
+   |
+LL |     0 + if b { 1 } else { 2 } + if b { 3 } else { 4 } + 0;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: the operation is ineffective. Consider reducing it to `a`
+  --> $DIR/identity_op.rs:106:7
+   |
+LL |     f(1 * a + { 8 * 5 });
+   |       ^^^^^
+
+error: the operation is ineffective. Consider reducing it to `{ 2 * 4 }`
+  --> $DIR/identity_op.rs:108:20
+   |
+LL |     const _: i32 = { 2 * 4 } + 0 + 3;
+   |                    ^^^^^^^^^^^^^
+
+error: aborting due to 33 previous errors
 
diff --git a/tests/ui/impl.rs b/tests/ui/impl.rs
index 39443775015..aea52a852f9 100644
--- a/tests/ui/impl.rs
+++ b/tests/ui/impl.rs
@@ -1,4 +1,4 @@
-#![allow(dead_code)]
+#![allow(dead_code, clippy::extra_unused_lifetimes)]
 #![warn(clippy::multiple_inherent_impl)]
 
 struct MyStruct;
diff --git a/tests/ui/needless_late_init.rs b/tests/ui/needless_late_init.rs
index 3cfbfb6033b..54e66b391b8 100644
--- a/tests/ui/needless_late_init.rs
+++ b/tests/ui/needless_late_init.rs
@@ -1,5 +1,15 @@
-#![allow(unused)]
-#![allow(clippy::let_unit_value)]
+#![feature(let_chains)]
+#![allow(unused, clippy::nonminimal_bool, clippy::let_unit_value)]
+
+use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
+use std::rc::Rc;
+
+struct SignificantDrop;
+impl std::ops::Drop for SignificantDrop {
+    fn drop(&mut self) {
+        println!("dropped");
+    }
+}
 
 fn main() {
     let a;
@@ -18,13 +28,6 @@ fn main() {
         b = "five"
     }
 
-    let c;
-    if let Some(n) = Some(5) {
-        c = n;
-    } else {
-        c = -50;
-    }
-
     let d;
     if true {
         let temp = 5;
@@ -37,7 +40,7 @@ fn main() {
     if true {
         e = format!("{} {}", a, b);
     } else {
-        e = format!("{}", c);
+        e = format!("{}", n);
     }
 
     let f;
@@ -53,7 +56,27 @@ fn main() {
         panic!();
     }
 
-    println!("{}", a);
+    // Drop order only matters if both are significant
+    let x;
+    let y = SignificantDrop;
+    x = 1;
+
+    let x;
+    let y = 1;
+    x = SignificantDrop;
+
+    let x;
+    // types that should be considered insignificant
+    let y = 1;
+    let y = "2";
+    let y = String::new();
+    let y = vec![3.0];
+    let y = HashMap::<usize, usize>::new();
+    let y = BTreeMap::<usize, usize>::new();
+    let y = HashSet::<usize>::new();
+    let y = BTreeSet::<usize>::new();
+    let y = Box::new(4);
+    x = SignificantDrop;
 }
 
 async fn in_async() -> &'static str {
@@ -177,5 +200,32 @@ fn does_not_lint() {
     }
     in_macro!();
 
-    println!("{}", x);
+    // ignore if-lets - https://github.com/rust-lang/rust-clippy/issues/8613
+    let x;
+    if let Some(n) = Some("v") {
+        x = 1;
+    } else {
+        x = 2;
+    }
+
+    let x;
+    if true && let Some(n) = Some("let chains too") {
+        x = 1;
+    } else {
+        x = 2;
+    }
+
+    // ignore mut bindings
+    // https://github.com/shepmaster/twox-hash/blob/b169c16d86eb8ea4a296b0acb9d00ca7e3c3005f/src/sixty_four.rs#L88-L93
+    // https://github.com/dtolnay/thiserror/blob/21c26903e29cb92ba1a7ff11e82ae2001646b60d/tests/test_generics.rs#L91-L100
+    let mut x: usize;
+    x = 1;
+    x = 2;
+    x = 3;
+
+    // should not move the declaration if `x` has a significant drop, and there
+    // is another binding with a significant drop between it and the first usage
+    let x;
+    let y = SignificantDrop;
+    x = SignificantDrop;
 }
diff --git a/tests/ui/needless_late_init.stderr b/tests/ui/needless_late_init.stderr
index 124fe5592c3..d33a117b288 100644
--- a/tests/ui/needless_late_init.stderr
+++ b/tests/ui/needless_late_init.stderr
@@ -1,5 +1,5 @@
 error: unneeded late initialization
-  --> $DIR/needless_late_init.rs:5:5
+  --> $DIR/needless_late_init.rs:15:5
    |
 LL |     let a;
    |     ^^^^^^
@@ -21,7 +21,7 @@ LL |     };
    |      +
 
 error: unneeded late initialization
-  --> $DIR/needless_late_init.rs:14:5
+  --> $DIR/needless_late_init.rs:24:5
    |
 LL |     let b;
    |     ^^^^^^
@@ -42,28 +42,7 @@ LL |     };
    |      +
 
 error: unneeded late initialization
-  --> $DIR/needless_late_init.rs:21:5
-   |
-LL |     let c;
-   |     ^^^^^^
-   |
-help: declare `c` here
-   |
-LL |     let c = if let Some(n) = Some(5) {
-   |     +++++++
-help: remove the assignments from the branches
-   |
-LL ~         n
-LL |     } else {
-LL ~         -50
-   |
-help: add a semicolon after the `if` expression
-   |
-LL |     };
-   |      +
-
-error: unneeded late initialization
-  --> $DIR/needless_late_init.rs:28:5
+  --> $DIR/needless_late_init.rs:31:5
    |
 LL |     let d;
    |     ^^^^^^
@@ -84,7 +63,7 @@ LL |     };
    |      +
 
 error: unneeded late initialization
-  --> $DIR/needless_late_init.rs:36:5
+  --> $DIR/needless_late_init.rs:39:5
    |
 LL |     let e;
    |     ^^^^^^
@@ -97,7 +76,7 @@ help: remove the assignments from the branches
    |
 LL ~         format!("{} {}", a, b)
 LL |     } else {
-LL ~         format!("{}", c)
+LL ~         format!("{}", n)
    |
 help: add a semicolon after the `if` expression
    |
@@ -105,7 +84,7 @@ LL |     };
    |      +
 
 error: unneeded late initialization
-  --> $DIR/needless_late_init.rs:43:5
+  --> $DIR/needless_late_init.rs:46:5
    |
 LL |     let f;
    |     ^^^^^^
@@ -121,7 +100,7 @@ LL +         1 => "three",
    | 
 
 error: unneeded late initialization
-  --> $DIR/needless_late_init.rs:49:5
+  --> $DIR/needless_late_init.rs:52:5
    |
 LL |     let g: usize;
    |     ^^^^^^^^^^^^^
@@ -141,8 +120,50 @@ LL |     };
    |      +
 
 error: unneeded late initialization
+  --> $DIR/needless_late_init.rs:60:5
+   |
+LL |     let x;
+   |     ^^^^^^ created here
+LL |     let y = SignificantDrop;
+LL |     x = 1;
+   |     ^^^^^ initialised here
+   |
+help: declare `x` here
+   |
+LL |     let x = 1;
+   |     ~~~~~
+
+error: unneeded late initialization
   --> $DIR/needless_late_init.rs:64:5
    |
+LL |     let x;
+   |     ^^^^^^ created here
+LL |     let y = 1;
+LL |     x = SignificantDrop;
+   |     ^^^^^^^^^^^^^^^^^^^ initialised here
+   |
+help: declare `x` here
+   |
+LL |     let x = SignificantDrop;
+   |     ~~~~~
+
+error: unneeded late initialization
+  --> $DIR/needless_late_init.rs:68:5
+   |
+LL |     let x;
+   |     ^^^^^^ created here
+...
+LL |     x = SignificantDrop;
+   |     ^^^^^^^^^^^^^^^^^^^ initialised here
+   |
+help: declare `x` here
+   |
+LL |     let x = SignificantDrop;
+   |     ~~~~~
+
+error: unneeded late initialization
+  --> $DIR/needless_late_init.rs:87:5
+   |
 LL |     let a;
    |     ^^^^^^
    |
@@ -162,7 +183,7 @@ LL |     };
    |      +
 
 error: unneeded late initialization
-  --> $DIR/needless_late_init.rs:81:5
+  --> $DIR/needless_late_init.rs:104:5
    |
 LL |     let a;
    |     ^^^^^^
@@ -182,5 +203,5 @@ help: add a semicolon after the `match` expression
 LL |     };
    |      +
 
-error: aborting due to 9 previous errors
+error: aborting due to 11 previous errors
 
diff --git a/tests/ui/needless_late_init_fixable.fixed b/tests/ui/needless_late_init_fixable.fixed
index b516f9d86b7..724477e8691 100644
--- a/tests/ui/needless_late_init_fixable.fixed
+++ b/tests/ui/needless_late_init_fixable.fixed
@@ -15,11 +15,5 @@ fn main() {
     let d: usize = 1;
 
     
-    let mut e = 1;
-    e = 2;
-
-    
-    let h = format!("{}", e);
-
-    println!("{}", a);
+    let e = format!("{}", d);
 }
diff --git a/tests/ui/needless_late_init_fixable.rs b/tests/ui/needless_late_init_fixable.rs
index 75a4bc916de..3e6bd363672 100644
--- a/tests/ui/needless_late_init_fixable.rs
+++ b/tests/ui/needless_late_init_fixable.rs
@@ -14,12 +14,6 @@ fn main() {
     let d: usize;
     d = 1;
 
-    let mut e;
-    e = 1;
-    e = 2;
-
-    let h;
-    h = format!("{}", e);
-
-    println!("{}", a);
+    let e;
+    e = format!("{}", d);
 }
diff --git a/tests/ui/needless_late_init_fixable.stderr b/tests/ui/needless_late_init_fixable.stderr
index 34dccc2cec8..8c664309e3e 100644
--- a/tests/ui/needless_late_init_fixable.stderr
+++ b/tests/ui/needless_late_init_fixable.stderr
@@ -2,7 +2,9 @@ error: unneeded late initialization
   --> $DIR/needless_late_init_fixable.rs:6:5
    |
 LL |     let a;
-   |     ^^^^^^
+   |     ^^^^^^ created here
+LL |     a = "zero";
+   |     ^^^^^^^^^^ initialised here
    |
    = note: `-D clippy::needless-late-init` implied by `-D warnings`
 help: declare `a` here
@@ -14,7 +16,10 @@ error: unneeded late initialization
   --> $DIR/needless_late_init_fixable.rs:9:5
    |
 LL |     let b;
-   |     ^^^^^^
+   |     ^^^^^^ created here
+LL |     let c;
+LL |     b = 1;
+   |     ^^^^^ initialised here
    |
 help: declare `b` here
    |
@@ -25,7 +30,10 @@ error: unneeded late initialization
   --> $DIR/needless_late_init_fixable.rs:10:5
    |
 LL |     let c;
-   |     ^^^^^^
+   |     ^^^^^^ created here
+LL |     b = 1;
+LL |     c = 2;
+   |     ^^^^^ initialised here
    |
 help: declare `c` here
    |
@@ -36,7 +44,9 @@ error: unneeded late initialization
   --> $DIR/needless_late_init_fixable.rs:14:5
    |
 LL |     let d: usize;
-   |     ^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^ created here
+LL |     d = 1;
+   |     ^^^^^ initialised here
    |
 help: declare `d` here
    |
@@ -46,24 +56,15 @@ LL |     let d: usize = 1;
 error: unneeded late initialization
   --> $DIR/needless_late_init_fixable.rs:17:5
    |
-LL |     let mut e;
-   |     ^^^^^^^^^^
+LL |     let e;
+   |     ^^^^^^ created here
+LL |     e = format!("{}", d);
+   |     ^^^^^^^^^^^^^^^^^^^^ initialised here
    |
 help: declare `e` here
    |
-LL |     let mut e = 1;
-   |     ~~~~~~~~~
-
-error: unneeded late initialization
-  --> $DIR/needless_late_init_fixable.rs:21:5
-   |
-LL |     let h;
-   |     ^^^^^^
-   |
-help: declare `h` here
-   |
-LL |     let h = format!("{}", e);
+LL |     let e = format!("{}", d);
    |     ~~~~~
 
-error: aborting due to 6 previous errors
+error: aborting due to 5 previous errors
 
diff --git a/tests/ui/new_without_default.rs b/tests/ui/new_without_default.rs
index e94f99c95f4..538927b1805 100644
--- a/tests/ui/new_without_default.rs
+++ b/tests/ui/new_without_default.rs
@@ -1,4 +1,4 @@
-#![allow(dead_code, clippy::missing_safety_doc)]
+#![allow(dead_code, clippy::missing_safety_doc, clippy::extra_unused_lifetimes)]
 #![warn(clippy::new_without_default)]
 
 pub struct Foo;
diff --git a/tests/ui/numbered_fields.fixed b/tests/ui/numbered_fields.fixed
index 1da97e96879..3710b3e9c81 100644
--- a/tests/ui/numbered_fields.fixed
+++ b/tests/ui/numbered_fields.fixed
@@ -30,4 +30,9 @@ fn main() {
 
     // Ok because it's in macro
     let _ = tuple_struct_init!();
+
+    type Alias = TupleStruct;
+
+    // Aliases can't be tuple constructed #8638
+    let _ = Alias { 0: 0, 1: 1, 2: 2 };
 }
diff --git a/tests/ui/numbered_fields.rs b/tests/ui/numbered_fields.rs
index 08ec405a560..2af84bc0642 100644
--- a/tests/ui/numbered_fields.rs
+++ b/tests/ui/numbered_fields.rs
@@ -38,4 +38,9 @@ fn main() {
 
     // Ok because it's in macro
     let _ = tuple_struct_init!();
+
+    type Alias = TupleStruct;
+
+    // Aliases can't be tuple constructed #8638
+    let _ = Alias { 0: 0, 1: 1, 2: 2 };
 }
diff --git a/tests/ui/rename.fixed b/tests/ui/rename.fixed
index 24a0c812291..9c4079ad6d3 100644
--- a/tests/ui/rename.fixed
+++ b/tests/ui/rename.fixed
@@ -1,71 +1,70 @@
-//! Test for Clippy lint renames.
+// This file was generated by `cargo dev update_lints`.
+// Use that command to update this file and do not edit by hand.
+// Manual edits will be overwritten.
+
 // run-rustfix
 
-#![allow(dead_code)]
-// allow the new lint name here, to test if the new name works
-#![allow(clippy::module_name_repetitions)]
-#![allow(clippy::new_without_default)]
+#![allow(clippy::blocks_in_if_conditions)]
+#![allow(clippy::box_collection)]
 #![allow(clippy::redundant_static_lifetimes)]
 #![allow(clippy::cognitive_complexity)]
+#![allow(clippy::disallowed_methods)]
+#![allow(clippy::disallowed_types)]
+#![allow(clippy::for_loops_over_fallibles)]
+#![allow(clippy::useless_conversion)]
+#![allow(clippy::match_result_ok)]
+#![allow(clippy::new_without_default)]
 #![allow(clippy::bind_instead_of_map)]
-#![allow(clippy::box_collection)]
-#![allow(clippy::blocks_in_if_conditions)]
+#![allow(clippy::expect_used)]
 #![allow(clippy::map_unwrap_or)]
 #![allow(clippy::unwrap_used)]
-#![allow(clippy::expect_used)]
-#![allow(clippy::for_loops_over_fallibles)]
-#![allow(clippy::useless_conversion)]
-#![allow(clippy::invisible_characters)]
+#![allow(clippy::needless_borrow)]
 #![allow(clippy::single_char_add_str)]
-#![allow(clippy::match_result_ok)]
-#![allow(clippy::disallowed_types)]
-#![allow(clippy::disallowed_methods)]
+#![allow(clippy::module_name_repetitions)]
 #![allow(clippy::recursive_format_impl)]
-// uplifted lints
-#![allow(invalid_value)]
-#![allow(array_into_iter)]
-#![allow(unused_labels)]
+#![allow(clippy::invisible_characters)]
 #![allow(drop_bounds)]
-#![allow(temporary_cstring_as_ptr)]
-#![allow(non_fmt_panics)]
-#![allow(unknown_lints)]
+#![allow(array_into_iter)]
 #![allow(invalid_atomic_ordering)]
+#![allow(invalid_value)]
 #![allow(enum_intrinsics_non_enums)]
-// warn for the old lint name here, to test if the renaming worked
-#![warn(clippy::module_name_repetitions)]
-#![warn(clippy::new_without_default)]
+#![allow(non_fmt_panics)]
+#![allow(temporary_cstring_as_ptr)]
+#![allow(unknown_lints)]
+#![allow(unused_labels)]
+#![warn(clippy::blocks_in_if_conditions)]
+#![warn(clippy::blocks_in_if_conditions)]
+#![warn(clippy::box_collection)]
 #![warn(clippy::redundant_static_lifetimes)]
 #![warn(clippy::cognitive_complexity)]
+#![warn(clippy::disallowed_methods)]
+#![warn(clippy::disallowed_types)]
+#![warn(clippy::for_loops_over_fallibles)]
+#![warn(clippy::for_loops_over_fallibles)]
+#![warn(clippy::useless_conversion)]
+#![warn(clippy::match_result_ok)]
+#![warn(clippy::new_without_default)]
 #![warn(clippy::bind_instead_of_map)]
-#![warn(clippy::box_collection)]
-#![warn(clippy::blocks_in_if_conditions)]
-#![warn(clippy::blocks_in_if_conditions)]
-#![warn(clippy::map_unwrap_or)]
+#![warn(clippy::expect_used)]
 #![warn(clippy::map_unwrap_or)]
 #![warn(clippy::map_unwrap_or)]
 #![warn(clippy::unwrap_used)]
-#![warn(clippy::unwrap_used)]
-#![warn(clippy::expect_used)]
+#![warn(clippy::needless_borrow)]
 #![warn(clippy::expect_used)]
-#![warn(clippy::for_loops_over_fallibles)]
-#![warn(clippy::for_loops_over_fallibles)]
-#![warn(clippy::useless_conversion)]
-#![warn(clippy::invisible_characters)]
+#![warn(clippy::map_unwrap_or)]
+#![warn(clippy::unwrap_used)]
 #![warn(clippy::single_char_add_str)]
-#![warn(clippy::match_result_ok)]
-#![warn(clippy::disallowed_types)]
-#![warn(clippy::disallowed_methods)]
-#![warn(clippy::needless_borrow)]
+#![warn(clippy::module_name_repetitions)]
 #![warn(clippy::recursive_format_impl)]
-// uplifted lints
-#![warn(invalid_value)]
-#![warn(array_into_iter)]
-#![warn(unused_labels)]
+#![warn(clippy::invisible_characters)]
 #![warn(drop_bounds)]
-#![warn(temporary_cstring_as_ptr)]
-#![warn(non_fmt_panics)]
-#![warn(unknown_lints)]
+#![warn(array_into_iter)]
 #![warn(invalid_atomic_ordering)]
+#![warn(invalid_value)]
 #![warn(enum_intrinsics_non_enums)]
+#![warn(non_fmt_panics)]
+#![warn(temporary_cstring_as_ptr)]
+#![warn(unknown_lints)]
+#![warn(unused_labels)]
 
 fn main() {}
diff --git a/tests/ui/rename.rs b/tests/ui/rename.rs
index ea64234c680..e83e66b7fbd 100644
--- a/tests/ui/rename.rs
+++ b/tests/ui/rename.rs
@@ -1,71 +1,70 @@
-//! Test for Clippy lint renames.
+// This file was generated by `cargo dev update_lints`.
+// Use that command to update this file and do not edit by hand.
+// Manual edits will be overwritten.
+
 // run-rustfix
 
-#![allow(dead_code)]
-// allow the new lint name here, to test if the new name works
-#![allow(clippy::module_name_repetitions)]
-#![allow(clippy::new_without_default)]
+#![allow(clippy::blocks_in_if_conditions)]
+#![allow(clippy::box_collection)]
 #![allow(clippy::redundant_static_lifetimes)]
 #![allow(clippy::cognitive_complexity)]
+#![allow(clippy::disallowed_methods)]
+#![allow(clippy::disallowed_types)]
+#![allow(clippy::for_loops_over_fallibles)]
+#![allow(clippy::useless_conversion)]
+#![allow(clippy::match_result_ok)]
+#![allow(clippy::new_without_default)]
 #![allow(clippy::bind_instead_of_map)]
-#![allow(clippy::box_collection)]
-#![allow(clippy::blocks_in_if_conditions)]
+#![allow(clippy::expect_used)]
 #![allow(clippy::map_unwrap_or)]
 #![allow(clippy::unwrap_used)]
-#![allow(clippy::expect_used)]
-#![allow(clippy::for_loops_over_fallibles)]
-#![allow(clippy::useless_conversion)]
-#![allow(clippy::invisible_characters)]
+#![allow(clippy::needless_borrow)]
 #![allow(clippy::single_char_add_str)]
-#![allow(clippy::match_result_ok)]
-#![allow(clippy::disallowed_types)]
-#![allow(clippy::disallowed_methods)]
+#![allow(clippy::module_name_repetitions)]
 #![allow(clippy::recursive_format_impl)]
-// uplifted lints
-#![allow(invalid_value)]
-#![allow(array_into_iter)]
-#![allow(unused_labels)]
+#![allow(clippy::invisible_characters)]
 #![allow(drop_bounds)]
-#![allow(temporary_cstring_as_ptr)]
-#![allow(non_fmt_panics)]
-#![allow(unknown_lints)]
+#![allow(array_into_iter)]
 #![allow(invalid_atomic_ordering)]
+#![allow(invalid_value)]
 #![allow(enum_intrinsics_non_enums)]
-// warn for the old lint name here, to test if the renaming worked
-#![warn(clippy::stutter)]
-#![warn(clippy::new_without_default_derive)]
+#![allow(non_fmt_panics)]
+#![allow(temporary_cstring_as_ptr)]
+#![allow(unknown_lints)]
+#![allow(unused_labels)]
+#![warn(clippy::block_in_if_condition_expr)]
+#![warn(clippy::block_in_if_condition_stmt)]
+#![warn(clippy::box_vec)]
 #![warn(clippy::const_static_lifetime)]
 #![warn(clippy::cyclomatic_complexity)]
+#![warn(clippy::disallowed_method)]
+#![warn(clippy::disallowed_type)]
+#![warn(clippy::for_loop_over_option)]
+#![warn(clippy::for_loop_over_result)]
+#![warn(clippy::identity_conversion)]
+#![warn(clippy::if_let_some_result)]
+#![warn(clippy::new_without_default_derive)]
 #![warn(clippy::option_and_then_some)]
-#![warn(clippy::box_vec)]
-#![warn(clippy::block_in_if_condition_expr)]
-#![warn(clippy::block_in_if_condition_stmt)]
+#![warn(clippy::option_expect_used)]
 #![warn(clippy::option_map_unwrap_or)]
 #![warn(clippy::option_map_unwrap_or_else)]
-#![warn(clippy::result_map_unwrap_or_else)]
 #![warn(clippy::option_unwrap_used)]
-#![warn(clippy::result_unwrap_used)]
-#![warn(clippy::option_expect_used)]
+#![warn(clippy::ref_in_deref)]
 #![warn(clippy::result_expect_used)]
-#![warn(clippy::for_loop_over_option)]
-#![warn(clippy::for_loop_over_result)]
-#![warn(clippy::identity_conversion)]
-#![warn(clippy::zero_width_space)]
+#![warn(clippy::result_map_unwrap_or_else)]
+#![warn(clippy::result_unwrap_used)]
 #![warn(clippy::single_char_push_str)]
-#![warn(clippy::if_let_some_result)]
-#![warn(clippy::disallowed_type)]
-#![warn(clippy::disallowed_method)]
-#![warn(clippy::ref_in_deref)]
+#![warn(clippy::stutter)]
 #![warn(clippy::to_string_in_display)]
-// uplifted lints
-#![warn(clippy::invalid_ref)]
-#![warn(clippy::into_iter_on_array)]
-#![warn(clippy::unused_label)]
+#![warn(clippy::zero_width_space)]
 #![warn(clippy::drop_bounds)]
-#![warn(clippy::temporary_cstring_as_ptr)]
-#![warn(clippy::panic_params)]
-#![warn(clippy::unknown_clippy_lints)]
+#![warn(clippy::into_iter_on_array)]
 #![warn(clippy::invalid_atomic_ordering)]
+#![warn(clippy::invalid_ref)]
 #![warn(clippy::mem_discriminant_non_enum)]
+#![warn(clippy::panic_params)]
+#![warn(clippy::temporary_cstring_as_ptr)]
+#![warn(clippy::unknown_clippy_lints)]
+#![warn(clippy::unused_label)]
 
 fn main() {}
diff --git a/tests/ui/rename.stderr b/tests/ui/rename.stderr
index 8b132a78384..f811b10d017 100644
--- a/tests/ui/rename.stderr
+++ b/tests/ui/rename.stderr
@@ -1,82 +1,82 @@
-error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions`
+error: lint `clippy::block_in_if_condition_expr` has been renamed to `clippy::blocks_in_if_conditions`
   --> $DIR/rename.rs:35:9
    |
-LL | #![warn(clippy::stutter)]
-   |         ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions`
+LL | #![warn(clippy::block_in_if_condition_expr)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions`
    |
    = note: `-D renamed-and-removed-lints` implied by `-D warnings`
 
-error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default`
+error: lint `clippy::block_in_if_condition_stmt` has been renamed to `clippy::blocks_in_if_conditions`
   --> $DIR/rename.rs:36:9
    |
-LL | #![warn(clippy::new_without_default_derive)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default`
+LL | #![warn(clippy::block_in_if_condition_stmt)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions`
 
-error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes`
+error: lint `clippy::box_vec` has been renamed to `clippy::box_collection`
   --> $DIR/rename.rs:37:9
    |
+LL | #![warn(clippy::box_vec)]
+   |         ^^^^^^^^^^^^^^^ help: use the new name: `clippy::box_collection`
+
+error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes`
+  --> $DIR/rename.rs:38:9
+   |
 LL | #![warn(clippy::const_static_lifetime)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes`
 
 error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity`
-  --> $DIR/rename.rs:38:9
+  --> $DIR/rename.rs:39:9
    |
 LL | #![warn(clippy::cyclomatic_complexity)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity`
 
-error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map`
-  --> $DIR/rename.rs:39:9
-   |
-LL | #![warn(clippy::option_and_then_some)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map`
-
-error: lint `clippy::box_vec` has been renamed to `clippy::box_collection`
+error: lint `clippy::disallowed_method` has been renamed to `clippy::disallowed_methods`
   --> $DIR/rename.rs:40:9
    |
-LL | #![warn(clippy::box_vec)]
-   |         ^^^^^^^^^^^^^^^ help: use the new name: `clippy::box_collection`
+LL | #![warn(clippy::disallowed_method)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_methods`
 
-error: lint `clippy::block_in_if_condition_expr` has been renamed to `clippy::blocks_in_if_conditions`
+error: lint `clippy::disallowed_type` has been renamed to `clippy::disallowed_types`
   --> $DIR/rename.rs:41:9
    |
-LL | #![warn(clippy::block_in_if_condition_expr)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions`
+LL | #![warn(clippy::disallowed_type)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_types`
 
-error: lint `clippy::block_in_if_condition_stmt` has been renamed to `clippy::blocks_in_if_conditions`
+error: lint `clippy::for_loop_over_option` has been renamed to `clippy::for_loops_over_fallibles`
   --> $DIR/rename.rs:42:9
    |
-LL | #![warn(clippy::block_in_if_condition_stmt)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions`
+LL | #![warn(clippy::for_loop_over_option)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::for_loops_over_fallibles`
 
-error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or`
+error: lint `clippy::for_loop_over_result` has been renamed to `clippy::for_loops_over_fallibles`
   --> $DIR/rename.rs:43:9
    |
-LL | #![warn(clippy::option_map_unwrap_or)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
+LL | #![warn(clippy::for_loop_over_result)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::for_loops_over_fallibles`
 
-error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
+error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion`
   --> $DIR/rename.rs:44:9
    |
-LL | #![warn(clippy::option_map_unwrap_or_else)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
+LL | #![warn(clippy::identity_conversion)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion`
 
-error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
+error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok`
   --> $DIR/rename.rs:45:9
    |
-LL | #![warn(clippy::result_map_unwrap_or_else)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
+LL | #![warn(clippy::if_let_some_result)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok`
 
-error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used`
+error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default`
   --> $DIR/rename.rs:46:9
    |
-LL | #![warn(clippy::option_unwrap_used)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
+LL | #![warn(clippy::new_without_default_derive)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default`
 
-error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used`
+error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map`
   --> $DIR/rename.rs:47:9
    |
-LL | #![warn(clippy::result_unwrap_used)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
+LL | #![warn(clippy::option_and_then_some)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map`
 
 error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used`
   --> $DIR/rename.rs:48:9
@@ -84,107 +84,113 @@ error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_use
 LL | #![warn(clippy::option_expect_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
 
-error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used`
+error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or`
   --> $DIR/rename.rs:49:9
    |
-LL | #![warn(clippy::result_expect_used)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
+LL | #![warn(clippy::option_map_unwrap_or)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
-error: lint `clippy::for_loop_over_option` has been renamed to `clippy::for_loops_over_fallibles`
+error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
   --> $DIR/rename.rs:50:9
    |
-LL | #![warn(clippy::for_loop_over_option)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::for_loops_over_fallibles`
+LL | #![warn(clippy::option_map_unwrap_or_else)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
-error: lint `clippy::for_loop_over_result` has been renamed to `clippy::for_loops_over_fallibles`
+error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used`
   --> $DIR/rename.rs:51:9
    |
-LL | #![warn(clippy::for_loop_over_result)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::for_loops_over_fallibles`
+LL | #![warn(clippy::option_unwrap_used)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
 
-error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion`
+error: lint `clippy::ref_in_deref` has been renamed to `clippy::needless_borrow`
   --> $DIR/rename.rs:52:9
    |
-LL | #![warn(clippy::identity_conversion)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion`
+LL | #![warn(clippy::ref_in_deref)]
+   |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::needless_borrow`
 
-error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters`
+error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used`
   --> $DIR/rename.rs:53:9
    |
-LL | #![warn(clippy::zero_width_space)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters`
+LL | #![warn(clippy::result_expect_used)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
 
-error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str`
+error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
   --> $DIR/rename.rs:54:9
    |
-LL | #![warn(clippy::single_char_push_str)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str`
+LL | #![warn(clippy::result_map_unwrap_or_else)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
-error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok`
+error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used`
   --> $DIR/rename.rs:55:9
    |
-LL | #![warn(clippy::if_let_some_result)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok`
+LL | #![warn(clippy::result_unwrap_used)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
 
-error: lint `clippy::disallowed_type` has been renamed to `clippy::disallowed_types`
+error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str`
   --> $DIR/rename.rs:56:9
    |
-LL | #![warn(clippy::disallowed_type)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_types`
+LL | #![warn(clippy::single_char_push_str)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str`
 
-error: lint `clippy::disallowed_method` has been renamed to `clippy::disallowed_methods`
+error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions`
   --> $DIR/rename.rs:57:9
    |
-LL | #![warn(clippy::disallowed_method)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_methods`
+LL | #![warn(clippy::stutter)]
+   |         ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions`
 
-error: lint `clippy::ref_in_deref` has been renamed to `clippy::needless_borrow`
+error: lint `clippy::to_string_in_display` has been renamed to `clippy::recursive_format_impl`
   --> $DIR/rename.rs:58:9
    |
-LL | #![warn(clippy::ref_in_deref)]
-   |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::needless_borrow`
+LL | #![warn(clippy::to_string_in_display)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::recursive_format_impl`
 
-error: lint `clippy::to_string_in_display` has been renamed to `clippy::recursive_format_impl`
+error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters`
   --> $DIR/rename.rs:59:9
    |
-LL | #![warn(clippy::to_string_in_display)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::recursive_format_impl`
+LL | #![warn(clippy::zero_width_space)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters`
 
-error: lint `clippy::invalid_ref` has been renamed to `invalid_value`
-  --> $DIR/rename.rs:61:9
+error: lint `clippy::drop_bounds` has been renamed to `drop_bounds`
+  --> $DIR/rename.rs:60:9
    |
-LL | #![warn(clippy::invalid_ref)]
-   |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value`
+LL | #![warn(clippy::drop_bounds)]
+   |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds`
 
 error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter`
-  --> $DIR/rename.rs:62:9
+  --> $DIR/rename.rs:61:9
    |
 LL | #![warn(clippy::into_iter_on_array)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter`
 
-error: lint `clippy::unused_label` has been renamed to `unused_labels`
+error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering`
+  --> $DIR/rename.rs:62:9
+   |
+LL | #![warn(clippy::invalid_atomic_ordering)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering`
+
+error: lint `clippy::invalid_ref` has been renamed to `invalid_value`
   --> $DIR/rename.rs:63:9
    |
-LL | #![warn(clippy::unused_label)]
-   |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels`
+LL | #![warn(clippy::invalid_ref)]
+   |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value`
 
-error: lint `clippy::drop_bounds` has been renamed to `drop_bounds`
+error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums`
   --> $DIR/rename.rs:64:9
    |
-LL | #![warn(clippy::drop_bounds)]
-   |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds`
+LL | #![warn(clippy::mem_discriminant_non_enum)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums`
 
-error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr`
+error: lint `clippy::panic_params` has been renamed to `non_fmt_panics`
   --> $DIR/rename.rs:65:9
    |
-LL | #![warn(clippy::temporary_cstring_as_ptr)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr`
+LL | #![warn(clippy::panic_params)]
+   |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics`
 
-error: lint `clippy::panic_params` has been renamed to `non_fmt_panics`
+error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr`
   --> $DIR/rename.rs:66:9
    |
-LL | #![warn(clippy::panic_params)]
-   |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics`
+LL | #![warn(clippy::temporary_cstring_as_ptr)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr`
 
 error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints`
   --> $DIR/rename.rs:67:9
@@ -192,17 +198,11 @@ error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints`
 LL | #![warn(clippy::unknown_clippy_lints)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints`
 
-error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering`
+error: lint `clippy::unused_label` has been renamed to `unused_labels`
   --> $DIR/rename.rs:68:9
    |
-LL | #![warn(clippy::invalid_atomic_ordering)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering`
-
-error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums`
-  --> $DIR/rename.rs:69:9
-   |
-LL | #![warn(clippy::mem_discriminant_non_enum)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums`
+LL | #![warn(clippy::unused_label)]
+   |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels`
 
 error: aborting due to 34 previous errors
 
diff --git a/tests/ui/useless_attribute.fixed b/tests/ui/useless_attribute.fixed
index ce58a80347b..c23231a99e9 100644
--- a/tests/ui/useless_attribute.fixed
+++ b/tests/ui/useless_attribute.fixed
@@ -57,6 +57,12 @@ pub use std::io::prelude::*;
 #[allow(clippy::enum_glob_use)]
 pub use std::cmp::Ordering::*;
 
+// don't lint on clippy::redundant_pub_crate
+mod c {
+    #[allow(clippy::redundant_pub_crate)]
+    pub(crate) struct S;
+}
+
 fn test_indented_attr() {
     #![allow(clippy::almost_swapped)]
     use std::collections::HashSet;
diff --git a/tests/ui/useless_attribute.rs b/tests/ui/useless_attribute.rs
index c82bb9ba07f..7a7b198ea60 100644
--- a/tests/ui/useless_attribute.rs
+++ b/tests/ui/useless_attribute.rs
@@ -57,6 +57,12 @@ pub use std::io::prelude::*;
 #[allow(clippy::enum_glob_use)]
 pub use std::cmp::Ordering::*;
 
+// don't lint on clippy::redundant_pub_crate
+mod c {
+    #[allow(clippy::redundant_pub_crate)]
+    pub(crate) struct S;
+}
+
 fn test_indented_attr() {
     #[allow(clippy::almost_swapped)]
     use std::collections::HashSet;
diff --git a/tests/ui/useless_attribute.stderr b/tests/ui/useless_attribute.stderr
index d0194e4bbbe..255d2876355 100644
--- a/tests/ui/useless_attribute.stderr
+++ b/tests/ui/useless_attribute.stderr
@@ -13,7 +13,7 @@ LL | #[cfg_attr(feature = "cargo-clippy", allow(dead_code))]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: if you just forgot a `!`, use: `#![cfg_attr(feature = "cargo-clippy", allow(dead_code)`
 
 error: useless lint attribute
-  --> $DIR/useless_attribute.rs:61:5
+  --> $DIR/useless_attribute.rs:67:5
    |
 LL |     #[allow(clippy::almost_swapped)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: if you just forgot a `!`, use: `#![allow(clippy::almost_swapped)]`