about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/tools/clippy/CHANGELOG.md4
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_slice_different_sizes.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/declared_lints.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/dereference.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/fn_null_check.rs106
-rw-r--r--src/tools/clippy/clippy_lints/src/format_args.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/mod.rs33
-rw-r--r--src/tools/clippy/clippy_lints/src/large_const_arrays.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/large_enum_variant.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/large_stack_arrays.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/len_zero.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/explicit_counter_loop.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_async_fn.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_clamp.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_strip.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/manual_filter.rs17
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_single_binding.rs18
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_skip_next.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/str_splitn.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_late_init.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/octal_escapes.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/misrefactored_assign_op.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/permissions_set_readonly_false.rs52
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_clone.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/returns.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/same_name_method.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/size_of_ref.rs73
-rw-r--r--src/tools/clippy/clippy_lints/src/swap.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/mod.rs31
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/transmute_null_to_fn.rs64
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/transmuting_null.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/useless_conversion.rs28
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/conf.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/write.rs4
-rw-r--r--src/tools/clippy/clippy_utils/src/consts.rs7
-rw-r--r--src/tools/clippy/clippy_utils/src/diagnostics.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/mir/maybe_storage_live.rs52
-rw-r--r--src/tools/clippy/clippy_utils/src/mir/mod.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs274
-rw-r--r--src/tools/clippy/clippy_utils/src/sugg.rs1
-rw-r--r--src/tools/clippy/rust-toolchain2
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-10044.rs3
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-10044.stderr10
-rw-r--r--src/tools/clippy/tests/ui/floating_point_powi.fixed9
-rw-r--r--src/tools/clippy/tests/ui/floating_point_powi.rs9
-rw-r--r--src/tools/clippy/tests/ui/floating_point_powi.stderr44
-rw-r--r--src/tools/clippy/tests/ui/fn_null_check.rs21
-rw-r--r--src/tools/clippy/tests/ui/fn_null_check.stderr43
-rw-r--r--src/tools/clippy/tests/ui/manual_filter.fixed41
-rw-r--r--src/tools/clippy/tests/ui/manual_filter.rs41
-rw-r--r--src/tools/clippy/tests/ui/manual_retain.fixed2
-rw-r--r--src/tools/clippy/tests/ui/manual_retain.rs2
-rw-r--r--src/tools/clippy/tests/ui/match_single_binding.fixed13
-rw-r--r--src/tools/clippy/tests/ui/match_single_binding.rs14
-rw-r--r--src/tools/clippy/tests/ui/match_single_binding.stderr27
-rw-r--r--src/tools/clippy/tests/ui/match_wildcard_for_single_variants.fixed22
-rw-r--r--src/tools/clippy/tests/ui/match_wildcard_for_single_variants.rs22
-rw-r--r--src/tools/clippy/tests/ui/match_wildcard_for_single_variants.stderr8
-rw-r--r--src/tools/clippy/tests/ui/needless_borrow.fixed13
-rw-r--r--src/tools/clippy/tests/ui/needless_borrow.rs13
-rw-r--r--src/tools/clippy/tests/ui/needless_borrow.stderr8
-rw-r--r--src/tools/clippy/tests/ui/needless_return.fixed5
-rw-r--r--src/tools/clippy/tests/ui/needless_return.rs5
-rw-r--r--src/tools/clippy/tests/ui/needless_return.stderr92
-rw-r--r--src/tools/clippy/tests/ui/permissions_set_readonly_false.rs29
-rw-r--r--src/tools/clippy/tests/ui/permissions_set_readonly_false.stderr13
-rw-r--r--src/tools/clippy/tests/ui/redundant_clone.fixed6
-rw-r--r--src/tools/clippy/tests/ui/redundant_clone.rs6
-rw-r--r--src/tools/clippy/tests/ui/redundant_clone.stderr14
-rw-r--r--src/tools/clippy/tests/ui/size_of_ref.rs27
-rw-r--r--src/tools/clippy/tests/ui/size_of_ref.stderr27
-rw-r--r--src/tools/clippy/tests/ui/transmute_null_to_fn.rs28
-rw-r--r--src/tools/clippy/tests/ui/transmute_null_to_fn.stderr27
-rw-r--r--src/tools/clippy/tests/ui/useless_conversion.fixed73
-rw-r--r--src/tools/clippy/tests/ui/useless_conversion.rs73
-rw-r--r--src/tools/clippy/tests/ui/useless_conversion.stderr54
-rw-r--r--src/tools/clippy/tests/ui/wildcard_imports.fixed1
-rw-r--r--src/tools/clippy/tests/ui/wildcard_imports.rs1
-rw-r--r--src/tools/clippy/tests/ui/wildcard_imports.stderr42
-rw-r--r--src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.fixed240
-rw-r--r--src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.stderr132
-rw-r--r--src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.fixed240
-rw-r--r--src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.stderr132
-rw-r--r--src/tools/clippy/tests/ui/wildcard_imports_2021.rs241
-rw-r--r--src/tools/clippy/tests/ui/wildcard_imports_2021.stderr132
97 files changed, 2555 insertions, 356 deletions
diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md
index 903ee938d9d..02f3188f8be 100644
--- a/src/tools/clippy/CHANGELOG.md
+++ b/src/tools/clippy/CHANGELOG.md
@@ -4203,6 +4203,7 @@ Released 2018-09-13
 [`float_cmp_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#float_cmp_const
 [`float_equality_without_abs`]: https://rust-lang.github.io/rust-clippy/master/index.html#float_equality_without_abs
 [`fn_address_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_address_comparisons
+[`fn_null_check`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_null_check
 [`fn_params_excessive_bools`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_params_excessive_bools
 [`fn_to_numeric_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_to_numeric_cast
 [`fn_to_numeric_cast_any`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_to_numeric_cast_any
@@ -4460,6 +4461,7 @@ Released 2018-09-13
 [`partialeq_to_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#partialeq_to_none
 [`path_buf_push_overwrite`]: https://rust-lang.github.io/rust-clippy/master/index.html#path_buf_push_overwrite
 [`pattern_type_mismatch`]: https://rust-lang.github.io/rust-clippy/master/index.html#pattern_type_mismatch
+[`permissions_set_readonly_false`]: https://rust-lang.github.io/rust-clippy/master/index.html#permissions_set_readonly_false
 [`positional_named_format_parameters`]: https://rust-lang.github.io/rust-clippy/master/index.html#positional_named_format_parameters
 [`possible_missing_comma`]: https://rust-lang.github.io/rust-clippy/master/index.html#possible_missing_comma
 [`precedence`]: https://rust-lang.github.io/rust-clippy/master/index.html#precedence
@@ -4545,6 +4547,7 @@ Released 2018-09-13
 [`single_match`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_match
 [`single_match_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_match_else
 [`size_of_in_element_count`]: https://rust-lang.github.io/rust-clippy/master/index.html#size_of_in_element_count
+[`size_of_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#size_of_ref
 [`skip_while_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#skip_while_next
 [`slow_vector_initialization`]: https://rust-lang.github.io/rust-clippy/master/index.html#slow_vector_initialization
 [`stable_sort_primitive`]: https://rust-lang.github.io/rust-clippy/master/index.html#stable_sort_primitive
@@ -4590,6 +4593,7 @@ Released 2018-09-13
 [`transmute_int_to_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_bool
 [`transmute_int_to_char`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_char
 [`transmute_int_to_float`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_float
+[`transmute_null_to_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_null_to_fn
 [`transmute_num_to_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_num_to_bytes
 [`transmute_ptr_to_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_ptr_to_ptr
 [`transmute_ptr_to_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_ptr_to_ref
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_slice_different_sizes.rs b/src/tools/clippy/clippy_lints/src/casts/cast_slice_different_sizes.rs
index e862f13e69f..c8e54d7b8e0 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_slice_different_sizes.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_slice_different_sizes.rs
@@ -54,7 +54,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, msrv: &Msrv
 
                         diag.span_suggestion(
                             expr.span,
-                            &format!("replace with `ptr::slice_from_raw_parts{mutbl_fn_str}`"),
+                            format!("replace with `ptr::slice_from_raw_parts{mutbl_fn_str}`"),
                             sugg,
                             rustc_errors::Applicability::HasPlaceholders,
                         );
diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs
index 3cd7d1d7e72..2982460c9cf 100644
--- a/src/tools/clippy/clippy_lints/src/declared_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs
@@ -161,6 +161,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::float_literal::LOSSY_FLOAT_LITERAL_INFO,
     crate::floating_point_arithmetic::IMPRECISE_FLOPS_INFO,
     crate::floating_point_arithmetic::SUBOPTIMAL_FLOPS_INFO,
+    crate::fn_null_check::FN_NULL_CHECK_INFO,
     crate::format::USELESS_FORMAT_INFO,
     crate::format_args::FORMAT_IN_FORMAT_ARGS_INFO,
     crate::format_args::TO_STRING_IN_FORMAT_ARGS_INFO,
@@ -494,6 +495,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::pass_by_ref_or_value::LARGE_TYPES_PASSED_BY_VALUE_INFO,
     crate::pass_by_ref_or_value::TRIVIALLY_COPY_PASS_BY_REF_INFO,
     crate::pattern_type_mismatch::PATTERN_TYPE_MISMATCH_INFO,
+    crate::permissions_set_readonly_false::PERMISSIONS_SET_READONLY_FALSE_INFO,
     crate::precedence::PRECEDENCE_INFO,
     crate::ptr::CMP_NULL_INFO,
     crate::ptr::INVALID_NULL_PTR_USAGE_INFO,
@@ -535,6 +537,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::single_char_lifetime_names::SINGLE_CHAR_LIFETIME_NAMES_INFO,
     crate::single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS_INFO,
     crate::size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT_INFO,
+    crate::size_of_ref::SIZE_OF_REF_INFO,
     crate::slow_vector_initialization::SLOW_VECTOR_INITIALIZATION_INFO,
     crate::std_instead_of_core::ALLOC_INSTEAD_OF_CORE_INFO,
     crate::std_instead_of_core::STD_INSTEAD_OF_ALLOC_INFO,
@@ -568,6 +571,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::transmute::TRANSMUTE_INT_TO_BOOL_INFO,
     crate::transmute::TRANSMUTE_INT_TO_CHAR_INFO,
     crate::transmute::TRANSMUTE_INT_TO_FLOAT_INFO,
+    crate::transmute::TRANSMUTE_NULL_TO_FN_INFO,
     crate::transmute::TRANSMUTE_NUM_TO_BYTES_INFO,
     crate::transmute::TRANSMUTE_PTR_TO_PTR_INFO,
     crate::transmute::TRANSMUTE_PTR_TO_REF_INFO,
diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs
index 7b43d8ccc67..728941b8b3d 100644
--- a/src/tools/clippy/clippy_lints/src/dereference.rs
+++ b/src/tools/clippy/clippy_lints/src/dereference.rs
@@ -1282,10 +1282,10 @@ fn referent_used_exactly_once<'tcx>(
             possible_borrowers.push((body_owner_local_def_id, PossibleBorrowerMap::new(cx, mir)));
         }
         let possible_borrower = &mut possible_borrowers.last_mut().unwrap().1;
-        // If `only_borrowers` were used here, the `copyable_iterator::warn` test would fail. The reason is
-        // that `PossibleBorrowerVisitor::visit_terminator` considers `place.local` a possible borrower of
-        // itself. See the comment in that method for an explanation as to why.
-        possible_borrower.bounded_borrowers(&[local], &[local, place.local], place.local, location)
+        // If `place.local` were not included here, the `copyable_iterator::warn` test would fail. The
+        // reason is that `PossibleBorrowerVisitor::visit_terminator` considers `place.local` a possible
+        // borrower of itself. See the comment in that method for an explanation as to why.
+        possible_borrower.at_most_borrowers(cx, &[local, place.local], place.local, location)
             && used_exactly_once(mir, place.local).unwrap_or(false)
     } else {
         false
diff --git a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
index 0ed30196475..f95b628e6c3 100644
--- a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
+++ b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
@@ -324,7 +324,7 @@ fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args:
                     let maybe_neg_sugg = |expr, hir_id| {
                         let sugg = Sugg::hir(cx, expr, "..");
                         if matches!(op, BinOpKind::Sub) && hir_id == rhs.hir_id {
-                            format!("-{sugg}")
+                            format!("-{}", sugg.maybe_par())
                         } else {
                             sugg.to_string()
                         }
diff --git a/src/tools/clippy/clippy_lints/src/fn_null_check.rs b/src/tools/clippy/clippy_lints/src/fn_null_check.rs
new file mode 100644
index 00000000000..91c8c340ce2
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/fn_null_check.rs
@@ -0,0 +1,106 @@
+use clippy_utils::consts::{constant, Constant};
+use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::{is_integer_literal, is_path_diagnostic_item};
+use rustc_hir::{BinOpKind, Expr, ExprKind, TyKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::sym;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for comparing a function pointer to null.
+    ///
+    /// ### Why is this bad?
+    /// Function pointers are assumed to not be null.
+    ///
+    /// ### Example
+    /// ```rust,ignore
+    /// let fn_ptr: fn() = /* somehow obtained nullable function pointer */
+    ///
+    /// if (fn_ptr as *const ()).is_null() { ... }
+    /// ```
+    /// Use instead:
+    /// ```rust,ignore
+    /// let fn_ptr: Option<fn()> = /* somehow obtained nullable function pointer */
+    ///
+    /// if fn_ptr.is_none() { ... }
+    /// ```
+    #[clippy::version = "1.67.0"]
+    pub FN_NULL_CHECK,
+    correctness,
+    "`fn()` type assumed to be nullable"
+}
+declare_lint_pass!(FnNullCheck => [FN_NULL_CHECK]);
+
+fn lint_expr(cx: &LateContext<'_>, expr: &Expr<'_>) {
+    span_lint_and_help(
+        cx,
+        FN_NULL_CHECK,
+        expr.span,
+        "function pointer assumed to be nullable, even though it isn't",
+        None,
+        "try wrapping your function pointer type in `Option<T>` instead, and using `is_none` to check for null pointer value",
+    );
+}
+
+fn is_fn_ptr_cast(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+    if let ExprKind::Cast(cast_expr, cast_ty) = expr.kind
+        && let TyKind::Ptr(_) = cast_ty.kind
+    {
+        cx.typeck_results().expr_ty_adjusted(cast_expr).is_fn()
+    } else {
+        false
+    }
+}
+
+impl<'tcx> LateLintPass<'tcx> for FnNullCheck {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        match expr.kind {
+            // Catching:
+            // (fn_ptr as *<const/mut> <ty>).is_null()
+            ExprKind::MethodCall(method_name, receiver, _, _)
+                if method_name.ident.as_str() == "is_null" && is_fn_ptr_cast(cx, receiver) =>
+            {
+                lint_expr(cx, expr);
+            },
+
+            ExprKind::Binary(op, left, right) if matches!(op.node, BinOpKind::Eq) => {
+                let to_check: &Expr<'_>;
+                if is_fn_ptr_cast(cx, left) {
+                    to_check = right;
+                } else if is_fn_ptr_cast(cx, right) {
+                    to_check = left;
+                } else {
+                    return;
+                }
+
+                match to_check.kind {
+                    // Catching:
+                    // (fn_ptr as *<const/mut> <ty>) == (0 as <ty>)
+                    ExprKind::Cast(cast_expr, _) if is_integer_literal(cast_expr, 0) => {
+                        lint_expr(cx, expr);
+                    },
+
+                    // Catching:
+                    // (fn_ptr as *<const/mut> <ty>) == std::ptr::null()
+                    ExprKind::Call(func, []) if is_path_diagnostic_item(cx, func, sym::ptr_null) => {
+                        lint_expr(cx, expr);
+                    },
+
+                    // Catching:
+                    // (fn_ptr as *<const/mut> <ty>) == <const that evaluates to null_ptr>
+                    _ if matches!(
+                        constant(cx, cx.typeck_results(), to_check),
+                        Some((Constant::RawPtr(0), _))
+                    ) =>
+                    {
+                        lint_expr(cx, expr);
+                    },
+
+                    _ => {},
+                }
+            },
+            _ => {},
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/format_args.rs b/src/tools/clippy/clippy_lints/src/format_args.rs
index 69f7c152fc4..043112bbc95 100644
--- a/src/tools/clippy/clippy_lints/src/format_args.rs
+++ b/src/tools/clippy/clippy_lints/src/format_args.rs
@@ -382,7 +382,7 @@ fn check_format_in_format_args(
         call_site,
         &format!("`format!` in `{name}!` args"),
         |diag| {
-            diag.help(&format!(
+            diag.help(format!(
                 "combine the `format!(..)` arguments with the outer `{name}!(..)` call"
             ));
             diag.help("or consider changing `format!` to `format_args!`");
diff --git a/src/tools/clippy/clippy_lints/src/functions/mod.rs b/src/tools/clippy/clippy_lints/src/functions/mod.rs
index 91e6ffe6447..9dbce3f889b 100644
--- a/src/tools/clippy/clippy_lints/src/functions/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/mod.rs
@@ -63,23 +63,40 @@ declare_clippy_lint! {
     /// arguments but are not marked `unsafe`.
     ///
     /// ### Why is this bad?
-    /// The function should probably be marked `unsafe`, since
-    /// for an arbitrary raw pointer, there is no way of telling for sure if it is
-    /// valid.
+    /// The function should almost definitely be marked `unsafe`, since for an
+    /// arbitrary raw pointer, there is no way of telling for sure if it is valid.
+    ///
+    /// In general, this lint should **never be disabled** unless it is definitely a
+    /// false positive (please submit an issue if so) since it breaks Rust's
+    /// soundness guarantees, directly exposing API users to potentially dangerous
+    /// program behavior. This is also true for internal APIs, as it is easy to leak
+    /// unsoundness.
+    ///
+    /// ### Context
+    /// In Rust, an `unsafe {...}` block is used to indicate that the code in that
+    /// section has been verified in some way that the compiler can not. For a
+    /// function that accepts a raw pointer then accesses the pointer's data, this is
+    /// generally impossible as the incoming pointer could point anywhere, valid or
+    /// not. So, the signature should be marked `unsafe fn`: this indicates that the
+    /// function's caller must provide some verification that the arguments it sends
+    /// are valid (and then call the function within an `unsafe` block).
     ///
     /// ### Known problems
     /// * It does not check functions recursively so if the pointer is passed to a
     /// private non-`unsafe` function which does the dereferencing, the lint won't
-    /// trigger.
+    /// trigger (false negative).
     /// * It only checks for arguments whose type are raw pointers, not raw pointers
     /// got from an argument in some other way (`fn foo(bar: &[*const u8])` or
-    /// `some_argument.get_raw_ptr()`).
+    /// `some_argument.get_raw_ptr()`) (false negative).
     ///
     /// ### Example
     /// ```rust,ignore
     /// pub fn foo(x: *const u8) {
     ///     println!("{}", unsafe { *x });
     /// }
+    ///
+    /// // this call "looks" safe but will segfault or worse!
+    /// // foo(invalid_ptr);
     /// ```
     ///
     /// Use instead:
@@ -87,6 +104,12 @@ declare_clippy_lint! {
     /// pub unsafe fn foo(x: *const u8) {
     ///     println!("{}", unsafe { *x });
     /// }
+    ///
+    /// // this would cause a compiler error for calling without `unsafe`
+    /// // foo(invalid_ptr);
+    ///
+    /// // sound call if the caller knows the pointer is valid
+    /// unsafe { foo(valid_ptr); }
     /// ```
     #[clippy::version = "pre 1.29.0"]
     pub NOT_UNSAFE_PTR_ARG_DEREF,
diff --git a/src/tools/clippy/clippy_lints/src/large_const_arrays.rs b/src/tools/clippy/clippy_lints/src/large_const_arrays.rs
index 76c83ab47d0..db637dfc068 100644
--- a/src/tools/clippy/clippy_lints/src/large_const_arrays.rs
+++ b/src/tools/clippy/clippy_lints/src/large_const_arrays.rs
@@ -34,12 +34,12 @@ declare_clippy_lint! {
 }
 
 pub struct LargeConstArrays {
-    maximum_allowed_size: u64,
+    maximum_allowed_size: u128,
 }
 
 impl LargeConstArrays {
     #[must_use]
-    pub fn new(maximum_allowed_size: u64) -> Self {
+    pub fn new(maximum_allowed_size: u128) -> Self {
         Self { maximum_allowed_size }
     }
 }
@@ -56,7 +56,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeConstArrays {
             if let ConstKind::Value(ty::ValTree::Leaf(element_count)) = cst.kind();
             if let Ok(element_count) = element_count.try_to_machine_usize(cx.tcx);
             if let Ok(element_size) = cx.layout_of(*element_type).map(|l| l.size.bytes());
-            if self.maximum_allowed_size < element_count * element_size;
+            if self.maximum_allowed_size < u128::from(element_count) * u128::from(element_size);
 
             then {
                 let hi_pos = item.ident.span.lo() - BytePos::from_usize(1);
diff --git a/src/tools/clippy/clippy_lints/src/large_enum_variant.rs b/src/tools/clippy/clippy_lints/src/large_enum_variant.rs
index b18456ee523..b8d4abdbb78 100644
--- a/src/tools/clippy/clippy_lints/src/large_enum_variant.rs
+++ b/src/tools/clippy/clippy_lints/src/large_enum_variant.rs
@@ -111,7 +111,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant {
                         );
                         diag.span_label(
                             def.variants[variants_size[1].ind].span,
-                            &if variants_size[1].fields_size.is_empty() {
+                            if variants_size[1].fields_size.is_empty() {
                                 "the second-largest variant carries no data at all".to_owned()
                             } else {
                                 format!(
diff --git a/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs b/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs
index 5857d81ab1f..89ae83d48f5 100644
--- a/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs
+++ b/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs
@@ -24,12 +24,12 @@ declare_clippy_lint! {
 }
 
 pub struct LargeStackArrays {
-    maximum_allowed_size: u64,
+    maximum_allowed_size: u128,
 }
 
 impl LargeStackArrays {
     #[must_use]
-    pub fn new(maximum_allowed_size: u64) -> Self {
+    pub fn new(maximum_allowed_size: u128) -> Self {
         Self { maximum_allowed_size }
     }
 }
@@ -45,7 +45,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeStackArrays {
           && let Ok(element_size) = cx.layout_of(*element_type).map(|l| l.size.bytes())
           && !cx.tcx.hir().parent_iter(expr.hir_id)
               .any(|(_, node)| matches!(node, Node::Item(Item { kind: ItemKind::Static(..), .. })))
-          && self.maximum_allowed_size < element_count * element_size {
+          && self.maximum_allowed_size < u128::from(element_count) * u128::from(element_size) {
               span_lint_and_help(
                   cx,
                   LARGE_STACK_ARRAYS,
diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs
index e88d1764a24..9eba4675629 100644
--- a/src/tools/clippy/clippy_lints/src/len_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/len_zero.rs
@@ -361,7 +361,7 @@ fn check_for_is_empty<'tcx>(
             db.span_note(span, "`is_empty` defined here");
         }
         if let Some(self_kind) = self_kind {
-            db.note(&output.expected_sig(self_kind));
+            db.note(output.expected_sig(self_kind));
         }
     });
 }
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index 39850d59803..dcd8ca81ae8 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -125,6 +125,7 @@ mod explicit_write;
 mod fallible_impl_from;
 mod float_literal;
 mod floating_point_arithmetic;
+mod fn_null_check;
 mod format;
 mod format_args;
 mod format_impl;
@@ -234,6 +235,7 @@ mod partialeq_ne_impl;
 mod partialeq_to_none;
 mod pass_by_ref_or_value;
 mod pattern_type_mismatch;
+mod permissions_set_readonly_false;
 mod precedence;
 mod ptr;
 mod ptr_offset_with_cast;
@@ -263,6 +265,7 @@ mod shadow;
 mod single_char_lifetime_names;
 mod single_component_path_imports;
 mod size_of_in_element_count;
+mod size_of_ref;
 mod slow_vector_initialization;
 mod std_instead_of_core;
 mod strings;
@@ -334,7 +337,7 @@ pub fn read_conf(sess: &Session, path: &io::Result<Option<PathBuf>>) -> Conf {
         Ok(Some(path)) => path,
         Ok(None) => return Conf::default(),
         Err(error) => {
-            sess.struct_err(&format!("error finding Clippy's configuration file: {error}"))
+            sess.struct_err(format!("error finding Clippy's configuration file: {error}"))
                 .emit();
             return Conf::default();
         },
@@ -902,6 +905,9 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|_| Box::new(suspicious_xor_used_as_pow::ConfusingXorAndPow));
     store.register_late_pass(move |_| Box::new(manual_is_ascii_check::ManualIsAsciiCheck::new(msrv())));
     store.register_late_pass(|_| Box::new(semicolon_block::SemicolonBlock));
+    store.register_late_pass(|_| Box::new(fn_null_check::FnNullCheck));
+    store.register_late_pass(|_| Box::new(permissions_set_readonly_false::PermissionsSetReadonlyFalse));
+    store.register_late_pass(|_| Box::new(size_of_ref::SizeOfRef));
     // add lints here, do not remove this comment, it's used in `new_lint`
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/loops/explicit_counter_loop.rs b/src/tools/clippy/clippy_lints/src/loops/explicit_counter_loop.rs
index 14f22348132..1953ee8a717 100644
--- a/src/tools/clippy/clippy_lints/src/loops/explicit_counter_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/explicit_counter_loop.rs
@@ -77,7 +77,7 @@ pub(super) fn check<'tcx>(
                                 applicability,
                             );
 
-                            diag.note(&format!(
+                            diag.note(format!(
                                 "`{name}` is of type `{int_name}`, making it ineligible for `Iterator::enumerate`"
                             ));
                         },
diff --git a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs
index 075ecbe7ede..af7c0563555 100644
--- a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs
@@ -76,7 +76,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualAsyncFn {
                                 let help = format!("make the function `async` and {ret_sugg}");
                                 diag.span_suggestion(
                                     header_span,
-                                    &help,
+                                    help,
                                     format!("async {}{ret_snip}", &header_snip[..ret_pos]),
                                     Applicability::MachineApplicable
                                 );
diff --git a/src/tools/clippy/clippy_lints/src/manual_clamp.rs b/src/tools/clippy/clippy_lints/src/manual_clamp.rs
index bb6d628af3b..f239736d38a 100644
--- a/src/tools/clippy/clippy_lints/src/manual_clamp.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_clamp.rs
@@ -35,6 +35,9 @@ declare_clippy_lint! {
     /// Some may consider panicking in these situations to be desirable, but it also may
     /// introduce panicking where there wasn't any before.
     ///
+    /// See also [the discussion in the
+    /// PR](https://github.com/rust-lang/rust-clippy/pull/9484#issuecomment-1278922613).
+    ///
     /// ### Examples
     /// ```rust
     /// # let (input, min, max) = (0, -2, 1);
@@ -78,7 +81,7 @@ declare_clippy_lint! {
     /// ```
     #[clippy::version = "1.66.0"]
     pub MANUAL_CLAMP,
-    complexity,
+    nursery,
     "using a clamp pattern instead of the clamp function"
 }
 impl_lint_pass!(ManualClamp => [MANUAL_CLAMP]);
diff --git a/src/tools/clippy/clippy_lints/src/manual_strip.rs b/src/tools/clippy/clippy_lints/src/manual_strip.rs
index de166b9765f..c795c1d9a16 100644
--- a/src/tools/clippy/clippy_lints/src/manual_strip.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_strip.rs
@@ -109,7 +109,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualStrip {
 
                     let test_span = expr.span.until(then.span);
                     span_lint_and_then(cx, MANUAL_STRIP, strippings[0], &format!("stripping a {kind_word} manually"), |diag| {
-                        diag.span_note(test_span, &format!("the {kind_word} was tested here"));
+                        diag.span_note(test_span, format!("the {kind_word} was tested here"));
                         multispan_sugg(
                             diag,
                             &format!("try using the `strip_{kind_word}` method"),
diff --git a/src/tools/clippy/clippy_lints/src/matches/manual_filter.rs b/src/tools/clippy/clippy_lints/src/matches/manual_filter.rs
index d521a529e0d..f6bf0e7aa1a 100644
--- a/src/tools/clippy/clippy_lints/src/matches/manual_filter.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/manual_filter.rs
@@ -3,7 +3,7 @@ use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::visitors::contains_unsafe_block;
 use clippy_utils::{is_res_lang_ctor, path_res, path_to_local_id};
 
-use rustc_hir::LangItem::OptionSome;
+use rustc_hir::LangItem::{OptionNone, OptionSome};
 use rustc_hir::{Arm, Expr, ExprKind, HirId, Pat, PatKind};
 use rustc_lint::LateContext;
 use rustc_span::{sym, SyntaxContext};
@@ -25,15 +25,13 @@ fn get_cond_expr<'tcx>(
         if let Some(block_expr) = peels_blocks_incl_unsafe_opt(expr);
         if let ExprKind::If(cond, then_expr, Some(else_expr)) = block_expr.kind;
         if let PatKind::Binding(_,target, ..) = pat.kind;
-        if let (then_visitor, else_visitor)
-            = (is_some_expr(cx, target, ctxt, then_expr),
-                is_some_expr(cx, target, ctxt, else_expr));
-        if then_visitor != else_visitor; // check that one expr resolves to `Some(x)`, the other to `None`
+        if is_some_expr(cx, target, ctxt, then_expr) && is_none_expr(cx, else_expr)
+            || is_none_expr(cx, then_expr) && is_some_expr(cx, target, ctxt, else_expr); // check that one expr resolves to `Some(x)`, the other to `None`
         then {
             return Some(SomeExpr {
                     expr: peels_blocks_incl_unsafe(cond.peel_drop_temps()),
                     needs_unsafe_block: contains_unsafe_block(cx, expr),
-                    needs_negated: !then_visitor // if the `then_expr` resolves to `None`, need to negate the cond
+                    needs_negated: is_none_expr(cx, then_expr) // if the `then_expr` resolves to `None`, need to negate the cond
                 })
             }
     };
@@ -74,6 +72,13 @@ fn is_some_expr(cx: &LateContext<'_>, target: HirId, ctxt: SyntaxContext, expr:
     false
 }
 
+fn is_none_expr(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+    if let Some(inner_expr) = peels_blocks_incl_unsafe_opt(expr) {
+        return is_res_lang_ctor(cx, path_res(cx, inner_expr), OptionNone);
+    };
+    false
+}
+
 // given the closure: `|<pattern>| <expr>`
 // returns `|&<pattern>| <expr>`
 fn add_ampersand_if_copy(body_str: String, has_copy_trait: bool) -> String {
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_single_binding.rs b/src/tools/clippy/clippy_lints/src/matches/match_single_binding.rs
index 1bf8d4e96ad..c94a1f76330 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_single_binding.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_single_binding.rs
@@ -31,19 +31,11 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e
     };
 
     // Do we need to add ';' to suggestion ?
-    match match_body.kind {
-        ExprKind::Block(block, _) => {
-            // macro + expr_ty(body) == ()
-            if block.span.from_expansion() && cx.typeck_results().expr_ty(match_body).is_unit() {
-                snippet_body.push(';');
-            }
-        },
-        _ => {
-            // expr_ty(body) == ()
-            if cx.typeck_results().expr_ty(match_body).is_unit() {
-                snippet_body.push(';');
-            }
-        },
+    if let ExprKind::Block(block, _) = match_body.kind {
+        // macro + expr_ty(body) == ()
+        if block.span.from_expansion() && cx.typeck_results().expr_ty(match_body).is_unit() {
+            snippet_body.push(';');
+        }
     }
 
     let mut applicability = Applicability::MaybeIncorrect;
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs b/src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs
index 7f8d124838c..59de8c0384b 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs
@@ -30,7 +30,7 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) {
     let mut has_non_wild = false;
     for arm in arms {
         match peel_hir_pat_refs(arm.pat).0.kind {
-            PatKind::Wild => wildcard_span = Some(arm.pat.span),
+            PatKind::Wild if arm.guard.is_none() => wildcard_span = Some(arm.pat.span),
             PatKind::Binding(_, _, ident, None) => {
                 wildcard_span = Some(arm.pat.span);
                 wildcard_ident = Some(ident);
diff --git a/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs b/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs
index d8c821bc9ee..424482859ee 100644
--- a/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs
@@ -36,7 +36,7 @@ pub fn check(
                 expr.span,
                 &format!("calling `to_string` on `{arg_ty}`"),
                 |diag| {
-                    diag.help(&format!(
+                    diag.help(format!(
                         "`{self_ty}` implements `ToString` through a slower blanket impl, but `{deref_self_ty}` has a fast specialization of `ToString`"
                     ));
                     let mut applicability = Applicability::MachineApplicable;
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_skip_next.rs b/src/tools/clippy/clippy_lints/src/methods/iter_skip_next.rs
index beb772100af..279175e20c3 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_skip_next.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_skip_next.rs
@@ -29,7 +29,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr
                         application = Applicability::Unspecified;
                         diag.span_help(
                             pat.span,
-                            &format!("for this change `{}` has to be mutable", snippet(cx, pat.span, "..")),
+                            format!("for this change `{}` has to be mutable", snippet(cx, pat.span, "..")),
                         );
                     }
                 }
diff --git a/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs b/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs
index 910ee14855e..4c6328481e4 100644
--- a/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs
@@ -84,7 +84,7 @@ pub(super) fn check<'tcx>(
                 suggestion.push((map_arg_span.with_hi(map_arg_span.lo()), format!("{unwrap_snippet}, ")));
             }
 
-            diag.multipart_suggestion(&format!("use `{suggest}` instead"), suggestion, applicability);
+            diag.multipart_suggestion(format!("use `{suggest}` instead"), suggestion, applicability);
         });
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs
index 3c01ce1fecd..d00708e828e 100644
--- a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs
@@ -167,7 +167,7 @@ fn check_manual_split_once_indirect(
             };
             diag.span_suggestion_verbose(
                 local.span,
-                &format!("try `{r}split_once`"),
+                format!("try `{r}split_once`"),
                 format!("let ({lhs}, {rhs}) = {self_snip}.{r}split_once({pat_snip}){unwrap};"),
                 app,
             );
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs
index 0e73459ad65..47e2e744112 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs
@@ -62,7 +62,7 @@ pub(super) fn check<'tcx>(
                     span_lint_and_then(cx, UNNECESSARY_LAZY_EVALUATIONS, expr.span, msg, |diag| {
                         diag.span_suggestion(
                             span,
-                            &format!("use `{simplify_using}(..)` instead"),
+                            format!("use `{simplify_using}(..)` instead"),
                             format!("{simplify_using}({})", snippet(cx, body_expr.span, "..")),
                             applicability,
                         );
diff --git a/src/tools/clippy/clippy_lints/src/needless_late_init.rs b/src/tools/clippy/clippy_lints/src/needless_late_init.rs
index 67debe7e08a..5a9387b34cc 100644
--- a/src/tools/clippy/clippy_lints/src/needless_late_init.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_late_init.rs
@@ -284,7 +284,7 @@ fn check<'tcx>(
 
                     diag.span_suggestion(
                         assign.lhs_span,
-                        &format!("declare `{binding_name}` here"),
+                        format!("declare `{binding_name}` here"),
                         let_snippet,
                         Applicability::MachineApplicable,
                     );
@@ -304,7 +304,7 @@ fn check<'tcx>(
 
                     diag.span_suggestion_verbose(
                         usage.stmt.span.shrink_to_lo(),
-                        &format!("declare `{binding_name}` here"),
+                        format!("declare `{binding_name}` here"),
                         format!("{let_snippet} = "),
                         applicability,
                     );
@@ -335,7 +335,7 @@ fn check<'tcx>(
 
                     diag.span_suggestion_verbose(
                         usage.stmt.span.shrink_to_lo(),
-                        &format!("declare `{binding_name}` here"),
+                        format!("declare `{binding_name}` here"),
                         format!("{let_snippet} = "),
                         applicability,
                     );
diff --git a/src/tools/clippy/clippy_lints/src/octal_escapes.rs b/src/tools/clippy/clippy_lints/src/octal_escapes.rs
index ae0a41db918..7376ab0c846 100644
--- a/src/tools/clippy/clippy_lints/src/octal_escapes.rs
+++ b/src/tools/clippy/clippy_lints/src/octal_escapes.rs
@@ -125,7 +125,7 @@ fn check_lit(cx: &EarlyContext<'_>, lit: &Lit, span: Span, is_string: bool) {
             if is_string { "string" } else { "byte string" }
         ),
         |diag| {
-            diag.help(&format!(
+            diag.help(format!(
                 "octal escapes are not supported, `\\0` is always a null {}",
                 if is_string { "character" } else { "byte" }
             ));
@@ -139,7 +139,7 @@ fn check_lit(cx: &EarlyContext<'_>, lit: &Lit, span: Span, is_string: bool) {
             // suggestion 2: unambiguous null byte
             diag.span_suggestion(
                 span,
-                &format!(
+                format!(
                     "if the null {} is intended, disambiguate using",
                     if is_string { "character" } else { "byte" }
                 ),
diff --git a/src/tools/clippy/clippy_lints/src/operators/misrefactored_assign_op.rs b/src/tools/clippy/clippy_lints/src/operators/misrefactored_assign_op.rs
index ae805147f07..015f6c14e76 100644
--- a/src/tools/clippy/clippy_lints/src/operators/misrefactored_assign_op.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/misrefactored_assign_op.rs
@@ -50,7 +50,7 @@ fn lint_misrefactored_assign_op(
                 let long = format!("{snip_a} = {}", sugg::make_binop(op.into(), a, r));
                 diag.span_suggestion(
                     expr.span,
-                    &format!(
+                    format!(
                         "did you mean `{snip_a} = {snip_a} {} {snip_r}` or `{long}`? Consider replacing it with",
                         op.as_str()
                     ),
diff --git a/src/tools/clippy/clippy_lints/src/permissions_set_readonly_false.rs b/src/tools/clippy/clippy_lints/src/permissions_set_readonly_false.rs
new file mode 100644
index 00000000000..e7095ec191f
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/permissions_set_readonly_false.rs
@@ -0,0 +1,52 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::paths;
+use clippy_utils::ty::match_type;
+use rustc_ast::ast::LitKind;
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for calls to `std::fs::Permissions.set_readonly` with argument `false`.
+    ///
+    /// ### Why is this bad?
+    /// On Unix platforms this results in the file being world writable,
+    /// equivalent to `chmod a+w <file>`.
+    /// ### Example
+    /// ```rust
+    /// use std::fs::File;
+    /// let f = File::create("foo.txt").unwrap();
+    /// let metadata = f.metadata().unwrap();
+    /// let mut permissions = metadata.permissions();
+    /// permissions.set_readonly(false);
+    /// ```
+    #[clippy::version = "1.66.0"]
+    pub PERMISSIONS_SET_READONLY_FALSE,
+    suspicious,
+    "Checks for calls to `std::fs::Permissions.set_readonly` with argument `false`"
+}
+declare_lint_pass!(PermissionsSetReadonlyFalse => [PERMISSIONS_SET_READONLY_FALSE]);
+
+impl<'tcx> LateLintPass<'tcx> for PermissionsSetReadonlyFalse {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
+        if let ExprKind::MethodCall(path, receiver, [arg], _) = &expr.kind
+            && match_type(cx, cx.typeck_results().expr_ty(receiver), &paths::PERMISSIONS)
+            && path.ident.name == sym!(set_readonly)
+            && let ExprKind::Lit(lit) = &arg.kind
+            && LitKind::Bool(false) == lit.node
+        {
+            span_lint_and_then(
+                cx,
+                PERMISSIONS_SET_READONLY_FALSE,
+                expr.span,
+                "call to `set_readonly` with argument `false`",
+                |diag| {
+                    diag.note("on Unix platforms this results in the file being world writable");
+                    diag.help("you can set the desired permissions using `PermissionsExt`. For more information, see\n\
+                        https://doc.rust-lang.org/std/os/unix/fs/trait.PermissionsExt.html");
+                }
+            );
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/redundant_clone.rs b/src/tools/clippy/clippy_lints/src/redundant_clone.rs
index c1677fb3da1..0e7c5cca724 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_clone.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_clone.rs
@@ -131,7 +131,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone {
                 // `res = clone(arg)` can be turned into `res = move arg;`
                 // if `arg` is the only borrow of `cloned` at this point.
 
-                if cannot_move_out || !possible_borrower.only_borrowers(&[arg], cloned, loc) {
+                if cannot_move_out || !possible_borrower.at_most_borrowers(cx, &[arg], cloned, loc) {
                     continue;
                 }
 
@@ -178,7 +178,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone {
                 // StorageDead(pred_arg);
                 // res = to_path_buf(cloned);
                 // ```
-                if cannot_move_out || !possible_borrower.only_borrowers(&[arg, cloned], local, loc) {
+                if cannot_move_out || !possible_borrower.at_most_borrowers(cx, &[arg, cloned], local, loc) {
                     continue;
                 }
 
diff --git a/src/tools/clippy/clippy_lints/src/returns.rs b/src/tools/clippy/clippy_lints/src/returns.rs
index 81143d7799e..d4d50660520 100644
--- a/src/tools/clippy/clippy_lints/src/returns.rs
+++ b/src/tools/clippy/clippy_lints/src/returns.rs
@@ -6,7 +6,7 @@ use core::ops::ControlFlow;
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::FnKind;
-use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, HirId, MatchSource, PatKind, StmtKind};
+use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, HirId, LangItem, MatchSource, PatKind, QPath, StmtKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::subst::GenericArgKind;
@@ -207,6 +207,12 @@ fn check_final_expr<'tcx>(
     match &peeled_drop_expr.kind {
         // simple return is always "bad"
         ExprKind::Ret(ref inner) => {
+            // if desugar of `do yeet`, don't lint
+            if let Some(inner_expr) = inner
+                && let ExprKind::Call(path_expr, _) = inner_expr.kind
+                && let ExprKind::Path(QPath::LangItem(LangItem::TryTraitFromYeet, _, _)) = path_expr.kind {
+                    return;
+            }
             if cx.tcx.hir().attrs(expr.hir_id).is_empty() {
                 let borrows = inner.map_or(false, |inner| last_statement_borrows(cx, inner));
                 if !borrows {
diff --git a/src/tools/clippy/clippy_lints/src/same_name_method.rs b/src/tools/clippy/clippy_lints/src/same_name_method.rs
index caab5851baf..17763128cd1 100644
--- a/src/tools/clippy/clippy_lints/src/same_name_method.rs
+++ b/src/tools/clippy/clippy_lints/src/same_name_method.rs
@@ -108,7 +108,7 @@ impl<'tcx> LateLintPass<'tcx> for SameNameMethod {
                                     |diag| {
                                         diag.span_note(
                                             trait_method_span,
-                                            &format!("existing `{method_name}` defined here"),
+                                            format!("existing `{method_name}` defined here"),
                                         );
                                     },
                                 );
@@ -151,7 +151,7 @@ impl<'tcx> LateLintPass<'tcx> for SameNameMethod {
                                         // iterate on trait_spans?
                                         diag.span_note(
                                             trait_spans[0],
-                                            &format!("existing `{method_name}` defined here"),
+                                            format!("existing `{method_name}` defined here"),
                                         );
                                     },
                                 );
diff --git a/src/tools/clippy/clippy_lints/src/size_of_ref.rs b/src/tools/clippy/clippy_lints/src/size_of_ref.rs
new file mode 100644
index 00000000000..3fcdb4288ce
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/size_of_ref.rs
@@ -0,0 +1,73 @@
+use clippy_utils::{diagnostics::span_lint_and_help, path_def_id, ty::peel_mid_ty_refs};
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::sym;
+
+declare_clippy_lint! {
+    /// ### What it does
+    ///
+    /// Checks for calls to `std::mem::size_of_val()` where the argument is
+    /// a reference to a reference.
+    ///
+    /// ### Why is this bad?
+    ///
+    /// Calling `size_of_val()` with a reference to a reference as the argument
+    /// yields the size of the reference-type, not the size of the value behind
+    /// the reference.
+    ///
+    /// ### Example
+    /// ```rust
+    /// struct Foo {
+    ///     buffer: [u8],
+    /// }
+    ///
+    /// impl Foo {
+    ///     fn size(&self) -> usize {
+    ///         // Note that `&self` as an argument is a `&&Foo`: Because `self`
+    ///         // is already a reference, `&self` is a double-reference.
+    ///         // The return value of `size_of_val()` therefor is the
+    ///         // size of the reference-type, not the size of `self`.
+    ///         std::mem::size_of_val(&self)
+    ///     }
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// struct Foo {
+    ///     buffer: [u8],
+    /// }
+    ///
+    /// impl Foo {
+    ///     fn size(&self) -> usize {
+    ///         // Correct
+    ///         std::mem::size_of_val(self)
+    ///     }
+    /// }
+    /// ```
+    #[clippy::version = "1.67.0"]
+    pub SIZE_OF_REF,
+    suspicious,
+    "Argument to `std::mem::size_of_val()` is a double-reference, which is almost certainly unintended"
+}
+declare_lint_pass!(SizeOfRef => [SIZE_OF_REF]);
+
+impl LateLintPass<'_> for SizeOfRef {
+    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) {
+        if let ExprKind::Call(path, [arg]) = expr.kind
+            && let Some(def_id) = path_def_id(cx, path)
+            && cx.tcx.is_diagnostic_item(sym::mem_size_of_val, def_id)
+            && let arg_ty = cx.typeck_results().expr_ty(arg)
+            && peel_mid_ty_refs(arg_ty).1 > 1
+        {
+            span_lint_and_help(
+                cx,
+                SIZE_OF_REF,
+                expr.span,
+                "argument to `std::mem::size_of_val()` is a reference to a reference",
+                None,
+                "dereference the argument to `std::mem::size_of_val()` to get the size of the value instead of the size of the reference-type",
+            );
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/swap.rs b/src/tools/clippy/clippy_lints/src/swap.rs
index c374529d1ea..17e9cc5f6b7 100644
--- a/src/tools/clippy/clippy_lints/src/swap.rs
+++ b/src/tools/clippy/clippy_lints/src/swap.rs
@@ -132,7 +132,7 @@ fn generate_swap_warning(cx: &LateContext<'_>, e1: &Expr<'_>, e2: &Expr<'_>, spa
                 applicability,
             );
             if !is_xor_based {
-                diag.note(&format!("or maybe you should use `{sugg}::mem::replace`?"));
+                diag.note(format!("or maybe you should use `{sugg}::mem::replace`?"));
             }
         },
     );
@@ -214,7 +214,7 @@ fn check_suspicious_swap(cx: &LateContext<'_>, block: &Block<'_>) {
                                 Applicability::MaybeIncorrect,
                             );
                             diag.note(
-                                &format!("or maybe you should use `{sugg}::mem::replace`?")
+                                format!("or maybe you should use `{sugg}::mem::replace`?")
                             );
                         }
                     });
diff --git a/src/tools/clippy/clippy_lints/src/transmute/mod.rs b/src/tools/clippy/clippy_lints/src/transmute/mod.rs
index 83e651aba8e..691d759d773 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/mod.rs
@@ -3,6 +3,7 @@ mod transmute_float_to_int;
 mod transmute_int_to_bool;
 mod transmute_int_to_char;
 mod transmute_int_to_float;
+mod transmute_null_to_fn;
 mod transmute_num_to_bytes;
 mod transmute_ptr_to_ptr;
 mod transmute_ptr_to_ref;
@@ -409,6 +410,34 @@ declare_clippy_lint! {
     "transmutes from a null pointer to a reference, which is undefined behavior"
 }
 
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for null function pointer creation through transmute.
+    ///
+    /// ### Why is this bad?
+    /// Creating a null function pointer is undefined behavior.
+    ///
+    /// More info: https://doc.rust-lang.org/nomicon/ffi.html#the-nullable-pointer-optimization
+    ///
+    /// ### Known problems
+    /// Not all cases can be detected at the moment of this writing.
+    /// For example, variables which hold a null pointer and are then fed to a `transmute`
+    /// call, aren't detectable yet.
+    ///
+    /// ### Example
+    /// ```rust
+    /// let null_fn: fn() = unsafe { std::mem::transmute( std::ptr::null::<()>() ) };
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// let null_fn: Option<fn()> = None;
+    /// ```
+    #[clippy::version = "1.67.0"]
+    pub TRANSMUTE_NULL_TO_FN,
+    correctness,
+    "transmute results in a null function pointer, which is undefined behavior"
+}
+
 pub struct Transmute {
     msrv: Msrv,
 }
@@ -428,6 +457,7 @@ impl_lint_pass!(Transmute => [
     TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS,
     TRANSMUTE_UNDEFINED_REPR,
     TRANSMUTING_NULL,
+    TRANSMUTE_NULL_TO_FN,
 ]);
 impl Transmute {
     #[must_use]
@@ -461,6 +491,7 @@ impl<'tcx> LateLintPass<'tcx> for Transmute {
                 let linted = wrong_transmute::check(cx, e, from_ty, to_ty)
                     | crosspointer_transmute::check(cx, e, from_ty, to_ty)
                     | transmuting_null::check(cx, e, arg, to_ty)
+                    | transmute_null_to_fn::check(cx, e, arg, to_ty)
                     | transmute_ptr_to_ref::check(cx, e, from_ty, to_ty, arg, path, &self.msrv)
                     | transmute_int_to_char::check(cx, e, from_ty, to_ty, arg, const_context)
                     | transmute_ref_to_ref::check(cx, e, from_ty, to_ty, arg, const_context)
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_null_to_fn.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_null_to_fn.rs
new file mode 100644
index 00000000000..e75d7f6bf1d
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_null_to_fn.rs
@@ -0,0 +1,64 @@
+use clippy_utils::consts::{constant, Constant};
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::{is_integer_literal, is_path_diagnostic_item};
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::LateContext;
+use rustc_middle::ty::Ty;
+use rustc_span::symbol::sym;
+
+use super::TRANSMUTE_NULL_TO_FN;
+
+fn lint_expr(cx: &LateContext<'_>, expr: &Expr<'_>) {
+    span_lint_and_then(
+        cx,
+        TRANSMUTE_NULL_TO_FN,
+        expr.span,
+        "transmuting a known null pointer into a function pointer",
+        |diag| {
+            diag.span_label(expr.span, "this transmute results in undefined behavior");
+            diag.help(
+               "try wrapping your function pointer type in `Option<T>` instead, and using `None` as a null pointer value"
+            );
+        },
+    );
+}
+
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'tcx Expr<'_>, to_ty: Ty<'tcx>) -> bool {
+    if !to_ty.is_fn() {
+        return false;
+    }
+
+    match arg.kind {
+        // Catching:
+        // transmute over constants that resolve to `null`.
+        ExprKind::Path(ref _qpath)
+            if matches!(constant(cx, cx.typeck_results(), arg), Some((Constant::RawPtr(0), _))) =>
+        {
+            lint_expr(cx, expr);
+            true
+        },
+
+        // Catching:
+        // `std::mem::transmute(0 as *const i32)`
+        ExprKind::Cast(inner_expr, _cast_ty) if is_integer_literal(inner_expr, 0) => {
+            lint_expr(cx, expr);
+            true
+        },
+
+        // Catching:
+        // `std::mem::transmute(std::ptr::null::<i32>())`
+        ExprKind::Call(func1, []) if is_path_diagnostic_item(cx, func1, sym::ptr_null) => {
+            lint_expr(cx, expr);
+            true
+        },
+
+        _ => {
+            // FIXME:
+            // Also catch transmutations of variables which are known nulls.
+            // To do this, MIR const propagation seems to be the better tool.
+            // Whenever MIR const prop routines are more developed, this will
+            // become available. As of this writing (25/03/19) it is not yet.
+            false
+        },
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs
index 34642f4b122..af0242348ac 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs
@@ -77,7 +77,7 @@ pub(super) fn check<'tcx>(
                     &format!("transmute from `{from_ty_orig}` which has an undefined layout"),
                     |diag| {
                         if from_ty_orig.peel_refs() != from_ty.peel_refs() {
-                            diag.note(&format!("the contained type `{from_ty}` has an undefined layout"));
+                            diag.note(format!("the contained type `{from_ty}` has an undefined layout"));
                         }
                     },
                 );
@@ -91,7 +91,7 @@ pub(super) fn check<'tcx>(
                     &format!("transmute to `{to_ty_orig}` which has an undefined layout"),
                     |diag| {
                         if to_ty_orig.peel_refs() != to_ty.peel_refs() {
-                            diag.note(&format!("the contained type `{to_ty}` has an undefined layout"));
+                            diag.note(format!("the contained type `{to_ty}` has an undefined layout"));
                         }
                     },
                 );
@@ -119,16 +119,16 @@ pub(super) fn check<'tcx>(
                     ),
                     |diag| {
                         if let Some(same_adt_did) = same_adt_did {
-                            diag.note(&format!(
+                            diag.note(format!(
                                 "two instances of the same generic type (`{}`) may have different layouts",
                                 cx.tcx.item_name(same_adt_did)
                             ));
                         } else {
                             if from_ty_orig.peel_refs() != from_ty {
-                                diag.note(&format!("the contained type `{from_ty}` has an undefined layout"));
+                                diag.note(format!("the contained type `{from_ty}` has an undefined layout"));
                             }
                             if to_ty_orig.peel_refs() != to_ty {
-                                diag.note(&format!("the contained type `{to_ty}` has an undefined layout"));
+                                diag.note(format!("the contained type `{to_ty}` has an undefined layout"));
                             }
                         }
                     },
@@ -146,7 +146,7 @@ pub(super) fn check<'tcx>(
                     &format!("transmute from `{from_ty_orig}` which has an undefined layout"),
                     |diag| {
                         if from_ty_orig.peel_refs() != from_ty {
-                            diag.note(&format!("the contained type `{from_ty}` has an undefined layout"));
+                            diag.note(format!("the contained type `{from_ty}` has an undefined layout"));
                         }
                     },
                 );
@@ -163,7 +163,7 @@ pub(super) fn check<'tcx>(
                     &format!("transmute into `{to_ty_orig}` which has an undefined layout"),
                     |diag| {
                         if to_ty_orig.peel_refs() != to_ty {
-                            diag.note(&format!("the contained type `{to_ty}` has an undefined layout"));
+                            diag.note(format!("the contained type `{to_ty}` has an undefined layout"));
                         }
                     },
                 );
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs b/src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs
index 6b444922a7c..b79d4e915a2 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs
@@ -24,7 +24,7 @@ pub(super) fn check<'tcx>(
             &format!("transmute from `{from_ty}` to `{to_ty}` which could be expressed as a pointer cast instead"),
             |diag| {
                 if let Some(arg) = sugg::Sugg::hir_opt(cx, arg) {
-                    let sugg = arg.as_ty(&to_ty.to_string()).to_string();
+                    let sugg = arg.as_ty(to_ty.to_string()).to_string();
                     diag.span_suggestion(e.span, "try", sugg, Applicability::MachineApplicable);
                 }
             },
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmuting_null.rs b/src/tools/clippy/clippy_lints/src/transmute/transmuting_null.rs
index 19ce5ae72c2..1e407fc4138 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/transmuting_null.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/transmuting_null.rs
@@ -18,8 +18,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'t
     // Catching transmute over constants that resolve to `null`.
     let mut const_eval_context = constant_context(cx, cx.typeck_results());
     if let ExprKind::Path(ref _qpath) = arg.kind &&
-        let Some(Constant::RawPtr(x)) = const_eval_context.expr(arg) &&
-        x == 0
+        let Some(Constant::RawPtr(0)) = const_eval_context.expr(arg)
     {
         span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG);
         return true;
diff --git a/src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs b/src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs
index f919bbd5afc..871c3fadbba 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs
@@ -61,7 +61,7 @@ pub(super) fn check<'tcx>(
                 "transmute from an integer to a pointer",
                 |diag| {
                     if let Some(arg) = sugg::Sugg::hir_opt(cx, arg) {
-                        diag.span_suggestion(e.span, "try", arg.as_ty(&to_ty.to_string()), Applicability::Unspecified);
+                        diag.span_suggestion(e.span, "try", arg.as_ty(to_ty.to_string()), Applicability::Unspecified);
                     }
                 },
             );
diff --git a/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs b/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs
index fae5385ffc8..f9b9a66b5fa 100644
--- a/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs
+++ b/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs
@@ -31,7 +31,7 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_
             &format!("usage of `{outer_sym}<{generic_snippet}>`"),
             |diag| {
                 diag.span_suggestion(hir_ty.span, "try", format!("{generic_snippet}"), applicability);
-                diag.note(&format!(
+                diag.note(format!(
                     "`{generic_snippet}` is already a pointer, `{outer_sym}<{generic_snippet}>` allocates a pointer on the heap"
                 ));
             },
@@ -78,7 +78,7 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_
                     format!("{outer_sym}<{generic_snippet}>"),
                     applicability,
                 );
-                diag.note(&format!(
+                diag.note(format!(
                     "`{inner_sym}<{generic_snippet}>` is already on the heap, `{outer_sym}<{inner_sym}<{generic_snippet}>>` makes an extra allocation"
                 ));
             },
@@ -91,10 +91,10 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_
             hir_ty.span,
             &format!("usage of `{outer_sym}<{inner_sym}<{generic_snippet}>>`"),
             |diag| {
-                diag.note(&format!(
+                diag.note(format!(
                     "`{inner_sym}<{generic_snippet}>` is already on the heap, `{outer_sym}<{inner_sym}<{generic_snippet}>>` makes an extra allocation"
                 ));
-                diag.help(&format!(
+                diag.help(format!(
                     "consider using just `{outer_sym}<{generic_snippet}>` or `{inner_sym}<{generic_snippet}>`"
                 ));
             },
diff --git a/src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs b/src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs
index f6d3fb00f4e..ef9f740f704 100644
--- a/src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs
+++ b/src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs
@@ -129,7 +129,7 @@ fn lint_unit_args(cx: &LateContext<'_>, expr: &Expr<'_>, args_to_recover: &[&Exp
 
                 if arg_snippets_without_empty_blocks.is_empty() {
                     db.multipart_suggestion(
-                        &format!("use {singular}unit literal{plural} instead"),
+                        format!("use {singular}unit literal{plural} instead"),
                         args_to_recover
                             .iter()
                             .map(|arg| (arg.span, "()".to_string()))
@@ -142,7 +142,7 @@ fn lint_unit_args(cx: &LateContext<'_>, expr: &Expr<'_>, args_to_recover: &[&Exp
                     let it_or_them = if plural { "them" } else { "it" };
                     db.span_suggestion(
                         expr.span,
-                        &format!(
+                        format!(
                             "{or}move the expression{empty_or_s} in front of the call and replace {it_or_them} with the unit literal `()`"
                         ),
                         sugg,
diff --git a/src/tools/clippy/clippy_lints/src/useless_conversion.rs b/src/tools/clippy/clippy_lints/src/useless_conversion.rs
index 3743d5d97a7..a95e7b61374 100644
--- a/src/tools/clippy/clippy_lints/src/useless_conversion.rs
+++ b/src/tools/clippy/clippy_lints/src/useless_conversion.rs
@@ -1,11 +1,11 @@
 use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg};
 use clippy_utils::source::{snippet, snippet_with_macro_callsite};
 use clippy_utils::sugg::Sugg;
-use clippy_utils::ty::{is_type_diagnostic_item, same_type_and_consts};
-use clippy_utils::{get_parent_expr, is_trait_method, match_def_path, paths};
+use clippy_utils::ty::{is_copy, is_type_diagnostic_item, same_type_and_consts};
+use clippy_utils::{get_parent_expr, is_trait_method, match_def_path, path_to_local, paths};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
-use rustc_hir::{Expr, ExprKind, HirId, MatchSource};
+use rustc_hir::{BindingAnnotation, Expr, ExprKind, HirId, MatchSource, Node, PatKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
@@ -81,16 +81,24 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
                     }
                 }
                 if is_trait_method(cx, e, sym::IntoIterator) && name.ident.name == sym::into_iter {
-                    if let Some(parent_expr) = get_parent_expr(cx, e) {
-                        if let ExprKind::MethodCall(parent_name, ..) = parent_expr.kind {
-                            if parent_name.ident.name != sym::into_iter {
-                                return;
-                            }
-                        }
+                    if get_parent_expr(cx, e).is_some() &&
+                       let Some(id) = path_to_local(recv) &&
+                       let Node::Pat(pat) = cx.tcx.hir().get(id) &&
+                       let PatKind::Binding(ann, ..) = pat.kind &&
+                       ann != BindingAnnotation::MUT
+                    {
+                        // Do not remove .into_iter() applied to a non-mutable local variable used in
+                        // a larger expression context as it would differ in mutability.
+                        return;
                     }
+
                     let a = cx.typeck_results().expr_ty(e);
                     let b = cx.typeck_results().expr_ty(recv);
-                    if same_type_and_consts(a, b) {
+
+                    // If the types are identical then .into_iter() can be removed, unless the type
+                    // implements Copy, in which case .into_iter() returns a copy of the receiver and
+                    // cannot be safely omitted.
+                    if same_type_and_consts(a, b) && !is_copy(cx, b) {
                         let sugg = snippet(cx, recv.span, "<expr>").into_owned();
                         span_lint_and_sugg(
                             cx,
diff --git a/src/tools/clippy/clippy_lints/src/utils/conf.rs b/src/tools/clippy/clippy_lints/src/utils/conf.rs
index 3e7d0028c0f..c1589c771c4 100644
--- a/src/tools/clippy/clippy_lints/src/utils/conf.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/conf.rs
@@ -333,7 +333,7 @@ define_Conf! {
     /// Lint: LARGE_STACK_ARRAYS, LARGE_CONST_ARRAYS.
     ///
     /// The maximum allowed size for arrays on the stack
-    (array_size_threshold: u64 = 512_000),
+    (array_size_threshold: u128 = 512_000),
     /// Lint: VEC_BOX.
     ///
     /// The size of the boxed type in bytes, where boxing in a `Vec` is allowed
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs
index 857abe77e21..929544cd69d 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs
@@ -558,8 +558,8 @@ impl fmt::Display for ClippyConfiguration {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> fmt::Result {
         writeln!(
             f,
-            "* `{}`: `{}`: {} (defaults to `{}`)",
-            self.name, self.config_type, self.doc, self.default
+            "* `{}`: `{}`(defaults to `{}`): {}",
+            self.name, self.config_type, self.default, self.doc
         )
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/write.rs b/src/tools/clippy/clippy_lints/src/write.rs
index 6b321765bc0..df335038881 100644
--- a/src/tools/clippy/clippy_lints/src/write.rs
+++ b/src/tools/clippy/clippy_lints/src/write.rs
@@ -377,7 +377,7 @@ fn check_newline(cx: &LateContext<'_>, format_args: &FormatArgsExpn<'_>, macro_c
                     // print!("\n"), write!(f, "\n")
 
                     diag.multipart_suggestion(
-                        &format!("use `{name}ln!` instead"),
+                        format!("use `{name}ln!` instead"),
                         vec![(name_span, format!("{name}ln")), (format_string_span, String::new())],
                         Applicability::MachineApplicable,
                     );
@@ -388,7 +388,7 @@ fn check_newline(cx: &LateContext<'_>, format_args: &FormatArgsExpn<'_>, macro_c
                     let newline_span = format_string_span.with_lo(hi - BytePos(3)).with_hi(hi - BytePos(1));
 
                     diag.multipart_suggestion(
-                        &format!("use `{name}ln!` instead"),
+                        format!("use `{name}ln!` instead"),
                         vec![(name_span, format!("{name}ln")), (newline_span, String::new())],
                         Applicability::MachineApplicable,
                     );
diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs
index 7a637d32bab..a67bd8d4600 100644
--- a/src/tools/clippy/clippy_utils/src/consts.rs
+++ b/src/tools/clippy/clippy_utils/src/consts.rs
@@ -620,12 +620,7 @@ pub fn miri_to_const<'tcx>(tcx: TyCtxt<'tcx>, result: mir::ConstantKind<'tcx>) -
                 ty::Float(FloatTy::F64) => Some(Constant::F64(f64::from_bits(
                     int.try_into().expect("invalid f64 bit representation"),
                 ))),
-                ty::RawPtr(type_and_mut) => {
-                    if let ty::Uint(_) = type_and_mut.ty.kind() {
-                        return Some(Constant::RawPtr(int.assert_bits(int.size())));
-                    }
-                    None
-                },
+                ty::RawPtr(_) => Some(Constant::RawPtr(int.assert_bits(int.size()))),
                 // FIXME: implement other conversions.
                 _ => None,
             }
diff --git a/src/tools/clippy/clippy_utils/src/diagnostics.rs b/src/tools/clippy/clippy_utils/src/diagnostics.rs
index 16b160b6fd2..812f6fe71a0 100644
--- a/src/tools/clippy/clippy_utils/src/diagnostics.rs
+++ b/src/tools/clippy/clippy_utils/src/diagnostics.rs
@@ -17,7 +17,7 @@ use std::env;
 fn docs_link(diag: &mut Diagnostic, lint: &'static Lint) {
     if env::var("CLIPPY_DISABLE_DOCS_LINKS").is_err() {
         if let Some(lint) = lint.name_lower().strip_prefix("clippy::") {
-            diag.help(&format!(
+            diag.help(format!(
                 "for further information visit https://rust-lang.github.io/rust-clippy/{}/index.html#{lint}",
                 &option_env!("RUST_RELEASE_NUM").map_or("master".to_string(), |n| {
                     // extract just major + minor version and ignore patch versions
diff --git a/src/tools/clippy/clippy_utils/src/mir/maybe_storage_live.rs b/src/tools/clippy/clippy_utils/src/mir/maybe_storage_live.rs
deleted file mode 100644
index d262b335d99..00000000000
--- a/src/tools/clippy/clippy_utils/src/mir/maybe_storage_live.rs
+++ /dev/null
@@ -1,52 +0,0 @@
-use rustc_index::bit_set::BitSet;
-use rustc_middle::mir;
-use rustc_mir_dataflow::{AnalysisDomain, CallReturnPlaces, GenKill, GenKillAnalysis};
-
-/// Determines liveness of each local purely based on `StorageLive`/`Dead`.
-#[derive(Copy, Clone)]
-pub(super) struct MaybeStorageLive;
-
-impl<'tcx> AnalysisDomain<'tcx> for MaybeStorageLive {
-    type Domain = BitSet<mir::Local>;
-    const NAME: &'static str = "maybe_storage_live";
-
-    fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain {
-        // bottom = dead
-        BitSet::new_empty(body.local_decls.len())
-    }
-
-    fn initialize_start_block(&self, body: &mir::Body<'tcx>, state: &mut Self::Domain) {
-        for arg in body.args_iter() {
-            state.insert(arg);
-        }
-    }
-}
-
-impl<'tcx> GenKillAnalysis<'tcx> for MaybeStorageLive {
-    type Idx = mir::Local;
-
-    fn statement_effect(&self, trans: &mut impl GenKill<Self::Idx>, stmt: &mir::Statement<'tcx>, _: mir::Location) {
-        match stmt.kind {
-            mir::StatementKind::StorageLive(l) => trans.gen(l),
-            mir::StatementKind::StorageDead(l) => trans.kill(l),
-            _ => (),
-        }
-    }
-
-    fn terminator_effect(
-        &self,
-        _trans: &mut impl GenKill<Self::Idx>,
-        _terminator: &mir::Terminator<'tcx>,
-        _loc: mir::Location,
-    ) {
-    }
-
-    fn call_return_effect(
-        &self,
-        _trans: &mut impl GenKill<Self::Idx>,
-        _block: mir::BasicBlock,
-        _return_places: CallReturnPlaces<'_, 'tcx>,
-    ) {
-        // Nothing to do when a call returns successfully
-    }
-}
diff --git a/src/tools/clippy/clippy_utils/src/mir/mod.rs b/src/tools/clippy/clippy_utils/src/mir/mod.rs
index 818e603f665..26c0015e87e 100644
--- a/src/tools/clippy/clippy_utils/src/mir/mod.rs
+++ b/src/tools/clippy/clippy_utils/src/mir/mod.rs
@@ -5,8 +5,6 @@ use rustc_middle::mir::{
 };
 use rustc_middle::ty::TyCtxt;
 
-mod maybe_storage_live;
-
 mod possible_borrower;
 pub use possible_borrower::PossibleBorrowerMap;
 
diff --git a/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs b/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs
index 25717bf3d2f..395d46e7a2f 100644
--- a/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs
+++ b/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs
@@ -1,92 +1,137 @@
-use super::{
-    maybe_storage_live::MaybeStorageLive, possible_origin::PossibleOriginVisitor,
-    transitive_relation::TransitiveRelation,
-};
+use super::possible_origin::PossibleOriginVisitor;
 use crate::ty::is_copy;
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
 use rustc_index::bit_set::{BitSet, HybridBitSet};
 use rustc_lint::LateContext;
-use rustc_middle::mir::{self, visit::Visitor as _, Mutability};
-use rustc_middle::ty::{self, visit::TypeVisitor};
-use rustc_mir_dataflow::{Analysis, ResultsCursor};
+use rustc_middle::mir::{
+    self, visit::Visitor as _, BasicBlock, Local, Location, Mutability, Statement, StatementKind, Terminator,
+};
+use rustc_middle::ty::{self, visit::TypeVisitor, TyCtxt};
+use rustc_mir_dataflow::{
+    fmt::DebugWithContext, impls::MaybeStorageLive, lattice::JoinSemiLattice, Analysis, AnalysisDomain,
+    CallReturnPlaces, ResultsCursor,
+};
+use std::borrow::Cow;
 use std::ops::ControlFlow;
 
 /// Collects the possible borrowers of each local.
 /// For example, `b = &a; c = &a;` will make `b` and (transitively) `c`
 /// possible borrowers of `a`.
 #[allow(clippy::module_name_repetitions)]
-struct PossibleBorrowerVisitor<'a, 'b, 'tcx> {
-    possible_borrower: TransitiveRelation,
+struct PossibleBorrowerAnalysis<'b, 'tcx> {
+    tcx: TyCtxt<'tcx>,
     body: &'b mir::Body<'tcx>,
-    cx: &'a LateContext<'tcx>,
     possible_origin: FxHashMap<mir::Local, HybridBitSet<mir::Local>>,
 }
 
-impl<'a, 'b, 'tcx> PossibleBorrowerVisitor<'a, 'b, 'tcx> {
-    fn new(
-        cx: &'a LateContext<'tcx>,
-        body: &'b mir::Body<'tcx>,
-        possible_origin: FxHashMap<mir::Local, HybridBitSet<mir::Local>>,
-    ) -> Self {
+#[derive(Clone, Debug, Eq, PartialEq)]
+struct PossibleBorrowerState {
+    map: FxIndexMap<Local, BitSet<Local>>,
+    domain_size: usize,
+}
+
+impl PossibleBorrowerState {
+    fn new(domain_size: usize) -> Self {
         Self {
-            possible_borrower: TransitiveRelation::default(),
-            cx,
-            body,
-            possible_origin,
+            map: FxIndexMap::default(),
+            domain_size,
         }
     }
 
-    fn into_map(
-        self,
-        cx: &'a LateContext<'tcx>,
-        maybe_live: ResultsCursor<'b, 'tcx, MaybeStorageLive>,
-    ) -> PossibleBorrowerMap<'b, 'tcx> {
-        let mut map = FxHashMap::default();
-        for row in (1..self.body.local_decls.len()).map(mir::Local::from_usize) {
-            if is_copy(cx, self.body.local_decls[row].ty) {
-                continue;
-            }
+    #[allow(clippy::similar_names)]
+    fn add(&mut self, borrowed: Local, borrower: Local) {
+        self.map
+            .entry(borrowed)
+            .or_insert(BitSet::new_empty(self.domain_size))
+            .insert(borrower);
+    }
+}
 
-            let mut borrowers = self.possible_borrower.reachable_from(row, self.body.local_decls.len());
-            borrowers.remove(mir::Local::from_usize(0));
+impl<C> DebugWithContext<C> for PossibleBorrowerState {
+    fn fmt_with(&self, _ctxt: &C, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        <_ as std::fmt::Debug>::fmt(self, f)
+    }
+    fn fmt_diff_with(&self, _old: &Self, _ctxt: &C, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        unimplemented!()
+    }
+}
+
+impl JoinSemiLattice for PossibleBorrowerState {
+    fn join(&mut self, other: &Self) -> bool {
+        let mut changed = false;
+        for (&borrowed, borrowers) in other.map.iter() {
             if !borrowers.is_empty() {
-                map.insert(row, borrowers);
+                changed |= self
+                    .map
+                    .entry(borrowed)
+                    .or_insert(BitSet::new_empty(self.domain_size))
+                    .union(borrowers);
             }
         }
+        changed
+    }
+}
 
-        let bs = BitSet::new_empty(self.body.local_decls.len());
-        PossibleBorrowerMap {
-            map,
-            maybe_live,
-            bitset: (bs.clone(), bs),
+impl<'b, 'tcx> AnalysisDomain<'tcx> for PossibleBorrowerAnalysis<'b, 'tcx> {
+    type Domain = PossibleBorrowerState;
+
+    const NAME: &'static str = "possible_borrower";
+
+    fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain {
+        PossibleBorrowerState::new(body.local_decls.len())
+    }
+
+    fn initialize_start_block(&self, _body: &mir::Body<'tcx>, _entry_set: &mut Self::Domain) {}
+}
+
+impl<'b, 'tcx> PossibleBorrowerAnalysis<'b, 'tcx> {
+    fn new(
+        tcx: TyCtxt<'tcx>,
+        body: &'b mir::Body<'tcx>,
+        possible_origin: FxHashMap<mir::Local, HybridBitSet<mir::Local>>,
+    ) -> Self {
+        Self {
+            tcx,
+            body,
+            possible_origin,
         }
     }
 }
 
-impl<'a, 'b, 'tcx> mir::visit::Visitor<'tcx> for PossibleBorrowerVisitor<'a, 'b, 'tcx> {
-    fn visit_assign(&mut self, place: &mir::Place<'tcx>, rvalue: &mir::Rvalue<'_>, _location: mir::Location) {
-        let lhs = place.local;
-        match rvalue {
-            mir::Rvalue::Ref(_, _, borrowed) => {
-                self.possible_borrower.add(borrowed.local, lhs);
-            },
-            other => {
-                if ContainsRegion
-                    .visit_ty(place.ty(&self.body.local_decls, self.cx.tcx).ty)
-                    .is_continue()
-                {
-                    return;
-                }
-                rvalue_locals(other, |rhs| {
-                    if lhs != rhs {
-                        self.possible_borrower.add(rhs, lhs);
+impl<'b, 'tcx> Analysis<'tcx> for PossibleBorrowerAnalysis<'b, 'tcx> {
+    fn apply_call_return_effect(
+        &self,
+        _state: &mut Self::Domain,
+        _block: BasicBlock,
+        _return_places: CallReturnPlaces<'_, 'tcx>,
+    ) {
+    }
+
+    fn apply_statement_effect(&self, state: &mut Self::Domain, statement: &Statement<'tcx>, _location: Location) {
+        if let StatementKind::Assign(box (place, rvalue)) = &statement.kind {
+            let lhs = place.local;
+            match rvalue {
+                mir::Rvalue::Ref(_, _, borrowed) => {
+                    state.add(borrowed.local, lhs);
+                },
+                other => {
+                    if ContainsRegion
+                        .visit_ty(place.ty(&self.body.local_decls, self.tcx).ty)
+                        .is_continue()
+                    {
+                        return;
                     }
-                });
-            },
+                    rvalue_locals(other, |rhs| {
+                        if lhs != rhs {
+                            state.add(rhs, lhs);
+                        }
+                    });
+                },
+            }
         }
     }
 
-    fn visit_terminator(&mut self, terminator: &mir::Terminator<'_>, _loc: mir::Location) {
+    fn apply_terminator_effect(&self, state: &mut Self::Domain, terminator: &Terminator<'tcx>, _location: Location) {
         if let mir::TerminatorKind::Call {
             args,
             destination: mir::Place { local: dest, .. },
@@ -126,10 +171,10 @@ impl<'a, 'b, 'tcx> mir::visit::Visitor<'tcx> for PossibleBorrowerVisitor<'a, 'b,
 
             for y in mutable_variables {
                 for x in &immutable_borrowers {
-                    self.possible_borrower.add(*x, y);
+                    state.add(*x, y);
                 }
                 for x in &mutable_borrowers {
-                    self.possible_borrower.add(*x, y);
+                    state.add(*x, y);
                 }
             }
         }
@@ -165,73 +210,98 @@ fn rvalue_locals(rvalue: &mir::Rvalue<'_>, mut visit: impl FnMut(mir::Local)) {
     }
 }
 
-/// Result of `PossibleBorrowerVisitor`.
+/// Result of `PossibleBorrowerAnalysis`.
 #[allow(clippy::module_name_repetitions)]
 pub struct PossibleBorrowerMap<'b, 'tcx> {
-    /// Mapping `Local -> its possible borrowers`
-    pub map: FxHashMap<mir::Local, HybridBitSet<mir::Local>>,
-    maybe_live: ResultsCursor<'b, 'tcx, MaybeStorageLive>,
-    // Caches to avoid allocation of `BitSet` on every query
-    pub bitset: (BitSet<mir::Local>, BitSet<mir::Local>),
+    body: &'b mir::Body<'tcx>,
+    possible_borrower: ResultsCursor<'b, 'tcx, PossibleBorrowerAnalysis<'b, 'tcx>>,
+    maybe_live: ResultsCursor<'b, 'tcx, MaybeStorageLive<'b>>,
+    pushed: BitSet<Local>,
+    stack: Vec<Local>,
 }
 
-impl<'a, 'b, 'tcx> PossibleBorrowerMap<'b, 'tcx> {
-    pub fn new(cx: &'a LateContext<'tcx>, mir: &'b mir::Body<'tcx>) -> Self {
+impl<'b, 'tcx> PossibleBorrowerMap<'b, 'tcx> {
+    pub fn new(cx: &LateContext<'tcx>, mir: &'b mir::Body<'tcx>) -> Self {
         let possible_origin = {
             let mut vis = PossibleOriginVisitor::new(mir);
             vis.visit_body(mir);
             vis.into_map(cx)
         };
-        let maybe_storage_live_result = MaybeStorageLive
+        let possible_borrower = PossibleBorrowerAnalysis::new(cx.tcx, mir, possible_origin)
             .into_engine(cx.tcx, mir)
-            .pass_name("redundant_clone")
+            .pass_name("possible_borrower")
             .iterate_to_fixpoint()
             .into_results_cursor(mir);
-        let mut vis = PossibleBorrowerVisitor::new(cx, mir, possible_origin);
-        vis.visit_body(mir);
-        vis.into_map(cx, maybe_storage_live_result)
-    }
-
-    /// Returns true if the set of borrowers of `borrowed` living at `at` matches with `borrowers`.
-    pub fn only_borrowers(&mut self, borrowers: &[mir::Local], borrowed: mir::Local, at: mir::Location) -> bool {
-        self.bounded_borrowers(borrowers, borrowers, borrowed, at)
+        let maybe_live = MaybeStorageLive::new(Cow::Owned(BitSet::new_empty(mir.local_decls.len())))
+            .into_engine(cx.tcx, mir)
+            .pass_name("possible_borrower")
+            .iterate_to_fixpoint()
+            .into_results_cursor(mir);
+        PossibleBorrowerMap {
+            body: mir,
+            possible_borrower,
+            maybe_live,
+            pushed: BitSet::new_empty(mir.local_decls.len()),
+            stack: Vec::with_capacity(mir.local_decls.len()),
+        }
     }
 
-    /// Returns true if the set of borrowers of `borrowed` living at `at` includes at least `below`
-    /// but no more than `above`.
-    pub fn bounded_borrowers(
+    /// Returns true if the set of borrowers of `borrowed` living at `at` includes no more than
+    /// `borrowers`.
+    /// Notes:
+    /// 1. It would be nice if `PossibleBorrowerMap` could store `cx` so that `at_most_borrowers`
+    /// would not require it to be passed in. But a `PossibleBorrowerMap` is stored in `LintPass`
+    /// `Dereferencing`, which outlives any `LateContext`.
+    /// 2. In all current uses of `at_most_borrowers`, `borrowers` is a slice of at most two
+    /// elements. Thus, `borrowers.contains(...)` is effectively a constant-time operation. If
+    /// `at_most_borrowers`'s uses were to expand beyond this, its implementation might have to be
+    /// adjusted.
+    pub fn at_most_borrowers(
         &mut self,
-        below: &[mir::Local],
-        above: &[mir::Local],
+        cx: &LateContext<'tcx>,
+        borrowers: &[mir::Local],
         borrowed: mir::Local,
         at: mir::Location,
     ) -> bool {
-        self.maybe_live.seek_after_primary_effect(at);
+        if is_copy(cx, self.body.local_decls[borrowed].ty) {
+            return true;
+        }
 
-        self.bitset.0.clear();
-        let maybe_live = &mut self.maybe_live;
-        if let Some(bitset) = self.map.get(&borrowed) {
-            for b in bitset.iter().filter(move |b| maybe_live.contains(*b)) {
-                self.bitset.0.insert(b);
+        self.possible_borrower.seek_before_primary_effect(at);
+        self.maybe_live.seek_before_primary_effect(at);
+
+        let possible_borrower = &self.possible_borrower.get().map;
+        let maybe_live = &self.maybe_live;
+
+        self.pushed.clear();
+        self.stack.clear();
+
+        if let Some(borrowers) = possible_borrower.get(&borrowed) {
+            for b in borrowers.iter() {
+                if self.pushed.insert(b) {
+                    self.stack.push(b);
+                }
             }
         } else {
-            return false;
+            // Nothing borrows `borrowed` at `at`.
+            return true;
         }
 
-        self.bitset.1.clear();
-        for b in below {
-            self.bitset.1.insert(*b);
-        }
-
-        if !self.bitset.0.superset(&self.bitset.1) {
-            return false;
-        }
+        while let Some(borrower) = self.stack.pop() {
+            if maybe_live.contains(borrower) && !borrowers.contains(&borrower) {
+                return false;
+            }
 
-        for b in above {
-            self.bitset.0.remove(*b);
+            if let Some(borrowers) = possible_borrower.get(&borrower) {
+                for b in borrowers.iter() {
+                    if self.pushed.insert(b) {
+                        self.stack.push(b);
+                    }
+                }
+            }
         }
 
-        self.bitset.0.is_empty()
+        true
     }
 
     pub fn local_is_alive_at(&mut self, local: mir::Local, at: mir::Location) -> bool {
diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs
index b66604f33db..4c4c077d771 100644
--- a/src/tools/clippy/clippy_utils/src/sugg.rs
+++ b/src/tools/clippy/clippy_utils/src/sugg.rs
@@ -185,7 +185,6 @@ impl<'a> Sugg<'a> {
     ) -> Self {
         use rustc_ast::ast::RangeLimits;
 
-        #[expect(clippy::match_wildcard_for_single_variants)]
         match expr.kind {
             _ if expr.span.ctxt() != ctxt => Sugg::NonParen(snippet_with_context(cx, expr.span, ctxt, default, app).0),
             ast::ExprKind::AddrOf(..)
diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain
index 8e21cef32ab..9399d422036 100644
--- a/src/tools/clippy/rust-toolchain
+++ b/src/tools/clippy/rust-toolchain
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2022-12-17"
+channel = "nightly-2022-12-29"
 components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
diff --git a/src/tools/clippy/tests/ui/crashes/ice-10044.rs b/src/tools/clippy/tests/ui/crashes/ice-10044.rs
new file mode 100644
index 00000000000..65f38fe7118
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-10044.rs
@@ -0,0 +1,3 @@
+fn main() {
+    [0; usize::MAX];
+}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-10044.stderr b/src/tools/clippy/tests/ui/crashes/ice-10044.stderr
new file mode 100644
index 00000000000..731f8265ad6
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-10044.stderr
@@ -0,0 +1,10 @@
+error: statement with no effect
+  --> $DIR/ice-10044.rs:2:5
+   |
+LL |     [0; usize::MAX];
+   |     ^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::no-effect` implied by `-D warnings`
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/floating_point_powi.fixed b/src/tools/clippy/tests/ui/floating_point_powi.fixed
index 884d05fed71..8ffd4cc5137 100644
--- a/src/tools/clippy/tests/ui/floating_point_powi.fixed
+++ b/src/tools/clippy/tests/ui/floating_point_powi.fixed
@@ -14,6 +14,15 @@ fn main() {
     let _ = (y as f32).mul_add(y as f32, x);
     let _ = x.mul_add(x, y).sqrt();
     let _ = y.mul_add(y, x).sqrt();
+
+    let _ = (x - 1.0).mul_add(x - 1.0, -y);
+    let _ = (x - 1.0).mul_add(x - 1.0, -y) + 3.0;
+    let _ = (x - 1.0).mul_add(x - 1.0, -(y + 3.0));
+    let _ = (y + 1.0).mul_add(-(y + 1.0), x);
+    let _ = (3.0 * y).mul_add(-(3.0 * y), x);
+    let _ = (y + 1.0 + x).mul_add(-(y + 1.0 + x), x);
+    let _ = (y + 1.0 + 2.0).mul_add(-(y + 1.0 + 2.0), x);
+
     // Cases where the lint shouldn't be applied
     let _ = x.powi(2);
     let _ = x.powi(1 + 1);
diff --git a/src/tools/clippy/tests/ui/floating_point_powi.rs b/src/tools/clippy/tests/ui/floating_point_powi.rs
index e6a1c895371..9ae3455a134 100644
--- a/src/tools/clippy/tests/ui/floating_point_powi.rs
+++ b/src/tools/clippy/tests/ui/floating_point_powi.rs
@@ -14,6 +14,15 @@ fn main() {
     let _ = x + (y as f32).powi(2);
     let _ = (x.powi(2) + y).sqrt();
     let _ = (x + y.powi(2)).sqrt();
+
+    let _ = (x - 1.0).powi(2) - y;
+    let _ = (x - 1.0).powi(2) - y + 3.0;
+    let _ = (x - 1.0).powi(2) - (y + 3.0);
+    let _ = x - (y + 1.0).powi(2);
+    let _ = x - (3.0 * y).powi(2);
+    let _ = x - (y + 1.0 + x).powi(2);
+    let _ = x - (y + 1.0 + 2.0).powi(2);
+
     // Cases where the lint shouldn't be applied
     let _ = x.powi(2);
     let _ = x.powi(1 + 1);
diff --git a/src/tools/clippy/tests/ui/floating_point_powi.stderr b/src/tools/clippy/tests/ui/floating_point_powi.stderr
index 5df0de1fef2..fdf6d088052 100644
--- a/src/tools/clippy/tests/ui/floating_point_powi.stderr
+++ b/src/tools/clippy/tests/ui/floating_point_powi.stderr
@@ -42,5 +42,47 @@ error: multiply and add expressions can be calculated more efficiently and accur
 LL |     let _ = (x + y.powi(2)).sqrt();
    |             ^^^^^^^^^^^^^^^ help: consider using: `y.mul_add(y, x)`
 
-error: aborting due to 7 previous errors
+error: multiply and add expressions can be calculated more efficiently and accurately
+  --> $DIR/floating_point_powi.rs:18:13
+   |
+LL |     let _ = (x - 1.0).powi(2) - y;
+   |             ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x - 1.0).mul_add(x - 1.0, -y)`
+
+error: multiply and add expressions can be calculated more efficiently and accurately
+  --> $DIR/floating_point_powi.rs:19:13
+   |
+LL |     let _ = (x - 1.0).powi(2) - y + 3.0;
+   |             ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x - 1.0).mul_add(x - 1.0, -y)`
+
+error: multiply and add expressions can be calculated more efficiently and accurately
+  --> $DIR/floating_point_powi.rs:20:13
+   |
+LL |     let _ = (x - 1.0).powi(2) - (y + 3.0);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x - 1.0).mul_add(x - 1.0, -(y + 3.0))`
+
+error: multiply and add expressions can be calculated more efficiently and accurately
+  --> $DIR/floating_point_powi.rs:21:13
+   |
+LL |     let _ = x - (y + 1.0).powi(2);
+   |             ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(y + 1.0).mul_add(-(y + 1.0), x)`
+
+error: multiply and add expressions can be calculated more efficiently and accurately
+  --> $DIR/floating_point_powi.rs:22:13
+   |
+LL |     let _ = x - (3.0 * y).powi(2);
+   |             ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(3.0 * y).mul_add(-(3.0 * y), x)`
+
+error: multiply and add expressions can be calculated more efficiently and accurately
+  --> $DIR/floating_point_powi.rs:23:13
+   |
+LL |     let _ = x - (y + 1.0 + x).powi(2);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(y + 1.0 + x).mul_add(-(y + 1.0 + x), x)`
+
+error: multiply and add expressions can be calculated more efficiently and accurately
+  --> $DIR/floating_point_powi.rs:24:13
+   |
+LL |     let _ = x - (y + 1.0 + 2.0).powi(2);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(y + 1.0 + 2.0).mul_add(-(y + 1.0 + 2.0), x)`
+
+error: aborting due to 14 previous errors
 
diff --git a/src/tools/clippy/tests/ui/fn_null_check.rs b/src/tools/clippy/tests/ui/fn_null_check.rs
new file mode 100644
index 00000000000..df5bc8420d5
--- /dev/null
+++ b/src/tools/clippy/tests/ui/fn_null_check.rs
@@ -0,0 +1,21 @@
+#![allow(unused)]
+#![warn(clippy::fn_null_check)]
+#![allow(clippy::cmp_null)]
+#![allow(clippy::ptr_eq)]
+#![allow(clippy::zero_ptr)]
+
+pub const ZPTR: *const () = 0 as *const _;
+pub const NOT_ZPTR: *const () = 1 as *const _;
+
+fn main() {
+    let fn_ptr = main;
+
+    if (fn_ptr as *mut ()).is_null() {}
+    if (fn_ptr as *const u8).is_null() {}
+    if (fn_ptr as *const ()) == std::ptr::null() {}
+    if (fn_ptr as *const ()) == (0 as *const ()) {}
+    if (fn_ptr as *const ()) == ZPTR {}
+
+    // no lint
+    if (fn_ptr as *const ()) == NOT_ZPTR {}
+}
diff --git a/src/tools/clippy/tests/ui/fn_null_check.stderr b/src/tools/clippy/tests/ui/fn_null_check.stderr
new file mode 100644
index 00000000000..660dd323979
--- /dev/null
+++ b/src/tools/clippy/tests/ui/fn_null_check.stderr
@@ -0,0 +1,43 @@
+error: function pointer assumed to be nullable, even though it isn't
+  --> $DIR/fn_null_check.rs:13:8
+   |
+LL |     if (fn_ptr as *mut ()).is_null() {}
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: try wrapping your function pointer type in `Option<T>` instead, and using `is_none` to check for null pointer value
+   = note: `-D clippy::fn-null-check` implied by `-D warnings`
+
+error: function pointer assumed to be nullable, even though it isn't
+  --> $DIR/fn_null_check.rs:14:8
+   |
+LL |     if (fn_ptr as *const u8).is_null() {}
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: try wrapping your function pointer type in `Option<T>` instead, and using `is_none` to check for null pointer value
+
+error: function pointer assumed to be nullable, even though it isn't
+  --> $DIR/fn_null_check.rs:15:8
+   |
+LL |     if (fn_ptr as *const ()) == std::ptr::null() {}
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: try wrapping your function pointer type in `Option<T>` instead, and using `is_none` to check for null pointer value
+
+error: function pointer assumed to be nullable, even though it isn't
+  --> $DIR/fn_null_check.rs:16:8
+   |
+LL |     if (fn_ptr as *const ()) == (0 as *const ()) {}
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: try wrapping your function pointer type in `Option<T>` instead, and using `is_none` to check for null pointer value
+
+error: function pointer assumed to be nullable, even though it isn't
+  --> $DIR/fn_null_check.rs:17:8
+   |
+LL |     if (fn_ptr as *const ()) == ZPTR {}
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: try wrapping your function pointer type in `Option<T>` instead, and using `is_none` to check for null pointer value
+
+error: aborting due to 5 previous errors
+
diff --git a/src/tools/clippy/tests/ui/manual_filter.fixed b/src/tools/clippy/tests/ui/manual_filter.fixed
index 3553291b87d..ef6780dc96d 100644
--- a/src/tools/clippy/tests/ui/manual_filter.fixed
+++ b/src/tools/clippy/tests/ui/manual_filter.fixed
@@ -116,4 +116,45 @@ fn main() {
         },
         None => None,
     };
+
+    match Some(20) {
+        // Don't Lint, because `Some(3*x)` is not `None`
+        None => None,
+        Some(x) => {
+            if x > 0 {
+                Some(3 * x)
+            } else {
+                Some(x)
+            }
+        },
+    };
+
+    // Don't lint: https://github.com/rust-lang/rust-clippy/issues/10088
+    let result = if let Some(a) = maybe_some() {
+        if let Some(b) = maybe_some() {
+            Some(a + b)
+        } else {
+            Some(a)
+        }
+    } else {
+        None
+    };
+
+    let allowed_integers = vec![3, 4, 5, 6];
+    // Don't lint, since there's a side effect in the else branch
+    match Some(21) {
+        Some(x) => {
+            if allowed_integers.contains(&x) {
+                Some(x)
+            } else {
+                println!("Invalid integer: {x:?}");
+                None
+            }
+        },
+        None => None,
+    };
+}
+
+fn maybe_some() -> Option<u32> {
+    Some(0)
 }
diff --git a/src/tools/clippy/tests/ui/manual_filter.rs b/src/tools/clippy/tests/ui/manual_filter.rs
index aa9f90f752b..ea0ce83172b 100644
--- a/src/tools/clippy/tests/ui/manual_filter.rs
+++ b/src/tools/clippy/tests/ui/manual_filter.rs
@@ -240,4 +240,45 @@ fn main() {
         },
         None => None,
     };
+
+    match Some(20) {
+        // Don't Lint, because `Some(3*x)` is not `None`
+        None => None,
+        Some(x) => {
+            if x > 0 {
+                Some(3 * x)
+            } else {
+                Some(x)
+            }
+        },
+    };
+
+    // Don't lint: https://github.com/rust-lang/rust-clippy/issues/10088
+    let result = if let Some(a) = maybe_some() {
+        if let Some(b) = maybe_some() {
+            Some(a + b)
+        } else {
+            Some(a)
+        }
+    } else {
+        None
+    };
+
+    let allowed_integers = vec![3, 4, 5, 6];
+    // Don't lint, since there's a side effect in the else branch
+    match Some(21) {
+        Some(x) => {
+            if allowed_integers.contains(&x) {
+                Some(x)
+            } else {
+                println!("Invalid integer: {x:?}");
+                None
+            }
+        },
+        None => None,
+    };
+}
+
+fn maybe_some() -> Option<u32> {
+    Some(0)
 }
diff --git a/src/tools/clippy/tests/ui/manual_retain.fixed b/src/tools/clippy/tests/ui/manual_retain.fixed
index e5ae3cf3e50..8f25fea678f 100644
--- a/src/tools/clippy/tests/ui/manual_retain.fixed
+++ b/src/tools/clippy/tests/ui/manual_retain.fixed
@@ -1,6 +1,6 @@
 // run-rustfix
 #![warn(clippy::manual_retain)]
-#![allow(unused)]
+#![allow(unused, clippy::redundant_clone)]
 use std::collections::BTreeMap;
 use std::collections::BTreeSet;
 use std::collections::BinaryHeap;
diff --git a/src/tools/clippy/tests/ui/manual_retain.rs b/src/tools/clippy/tests/ui/manual_retain.rs
index 1021f15edd1..e6b3995a689 100644
--- a/src/tools/clippy/tests/ui/manual_retain.rs
+++ b/src/tools/clippy/tests/ui/manual_retain.rs
@@ -1,6 +1,6 @@
 // run-rustfix
 #![warn(clippy::manual_retain)]
-#![allow(unused)]
+#![allow(unused, clippy::redundant_clone)]
 use std::collections::BTreeMap;
 use std::collections::BTreeSet;
 use std::collections::BinaryHeap;
diff --git a/src/tools/clippy/tests/ui/match_single_binding.fixed b/src/tools/clippy/tests/ui/match_single_binding.fixed
index a6e315e4773..6cfb6661a03 100644
--- a/src/tools/clippy/tests/ui/match_single_binding.fixed
+++ b/src/tools/clippy/tests/ui/match_single_binding.fixed
@@ -133,3 +133,16 @@ fn issue_9575() {
         println!("Needs curlies");
     };
 }
+
+#[allow(dead_code)]
+fn issue_9725(r: Option<u32>) {
+    let x = r;
+    match x {
+        Some(_) => {
+            println!("Some");
+        },
+        None => {
+            println!("None");
+        },
+    };
+}
diff --git a/src/tools/clippy/tests/ui/match_single_binding.rs b/src/tools/clippy/tests/ui/match_single_binding.rs
index cecbd703e56..f188aeb5f2f 100644
--- a/src/tools/clippy/tests/ui/match_single_binding.rs
+++ b/src/tools/clippy/tests/ui/match_single_binding.rs
@@ -148,3 +148,17 @@ fn issue_9575() {
         _ => println!("Needs curlies"),
     };
 }
+
+#[allow(dead_code)]
+fn issue_9725(r: Option<u32>) {
+    match r {
+        x => match x {
+            Some(_) => {
+                println!("Some");
+            },
+            None => {
+                println!("None");
+            },
+        },
+    };
+}
diff --git a/src/tools/clippy/tests/ui/match_single_binding.stderr b/src/tools/clippy/tests/ui/match_single_binding.stderr
index 2b9ec7ee702..e960d64ad2b 100644
--- a/src/tools/clippy/tests/ui/match_single_binding.stderr
+++ b/src/tools/clippy/tests/ui/match_single_binding.stderr
@@ -213,5 +213,30 @@ LL +         println!("Needs curlies");
 LL ~     };
    |
 
-error: aborting due to 14 previous errors
+error: this match could be written as a `let` statement
+  --> $DIR/match_single_binding.rs:154:5
+   |
+LL | /     match r {
+LL | |         x => match x {
+LL | |             Some(_) => {
+LL | |                 println!("Some");
+...  |
+LL | |         },
+LL | |     };
+   | |_____^
+   |
+help: consider using a `let` statement
+   |
+LL ~     let x = r;
+LL +     match x {
+LL +         Some(_) => {
+LL +             println!("Some");
+LL +         },
+LL +         None => {
+LL +             println!("None");
+LL +         },
+LL ~     };
+   |
+
+error: aborting due to 15 previous errors
 
diff --git a/src/tools/clippy/tests/ui/match_wildcard_for_single_variants.fixed b/src/tools/clippy/tests/ui/match_wildcard_for_single_variants.fixed
index e675c183ea7..fc252cdd352 100644
--- a/src/tools/clippy/tests/ui/match_wildcard_for_single_variants.fixed
+++ b/src/tools/clippy/tests/ui/match_wildcard_for_single_variants.fixed
@@ -132,3 +132,25 @@ fn main() {
         }
     }
 }
+
+mod issue9993 {
+    enum Foo {
+        A(bool),
+        B,
+    }
+
+    fn test() {
+        let _ = match Foo::A(true) {
+            _ if false => 0,
+            Foo::A(true) => 1,
+            Foo::A(false) => 2,
+            Foo::B => 3,
+        };
+
+        let _ = match Foo::B {
+            _ if false => 0,
+            Foo::A(_) => 1,
+            Foo::B => 2,
+        };
+    }
+}
diff --git a/src/tools/clippy/tests/ui/match_wildcard_for_single_variants.rs b/src/tools/clippy/tests/ui/match_wildcard_for_single_variants.rs
index 38c3ffc00c7..9a5c849e6ec 100644
--- a/src/tools/clippy/tests/ui/match_wildcard_for_single_variants.rs
+++ b/src/tools/clippy/tests/ui/match_wildcard_for_single_variants.rs
@@ -132,3 +132,25 @@ fn main() {
         }
     }
 }
+
+mod issue9993 {
+    enum Foo {
+        A(bool),
+        B,
+    }
+
+    fn test() {
+        let _ = match Foo::A(true) {
+            _ if false => 0,
+            Foo::A(true) => 1,
+            Foo::A(false) => 2,
+            Foo::B => 3,
+        };
+
+        let _ = match Foo::B {
+            _ if false => 0,
+            Foo::A(_) => 1,
+            _ => 2,
+        };
+    }
+}
diff --git a/src/tools/clippy/tests/ui/match_wildcard_for_single_variants.stderr b/src/tools/clippy/tests/ui/match_wildcard_for_single_variants.stderr
index 34538dea8e5..6fa313dc911 100644
--- a/src/tools/clippy/tests/ui/match_wildcard_for_single_variants.stderr
+++ b/src/tools/clippy/tests/ui/match_wildcard_for_single_variants.stderr
@@ -48,5 +48,11 @@ error: wildcard matches only a single variant and will also match any future add
 LL |         _ => (),
    |         ^ help: try this: `Color::Blue`
 
-error: aborting due to 8 previous errors
+error: wildcard matches only a single variant and will also match any future added variants
+  --> $DIR/match_wildcard_for_single_variants.rs:153:13
+   |
+LL |             _ => 2,
+   |             ^ help: try this: `Foo::B`
+
+error: aborting due to 9 previous errors
 
diff --git a/src/tools/clippy/tests/ui/needless_borrow.fixed b/src/tools/clippy/tests/ui/needless_borrow.fixed
index 4cb7f6b687f..31e1cb6c3d7 100644
--- a/src/tools/clippy/tests/ui/needless_borrow.fixed
+++ b/src/tools/clippy/tests/ui/needless_borrow.fixed
@@ -1,5 +1,5 @@
 // run-rustfix
-#![feature(lint_reasons)]
+#![feature(custom_inner_attributes, lint_reasons, rustc_private)]
 #![allow(
     unused,
     clippy::uninlined_format_args,
@@ -491,3 +491,14 @@ mod issue_9782_method_variant {
         S.foo::<&[u8; 100]>(&a);
     }
 }
+
+extern crate rustc_lint;
+extern crate rustc_span;
+
+#[allow(dead_code)]
+mod span_lint {
+    use rustc_lint::{LateContext, Lint, LintContext};
+    fn foo(cx: &LateContext<'_>, lint: &'static Lint) {
+        cx.struct_span_lint(lint, rustc_span::Span::default(), "", |diag| diag.note(String::new()));
+    }
+}
diff --git a/src/tools/clippy/tests/ui/needless_borrow.rs b/src/tools/clippy/tests/ui/needless_borrow.rs
index 9a01190ed8d..55c2738fcf2 100644
--- a/src/tools/clippy/tests/ui/needless_borrow.rs
+++ b/src/tools/clippy/tests/ui/needless_borrow.rs
@@ -1,5 +1,5 @@
 // run-rustfix
-#![feature(lint_reasons)]
+#![feature(custom_inner_attributes, lint_reasons, rustc_private)]
 #![allow(
     unused,
     clippy::uninlined_format_args,
@@ -491,3 +491,14 @@ mod issue_9782_method_variant {
         S.foo::<&[u8; 100]>(&a);
     }
 }
+
+extern crate rustc_lint;
+extern crate rustc_span;
+
+#[allow(dead_code)]
+mod span_lint {
+    use rustc_lint::{LateContext, Lint, LintContext};
+    fn foo(cx: &LateContext<'_>, lint: &'static Lint) {
+        cx.struct_span_lint(lint, rustc_span::Span::default(), "", |diag| diag.note(&String::new()));
+    }
+}
diff --git a/src/tools/clippy/tests/ui/needless_borrow.stderr b/src/tools/clippy/tests/ui/needless_borrow.stderr
index d26c317124b..98a48d68317 100644
--- a/src/tools/clippy/tests/ui/needless_borrow.stderr
+++ b/src/tools/clippy/tests/ui/needless_borrow.stderr
@@ -216,5 +216,11 @@ error: the borrowed expression implements the required traits
 LL |         foo(&a);
    |             ^^ help: change this to: `a`
 
-error: aborting due to 36 previous errors
+error: the borrowed expression implements the required traits
+  --> $DIR/needless_borrow.rs:502:85
+   |
+LL |         cx.struct_span_lint(lint, rustc_span::Span::default(), "", |diag| diag.note(&String::new()));
+   |                                                                                     ^^^^^^^^^^^^^^ help: change this to: `String::new()`
+
+error: aborting due to 37 previous errors
 
diff --git a/src/tools/clippy/tests/ui/needless_return.fixed b/src/tools/clippy/tests/ui/needless_return.fixed
index 4386aaec49e..d451be1f389 100644
--- a/src/tools/clippy/tests/ui/needless_return.fixed
+++ b/src/tools/clippy/tests/ui/needless_return.fixed
@@ -1,6 +1,7 @@
 // run-rustfix
 
 #![feature(lint_reasons)]
+#![feature(yeet_expr)]
 #![allow(unused)]
 #![allow(
     clippy::if_same_then_else,
@@ -272,4 +273,8 @@ mod issue9416 {
     }
 }
 
+fn issue9947() -> Result<(), String> {
+    do yeet "hello";
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/needless_return.rs b/src/tools/clippy/tests/ui/needless_return.rs
index 666dc54b76b..e1a1bea2c0b 100644
--- a/src/tools/clippy/tests/ui/needless_return.rs
+++ b/src/tools/clippy/tests/ui/needless_return.rs
@@ -1,6 +1,7 @@
 // run-rustfix
 
 #![feature(lint_reasons)]
+#![feature(yeet_expr)]
 #![allow(unused)]
 #![allow(
     clippy::if_same_then_else,
@@ -282,4 +283,8 @@ mod issue9416 {
     }
 }
 
+fn issue9947() -> Result<(), String> {
+    do yeet "hello";
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/needless_return.stderr b/src/tools/clippy/tests/ui/needless_return.stderr
index a8b5d86cd55..ca2253e6586 100644
--- a/src/tools/clippy/tests/ui/needless_return.stderr
+++ b/src/tools/clippy/tests/ui/needless_return.stderr
@@ -1,5 +1,5 @@
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:26:5
+  --> $DIR/needless_return.rs:27:5
    |
 LL |     return true;
    |     ^^^^^^^^^^^
@@ -8,7 +8,7 @@ LL |     return true;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:30:5
+  --> $DIR/needless_return.rs:31:5
    |
 LL |     return true;
    |     ^^^^^^^^^^^
@@ -16,7 +16,7 @@ LL |     return true;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:35:9
+  --> $DIR/needless_return.rs:36:9
    |
 LL |         return true;
    |         ^^^^^^^^^^^
@@ -24,7 +24,7 @@ LL |         return true;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:37:9
+  --> $DIR/needless_return.rs:38:9
    |
 LL |         return false;
    |         ^^^^^^^^^^^^
@@ -32,7 +32,7 @@ LL |         return false;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:43:17
+  --> $DIR/needless_return.rs:44:17
    |
 LL |         true => return false,
    |                 ^^^^^^^^^^^^
@@ -40,7 +40,7 @@ LL |         true => return false,
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:45:13
+  --> $DIR/needless_return.rs:46:13
    |
 LL |             return true;
    |             ^^^^^^^^^^^
@@ -48,7 +48,7 @@ LL |             return true;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:52:9
+  --> $DIR/needless_return.rs:53:9
    |
 LL |         return true;
    |         ^^^^^^^^^^^
@@ -56,7 +56,7 @@ LL |         return true;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:54:16
+  --> $DIR/needless_return.rs:55:16
    |
 LL |     let _ = || return true;
    |                ^^^^^^^^^^^
@@ -64,7 +64,7 @@ LL |     let _ = || return true;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:58:5
+  --> $DIR/needless_return.rs:59:5
    |
 LL |     return the_answer!();
    |     ^^^^^^^^^^^^^^^^^^^^
@@ -72,7 +72,7 @@ LL |     return the_answer!();
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:61:21
+  --> $DIR/needless_return.rs:62:21
    |
 LL |   fn test_void_fun() {
    |  _____________________^
@@ -82,7 +82,7 @@ LL | |     return;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:66:11
+  --> $DIR/needless_return.rs:67:11
    |
 LL |       if b {
    |  ___________^
@@ -92,7 +92,7 @@ LL | |         return;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:68:13
+  --> $DIR/needless_return.rs:69:13
    |
 LL |       } else {
    |  _____________^
@@ -102,7 +102,7 @@ LL | |         return;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:76:14
+  --> $DIR/needless_return.rs:77:14
    |
 LL |         _ => return,
    |              ^^^^^^
@@ -110,7 +110,7 @@ LL |         _ => return,
    = help: replace `return` with a unit value
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:84:24
+  --> $DIR/needless_return.rs:85:24
    |
 LL |               let _ = 42;
    |  ________________________^
@@ -120,7 +120,7 @@ LL | |             return;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:87:14
+  --> $DIR/needless_return.rs:88:14
    |
 LL |         _ => return,
    |              ^^^^^^
@@ -128,7 +128,7 @@ LL |         _ => return,
    = help: replace `return` with a unit value
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:100:9
+  --> $DIR/needless_return.rs:101:9
    |
 LL |         return String::from("test");
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -136,7 +136,7 @@ LL |         return String::from("test");
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:102:9
+  --> $DIR/needless_return.rs:103:9
    |
 LL |         return String::new();
    |         ^^^^^^^^^^^^^^^^^^^^
@@ -144,7 +144,7 @@ LL |         return String::new();
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:124:32
+  --> $DIR/needless_return.rs:125:32
    |
 LL |         bar.unwrap_or_else(|_| return)
    |                                ^^^^^^
@@ -152,7 +152,7 @@ LL |         bar.unwrap_or_else(|_| return)
    = help: replace `return` with an empty block
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:128:21
+  --> $DIR/needless_return.rs:129:21
    |
 LL |           let _ = || {
    |  _____________________^
@@ -162,7 +162,7 @@ LL | |             return;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:131:20
+  --> $DIR/needless_return.rs:132:20
    |
 LL |         let _ = || return;
    |                    ^^^^^^
@@ -170,7 +170,7 @@ LL |         let _ = || return;
    = help: replace `return` with an empty block
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:137:32
+  --> $DIR/needless_return.rs:138:32
    |
 LL |         res.unwrap_or_else(|_| return Foo)
    |                                ^^^^^^^^^^
@@ -178,7 +178,7 @@ LL |         res.unwrap_or_else(|_| return Foo)
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:146:5
+  --> $DIR/needless_return.rs:147:5
    |
 LL |     return true;
    |     ^^^^^^^^^^^
@@ -186,7 +186,7 @@ LL |     return true;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:150:5
+  --> $DIR/needless_return.rs:151:5
    |
 LL |     return true;
    |     ^^^^^^^^^^^
@@ -194,7 +194,7 @@ LL |     return true;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:155:9
+  --> $DIR/needless_return.rs:156:9
    |
 LL |         return true;
    |         ^^^^^^^^^^^
@@ -202,7 +202,7 @@ LL |         return true;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:157:9
+  --> $DIR/needless_return.rs:158:9
    |
 LL |         return false;
    |         ^^^^^^^^^^^^
@@ -210,7 +210,7 @@ LL |         return false;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:163:17
+  --> $DIR/needless_return.rs:164:17
    |
 LL |         true => return false,
    |                 ^^^^^^^^^^^^
@@ -218,7 +218,7 @@ LL |         true => return false,
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:165:13
+  --> $DIR/needless_return.rs:166:13
    |
 LL |             return true;
    |             ^^^^^^^^^^^
@@ -226,7 +226,7 @@ LL |             return true;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:172:9
+  --> $DIR/needless_return.rs:173:9
    |
 LL |         return true;
    |         ^^^^^^^^^^^
@@ -234,7 +234,7 @@ LL |         return true;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:174:16
+  --> $DIR/needless_return.rs:175:16
    |
 LL |     let _ = || return true;
    |                ^^^^^^^^^^^
@@ -242,7 +242,7 @@ LL |     let _ = || return true;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:178:5
+  --> $DIR/needless_return.rs:179:5
    |
 LL |     return the_answer!();
    |     ^^^^^^^^^^^^^^^^^^^^
@@ -250,7 +250,7 @@ LL |     return the_answer!();
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:181:33
+  --> $DIR/needless_return.rs:182:33
    |
 LL |   async fn async_test_void_fun() {
    |  _________________________________^
@@ -260,7 +260,7 @@ LL | |     return;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:186:11
+  --> $DIR/needless_return.rs:187:11
    |
 LL |       if b {
    |  ___________^
@@ -270,7 +270,7 @@ LL | |         return;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:188:13
+  --> $DIR/needless_return.rs:189:13
    |
 LL |       } else {
    |  _____________^
@@ -280,7 +280,7 @@ LL | |         return;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:196:14
+  --> $DIR/needless_return.rs:197:14
    |
 LL |         _ => return,
    |              ^^^^^^
@@ -288,7 +288,7 @@ LL |         _ => return,
    = help: replace `return` with a unit value
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:209:9
+  --> $DIR/needless_return.rs:210:9
    |
 LL |         return String::from("test");
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -296,7 +296,7 @@ LL |         return String::from("test");
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:211:9
+  --> $DIR/needless_return.rs:212:9
    |
 LL |         return String::new();
    |         ^^^^^^^^^^^^^^^^^^^^
@@ -304,7 +304,7 @@ LL |         return String::new();
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:227:5
+  --> $DIR/needless_return.rs:228:5
    |
 LL |     return format!("Hello {}", "world!");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -312,7 +312,7 @@ LL |     return format!("Hello {}", "world!");
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:238:9
+  --> $DIR/needless_return.rs:239:9
    |
 LL |         return true;
    |         ^^^^^^^^^^^
@@ -320,7 +320,7 @@ LL |         return true;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:240:9
+  --> $DIR/needless_return.rs:241:9
    |
 LL |         return false;
    |         ^^^^^^^^^^^^
@@ -328,7 +328,7 @@ LL |         return false;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:247:13
+  --> $DIR/needless_return.rs:248:13
    |
 LL |             return 10;
    |             ^^^^^^^^^
@@ -336,7 +336,7 @@ LL |             return 10;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:250:13
+  --> $DIR/needless_return.rs:251:13
    |
 LL |             return 100;
    |             ^^^^^^^^^^
@@ -344,7 +344,7 @@ LL |             return 100;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:258:9
+  --> $DIR/needless_return.rs:259:9
    |
 LL |         return 0;
    |         ^^^^^^^^
@@ -352,7 +352,7 @@ LL |         return 0;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:265:13
+  --> $DIR/needless_return.rs:266:13
    |
 LL |             return *(x as *const isize);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -360,7 +360,7 @@ LL |             return *(x as *const isize);
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:267:13
+  --> $DIR/needless_return.rs:268:13
    |
 LL |             return !*(x as *const isize);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -368,7 +368,7 @@ LL |             return !*(x as *const isize);
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:274:20
+  --> $DIR/needless_return.rs:275:20
    |
 LL |           let _ = 42;
    |  ____________________^
@@ -379,7 +379,7 @@ LL | |         return;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:281:20
+  --> $DIR/needless_return.rs:282:20
    |
 LL |         let _ = 42; return;
    |                    ^^^^^^^
diff --git a/src/tools/clippy/tests/ui/permissions_set_readonly_false.rs b/src/tools/clippy/tests/ui/permissions_set_readonly_false.rs
new file mode 100644
index 00000000000..28c00d10094
--- /dev/null
+++ b/src/tools/clippy/tests/ui/permissions_set_readonly_false.rs
@@ -0,0 +1,29 @@
+#![allow(unused)]
+#![warn(clippy::permissions_set_readonly_false)]
+
+use std::fs::File;
+
+struct A;
+
+impl A {
+    pub fn set_readonly(&mut self, b: bool) {}
+}
+
+fn set_readonly(b: bool) {}
+
+fn main() {
+    let f = File::create("foo.txt").unwrap();
+    let metadata = f.metadata().unwrap();
+    let mut permissions = metadata.permissions();
+    // lint here
+    permissions.set_readonly(false);
+    // no lint
+    permissions.set_readonly(true);
+
+    let mut a = A;
+    // no lint here - a is not of type std::fs::Permissions
+    a.set_readonly(false);
+
+    // no lint here - plain function
+    set_readonly(false);
+}
diff --git a/src/tools/clippy/tests/ui/permissions_set_readonly_false.stderr b/src/tools/clippy/tests/ui/permissions_set_readonly_false.stderr
new file mode 100644
index 00000000000..e7a8ee6cb19
--- /dev/null
+++ b/src/tools/clippy/tests/ui/permissions_set_readonly_false.stderr
@@ -0,0 +1,13 @@
+error: call to `set_readonly` with argument `false`
+  --> $DIR/permissions_set_readonly_false.rs:19:5
+   |
+LL |     permissions.set_readonly(false);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: on Unix platforms this results in the file being world writable
+   = help: you can set the desired permissions using `PermissionsExt`. For more information, see
+           https://doc.rust-lang.org/std/os/unix/fs/trait.PermissionsExt.html
+   = note: `-D clippy::permissions-set-readonly-false` implied by `-D warnings`
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/redundant_clone.fixed b/src/tools/clippy/tests/ui/redundant_clone.fixed
index 00b42745093..a157b6a6f9a 100644
--- a/src/tools/clippy/tests/ui/redundant_clone.fixed
+++ b/src/tools/clippy/tests/ui/redundant_clone.fixed
@@ -239,3 +239,9 @@ fn false_negative_5707() {
     let _z = x.clone(); // pr 7346 can't lint on `x`
     drop(y);
 }
+
+#[allow(unused, clippy::manual_retain)]
+fn possible_borrower_improvements() {
+    let mut s = String::from("foobar");
+    s = s.chars().filter(|&c| c != 'o').collect();
+}
diff --git a/src/tools/clippy/tests/ui/redundant_clone.rs b/src/tools/clippy/tests/ui/redundant_clone.rs
index f899127db8d..430672e8b8d 100644
--- a/src/tools/clippy/tests/ui/redundant_clone.rs
+++ b/src/tools/clippy/tests/ui/redundant_clone.rs
@@ -239,3 +239,9 @@ fn false_negative_5707() {
     let _z = x.clone(); // pr 7346 can't lint on `x`
     drop(y);
 }
+
+#[allow(unused, clippy::manual_retain)]
+fn possible_borrower_improvements() {
+    let mut s = String::from("foobar");
+    s = s.chars().filter(|&c| c != 'o').to_owned().collect();
+}
diff --git a/src/tools/clippy/tests/ui/redundant_clone.stderr b/src/tools/clippy/tests/ui/redundant_clone.stderr
index 782590034d0..1bacc2c76af 100644
--- a/src/tools/clippy/tests/ui/redundant_clone.stderr
+++ b/src/tools/clippy/tests/ui/redundant_clone.stderr
@@ -179,5 +179,17 @@ note: this value is dropped without further use
 LL |     foo(&x.clone(), move || {
    |          ^
 
-error: aborting due to 15 previous errors
+error: redundant clone
+  --> $DIR/redundant_clone.rs:246:40
+   |
+LL |     s = s.chars().filter(|&c| c != 'o').to_owned().collect();
+   |                                        ^^^^^^^^^^^ help: remove this
+   |
+note: this value is dropped without further use
+  --> $DIR/redundant_clone.rs:246:9
+   |
+LL |     s = s.chars().filter(|&c| c != 'o').to_owned().collect();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 16 previous errors
 
diff --git a/src/tools/clippy/tests/ui/size_of_ref.rs b/src/tools/clippy/tests/ui/size_of_ref.rs
new file mode 100644
index 00000000000..1e83ab82907
--- /dev/null
+++ b/src/tools/clippy/tests/ui/size_of_ref.rs
@@ -0,0 +1,27 @@
+#![allow(unused)]
+#![warn(clippy::size_of_ref)]
+
+use std::mem::size_of_val;
+
+fn main() {
+    let x = 5;
+    let y = &x;
+
+    size_of_val(&x); // no lint
+    size_of_val(y); // no lint
+
+    size_of_val(&&x);
+    size_of_val(&y);
+}
+
+struct S {
+    field: u32,
+    data: Vec<u8>,
+}
+
+impl S {
+    /// Get size of object including `self`, in bytes.
+    pub fn size(&self) -> usize {
+        std::mem::size_of_val(&self) + (std::mem::size_of::<u8>() * self.data.capacity())
+    }
+}
diff --git a/src/tools/clippy/tests/ui/size_of_ref.stderr b/src/tools/clippy/tests/ui/size_of_ref.stderr
new file mode 100644
index 00000000000..d4c13ac3290
--- /dev/null
+++ b/src/tools/clippy/tests/ui/size_of_ref.stderr
@@ -0,0 +1,27 @@
+error: argument to `std::mem::size_of_val()` is a reference to a reference
+  --> $DIR/size_of_ref.rs:13:5
+   |
+LL |     size_of_val(&&x);
+   |     ^^^^^^^^^^^^^^^^
+   |
+   = help: dereference the argument to `std::mem::size_of_val()` to get the size of the value instead of the size of the reference-type
+   = note: `-D clippy::size-of-ref` implied by `-D warnings`
+
+error: argument to `std::mem::size_of_val()` is a reference to a reference
+  --> $DIR/size_of_ref.rs:14:5
+   |
+LL |     size_of_val(&y);
+   |     ^^^^^^^^^^^^^^^
+   |
+   = help: dereference the argument to `std::mem::size_of_val()` to get the size of the value instead of the size of the reference-type
+
+error: argument to `std::mem::size_of_val()` is a reference to a reference
+  --> $DIR/size_of_ref.rs:25:9
+   |
+LL |         std::mem::size_of_val(&self) + (std::mem::size_of::<u8>() * self.data.capacity())
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: dereference the argument to `std::mem::size_of_val()` to get the size of the value instead of the size of the reference-type
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui/transmute_null_to_fn.rs b/src/tools/clippy/tests/ui/transmute_null_to_fn.rs
new file mode 100644
index 00000000000..b3ea3d9039e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/transmute_null_to_fn.rs
@@ -0,0 +1,28 @@
+#![allow(dead_code)]
+#![warn(clippy::transmute_null_to_fn)]
+#![allow(clippy::zero_ptr)]
+
+// Easy to lint because these only span one line.
+fn one_liners() {
+    unsafe {
+        let _: fn() = std::mem::transmute(0 as *const ());
+        let _: fn() = std::mem::transmute(std::ptr::null::<()>());
+    }
+}
+
+pub const ZPTR: *const usize = 0 as *const _;
+pub const NOT_ZPTR: *const usize = 1 as *const _;
+
+fn transmute_const() {
+    unsafe {
+        // Should raise a lint.
+        let _: fn() = std::mem::transmute(ZPTR);
+        // Should NOT raise a lint.
+        let _: fn() = std::mem::transmute(NOT_ZPTR);
+    }
+}
+
+fn main() {
+    one_liners();
+    transmute_const();
+}
diff --git a/src/tools/clippy/tests/ui/transmute_null_to_fn.stderr b/src/tools/clippy/tests/ui/transmute_null_to_fn.stderr
new file mode 100644
index 00000000000..f0c65497d75
--- /dev/null
+++ b/src/tools/clippy/tests/ui/transmute_null_to_fn.stderr
@@ -0,0 +1,27 @@
+error: transmuting a known null pointer into a function pointer
+  --> $DIR/transmute_null_to_fn.rs:8:23
+   |
+LL |         let _: fn() = std::mem::transmute(0 as *const ());
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this transmute results in undefined behavior
+   |
+   = help: try wrapping your function pointer type in `Option<T>` instead, and using `None` as a null pointer value
+   = note: `-D clippy::transmute-null-to-fn` implied by `-D warnings`
+
+error: transmuting a known null pointer into a function pointer
+  --> $DIR/transmute_null_to_fn.rs:9:23
+   |
+LL |         let _: fn() = std::mem::transmute(std::ptr::null::<()>());
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this transmute results in undefined behavior
+   |
+   = help: try wrapping your function pointer type in `Option<T>` instead, and using `None` as a null pointer value
+
+error: transmuting a known null pointer into a function pointer
+  --> $DIR/transmute_null_to_fn.rs:19:23
+   |
+LL |         let _: fn() = std::mem::transmute(ZPTR);
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^ this transmute results in undefined behavior
+   |
+   = help: try wrapping your function pointer type in `Option<T>` instead, and using `None` as a null pointer value
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui/useless_conversion.fixed b/src/tools/clippy/tests/ui/useless_conversion.fixed
index 70ff08f3655..94b206d8e58 100644
--- a/src/tools/clippy/tests/ui/useless_conversion.fixed
+++ b/src/tools/clippy/tests/ui/useless_conversion.fixed
@@ -33,12 +33,71 @@ fn test_issue_3913() -> Result<(), std::io::Error> {
     Ok(())
 }
 
-fn test_issue_5833() -> Result<(), ()> {
+fn dont_lint_into_iter_on_immutable_local_implementing_iterator_in_expr() {
     let text = "foo\r\nbar\n\nbaz\n";
     let lines = text.lines();
     if Some("ok") == lines.into_iter().next() {}
+}
 
-    Ok(())
+fn lint_into_iter_on_mutable_local_implementing_iterator_in_expr() {
+    let text = "foo\r\nbar\n\nbaz\n";
+    let mut lines = text.lines();
+    if Some("ok") == lines.next() {}
+}
+
+fn lint_into_iter_on_expr_implementing_iterator() {
+    let text = "foo\r\nbar\n\nbaz\n";
+    let mut lines = text.lines();
+    if Some("ok") == lines.next() {}
+}
+
+fn lint_into_iter_on_expr_implementing_iterator_2() {
+    let text = "foo\r\nbar\n\nbaz\n";
+    if Some("ok") == text.lines().next() {}
+}
+
+#[allow(const_item_mutation)]
+fn lint_into_iter_on_const_implementing_iterator() {
+    const NUMBERS: std::ops::Range<i32> = 0..10;
+    let _ = NUMBERS.next();
+}
+
+fn lint_into_iter_on_const_implementing_iterator_2() {
+    const NUMBERS: std::ops::Range<i32> = 0..10;
+    let mut n = NUMBERS;
+    n.next();
+}
+
+#[derive(Clone, Copy)]
+struct CopiableCounter {
+    counter: u32,
+}
+
+impl Iterator for CopiableCounter {
+    type Item = u32;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        self.counter = self.counter.wrapping_add(1);
+        Some(self.counter)
+    }
+}
+
+fn dont_lint_into_iter_on_copy_iter() {
+    let mut c = CopiableCounter { counter: 0 };
+    assert_eq!(c.into_iter().next(), Some(1));
+    assert_eq!(c.into_iter().next(), Some(1));
+    assert_eq!(c.next(), Some(1));
+    assert_eq!(c.next(), Some(2));
+}
+
+fn dont_lint_into_iter_on_static_copy_iter() {
+    static mut C: CopiableCounter = CopiableCounter { counter: 0 };
+    unsafe {
+        assert_eq!(C.into_iter().next(), Some(1));
+        assert_eq!(C.into_iter().next(), Some(1));
+        assert_eq!(C.next(), Some(1));
+        assert_eq!(C.next(), Some(2));
+    }
 }
 
 fn main() {
@@ -46,7 +105,15 @@ fn main() {
     test_generic2::<i32, i32>(10i32);
     test_questionmark().unwrap();
     test_issue_3913().unwrap();
-    test_issue_5833().unwrap();
+
+    dont_lint_into_iter_on_immutable_local_implementing_iterator_in_expr();
+    lint_into_iter_on_mutable_local_implementing_iterator_in_expr();
+    lint_into_iter_on_expr_implementing_iterator();
+    lint_into_iter_on_expr_implementing_iterator_2();
+    lint_into_iter_on_const_implementing_iterator();
+    lint_into_iter_on_const_implementing_iterator_2();
+    dont_lint_into_iter_on_copy_iter();
+    dont_lint_into_iter_on_static_copy_iter();
 
     let _: String = "foo".into();
     let _: String = From::from("foo");
diff --git a/src/tools/clippy/tests/ui/useless_conversion.rs b/src/tools/clippy/tests/ui/useless_conversion.rs
index f2444a8f436..c7ae927941b 100644
--- a/src/tools/clippy/tests/ui/useless_conversion.rs
+++ b/src/tools/clippy/tests/ui/useless_conversion.rs
@@ -33,12 +33,71 @@ fn test_issue_3913() -> Result<(), std::io::Error> {
     Ok(())
 }
 
-fn test_issue_5833() -> Result<(), ()> {
+fn dont_lint_into_iter_on_immutable_local_implementing_iterator_in_expr() {
     let text = "foo\r\nbar\n\nbaz\n";
     let lines = text.lines();
     if Some("ok") == lines.into_iter().next() {}
+}
 
-    Ok(())
+fn lint_into_iter_on_mutable_local_implementing_iterator_in_expr() {
+    let text = "foo\r\nbar\n\nbaz\n";
+    let mut lines = text.lines();
+    if Some("ok") == lines.into_iter().next() {}
+}
+
+fn lint_into_iter_on_expr_implementing_iterator() {
+    let text = "foo\r\nbar\n\nbaz\n";
+    let mut lines = text.lines().into_iter();
+    if Some("ok") == lines.next() {}
+}
+
+fn lint_into_iter_on_expr_implementing_iterator_2() {
+    let text = "foo\r\nbar\n\nbaz\n";
+    if Some("ok") == text.lines().into_iter().next() {}
+}
+
+#[allow(const_item_mutation)]
+fn lint_into_iter_on_const_implementing_iterator() {
+    const NUMBERS: std::ops::Range<i32> = 0..10;
+    let _ = NUMBERS.into_iter().next();
+}
+
+fn lint_into_iter_on_const_implementing_iterator_2() {
+    const NUMBERS: std::ops::Range<i32> = 0..10;
+    let mut n = NUMBERS.into_iter();
+    n.next();
+}
+
+#[derive(Clone, Copy)]
+struct CopiableCounter {
+    counter: u32,
+}
+
+impl Iterator for CopiableCounter {
+    type Item = u32;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        self.counter = self.counter.wrapping_add(1);
+        Some(self.counter)
+    }
+}
+
+fn dont_lint_into_iter_on_copy_iter() {
+    let mut c = CopiableCounter { counter: 0 };
+    assert_eq!(c.into_iter().next(), Some(1));
+    assert_eq!(c.into_iter().next(), Some(1));
+    assert_eq!(c.next(), Some(1));
+    assert_eq!(c.next(), Some(2));
+}
+
+fn dont_lint_into_iter_on_static_copy_iter() {
+    static mut C: CopiableCounter = CopiableCounter { counter: 0 };
+    unsafe {
+        assert_eq!(C.into_iter().next(), Some(1));
+        assert_eq!(C.into_iter().next(), Some(1));
+        assert_eq!(C.next(), Some(1));
+        assert_eq!(C.next(), Some(2));
+    }
 }
 
 fn main() {
@@ -46,7 +105,15 @@ fn main() {
     test_generic2::<i32, i32>(10i32);
     test_questionmark().unwrap();
     test_issue_3913().unwrap();
-    test_issue_5833().unwrap();
+
+    dont_lint_into_iter_on_immutable_local_implementing_iterator_in_expr();
+    lint_into_iter_on_mutable_local_implementing_iterator_in_expr();
+    lint_into_iter_on_expr_implementing_iterator();
+    lint_into_iter_on_expr_implementing_iterator_2();
+    lint_into_iter_on_const_implementing_iterator();
+    lint_into_iter_on_const_implementing_iterator_2();
+    dont_lint_into_iter_on_copy_iter();
+    dont_lint_into_iter_on_static_copy_iter();
 
     let _: String = "foo".into();
     let _: String = From::from("foo");
diff --git a/src/tools/clippy/tests/ui/useless_conversion.stderr b/src/tools/clippy/tests/ui/useless_conversion.stderr
index 65ee3807fa9..be067c6843a 100644
--- a/src/tools/clippy/tests/ui/useless_conversion.stderr
+++ b/src/tools/clippy/tests/ui/useless_conversion.stderr
@@ -22,71 +22,101 @@ error: useless conversion to the same type: `i32`
 LL |         let _: i32 = 0i32.into();
    |                      ^^^^^^^^^^^ help: consider removing `.into()`: `0i32`
 
+error: useless conversion to the same type: `std::str::Lines<'_>`
+  --> $DIR/useless_conversion.rs:45:22
+   |
+LL |     if Some("ok") == lines.into_iter().next() {}
+   |                      ^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `lines`
+
+error: useless conversion to the same type: `std::str::Lines<'_>`
+  --> $DIR/useless_conversion.rs:50:21
+   |
+LL |     let mut lines = text.lines().into_iter();
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `text.lines()`
+
+error: useless conversion to the same type: `std::str::Lines<'_>`
+  --> $DIR/useless_conversion.rs:56:22
+   |
+LL |     if Some("ok") == text.lines().into_iter().next() {}
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `text.lines()`
+
+error: useless conversion to the same type: `std::ops::Range<i32>`
+  --> $DIR/useless_conversion.rs:62:13
+   |
+LL |     let _ = NUMBERS.into_iter().next();
+   |             ^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `NUMBERS`
+
+error: useless conversion to the same type: `std::ops::Range<i32>`
+  --> $DIR/useless_conversion.rs:67:17
+   |
+LL |     let mut n = NUMBERS.into_iter();
+   |                 ^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `NUMBERS`
+
 error: useless conversion to the same type: `std::string::String`
-  --> $DIR/useless_conversion.rs:61:21
+  --> $DIR/useless_conversion.rs:128:21
    |
 LL |     let _: String = "foo".to_string().into();
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `"foo".to_string()`
 
 error: useless conversion to the same type: `std::string::String`
-  --> $DIR/useless_conversion.rs:62:21
+  --> $DIR/useless_conversion.rs:129:21
    |
 LL |     let _: String = From::from("foo".to_string());
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `From::from()`: `"foo".to_string()`
 
 error: useless conversion to the same type: `std::string::String`
-  --> $DIR/useless_conversion.rs:63:13
+  --> $DIR/useless_conversion.rs:130:13
    |
 LL |     let _ = String::from("foo".to_string());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `"foo".to_string()`
 
 error: useless conversion to the same type: `std::string::String`
-  --> $DIR/useless_conversion.rs:64:13
+  --> $DIR/useless_conversion.rs:131:13
    |
 LL |     let _ = String::from(format!("A: {:04}", 123));
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `format!("A: {:04}", 123)`
 
 error: useless conversion to the same type: `std::str::Lines<'_>`
-  --> $DIR/useless_conversion.rs:65:13
+  --> $DIR/useless_conversion.rs:132:13
    |
 LL |     let _ = "".lines().into_iter();
    |             ^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `"".lines()`
 
 error: useless conversion to the same type: `std::vec::IntoIter<i32>`
-  --> $DIR/useless_conversion.rs:66:13
+  --> $DIR/useless_conversion.rs:133:13
    |
 LL |     let _ = vec![1, 2, 3].into_iter().into_iter();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `vec![1, 2, 3].into_iter()`
 
 error: useless conversion to the same type: `std::string::String`
-  --> $DIR/useless_conversion.rs:67:21
+  --> $DIR/useless_conversion.rs:134:21
    |
 LL |     let _: String = format!("Hello {}", "world").into();
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `format!("Hello {}", "world")`
 
 error: useless conversion to the same type: `i32`
-  --> $DIR/useless_conversion.rs:72:13
+  --> $DIR/useless_conversion.rs:139:13
    |
 LL |     let _ = i32::from(a + b) * 3;
    |             ^^^^^^^^^^^^^^^^ help: consider removing `i32::from()`: `(a + b)`
 
 error: useless conversion to the same type: `Foo<'a'>`
-  --> $DIR/useless_conversion.rs:78:23
+  --> $DIR/useless_conversion.rs:145:23
    |
 LL |     let _: Foo<'a'> = s2.into();
    |                       ^^^^^^^^^ help: consider removing `.into()`: `s2`
 
 error: useless conversion to the same type: `Foo<'a'>`
-  --> $DIR/useless_conversion.rs:80:13
+  --> $DIR/useless_conversion.rs:147:13
    |
 LL |     let _ = Foo::<'a'>::from(s3);
    |             ^^^^^^^^^^^^^^^^^^^^ help: consider removing `Foo::<'a'>::from()`: `s3`
 
 error: useless conversion to the same type: `std::vec::IntoIter<Foo<'a'>>`
-  --> $DIR/useless_conversion.rs:82:13
+  --> $DIR/useless_conversion.rs:149:13
    |
 LL |     let _ = vec![s4, s4, s4].into_iter().into_iter();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `vec![s4, s4, s4].into_iter()`
 
-error: aborting due to 14 previous errors
+error: aborting due to 19 previous errors
 
diff --git a/src/tools/clippy/tests/ui/wildcard_imports.fixed b/src/tools/clippy/tests/ui/wildcard_imports.fixed
index ef55f1c31a8..0baec6f0b64 100644
--- a/src/tools/clippy/tests/ui/wildcard_imports.fixed
+++ b/src/tools/clippy/tests/ui/wildcard_imports.fixed
@@ -5,7 +5,6 @@
 // the 2015 edition here is needed because edition 2018 changed the module system
 // (see https://doc.rust-lang.org/edition-guide/rust-2018/path-changes.html) which means the lint
 // no longer detects some of the cases starting with Rust 2018.
-// FIXME: We should likely add another edition 2021 test case for this lint
 
 #![warn(clippy::wildcard_imports)]
 #![allow(unused, clippy::unnecessary_wraps, clippy::let_unit_value)]
diff --git a/src/tools/clippy/tests/ui/wildcard_imports.rs b/src/tools/clippy/tests/ui/wildcard_imports.rs
index b8128514206..db591d56ab4 100644
--- a/src/tools/clippy/tests/ui/wildcard_imports.rs
+++ b/src/tools/clippy/tests/ui/wildcard_imports.rs
@@ -5,7 +5,6 @@
 // the 2015 edition here is needed because edition 2018 changed the module system
 // (see https://doc.rust-lang.org/edition-guide/rust-2018/path-changes.html) which means the lint
 // no longer detects some of the cases starting with Rust 2018.
-// FIXME: We should likely add another edition 2021 test case for this lint
 
 #![warn(clippy::wildcard_imports)]
 #![allow(unused, clippy::unnecessary_wraps, clippy::let_unit_value)]
diff --git a/src/tools/clippy/tests/ui/wildcard_imports.stderr b/src/tools/clippy/tests/ui/wildcard_imports.stderr
index 626c1754fc8..6b469cdfc44 100644
--- a/src/tools/clippy/tests/ui/wildcard_imports.stderr
+++ b/src/tools/clippy/tests/ui/wildcard_imports.stderr
@@ -1,5 +1,5 @@
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:16:5
+  --> $DIR/wildcard_imports.rs:15:5
    |
 LL | use crate::fn_mod::*;
    |     ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo`
@@ -7,85 +7,85 @@ LL | use crate::fn_mod::*;
    = note: `-D clippy::wildcard-imports` implied by `-D warnings`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:17:5
+  --> $DIR/wildcard_imports.rs:16:5
    |
 LL | use crate::mod_mod::*;
    |     ^^^^^^^^^^^^^^^^^ help: try: `crate::mod_mod::inner_mod`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:18:5
+  --> $DIR/wildcard_imports.rs:17:5
    |
 LL | use crate::multi_fn_mod::*;
    |     ^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod}`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:20:5
+  --> $DIR/wildcard_imports.rs:19:5
    |
 LL | use crate::struct_mod::*;
    |     ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::struct_mod::{A, inner_struct_mod}`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:24:5
+  --> $DIR/wildcard_imports.rs:23:5
    |
 LL | use wildcard_imports_helper::inner::inner_for_self_import::*;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::inner::inner_for_self_import::inner_extern_bar`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:25:5
+  --> $DIR/wildcard_imports.rs:24:5
    |
 LL | use wildcard_imports_helper::*;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:96:13
+  --> $DIR/wildcard_imports.rs:95:13
    |
 LL |         use crate::fn_mod::*;
    |             ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:102:75
+  --> $DIR/wildcard_imports.rs:101:75
    |
 LL |         use wildcard_imports_helper::inner::inner_for_self_import::{self, *};
    |                                                                           ^ help: try: `inner_extern_foo`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:103:13
+  --> $DIR/wildcard_imports.rs:102:13
    |
 LL |         use wildcard_imports_helper::*;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:114:20
+  --> $DIR/wildcard_imports.rs:113:20
    |
 LL |         use self::{inner::*, inner2::*};
    |                    ^^^^^^^^ help: try: `inner::inner_foo`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:114:30
+  --> $DIR/wildcard_imports.rs:113:30
    |
 LL |         use self::{inner::*, inner2::*};
    |                              ^^^^^^^^^ help: try: `inner2::inner_bar`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:121:13
+  --> $DIR/wildcard_imports.rs:120:13
    |
 LL |         use wildcard_imports_helper::*;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:150:9
+  --> $DIR/wildcard_imports.rs:149:9
    |
 LL |     use crate::in_fn_test::*;
    |         ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:159:9
+  --> $DIR/wildcard_imports.rs:158:9
    |
 LL |     use crate:: in_fn_test::  * ;
    |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate:: in_fn_test::exported`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:160:9
+  --> $DIR/wildcard_imports.rs:159:9
    |
 LL |       use crate:: fn_mod::
    |  _________^
@@ -93,37 +93,37 @@ LL | |         *;
    | |_________^ help: try: `crate:: fn_mod::foo`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:171:13
+  --> $DIR/wildcard_imports.rs:170:13
    |
 LL |         use super::*;
    |             ^^^^^^^^ help: try: `super::foofoo`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:206:17
+  --> $DIR/wildcard_imports.rs:205:17
    |
 LL |             use super::*;
    |                 ^^^^^^^^ help: try: `super::insidefoo`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:214:13
+  --> $DIR/wildcard_imports.rs:213:13
    |
 LL |         use super_imports::*;
    |             ^^^^^^^^^^^^^^^^ help: try: `super_imports::foofoo`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:223:17
+  --> $DIR/wildcard_imports.rs:222:17
    |
 LL |             use super::super::*;
    |                 ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:232:13
+  --> $DIR/wildcard_imports.rs:231:13
    |
 LL |         use super::super::super_imports::*;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo`
 
 error: usage of wildcard import
-  --> $DIR/wildcard_imports.rs:240:13
+  --> $DIR/wildcard_imports.rs:239:13
    |
 LL |         use super::*;
    |             ^^^^^^^^ help: try: `super::foofoo`
diff --git a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.fixed b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.fixed
new file mode 100644
index 00000000000..6d534a10edc
--- /dev/null
+++ b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.fixed
@@ -0,0 +1,240 @@
+// revisions: edition2018 edition2021
+//[edition2018] edition:2018
+//[edition2021] edition:2021
+// run-rustfix
+// aux-build:wildcard_imports_helper.rs
+
+#![warn(clippy::wildcard_imports)]
+#![allow(unused, clippy::unnecessary_wraps, clippy::let_unit_value)]
+#![warn(unused_imports)]
+
+extern crate wildcard_imports_helper;
+
+use crate::fn_mod::foo;
+use crate::mod_mod::inner_mod;
+use crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod};
+use crate::struct_mod::{A, inner_struct_mod};
+
+#[allow(unused_imports)]
+use wildcard_imports_helper::inner::inner_for_self_import::inner_extern_bar;
+use wildcard_imports_helper::prelude::v1::*;
+use wildcard_imports_helper::{ExternA, extern_foo};
+
+use std::io::prelude::*;
+
+struct ReadFoo;
+
+impl Read for ReadFoo {
+    fn read(&mut self, _buf: &mut [u8]) -> std::io::Result<usize> {
+        Ok(0)
+    }
+}
+
+mod fn_mod {
+    pub fn foo() {}
+}
+
+mod mod_mod {
+    pub mod inner_mod {
+        pub fn foo() {}
+    }
+}
+
+mod multi_fn_mod {
+    pub fn multi_foo() {}
+    pub fn multi_bar() {}
+    pub fn multi_baz() {}
+    pub mod multi_inner_mod {
+        pub fn foo() {}
+    }
+}
+
+mod struct_mod {
+    pub struct A;
+    pub struct B;
+    pub mod inner_struct_mod {
+        pub struct C;
+    }
+
+    #[macro_export]
+    macro_rules! double_struct_import_test {
+        () => {
+            let _ = A;
+        };
+    }
+}
+
+fn main() {
+    foo();
+    multi_foo();
+    multi_bar();
+    multi_inner_mod::foo();
+    inner_mod::foo();
+    extern_foo();
+    inner_extern_bar();
+
+    let _ = A;
+    let _ = inner_struct_mod::C;
+    let _ = ExternA;
+    let _ = PreludeModAnywhere;
+
+    double_struct_import_test!();
+    double_struct_import_test!();
+}
+
+mod in_fn_test {
+    pub use self::inner_exported::*;
+    #[allow(unused_imports)]
+    pub(crate) use self::inner_exported2::*;
+
+    fn test_intern() {
+        use crate::fn_mod::foo;
+
+        foo();
+    }
+
+    fn test_extern() {
+        use wildcard_imports_helper::inner::inner_for_self_import::{self, inner_extern_foo};
+        use wildcard_imports_helper::{ExternA, extern_foo};
+
+        inner_for_self_import::inner_extern_foo();
+        inner_extern_foo();
+
+        extern_foo();
+
+        let _ = ExternA;
+    }
+
+    fn test_inner_nested() {
+        use self::{inner::inner_foo, inner2::inner_bar};
+
+        inner_foo();
+        inner_bar();
+    }
+
+    fn test_extern_reexported() {
+        use wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported};
+
+        extern_exported();
+        let _ = ExternExportedStruct;
+        let _ = ExternExportedEnum::A;
+    }
+
+    mod inner_exported {
+        pub fn exported() {}
+        pub struct ExportedStruct;
+        pub enum ExportedEnum {
+            A,
+        }
+    }
+
+    mod inner_exported2 {
+        pub(crate) fn exported2() {}
+    }
+
+    mod inner {
+        pub fn inner_foo() {}
+    }
+
+    mod inner2 {
+        pub fn inner_bar() {}
+    }
+}
+
+fn test_reexported() {
+    use crate::in_fn_test::{ExportedEnum, ExportedStruct, exported};
+
+    exported();
+    let _ = ExportedStruct;
+    let _ = ExportedEnum::A;
+}
+
+#[rustfmt::skip]
+fn test_weird_formatting() {
+    use crate:: in_fn_test::exported;
+    use crate:: fn_mod::foo;
+
+    exported();
+    foo();
+}
+
+mod super_imports {
+    fn foofoo() {}
+
+    mod should_be_replaced {
+        use super::foofoo;
+
+        fn with_super() {
+            let _ = foofoo();
+        }
+    }
+
+    mod test_should_pass {
+        use super::*;
+
+        fn with_super() {
+            let _ = foofoo();
+        }
+    }
+
+    mod test_should_pass_inside_function {
+        fn with_super_inside_function() {
+            use super::*;
+            let _ = foofoo();
+        }
+    }
+
+    mod test_should_pass_further_inside {
+        fn insidefoo() {}
+        mod inner {
+            use super::*;
+            fn with_super() {
+                let _ = insidefoo();
+            }
+        }
+    }
+
+    mod should_be_replaced_further_inside {
+        fn insidefoo() {}
+        mod inner {
+            use super::insidefoo;
+            fn with_super() {
+                let _ = insidefoo();
+            }
+        }
+    }
+
+    mod use_explicit_should_be_replaced {
+        use crate::super_imports::foofoo;
+
+        fn with_explicit() {
+            let _ = foofoo();
+        }
+    }
+
+    mod use_double_super_should_be_replaced {
+        mod inner {
+            use super::super::foofoo;
+
+            fn with_double_super() {
+                let _ = foofoo();
+            }
+        }
+    }
+
+    mod use_super_explicit_should_be_replaced {
+        use super::super::super_imports::foofoo;
+
+        fn with_super_explicit() {
+            let _ = foofoo();
+        }
+    }
+
+    mod attestation_should_be_replaced {
+        use super::foofoo;
+
+        fn with_explicit() {
+            let _ = foofoo();
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.stderr b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.stderr
new file mode 100644
index 00000000000..acca9f651b4
--- /dev/null
+++ b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.stderr
@@ -0,0 +1,132 @@
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:13:5
+   |
+LL | use crate::fn_mod::*;
+   |     ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo`
+   |
+   = note: `-D clippy::wildcard-imports` implied by `-D warnings`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:14:5
+   |
+LL | use crate::mod_mod::*;
+   |     ^^^^^^^^^^^^^^^^^ help: try: `crate::mod_mod::inner_mod`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:15:5
+   |
+LL | use crate::multi_fn_mod::*;
+   |     ^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod}`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:16:5
+   |
+LL | use crate::struct_mod::*;
+   |     ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::struct_mod::{A, inner_struct_mod}`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:19:5
+   |
+LL | use wildcard_imports_helper::inner::inner_for_self_import::*;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::inner::inner_for_self_import::inner_extern_bar`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:21:5
+   |
+LL | use wildcard_imports_helper::*;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:91:13
+   |
+LL |         use crate::fn_mod::*;
+   |             ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:97:75
+   |
+LL |         use wildcard_imports_helper::inner::inner_for_self_import::{self, *};
+   |                                                                           ^ help: try: `inner_extern_foo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:98:13
+   |
+LL |         use wildcard_imports_helper::*;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:109:20
+   |
+LL |         use self::{inner::*, inner2::*};
+   |                    ^^^^^^^^ help: try: `inner::inner_foo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:109:30
+   |
+LL |         use self::{inner::*, inner2::*};
+   |                              ^^^^^^^^^ help: try: `inner2::inner_bar`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:116:13
+   |
+LL |         use wildcard_imports_helper::*;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:145:9
+   |
+LL |     use crate::in_fn_test::*;
+   |         ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:154:9
+   |
+LL |     use crate:: in_fn_test::  * ;
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate:: in_fn_test::exported`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:155:9
+   |
+LL |       use crate:: fn_mod::
+   |  _________^
+LL | |         *;
+   | |_________^ help: try: `crate:: fn_mod::foo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:166:13
+   |
+LL |         use super::*;
+   |             ^^^^^^^^ help: try: `super::foofoo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:201:17
+   |
+LL |             use super::*;
+   |                 ^^^^^^^^ help: try: `super::insidefoo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:209:13
+   |
+LL |         use crate::super_imports::*;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::super_imports::foofoo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:218:17
+   |
+LL |             use super::super::*;
+   |                 ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:227:13
+   |
+LL |         use super::super::super_imports::*;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:235:13
+   |
+LL |         use super::*;
+   |             ^^^^^^^^ help: try: `super::foofoo`
+
+error: aborting due to 21 previous errors
+
diff --git a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.fixed b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.fixed
new file mode 100644
index 00000000000..6d534a10edc
--- /dev/null
+++ b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.fixed
@@ -0,0 +1,240 @@
+// revisions: edition2018 edition2021
+//[edition2018] edition:2018
+//[edition2021] edition:2021
+// run-rustfix
+// aux-build:wildcard_imports_helper.rs
+
+#![warn(clippy::wildcard_imports)]
+#![allow(unused, clippy::unnecessary_wraps, clippy::let_unit_value)]
+#![warn(unused_imports)]
+
+extern crate wildcard_imports_helper;
+
+use crate::fn_mod::foo;
+use crate::mod_mod::inner_mod;
+use crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod};
+use crate::struct_mod::{A, inner_struct_mod};
+
+#[allow(unused_imports)]
+use wildcard_imports_helper::inner::inner_for_self_import::inner_extern_bar;
+use wildcard_imports_helper::prelude::v1::*;
+use wildcard_imports_helper::{ExternA, extern_foo};
+
+use std::io::prelude::*;
+
+struct ReadFoo;
+
+impl Read for ReadFoo {
+    fn read(&mut self, _buf: &mut [u8]) -> std::io::Result<usize> {
+        Ok(0)
+    }
+}
+
+mod fn_mod {
+    pub fn foo() {}
+}
+
+mod mod_mod {
+    pub mod inner_mod {
+        pub fn foo() {}
+    }
+}
+
+mod multi_fn_mod {
+    pub fn multi_foo() {}
+    pub fn multi_bar() {}
+    pub fn multi_baz() {}
+    pub mod multi_inner_mod {
+        pub fn foo() {}
+    }
+}
+
+mod struct_mod {
+    pub struct A;
+    pub struct B;
+    pub mod inner_struct_mod {
+        pub struct C;
+    }
+
+    #[macro_export]
+    macro_rules! double_struct_import_test {
+        () => {
+            let _ = A;
+        };
+    }
+}
+
+fn main() {
+    foo();
+    multi_foo();
+    multi_bar();
+    multi_inner_mod::foo();
+    inner_mod::foo();
+    extern_foo();
+    inner_extern_bar();
+
+    let _ = A;
+    let _ = inner_struct_mod::C;
+    let _ = ExternA;
+    let _ = PreludeModAnywhere;
+
+    double_struct_import_test!();
+    double_struct_import_test!();
+}
+
+mod in_fn_test {
+    pub use self::inner_exported::*;
+    #[allow(unused_imports)]
+    pub(crate) use self::inner_exported2::*;
+
+    fn test_intern() {
+        use crate::fn_mod::foo;
+
+        foo();
+    }
+
+    fn test_extern() {
+        use wildcard_imports_helper::inner::inner_for_self_import::{self, inner_extern_foo};
+        use wildcard_imports_helper::{ExternA, extern_foo};
+
+        inner_for_self_import::inner_extern_foo();
+        inner_extern_foo();
+
+        extern_foo();
+
+        let _ = ExternA;
+    }
+
+    fn test_inner_nested() {
+        use self::{inner::inner_foo, inner2::inner_bar};
+
+        inner_foo();
+        inner_bar();
+    }
+
+    fn test_extern_reexported() {
+        use wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported};
+
+        extern_exported();
+        let _ = ExternExportedStruct;
+        let _ = ExternExportedEnum::A;
+    }
+
+    mod inner_exported {
+        pub fn exported() {}
+        pub struct ExportedStruct;
+        pub enum ExportedEnum {
+            A,
+        }
+    }
+
+    mod inner_exported2 {
+        pub(crate) fn exported2() {}
+    }
+
+    mod inner {
+        pub fn inner_foo() {}
+    }
+
+    mod inner2 {
+        pub fn inner_bar() {}
+    }
+}
+
+fn test_reexported() {
+    use crate::in_fn_test::{ExportedEnum, ExportedStruct, exported};
+
+    exported();
+    let _ = ExportedStruct;
+    let _ = ExportedEnum::A;
+}
+
+#[rustfmt::skip]
+fn test_weird_formatting() {
+    use crate:: in_fn_test::exported;
+    use crate:: fn_mod::foo;
+
+    exported();
+    foo();
+}
+
+mod super_imports {
+    fn foofoo() {}
+
+    mod should_be_replaced {
+        use super::foofoo;
+
+        fn with_super() {
+            let _ = foofoo();
+        }
+    }
+
+    mod test_should_pass {
+        use super::*;
+
+        fn with_super() {
+            let _ = foofoo();
+        }
+    }
+
+    mod test_should_pass_inside_function {
+        fn with_super_inside_function() {
+            use super::*;
+            let _ = foofoo();
+        }
+    }
+
+    mod test_should_pass_further_inside {
+        fn insidefoo() {}
+        mod inner {
+            use super::*;
+            fn with_super() {
+                let _ = insidefoo();
+            }
+        }
+    }
+
+    mod should_be_replaced_further_inside {
+        fn insidefoo() {}
+        mod inner {
+            use super::insidefoo;
+            fn with_super() {
+                let _ = insidefoo();
+            }
+        }
+    }
+
+    mod use_explicit_should_be_replaced {
+        use crate::super_imports::foofoo;
+
+        fn with_explicit() {
+            let _ = foofoo();
+        }
+    }
+
+    mod use_double_super_should_be_replaced {
+        mod inner {
+            use super::super::foofoo;
+
+            fn with_double_super() {
+                let _ = foofoo();
+            }
+        }
+    }
+
+    mod use_super_explicit_should_be_replaced {
+        use super::super::super_imports::foofoo;
+
+        fn with_super_explicit() {
+            let _ = foofoo();
+        }
+    }
+
+    mod attestation_should_be_replaced {
+        use super::foofoo;
+
+        fn with_explicit() {
+            let _ = foofoo();
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.stderr b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.stderr
new file mode 100644
index 00000000000..acca9f651b4
--- /dev/null
+++ b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.stderr
@@ -0,0 +1,132 @@
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:13:5
+   |
+LL | use crate::fn_mod::*;
+   |     ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo`
+   |
+   = note: `-D clippy::wildcard-imports` implied by `-D warnings`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:14:5
+   |
+LL | use crate::mod_mod::*;
+   |     ^^^^^^^^^^^^^^^^^ help: try: `crate::mod_mod::inner_mod`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:15:5
+   |
+LL | use crate::multi_fn_mod::*;
+   |     ^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod}`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:16:5
+   |
+LL | use crate::struct_mod::*;
+   |     ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::struct_mod::{A, inner_struct_mod}`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:19:5
+   |
+LL | use wildcard_imports_helper::inner::inner_for_self_import::*;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::inner::inner_for_self_import::inner_extern_bar`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:21:5
+   |
+LL | use wildcard_imports_helper::*;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:91:13
+   |
+LL |         use crate::fn_mod::*;
+   |             ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:97:75
+   |
+LL |         use wildcard_imports_helper::inner::inner_for_self_import::{self, *};
+   |                                                                           ^ help: try: `inner_extern_foo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:98:13
+   |
+LL |         use wildcard_imports_helper::*;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:109:20
+   |
+LL |         use self::{inner::*, inner2::*};
+   |                    ^^^^^^^^ help: try: `inner::inner_foo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:109:30
+   |
+LL |         use self::{inner::*, inner2::*};
+   |                              ^^^^^^^^^ help: try: `inner2::inner_bar`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:116:13
+   |
+LL |         use wildcard_imports_helper::*;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:145:9
+   |
+LL |     use crate::in_fn_test::*;
+   |         ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:154:9
+   |
+LL |     use crate:: in_fn_test::  * ;
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate:: in_fn_test::exported`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:155:9
+   |
+LL |       use crate:: fn_mod::
+   |  _________^
+LL | |         *;
+   | |_________^ help: try: `crate:: fn_mod::foo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:166:13
+   |
+LL |         use super::*;
+   |             ^^^^^^^^ help: try: `super::foofoo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:201:17
+   |
+LL |             use super::*;
+   |                 ^^^^^^^^ help: try: `super::insidefoo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:209:13
+   |
+LL |         use crate::super_imports::*;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::super_imports::foofoo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:218:17
+   |
+LL |             use super::super::*;
+   |                 ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:227:13
+   |
+LL |         use super::super::super_imports::*;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:235:13
+   |
+LL |         use super::*;
+   |             ^^^^^^^^ help: try: `super::foofoo`
+
+error: aborting due to 21 previous errors
+
diff --git a/src/tools/clippy/tests/ui/wildcard_imports_2021.rs b/src/tools/clippy/tests/ui/wildcard_imports_2021.rs
new file mode 100644
index 00000000000..b5ed58e6813
--- /dev/null
+++ b/src/tools/clippy/tests/ui/wildcard_imports_2021.rs
@@ -0,0 +1,241 @@
+// revisions: edition2018 edition2021
+//[edition2018] edition:2018
+//[edition2021] edition:2021
+// run-rustfix
+// aux-build:wildcard_imports_helper.rs
+
+#![warn(clippy::wildcard_imports)]
+#![allow(unused, clippy::unnecessary_wraps, clippy::let_unit_value)]
+#![warn(unused_imports)]
+
+extern crate wildcard_imports_helper;
+
+use crate::fn_mod::*;
+use crate::mod_mod::*;
+use crate::multi_fn_mod::*;
+use crate::struct_mod::*;
+
+#[allow(unused_imports)]
+use wildcard_imports_helper::inner::inner_for_self_import::*;
+use wildcard_imports_helper::prelude::v1::*;
+use wildcard_imports_helper::*;
+
+use std::io::prelude::*;
+
+struct ReadFoo;
+
+impl Read for ReadFoo {
+    fn read(&mut self, _buf: &mut [u8]) -> std::io::Result<usize> {
+        Ok(0)
+    }
+}
+
+mod fn_mod {
+    pub fn foo() {}
+}
+
+mod mod_mod {
+    pub mod inner_mod {
+        pub fn foo() {}
+    }
+}
+
+mod multi_fn_mod {
+    pub fn multi_foo() {}
+    pub fn multi_bar() {}
+    pub fn multi_baz() {}
+    pub mod multi_inner_mod {
+        pub fn foo() {}
+    }
+}
+
+mod struct_mod {
+    pub struct A;
+    pub struct B;
+    pub mod inner_struct_mod {
+        pub struct C;
+    }
+
+    #[macro_export]
+    macro_rules! double_struct_import_test {
+        () => {
+            let _ = A;
+        };
+    }
+}
+
+fn main() {
+    foo();
+    multi_foo();
+    multi_bar();
+    multi_inner_mod::foo();
+    inner_mod::foo();
+    extern_foo();
+    inner_extern_bar();
+
+    let _ = A;
+    let _ = inner_struct_mod::C;
+    let _ = ExternA;
+    let _ = PreludeModAnywhere;
+
+    double_struct_import_test!();
+    double_struct_import_test!();
+}
+
+mod in_fn_test {
+    pub use self::inner_exported::*;
+    #[allow(unused_imports)]
+    pub(crate) use self::inner_exported2::*;
+
+    fn test_intern() {
+        use crate::fn_mod::*;
+
+        foo();
+    }
+
+    fn test_extern() {
+        use wildcard_imports_helper::inner::inner_for_self_import::{self, *};
+        use wildcard_imports_helper::*;
+
+        inner_for_self_import::inner_extern_foo();
+        inner_extern_foo();
+
+        extern_foo();
+
+        let _ = ExternA;
+    }
+
+    fn test_inner_nested() {
+        use self::{inner::*, inner2::*};
+
+        inner_foo();
+        inner_bar();
+    }
+
+    fn test_extern_reexported() {
+        use wildcard_imports_helper::*;
+
+        extern_exported();
+        let _ = ExternExportedStruct;
+        let _ = ExternExportedEnum::A;
+    }
+
+    mod inner_exported {
+        pub fn exported() {}
+        pub struct ExportedStruct;
+        pub enum ExportedEnum {
+            A,
+        }
+    }
+
+    mod inner_exported2 {
+        pub(crate) fn exported2() {}
+    }
+
+    mod inner {
+        pub fn inner_foo() {}
+    }
+
+    mod inner2 {
+        pub fn inner_bar() {}
+    }
+}
+
+fn test_reexported() {
+    use crate::in_fn_test::*;
+
+    exported();
+    let _ = ExportedStruct;
+    let _ = ExportedEnum::A;
+}
+
+#[rustfmt::skip]
+fn test_weird_formatting() {
+    use crate:: in_fn_test::  * ;
+    use crate:: fn_mod::
+        *;
+
+    exported();
+    foo();
+}
+
+mod super_imports {
+    fn foofoo() {}
+
+    mod should_be_replaced {
+        use super::*;
+
+        fn with_super() {
+            let _ = foofoo();
+        }
+    }
+
+    mod test_should_pass {
+        use super::*;
+
+        fn with_super() {
+            let _ = foofoo();
+        }
+    }
+
+    mod test_should_pass_inside_function {
+        fn with_super_inside_function() {
+            use super::*;
+            let _ = foofoo();
+        }
+    }
+
+    mod test_should_pass_further_inside {
+        fn insidefoo() {}
+        mod inner {
+            use super::*;
+            fn with_super() {
+                let _ = insidefoo();
+            }
+        }
+    }
+
+    mod should_be_replaced_further_inside {
+        fn insidefoo() {}
+        mod inner {
+            use super::*;
+            fn with_super() {
+                let _ = insidefoo();
+            }
+        }
+    }
+
+    mod use_explicit_should_be_replaced {
+        use crate::super_imports::*;
+
+        fn with_explicit() {
+            let _ = foofoo();
+        }
+    }
+
+    mod use_double_super_should_be_replaced {
+        mod inner {
+            use super::super::*;
+
+            fn with_double_super() {
+                let _ = foofoo();
+            }
+        }
+    }
+
+    mod use_super_explicit_should_be_replaced {
+        use super::super::super_imports::*;
+
+        fn with_super_explicit() {
+            let _ = foofoo();
+        }
+    }
+
+    mod attestation_should_be_replaced {
+        use super::*;
+
+        fn with_explicit() {
+            let _ = foofoo();
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/wildcard_imports_2021.stderr b/src/tools/clippy/tests/ui/wildcard_imports_2021.stderr
new file mode 100644
index 00000000000..92f6d31530f
--- /dev/null
+++ b/src/tools/clippy/tests/ui/wildcard_imports_2021.stderr
@@ -0,0 +1,132 @@
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:9:5
+   |
+LL | use crate::fn_mod::*;
+   |     ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo`
+   |
+   = note: `-D clippy::wildcard-imports` implied by `-D warnings`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:10:5
+   |
+LL | use crate::mod_mod::*;
+   |     ^^^^^^^^^^^^^^^^^ help: try: `crate::mod_mod::inner_mod`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:11:5
+   |
+LL | use crate::multi_fn_mod::*;
+   |     ^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod}`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:12:5
+   |
+LL | use crate::struct_mod::*;
+   |     ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::struct_mod::{A, inner_struct_mod}`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:15:5
+   |
+LL | use wildcard_imports_helper::inner::inner_for_self_import::*;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::inner::inner_for_self_import::inner_extern_bar`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:17:5
+   |
+LL | use wildcard_imports_helper::*;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:87:13
+   |
+LL |         use crate::fn_mod::*;
+   |             ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:93:75
+   |
+LL |         use wildcard_imports_helper::inner::inner_for_self_import::{self, *};
+   |                                                                           ^ help: try: `inner_extern_foo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:94:13
+   |
+LL |         use wildcard_imports_helper::*;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:105:20
+   |
+LL |         use self::{inner::*, inner2::*};
+   |                    ^^^^^^^^ help: try: `inner::inner_foo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:105:30
+   |
+LL |         use self::{inner::*, inner2::*};
+   |                              ^^^^^^^^^ help: try: `inner2::inner_bar`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:112:13
+   |
+LL |         use wildcard_imports_helper::*;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:141:9
+   |
+LL |     use crate::in_fn_test::*;
+   |         ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:150:9
+   |
+LL |     use crate:: in_fn_test::  * ;
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate:: in_fn_test::exported`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:151:9
+   |
+LL |       use crate:: fn_mod::
+   |  _________^
+LL | |         *;
+   | |_________^ help: try: `crate:: fn_mod::foo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:162:13
+   |
+LL |         use super::*;
+   |             ^^^^^^^^ help: try: `super::foofoo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:197:17
+   |
+LL |             use super::*;
+   |                 ^^^^^^^^ help: try: `super::insidefoo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:205:13
+   |
+LL |         use crate::super_imports::*;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::super_imports::foofoo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:214:17
+   |
+LL |             use super::super::*;
+   |                 ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:223:13
+   |
+LL |         use super::super::super_imports::*;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports_2021.rs:231:13
+   |
+LL |         use super::*;
+   |             ^^^^^^^^ help: try: `super::foofoo`
+
+error: aborting due to 21 previous errors
+