about summary refs log tree commit diff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/compile-test.rs2
-rw-r--r--tests/dogfood.rs6
-rw-r--r--tests/lint_message_convention.rs2
-rw-r--r--tests/ui-internal/custom_ice_message.stderr1
-rw-r--r--tests/ui-toml/ifs_same_cond/clippy.toml1
-rw-r--r--tests/ui-toml/ifs_same_cond/ifs_same_cond.rs18
-rw-r--r--tests/ui-toml/ifs_same_cond/ifs_same_cond.stderr15
-rw-r--r--tests/ui/allow_attributes.fixed25
-rw-r--r--tests/ui/allow_attributes.rs25
-rw-r--r--tests/ui/allow_attributes.stderr16
-rw-r--r--tests/ui/almost_complete_range.fixed49
-rw-r--r--tests/ui/almost_complete_range.rs49
-rw-r--r--tests/ui/almost_complete_range.stderr93
-rw-r--r--tests/ui/as_conversions.rs13
-rw-r--r--tests/ui/as_conversions.stderr6
-rw-r--r--tests/ui/auxiliary/doc_unsafe_macros.rs16
-rw-r--r--tests/ui/auxiliary/implicit_hasher_macros.rs6
-rw-r--r--tests/ui/auxiliary/macro_rules.rs141
-rw-r--r--tests/ui/auxiliary/macro_use_helper.rs2
-rw-r--r--tests/ui/auxiliary/proc_macro_with_span.rs32
-rw-r--r--tests/ui/auxiliary/proc_macros.rs474
-rw-r--r--tests/ui/borrow_interior_mutable_const/auxiliary/helper.rs2
-rw-r--r--tests/ui/crashes/ice-10148.rs6
-rw-r--r--tests/ui/crashes/ice-6254.stderr2
-rw-r--r--tests/ui/default_numeric_fallback_f64.fixed17
-rw-r--r--tests/ui/default_numeric_fallback_f64.rs17
-rw-r--r--tests/ui/default_numeric_fallback_f64.stderr11
-rw-r--r--tests/ui/default_numeric_fallback_i32.fixed17
-rw-r--r--tests/ui/default_numeric_fallback_i32.rs17
-rw-r--r--tests/ui/default_numeric_fallback_i32.stderr11
-rw-r--r--tests/ui/default_trait_access.fixed6
-rw-r--r--tests/ui/default_trait_access.rs6
-rw-r--r--tests/ui/deref_addrof.fixed24
-rw-r--r--tests/ui/deref_addrof.rs24
-rw-r--r--tests/ui/deref_addrof.stderr38
-rw-r--r--tests/ui/deref_addrof_macro.rs15
-rw-r--r--tests/ui/doc_unsafe.rs12
-rw-r--r--tests/ui/empty_loop.rs15
-rw-r--r--tests/ui/equatable_if_let.fixed16
-rw-r--r--tests/ui/equatable_if_let.rs16
-rw-r--r--tests/ui/equatable_if_let.stderr32
-rw-r--r--tests/ui/field_reassign_with_default.rs36
-rw-r--r--tests/ui/field_reassign_with_default.stderr44
-rw-r--r--tests/ui/ifs_same_cond.rs26
-rw-r--r--tests/ui/ifs_same_cond.stderr14
-rw-r--r--tests/ui/implicit_hasher.rs25
-rw-r--r--tests/ui/implicit_hasher.stderr55
-rw-r--r--tests/ui/inconsistent_struct_constructor.fixed21
-rw-r--r--tests/ui/inconsistent_struct_constructor.rs21
-rw-r--r--tests/ui/inconsistent_struct_constructor.stderr4
-rw-r--r--tests/ui/large_enum_variant.rs13
-rw-r--r--tests/ui/macro_use_imports.fixed4
-rw-r--r--tests/ui/macro_use_imports.rs2
-rw-r--r--tests/ui/macro_use_imports.stderr2
-rw-r--r--tests/ui/macro_use_imports_expect.rs2
-rw-r--r--tests/ui/manual_async_fn.fixed6
-rw-r--r--tests/ui/manual_async_fn.rs12
-rw-r--r--tests/ui/manual_async_fn.stderr47
-rw-r--r--tests/ui/manual_clamp.rs19
-rw-r--r--tests/ui/manual_main_separator_str.fixed39
-rw-r--r--tests/ui/manual_main_separator_str.rs39
-rw-r--r--tests/ui/manual_main_separator_str.stderr28
-rw-r--r--tests/ui/manual_rem_euclid.fixed24
-rw-r--r--tests/ui/manual_rem_euclid.rs24
-rw-r--r--tests/ui/manual_rem_euclid.stderr17
-rw-r--r--tests/ui/match_single_binding.fixed41
-rw-r--r--tests/ui/match_single_binding.rs55
-rw-r--r--tests/ui/match_single_binding.stderr111
-rw-r--r--tests/ui/match_single_binding2.fixed4
-rw-r--r--tests/ui/match_single_binding2.stderr4
-rw-r--r--tests/ui/mem_replace_macro.rs23
-rw-r--r--tests/ui/mem_replace_macro.stderr11
-rw-r--r--tests/ui/missing_const_for_fn/cant_be_const.rs6
-rw-r--r--tests/ui/missing_doc.rs6
-rw-r--r--tests/ui/missing_doc_impl.rs6
-rw-r--r--tests/ui/mistyped_literal_suffix.fixed6
-rw-r--r--tests/ui/mistyped_literal_suffix.rs6
-rw-r--r--tests/ui/multiple_unsafe_ops_per_block.rs11
-rw-r--r--tests/ui/multiple_unsafe_ops_per_block.stderr18
-rw-r--r--tests/ui/must_use_unit.fixed11
-rw-r--r--tests/ui/must_use_unit.rs11
-rw-r--r--tests/ui/mut_mut.rs11
-rw-r--r--tests/ui/mut_mut.stderr25
-rw-r--r--tests/ui/needless_late_init.fixed36
-rw-r--r--tests/ui/needless_late_init.rs36
-rw-r--r--tests/ui/needless_late_init.stderr32
-rw-r--r--tests/ui/needless_lifetimes.fixed37
-rw-r--r--tests/ui/needless_lifetimes.rs37
-rw-r--r--tests/ui/needless_lifetimes.stderr15
-rw-r--r--tests/ui/needless_update.rs2
-rw-r--r--tests/ui/no_effect.rs7
-rw-r--r--tests/ui/no_effect.stderr58
-rw-r--r--tests/ui/no_mangle_with_rust_abi.fixed48
-rw-r--r--tests/ui/no_mangle_with_rust_abi.rs2
-rw-r--r--tests/ui/no_mangle_with_rust_abi.stderr74
-rw-r--r--tests/ui/nonminimal_bool.rs29
-rw-r--r--tests/ui/option_env_unwrap.rs24
-rw-r--r--tests/ui/option_env_unwrap.stderr42
-rw-r--r--tests/ui/ptr_as_ptr.fixed16
-rw-r--r--tests/ui/ptr_as_ptr.rs16
-rw-r--r--tests/ui/ptr_as_ptr.stderr25
-rw-r--r--tests/ui/redundant_async_block.fixed47
-rw-r--r--tests/ui/redundant_async_block.rs47
-rw-r--r--tests/ui/redundant_async_block.stderr22
-rw-r--r--tests/ui/redundant_pattern_matching_result.fixed4
-rw-r--r--tests/ui/redundant_pattern_matching_result.stderr4
-rw-r--r--tests/ui/single_match_else.rs6
-rw-r--r--tests/ui/string_add.rs11
-rw-r--r--tests/ui/swap.fixed15
-rw-r--r--tests/ui/swap.rs15
-rw-r--r--tests/ui/swap.stderr34
-rw-r--r--tests/ui/toplevel_ref_arg.fixed24
-rw-r--r--tests/ui/toplevel_ref_arg.rs24
-rw-r--r--tests/ui/toplevel_ref_arg.stderr21
-rw-r--r--tests/ui/toplevel_ref_arg_non_rustfix.rs22
-rw-r--r--tests/ui/toplevel_ref_arg_non_rustfix.stderr7
-rw-r--r--tests/ui/try_err.fixed65
-rw-r--r--tests/ui/try_err.rs65
-rw-r--r--tests/ui/try_err.stderr32
-rw-r--r--tests/ui/uninit.rs23
-rw-r--r--tests/ui/uninit.stderr12
-rw-r--r--tests/ui/uninit_vec.rs27
-rw-r--r--tests/ui/uninit_vec.stderr33
-rw-r--r--tests/ui/uninlined_format_args.fixed6
-rw-r--r--tests/ui/uninlined_format_args.rs6
-rw-r--r--tests/ui/unit_arg.rs6
-rw-r--r--tests/ui/unnecessary_lazy_eval.fixed6
-rw-r--r--tests/ui/unnecessary_lazy_eval.rs6
-rw-r--r--tests/ui/unnecessary_operation.fixed8
-rw-r--r--tests/ui/unnecessary_operation.rs8
-rw-r--r--tests/ui/unnecessary_operation.stderr38
-rw-r--r--tests/ui/unnecessary_struct_initialization.fixed73
-rw-r--r--tests/ui/unnecessary_struct_initialization.rs77
-rw-r--r--tests/ui/unnecessary_struct_initialization.stderr46
-rw-r--r--tests/ui/unnecessary_unsafety_doc.rs12
-rw-r--r--tests/ui/unnecessary_unsafety_doc.stderr2
-rw-r--r--tests/workspace.rs2
137 files changed, 2277 insertions, 1301 deletions
diff --git a/tests/compile-test.rs b/tests/compile-test.rs
index c10ee969c01..57890ff3173 100644
--- a/tests/compile-test.rs
+++ b/tests/compile-test.rs
@@ -1,5 +1,5 @@
 #![feature(test)] // compiletest_rs requires this attribute
-#![feature(once_cell)]
+#![feature(lazy_cell)]
 #![feature(is_sorted)]
 #![cfg_attr(feature = "deny-warnings", deny(warnings))]
 #![warn(rust_2018_idioms, unused_lifetimes)]
diff --git a/tests/dogfood.rs b/tests/dogfood.rs
index 9643c2c9707..68a878e9a3d 100644
--- a/tests/dogfood.rs
+++ b/tests/dogfood.rs
@@ -3,7 +3,7 @@
 //!
 //! See [Eating your own dog food](https://en.wikipedia.org/wiki/Eating_your_own_dog_food) for context
 
-#![feature(once_cell)]
+#![feature(lazy_cell)]
 #![cfg_attr(feature = "deny-warnings", deny(warnings))]
 #![warn(rust_2018_idioms, unused_lifetimes)]
 
@@ -37,10 +37,10 @@ fn dogfood_clippy() {
     }
 
     assert!(
-        !failed_packages.is_empty(),
+        failed_packages.is_empty(),
         "Dogfood failed for packages `{}`",
         failed_packages.iter().format(", "),
-    )
+    );
 }
 
 #[test]
diff --git a/tests/lint_message_convention.rs b/tests/lint_message_convention.rs
index abd0d1bc593..8feea800fdb 100644
--- a/tests/lint_message_convention.rs
+++ b/tests/lint_message_convention.rs
@@ -1,4 +1,4 @@
-#![feature(once_cell)]
+#![feature(lazy_cell)]
 #![cfg_attr(feature = "deny-warnings", deny(warnings))]
 #![warn(rust_2018_idioms, unused_lifetimes)]
 
diff --git a/tests/ui-internal/custom_ice_message.stderr b/tests/ui-internal/custom_ice_message.stderr
index 7ed0ef0274f..b4619e980f3 100644
--- a/tests/ui-internal/custom_ice_message.stderr
+++ b/tests/ui-internal/custom_ice_message.stderr
@@ -9,3 +9,4 @@ note: we would appreciate a bug report: https://github.com/rust-lang/rust-clippy
 
 note: Clippy version: foo
 
+thread panicked while panicking. aborting.
diff --git a/tests/ui-toml/ifs_same_cond/clippy.toml b/tests/ui-toml/ifs_same_cond/clippy.toml
new file mode 100644
index 00000000000..90a36ecd920
--- /dev/null
+++ b/tests/ui-toml/ifs_same_cond/clippy.toml
@@ -0,0 +1 @@
+ignore-interior-mutability = ["std::cell::Cell"]
diff --git a/tests/ui-toml/ifs_same_cond/ifs_same_cond.rs b/tests/ui-toml/ifs_same_cond/ifs_same_cond.rs
new file mode 100644
index 00000000000..d623ac7e020
--- /dev/null
+++ b/tests/ui-toml/ifs_same_cond/ifs_same_cond.rs
@@ -0,0 +1,18 @@
+#![warn(clippy::ifs_same_cond)]
+#![allow(clippy::if_same_then_else, clippy::comparison_chain)]
+
+fn main() {}
+
+fn issue10272() {
+    use std::cell::Cell;
+
+    // Because the `ignore-interior-mutability` configuration
+    // is set to ignore for `std::cell::Cell`, the following `get()` calls
+    // should trigger warning
+    let x = Cell::new(true);
+    if x.get() {
+    } else if !x.take() {
+    } else if x.get() {
+    } else {
+    }
+}
diff --git a/tests/ui-toml/ifs_same_cond/ifs_same_cond.stderr b/tests/ui-toml/ifs_same_cond/ifs_same_cond.stderr
new file mode 100644
index 00000000000..2841f62bc94
--- /dev/null
+++ b/tests/ui-toml/ifs_same_cond/ifs_same_cond.stderr
@@ -0,0 +1,15 @@
+error: this `if` has the same condition as a previous `if`
+  --> $DIR/ifs_same_cond.rs:15:15
+   |
+LL |     } else if x.get() {
+   |               ^^^^^^^
+   |
+note: same as this
+  --> $DIR/ifs_same_cond.rs:13:8
+   |
+LL |     if x.get() {
+   |        ^^^^^^^
+   = note: `-D clippy::ifs-same-cond` implied by `-D warnings`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/allow_attributes.fixed b/tests/ui/allow_attributes.fixed
new file mode 100644
index 00000000000..b8dd0619e6d
--- /dev/null
+++ b/tests/ui/allow_attributes.fixed
@@ -0,0 +1,25 @@
+// run-rustfix
+#![allow(unused)]
+#![warn(clippy::allow_attributes)]
+#![feature(lint_reasons)]
+
+fn main() {}
+
+// Using clippy::needless_borrow just as a placeholder, it isn't relevant.
+
+// Should lint
+#[expect(dead_code)]
+struct T1;
+
+struct T2; // Should not lint
+#[deny(clippy::needless_borrow)] // Should not lint
+struct T3;
+#[warn(clippy::needless_borrow)] // Should not lint
+struct T4;
+// `panic = "unwind"` should always be true
+#[cfg_attr(panic = "unwind", expect(dead_code))]
+struct CfgT;
+
+fn ignore_inner_attr() {
+    #![allow(unused)] // Should not lint
+}
diff --git a/tests/ui/allow_attributes.rs b/tests/ui/allow_attributes.rs
new file mode 100644
index 00000000000..295f560906a
--- /dev/null
+++ b/tests/ui/allow_attributes.rs
@@ -0,0 +1,25 @@
+// run-rustfix
+#![allow(unused)]
+#![warn(clippy::allow_attributes)]
+#![feature(lint_reasons)]
+
+fn main() {}
+
+// Using clippy::needless_borrow just as a placeholder, it isn't relevant.
+
+// Should lint
+#[allow(dead_code)]
+struct T1;
+
+struct T2; // Should not lint
+#[deny(clippy::needless_borrow)] // Should not lint
+struct T3;
+#[warn(clippy::needless_borrow)] // Should not lint
+struct T4;
+// `panic = "unwind"` should always be true
+#[cfg_attr(panic = "unwind", allow(dead_code))]
+struct CfgT;
+
+fn ignore_inner_attr() {
+    #![allow(unused)] // Should not lint
+}
diff --git a/tests/ui/allow_attributes.stderr b/tests/ui/allow_attributes.stderr
new file mode 100644
index 00000000000..681837e9ed7
--- /dev/null
+++ b/tests/ui/allow_attributes.stderr
@@ -0,0 +1,16 @@
+error: #[allow] attribute found
+  --> $DIR/allow_attributes.rs:11:3
+   |
+LL | #[allow(dead_code)]
+   |   ^^^^^ help: replace it with: `expect`
+   |
+   = note: `-D clippy::allow-attributes` implied by `-D warnings`
+
+error: #[allow] attribute found
+  --> $DIR/allow_attributes.rs:20:30
+   |
+LL | #[cfg_attr(panic = "unwind", allow(dead_code))]
+   |                              ^^^^^ help: replace it with: `expect`
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/almost_complete_range.fixed b/tests/ui/almost_complete_range.fixed
index 6046addf719..a4bf7fe18d5 100644
--- a/tests/ui/almost_complete_range.fixed
+++ b/tests/ui/almost_complete_range.fixed
@@ -1,6 +1,6 @@
 // run-rustfix
 // edition:2018
-// aux-build:macro_rules.rs
+// aux-build:proc_macros.rs
 
 #![feature(exclusive_range_pattern)]
 #![feature(stmt_expr_attributes)]
@@ -9,33 +9,10 @@
 #![allow(clippy::needless_parens_on_range_literals)]
 #![allow(clippy::double_parens)]
 
-#[macro_use]
-extern crate macro_rules;
-
-macro_rules! a {
-    () => {
-        'a'
-    };
-}
-macro_rules! A {
-    () => {
-        'A'
-    };
-}
-macro_rules! zero {
-    () => {
-        '0'
-    };
-}
-
-macro_rules! b {
-    () => {
-        let _ = 'a'..='z';
-        let _ = 'A'..='Z';
-        let _ = '0'..='9';
-    };
-}
+extern crate proc_macros;
+use proc_macros::{external, inline_macros};
 
+#[inline_macros]
 fn main() {
     #[rustfmt::skip]
     {
@@ -56,9 +33,9 @@ fn main() {
     let _ = b'B'..b'Z';
     let _ = b'1'..b'9';
 
-    let _ = a!()..='z';
-    let _ = A!()..='Z';
-    let _ = zero!()..='9';
+    let _ = inline!('a')..='z';
+    let _ = inline!('A')..='Z';
+    let _ = inline!('0')..='9';
 
     let _ = match 0u8 {
         b'a'..=b'z' if true => 1,
@@ -80,8 +57,16 @@ fn main() {
         _ => 7,
     };
 
-    almost_complete_range!();
-    b!();
+    external!(
+        let _ = 'a'..'z';
+        let _ = 'A'..'Z';
+        let _ = '0'..'9';
+    );
+    inline!(
+        let _ = 'a'..='z';
+        let _ = 'A'..='Z';
+        let _ = '0'..='9';
+    );
 }
 
 #[clippy::msrv = "1.25"]
diff --git a/tests/ui/almost_complete_range.rs b/tests/ui/almost_complete_range.rs
index ae7e07ab872..8237c3a1361 100644
--- a/tests/ui/almost_complete_range.rs
+++ b/tests/ui/almost_complete_range.rs
@@ -1,6 +1,6 @@
 // run-rustfix
 // edition:2018
-// aux-build:macro_rules.rs
+// aux-build:proc_macros.rs
 
 #![feature(exclusive_range_pattern)]
 #![feature(stmt_expr_attributes)]
@@ -9,33 +9,10 @@
 #![allow(clippy::needless_parens_on_range_literals)]
 #![allow(clippy::double_parens)]
 
-#[macro_use]
-extern crate macro_rules;
-
-macro_rules! a {
-    () => {
-        'a'
-    };
-}
-macro_rules! A {
-    () => {
-        'A'
-    };
-}
-macro_rules! zero {
-    () => {
-        '0'
-    };
-}
-
-macro_rules! b {
-    () => {
-        let _ = 'a'..'z';
-        let _ = 'A'..'Z';
-        let _ = '0'..'9';
-    };
-}
+extern crate proc_macros;
+use proc_macros::{external, inline_macros};
 
+#[inline_macros]
 fn main() {
     #[rustfmt::skip]
     {
@@ -56,9 +33,9 @@ fn main() {
     let _ = b'B'..b'Z';
     let _ = b'1'..b'9';
 
-    let _ = a!()..'z';
-    let _ = A!()..'Z';
-    let _ = zero!()..'9';
+    let _ = inline!('a')..'z';
+    let _ = inline!('A')..'Z';
+    let _ = inline!('0')..'9';
 
     let _ = match 0u8 {
         b'a'..b'z' if true => 1,
@@ -80,8 +57,16 @@ fn main() {
         _ => 7,
     };
 
-    almost_complete_range!();
-    b!();
+    external!(
+        let _ = 'a'..'z';
+        let _ = 'A'..'Z';
+        let _ = '0'..'9';
+    );
+    inline!(
+        let _ = 'a'..'z';
+        let _ = 'A'..'Z';
+        let _ = '0'..'9';
+    );
 }
 
 #[clippy::msrv = "1.25"]
diff --git a/tests/ui/almost_complete_range.stderr b/tests/ui/almost_complete_range.stderr
index a7a53287850..34521c13ab3 100644
--- a/tests/ui/almost_complete_range.stderr
+++ b/tests/ui/almost_complete_range.stderr
@@ -1,5 +1,5 @@
 error: almost complete ascii range
-  --> $DIR/almost_complete_range.rs:42:17
+  --> $DIR/almost_complete_range.rs:19:17
    |
 LL |         let _ = ('a') ..'z';
    |                 ^^^^^^--^^^
@@ -9,7 +9,7 @@ LL |         let _ = ('a') ..'z';
    = note: `-D clippy::almost-complete-range` implied by `-D warnings`
 
 error: almost complete ascii range
-  --> $DIR/almost_complete_range.rs:43:17
+  --> $DIR/almost_complete_range.rs:20:17
    |
 LL |         let _ = 'A' .. ('Z');
    |                 ^^^^--^^^^^^
@@ -17,7 +17,7 @@ LL |         let _ = 'A' .. ('Z');
    |                     help: use an inclusive range: `..=`
 
 error: almost complete ascii range
-  --> $DIR/almost_complete_range.rs:44:17
+  --> $DIR/almost_complete_range.rs:21:17
    |
 LL |         let _ = ((('0'))) .. ('9');
    |                 ^^^^^^^^^^--^^^^^^
@@ -25,7 +25,7 @@ LL |         let _ = ((('0'))) .. ('9');
    |                           help: use an inclusive range: `..=`
 
 error: almost complete ascii range
-  --> $DIR/almost_complete_range.rs:51:13
+  --> $DIR/almost_complete_range.rs:28:13
    |
 LL |     let _ = (b'a')..(b'z');
    |             ^^^^^^--^^^^^^
@@ -33,7 +33,7 @@ LL |     let _ = (b'a')..(b'z');
    |                   help: use an inclusive range: `..=`
 
 error: almost complete ascii range
-  --> $DIR/almost_complete_range.rs:52:13
+  --> $DIR/almost_complete_range.rs:29:13
    |
 LL |     let _ = b'A'..b'Z';
    |             ^^^^--^^^^
@@ -41,7 +41,7 @@ LL |     let _ = b'A'..b'Z';
    |                 help: use an inclusive range: `..=`
 
 error: almost complete ascii range
-  --> $DIR/almost_complete_range.rs:53:13
+  --> $DIR/almost_complete_range.rs:30:13
    |
 LL |     let _ = b'0'..b'9';
    |             ^^^^--^^^^
@@ -49,31 +49,31 @@ LL |     let _ = b'0'..b'9';
    |                 help: use an inclusive range: `..=`
 
 error: almost complete ascii range
-  --> $DIR/almost_complete_range.rs:59:13
+  --> $DIR/almost_complete_range.rs:36:13
    |
-LL |     let _ = a!()..'z';
-   |             ^^^^--^^^
-   |                 |
-   |                 help: use an inclusive range: `..=`
+LL |     let _ = inline!('a')..'z';
+   |             ^^^^^^^^^^^^--^^^
+   |                         |
+   |                         help: use an inclusive range: `..=`
 
 error: almost complete ascii range
-  --> $DIR/almost_complete_range.rs:60:13
+  --> $DIR/almost_complete_range.rs:37:13
    |
-LL |     let _ = A!()..'Z';
-   |             ^^^^--^^^
-   |                 |
-   |                 help: use an inclusive range: `..=`
+LL |     let _ = inline!('A')..'Z';
+   |             ^^^^^^^^^^^^--^^^
+   |                         |
+   |                         help: use an inclusive range: `..=`
 
 error: almost complete ascii range
-  --> $DIR/almost_complete_range.rs:61:13
+  --> $DIR/almost_complete_range.rs:38:13
    |
-LL |     let _ = zero!()..'9';
-   |             ^^^^^^^--^^^
-   |                    |
-   |                    help: use an inclusive range: `..=`
+LL |     let _ = inline!('0')..'9';
+   |             ^^^^^^^^^^^^--^^^
+   |                         |
+   |                         help: use an inclusive range: `..=`
 
 error: almost complete ascii range
-  --> $DIR/almost_complete_range.rs:64:9
+  --> $DIR/almost_complete_range.rs:41:9
    |
 LL |         b'a'..b'z' if true => 1,
    |         ^^^^--^^^^
@@ -81,7 +81,7 @@ LL |         b'a'..b'z' if true => 1,
    |             help: use an inclusive range: `..=`
 
 error: almost complete ascii range
-  --> $DIR/almost_complete_range.rs:65:9
+  --> $DIR/almost_complete_range.rs:42:9
    |
 LL |         b'A'..b'Z' if true => 2,
    |         ^^^^--^^^^
@@ -89,7 +89,7 @@ LL |         b'A'..b'Z' if true => 2,
    |             help: use an inclusive range: `..=`
 
 error: almost complete ascii range
-  --> $DIR/almost_complete_range.rs:66:9
+  --> $DIR/almost_complete_range.rs:43:9
    |
 LL |         b'0'..b'9' if true => 3,
    |         ^^^^--^^^^
@@ -97,7 +97,7 @@ LL |         b'0'..b'9' if true => 3,
    |             help: use an inclusive range: `..=`
 
 error: almost complete ascii range
-  --> $DIR/almost_complete_range.rs:74:9
+  --> $DIR/almost_complete_range.rs:51:9
    |
 LL |         'a'..'z' if true => 1,
    |         ^^^--^^^
@@ -105,7 +105,7 @@ LL |         'a'..'z' if true => 1,
    |            help: use an inclusive range: `..=`
 
 error: almost complete ascii range
-  --> $DIR/almost_complete_range.rs:75:9
+  --> $DIR/almost_complete_range.rs:52:9
    |
 LL |         'A'..'Z' if true => 2,
    |         ^^^--^^^
@@ -113,7 +113,7 @@ LL |         'A'..'Z' if true => 2,
    |            help: use an inclusive range: `..=`
 
 error: almost complete ascii range
-  --> $DIR/almost_complete_range.rs:76:9
+  --> $DIR/almost_complete_range.rs:53:9
    |
 LL |         '0'..'9' if true => 3,
    |         ^^^--^^^
@@ -121,46 +121,37 @@ LL |         '0'..'9' if true => 3,
    |            help: use an inclusive range: `..=`
 
 error: almost complete ascii range
-  --> $DIR/almost_complete_range.rs:33:17
+  --> $DIR/almost_complete_range.rs:66:17
    |
 LL |         let _ = 'a'..'z';
    |                 ^^^--^^^
    |                    |
    |                    help: use an inclusive range: `..=`
-...
-LL |     b!();
-   |     ---- in this macro invocation
    |
-   = note: this error originates in the macro `b` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: almost complete ascii range
-  --> $DIR/almost_complete_range.rs:34:17
+  --> $DIR/almost_complete_range.rs:67:17
    |
 LL |         let _ = 'A'..'Z';
    |                 ^^^--^^^
    |                    |
    |                    help: use an inclusive range: `..=`
-...
-LL |     b!();
-   |     ---- in this macro invocation
    |
-   = note: this error originates in the macro `b` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: almost complete ascii range
-  --> $DIR/almost_complete_range.rs:35:17
+  --> $DIR/almost_complete_range.rs:68:17
    |
 LL |         let _ = '0'..'9';
    |                 ^^^--^^^
    |                    |
    |                    help: use an inclusive range: `..=`
-...
-LL |     b!();
-   |     ---- in this macro invocation
    |
-   = note: this error originates in the macro `b` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: almost complete ascii range
-  --> $DIR/almost_complete_range.rs:90:9
+  --> $DIR/almost_complete_range.rs:75:9
    |
 LL |         'a'..'z' => 1,
    |         ^^^--^^^
@@ -168,7 +159,7 @@ LL |         'a'..'z' => 1,
    |            help: use an inclusive range: `...`
 
 error: almost complete ascii range
-  --> $DIR/almost_complete_range.rs:91:9
+  --> $DIR/almost_complete_range.rs:76:9
    |
 LL |         'A'..'Z' => 2,
    |         ^^^--^^^
@@ -176,7 +167,7 @@ LL |         'A'..'Z' => 2,
    |            help: use an inclusive range: `...`
 
 error: almost complete ascii range
-  --> $DIR/almost_complete_range.rs:92:9
+  --> $DIR/almost_complete_range.rs:77:9
    |
 LL |         '0'..'9' => 3,
    |         ^^^--^^^
@@ -184,7 +175,7 @@ LL |         '0'..'9' => 3,
    |            help: use an inclusive range: `...`
 
 error: almost complete ascii range
-  --> $DIR/almost_complete_range.rs:99:13
+  --> $DIR/almost_complete_range.rs:84:13
    |
 LL |     let _ = 'a'..'z';
    |             ^^^--^^^
@@ -192,7 +183,7 @@ LL |     let _ = 'a'..'z';
    |                help: use an inclusive range: `..=`
 
 error: almost complete ascii range
-  --> $DIR/almost_complete_range.rs:100:13
+  --> $DIR/almost_complete_range.rs:85:13
    |
 LL |     let _ = 'A'..'Z';
    |             ^^^--^^^
@@ -200,7 +191,7 @@ LL |     let _ = 'A'..'Z';
    |                help: use an inclusive range: `..=`
 
 error: almost complete ascii range
-  --> $DIR/almost_complete_range.rs:101:13
+  --> $DIR/almost_complete_range.rs:86:13
    |
 LL |     let _ = '0'..'9';
    |             ^^^--^^^
@@ -208,7 +199,7 @@ LL |     let _ = '0'..'9';
    |                help: use an inclusive range: `..=`
 
 error: almost complete ascii range
-  --> $DIR/almost_complete_range.rs:103:9
+  --> $DIR/almost_complete_range.rs:88:9
    |
 LL |         'a'..'z' => 1,
    |         ^^^--^^^
@@ -216,7 +207,7 @@ LL |         'a'..'z' => 1,
    |            help: use an inclusive range: `..=`
 
 error: almost complete ascii range
-  --> $DIR/almost_complete_range.rs:104:9
+  --> $DIR/almost_complete_range.rs:89:9
    |
 LL |         'A'..'Z' => 1,
    |         ^^^--^^^
@@ -224,7 +215,7 @@ LL |         'A'..'Z' => 1,
    |            help: use an inclusive range: `..=`
 
 error: almost complete ascii range
-  --> $DIR/almost_complete_range.rs:105:9
+  --> $DIR/almost_complete_range.rs:90:9
    |
 LL |         '0'..'9' => 3,
    |         ^^^--^^^
diff --git a/tests/ui/as_conversions.rs b/tests/ui/as_conversions.rs
index ba4394defbf..c50d4088b5e 100644
--- a/tests/ui/as_conversions.rs
+++ b/tests/ui/as_conversions.rs
@@ -1,20 +1,15 @@
-// aux-build:macro_rules.rs
+// aux-build:proc_macros.rs
 
 #![warn(clippy::as_conversions)]
 #![allow(clippy::borrow_as_ptr)]
 
-#[macro_use]
-extern crate macro_rules;
-
-fn with_external_macro() {
-    as_conv_with_arg!(0u32 as u64);
-    as_conv!();
-}
+extern crate proc_macros;
+use proc_macros::external;
 
 fn main() {
     let i = 0u32 as u64;
 
     let j = &i as *const u64 as *mut u64;
 
-    with_external_macro();
+    external!(0u32 as u64);
 }
diff --git a/tests/ui/as_conversions.stderr b/tests/ui/as_conversions.stderr
index f5d59e1e5d8..54037a64997 100644
--- a/tests/ui/as_conversions.stderr
+++ b/tests/ui/as_conversions.stderr
@@ -1,5 +1,5 @@
 error: using a potentially dangerous silent `as` conversion
-  --> $DIR/as_conversions.rs:15:13
+  --> $DIR/as_conversions.rs:10:13
    |
 LL |     let i = 0u32 as u64;
    |             ^^^^^^^^^^^
@@ -8,7 +8,7 @@ LL |     let i = 0u32 as u64;
    = note: `-D clippy::as-conversions` implied by `-D warnings`
 
 error: using a potentially dangerous silent `as` conversion
-  --> $DIR/as_conversions.rs:17:13
+  --> $DIR/as_conversions.rs:12:13
    |
 LL |     let j = &i as *const u64 as *mut u64;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -16,7 +16,7 @@ LL |     let j = &i as *const u64 as *mut u64;
    = help: consider using a safe wrapper for this conversion
 
 error: using a potentially dangerous silent `as` conversion
-  --> $DIR/as_conversions.rs:17:13
+  --> $DIR/as_conversions.rs:12:13
    |
 LL |     let j = &i as *const u64 as *mut u64;
    |             ^^^^^^^^^^^^^^^^
diff --git a/tests/ui/auxiliary/doc_unsafe_macros.rs b/tests/ui/auxiliary/doc_unsafe_macros.rs
deleted file mode 100644
index 3d917e3dc75..00000000000
--- a/tests/ui/auxiliary/doc_unsafe_macros.rs
+++ /dev/null
@@ -1,16 +0,0 @@
-#[macro_export]
-macro_rules! undocd_unsafe {
-    () => {
-        pub unsafe fn oy_vey() {
-            unimplemented!();
-        }
-    };
-}
-#[macro_export]
-macro_rules! undocd_safe {
-    () => {
-        pub fn vey_oy() {
-            unimplemented!();
-        }
-    };
-}
diff --git a/tests/ui/auxiliary/implicit_hasher_macros.rs b/tests/ui/auxiliary/implicit_hasher_macros.rs
deleted file mode 100644
index 1eb77c53183..00000000000
--- a/tests/ui/auxiliary/implicit_hasher_macros.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-#[macro_export]
-macro_rules! implicit_hasher_fn {
-    () => {
-        pub fn f(input: &HashMap<u32, u32>) {}
-    };
-}
diff --git a/tests/ui/auxiliary/macro_rules.rs b/tests/ui/auxiliary/macro_rules.rs
index a13af565203..a9bb61451dc 100644
--- a/tests/ui/auxiliary/macro_rules.rs
+++ b/tests/ui/auxiliary/macro_rules.rs
@@ -3,21 +3,6 @@
 //! Used to test that certain lints don't trigger in imported external macros
 
 #[macro_export]
-macro_rules! foofoo {
-    () => {
-        loop {}
-    };
-}
-
-#[macro_export]
-macro_rules! must_use_unit {
-    () => {
-        #[must_use]
-        fn foo() {}
-    };
-}
-
-#[macro_export]
 macro_rules! try_err {
     () => {
         pub fn try_err_fn() -> Result<i32, i32> {
@@ -37,84 +22,6 @@ macro_rules! string_add {
 }
 
 #[macro_export]
-macro_rules! take_external {
-    ($s:expr) => {
-        std::mem::replace($s, Default::default())
-    };
-}
-
-#[macro_export]
-macro_rules! option_env_unwrap_external {
-    ($env: expr) => {
-        option_env!($env).unwrap()
-    };
-    ($env: expr, $message: expr) => {
-        option_env!($env).expect($message)
-    };
-}
-
-#[macro_export]
-macro_rules! ref_arg_binding {
-    () => {
-        let ref _y = 42;
-    };
-}
-
-#[macro_export]
-macro_rules! ref_arg_function {
-    () => {
-        fn fun_example(ref _x: usize) {}
-    };
-}
-
-#[macro_export]
-macro_rules! as_conv_with_arg {
-    (0u32 as u64) => {
-        ()
-    };
-}
-
-#[macro_export]
-macro_rules! as_conv {
-    () => {
-        0u32 as u64
-    };
-}
-
-#[macro_export]
-macro_rules! large_enum_variant {
-    () => {
-        enum LargeEnumInMacro {
-            A(i32),
-            B([i32; 8000]),
-        }
-    };
-}
-
-#[macro_export]
-macro_rules! field_reassign_with_default {
-    () => {
-        #[derive(Default)]
-        struct A {
-            pub i: i32,
-            pub j: i64,
-        }
-        fn lint() {
-            let mut a: A = Default::default();
-            a.i = 42;
-            a;
-        }
-    };
-}
-
-#[macro_export]
-macro_rules! default_numeric_fallback {
-    () => {
-        let x = 22;
-    };
-}
-
-#[macro_export]
 macro_rules! mut_mut {
     () => {
         let mut_mut_ty: &mut &mut u32 = &mut &mut 1u32;
@@ -122,49 +29,11 @@ macro_rules! mut_mut {
 }
 
 #[macro_export]
-macro_rules! ptr_as_ptr_cast {
-    ($ptr: ident) => {
-        $ptr as *const i32
-    };
-}
-
-#[macro_export]
-macro_rules! manual_rem_euclid {
+macro_rules! issue_10421 {
     () => {
-        let value: i32 = 5;
-        let _: i32 = ((value % 4) + 4) % 4;
-    };
-}
-
-#[macro_export]
-macro_rules! equatable_if_let {
-    ($a:ident) => {{ if let 2 = $a {} }};
-}
-
-#[macro_export]
-macro_rules! almost_complete_range {
-    () => {
-        let _ = 'a'..'z';
-        let _ = 'A'..'Z';
-        let _ = '0'..'9';
-    };
-}
-
-#[macro_export]
-macro_rules! unsafe_macro {
-    () => {
-        unsafe {
-            *core::ptr::null::<()>();
-            *core::ptr::null::<()>();
-        }
-    };
-}
-
-#[macro_export]
-macro_rules! needless_lifetime {
-    () => {
-        fn needless_lifetime<'a>(x: &'a u8) -> &'a u8 {
-            unimplemented!()
-        }
+        let mut a = 1;
+        let mut b = 2;
+        a = b;
+        b = a;
     };
 }
diff --git a/tests/ui/auxiliary/macro_use_helper.rs b/tests/ui/auxiliary/macro_use_helper.rs
index ecb55d8cb48..7ed8a28dbd9 100644
--- a/tests/ui/auxiliary/macro_use_helper.rs
+++ b/tests/ui/auxiliary/macro_use_helper.rs
@@ -13,7 +13,7 @@ pub mod inner {
 
     // RE-EXPORT
     // this will stick in `inner` module
-    pub use macro_rules::foofoo;
+    pub use macro_rules::mut_mut;
     pub use macro_rules::try_err;
 
     pub mod nested {
diff --git a/tests/ui/auxiliary/proc_macro_with_span.rs b/tests/ui/auxiliary/proc_macro_with_span.rs
deleted file mode 100644
index 8ea631f2bbd..00000000000
--- a/tests/ui/auxiliary/proc_macro_with_span.rs
+++ /dev/null
@@ -1,32 +0,0 @@
-// compile-flags: --emit=link
-// no-prefer-dynamic
-
-#![crate_type = "proc-macro"]
-
-extern crate proc_macro;
-
-use proc_macro::{token_stream::IntoIter, Group, Span, TokenStream, TokenTree};
-
-#[proc_macro]
-pub fn with_span(input: TokenStream) -> TokenStream {
-    let mut iter = input.into_iter();
-    let span = iter.next().unwrap().span();
-    let mut res = TokenStream::new();
-    write_with_span(span, iter, &mut res);
-    res
-}
-
-fn write_with_span(s: Span, input: IntoIter, out: &mut TokenStream) {
-    for mut tt in input {
-        if let TokenTree::Group(g) = tt {
-            let mut stream = TokenStream::new();
-            write_with_span(s, g.stream().into_iter(), &mut stream);
-            let mut group = Group::new(g.delimiter(), stream);
-            group.set_span(s);
-            out.extend([TokenTree::Group(group)]);
-        } else {
-            tt.set_span(s);
-            out.extend([tt]);
-        }
-    }
-}
diff --git a/tests/ui/auxiliary/proc_macros.rs b/tests/ui/auxiliary/proc_macros.rs
new file mode 100644
index 00000000000..325be83a0d7
--- /dev/null
+++ b/tests/ui/auxiliary/proc_macros.rs
@@ -0,0 +1,474 @@
+// compile-flags: --emit=link
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+#![feature(let_chains)]
+#![feature(proc_macro_span)]
+#![allow(dead_code)]
+
+extern crate proc_macro;
+
+use core::mem;
+use proc_macro::{
+    token_stream::IntoIter,
+    Delimiter::{self, Brace, Parenthesis},
+    Group, Ident, Literal, Punct,
+    Spacing::{self, Alone, Joint},
+    Span, TokenStream, TokenTree as TT,
+};
+
+type Result<T> = core::result::Result<T, TokenStream>;
+
+/// Make a `compile_error!` pointing to the given span.
+fn make_error(msg: &str, span: Span) -> TokenStream {
+    TokenStream::from_iter([
+        TT::Ident(Ident::new("compile_error", span)),
+        TT::Punct(punct_with_span('!', Alone, span)),
+        TT::Group({
+            let mut msg = Literal::string(msg);
+            msg.set_span(span);
+            group_with_span(Parenthesis, TokenStream::from_iter([TT::Literal(msg)]), span)
+        }),
+    ])
+}
+
+fn expect_tt<T>(tt: Option<TT>, f: impl FnOnce(TT) -> Option<T>, expected: &str, span: Span) -> Result<T> {
+    match tt {
+        None => Err(make_error(
+            &format!("unexpected end of input, expected {expected}"),
+            span,
+        )),
+        Some(tt) => {
+            let span = tt.span();
+            match f(tt) {
+                Some(x) => Ok(x),
+                None => Err(make_error(&format!("unexpected token, expected {expected}"), span)),
+            }
+        },
+    }
+}
+
+fn punct_with_span(c: char, spacing: Spacing, span: Span) -> Punct {
+    let mut p = Punct::new(c, spacing);
+    p.set_span(span);
+    p
+}
+
+fn group_with_span(delimiter: Delimiter, stream: TokenStream, span: Span) -> Group {
+    let mut g = Group::new(delimiter, stream);
+    g.set_span(span);
+    g
+}
+
+/// Token used to escape the following token from the macro's span rules.
+const ESCAPE_CHAR: char = '$';
+
+/// Takes a single token followed by a sequence tokens. Returns the sequence of tokens with their
+/// span set to that of the first token. Tokens may be escaped with either `#ident` or `#(tokens)`.
+#[proc_macro]
+pub fn with_span(input: TokenStream) -> TokenStream {
+    let mut iter = input.into_iter();
+    let span = iter.next().unwrap().span();
+    let mut res = TokenStream::new();
+    if let Err(e) = write_with_span(span, iter, &mut res) {
+        e
+    } else {
+        res
+    }
+}
+
+/// Takes a sequence of tokens and return the tokens with the span set such that they appear to be
+/// from an external macro. Tokens may be escaped with either `#ident` or `#(tokens)`.
+#[proc_macro]
+pub fn external(input: TokenStream) -> TokenStream {
+    let mut res = TokenStream::new();
+    if let Err(e) = write_with_span(Span::mixed_site(), input.into_iter(), &mut res) {
+        e
+    } else {
+        res
+    }
+}
+
+/// Copies all the tokens, replacing all their spans with the given span. Tokens can be escaped
+/// either by `#ident` or `#(tokens)`.
+fn write_with_span(s: Span, mut input: IntoIter, out: &mut TokenStream) -> Result<()> {
+    while let Some(tt) = input.next() {
+        match tt {
+            TT::Punct(p) if p.as_char() == ESCAPE_CHAR => {
+                expect_tt(
+                    input.next(),
+                    |tt| match tt {
+                        tt @ (TT::Ident(_) | TT::Literal(_)) => {
+                            out.extend([tt]);
+                            Some(())
+                        },
+                        TT::Punct(mut p) if p.as_char() == ESCAPE_CHAR => {
+                            p.set_span(s);
+                            out.extend([TT::Punct(p)]);
+                            Some(())
+                        },
+                        TT::Group(g) if g.delimiter() == Parenthesis => {
+                            out.extend([TT::Group(group_with_span(Delimiter::None, g.stream(), g.span()))]);
+                            Some(())
+                        },
+                        _ => None,
+                    },
+                    "an ident, a literal, or parenthesized tokens",
+                    p.span(),
+                )?;
+            },
+            TT::Group(g) => {
+                let mut stream = TokenStream::new();
+                write_with_span(s, g.stream().into_iter(), &mut stream)?;
+                out.extend([TT::Group(group_with_span(g.delimiter(), stream, s))]);
+            },
+            mut tt => {
+                tt.set_span(s);
+                out.extend([tt]);
+            },
+        }
+    }
+    Ok(())
+}
+
+/// Within the item this attribute is attached to, an `inline!` macro is available which expands the
+/// contained tokens as though they came from a macro expansion.
+///
+/// Within the `inline!` macro, any token preceded by `$` is passed as though it were an argument
+/// with an automatically chosen fragment specifier. `$ident` will be passed as `ident`, `$1` or
+/// `$"literal"` will be passed as `literal`, `$'lt` will be passed as `lifetime`, and `$(...)` will
+/// pass the contained tokens as a `tt` sequence (the wrapping parenthesis are removed). If another
+/// specifier is required it can be specified within parenthesis like `$(@expr ...)`. This will
+/// expand the remaining tokens as a single argument.
+///
+/// Multiple `inline!` macros may be nested within each other. This will expand as nested macro
+/// calls. However, any arguments will be passed as though they came from the outermost context.
+#[proc_macro_attribute]
+pub fn inline_macros(args: TokenStream, input: TokenStream) -> TokenStream {
+    let mut args = args.into_iter();
+    let mac_name = match args.next() {
+        Some(TT::Ident(name)) => Some(name),
+        Some(tt) => {
+            return make_error(
+                "unexpected argument, expected either an ident or no arguments",
+                tt.span(),
+            );
+        },
+        None => None,
+    };
+    if let Some(tt) = args.next() {
+        return make_error(
+            "unexpected argument, expected either an ident or no arguments",
+            tt.span(),
+        );
+    };
+
+    let mac_name = if let Some(mac_name) = mac_name {
+        Ident::new(&format!("__inline_mac_{mac_name}"), Span::call_site())
+    } else {
+        let mut input = match LookaheadIter::new(input.clone().into_iter()) {
+            Some(x) => x,
+            None => return input,
+        };
+        loop {
+            match input.next() {
+                None => break Ident::new("__inline_mac", Span::call_site()),
+                Some(TT::Ident(kind)) => match &*kind.to_string() {
+                    "impl" => break Ident::new("__inline_mac_impl", Span::call_site()),
+                    kind @ ("struct" | "enum" | "union" | "fn" | "mod" | "trait" | "type" | "const" | "static") => {
+                        if let TT::Ident(name) = &input.tt {
+                            break Ident::new(&format!("__inline_mac_{kind}_{name}"), Span::call_site());
+                        } else {
+                            break Ident::new(&format!("__inline_mac_{kind}"), Span::call_site());
+                        }
+                    },
+                    _ => {},
+                },
+                _ => {},
+            }
+        }
+    };
+
+    let mut expander = Expander::default();
+    let mut mac = MacWriter::new(mac_name);
+    if let Err(e) = expander.expand(input.into_iter(), &mut mac) {
+        return e;
+    }
+    let mut out = TokenStream::new();
+    mac.finish(&mut out);
+    out.extend(expander.expn);
+    out
+}
+
+/// Wraps a `TokenStream` iterator with a single token lookahead.
+struct LookaheadIter {
+    tt: TT,
+    iter: IntoIter,
+}
+impl LookaheadIter {
+    fn new(mut iter: IntoIter) -> Option<Self> {
+        iter.next().map(|tt| Self { tt, iter })
+    }
+
+    /// Get's the lookahead token, replacing it with the next token in the stream.
+    /// Note: If there isn't a next token, this will not return the lookahead token.
+    fn next(&mut self) -> Option<TT> {
+        self.iter.next().map(|tt| mem::replace(&mut self.tt, tt))
+    }
+}
+
+/// Builds the macro used to implement all the `inline!` macro calls.
+struct MacWriter {
+    name: Ident,
+    macros: TokenStream,
+    next_idx: usize,
+}
+impl MacWriter {
+    fn new(name: Ident) -> Self {
+        Self {
+            name,
+            macros: TokenStream::new(),
+            next_idx: 0,
+        }
+    }
+
+    /// Inserts a new `inline!` call.
+    fn insert(&mut self, name_span: Span, bang_span: Span, body: Group, expander: &mut Expander) -> Result<()> {
+        let idx = self.next_idx;
+        self.next_idx += 1;
+
+        let mut inner = Expander::for_arm(idx);
+        inner.expand(body.stream().into_iter(), self)?;
+        let new_arm = inner.arm.unwrap();
+
+        self.macros.extend([
+            TT::Group(Group::new(Parenthesis, new_arm.args_def)),
+            TT::Punct(Punct::new('=', Joint)),
+            TT::Punct(Punct::new('>', Alone)),
+            TT::Group(Group::new(Parenthesis, inner.expn)),
+            TT::Punct(Punct::new(';', Alone)),
+        ]);
+
+        expander.expn.extend([
+            TT::Ident({
+                let mut name = self.name.clone();
+                name.set_span(name_span);
+                name
+            }),
+            TT::Punct(punct_with_span('!', Alone, bang_span)),
+        ]);
+        let mut call_body = TokenStream::from_iter([TT::Literal(Literal::usize_unsuffixed(idx))]);
+        if let Some(arm) = expander.arm.as_mut() {
+            if !new_arm.args.is_empty() {
+                arm.add_sub_args(new_arm.args, &mut call_body);
+            }
+        } else {
+            call_body.extend(new_arm.args);
+        }
+        let mut g = Group::new(body.delimiter(), call_body);
+        g.set_span(body.span());
+        expander.expn.extend([TT::Group(g)]);
+        Ok(())
+    }
+
+    /// Creates the macro definition.
+    fn finish(self, out: &mut TokenStream) {
+        if self.next_idx != 0 {
+            out.extend([
+                TT::Ident(Ident::new("macro_rules", Span::call_site())),
+                TT::Punct(Punct::new('!', Alone)),
+                TT::Ident(self.name),
+                TT::Group(Group::new(Brace, self.macros)),
+            ])
+        }
+    }
+}
+
+struct MacroArm {
+    args_def: TokenStream,
+    args: Vec<TT>,
+}
+impl MacroArm {
+    fn add_single_arg_def(&mut self, kind: &str, dollar_span: Span, arg_span: Span, out: &mut TokenStream) {
+        let mut name = Ident::new(&format!("_{}", self.args.len()), Span::call_site());
+        self.args_def.extend([
+            TT::Punct(Punct::new('$', Alone)),
+            TT::Ident(name.clone()),
+            TT::Punct(Punct::new(':', Alone)),
+            TT::Ident(Ident::new(kind, Span::call_site())),
+        ]);
+        name.set_span(arg_span);
+        out.extend([TT::Punct(punct_with_span('$', Alone, dollar_span)), TT::Ident(name)]);
+    }
+
+    fn add_parenthesized_arg_def(&mut self, kind: Ident, dollar_span: Span, arg_span: Span, out: &mut TokenStream) {
+        let mut name = Ident::new(&format!("_{}", self.args.len()), Span::call_site());
+        self.args_def.extend([TT::Group(Group::new(
+            Parenthesis,
+            TokenStream::from_iter([
+                TT::Punct(Punct::new('$', Alone)),
+                TT::Ident(name.clone()),
+                TT::Punct(Punct::new(':', Alone)),
+                TT::Ident(kind),
+            ]),
+        ))]);
+        name.set_span(arg_span);
+        out.extend([TT::Punct(punct_with_span('$', Alone, dollar_span)), TT::Ident(name)]);
+    }
+
+    fn add_multi_arg_def(&mut self, dollar_span: Span, arg_span: Span, out: &mut TokenStream) {
+        let mut name = Ident::new(&format!("_{}", self.args.len()), Span::call_site());
+        self.args_def.extend([TT::Group(Group::new(
+            Parenthesis,
+            TokenStream::from_iter([
+                TT::Punct(Punct::new('$', Alone)),
+                TT::Group(Group::new(
+                    Parenthesis,
+                    TokenStream::from_iter([
+                        TT::Punct(Punct::new('$', Alone)),
+                        TT::Ident(name.clone()),
+                        TT::Punct(Punct::new(':', Alone)),
+                        TT::Ident(Ident::new("tt", Span::call_site())),
+                    ]),
+                )),
+                TT::Punct(Punct::new('*', Alone)),
+            ]),
+        ))]);
+        name.set_span(arg_span);
+        out.extend([
+            TT::Punct(punct_with_span('$', Alone, dollar_span)),
+            TT::Group(group_with_span(
+                Parenthesis,
+                TokenStream::from_iter([TT::Punct(punct_with_span('$', Alone, dollar_span)), TT::Ident(name)]),
+                dollar_span,
+            )),
+            TT::Punct(punct_with_span('*', Alone, dollar_span)),
+        ]);
+    }
+
+    fn add_arg(&mut self, dollar_span: Span, tt: TT, input: &mut IntoIter, out: &mut TokenStream) -> Result<()> {
+        match tt {
+            TT::Punct(p) if p.as_char() == ESCAPE_CHAR => out.extend([TT::Punct(p)]),
+            TT::Punct(p) if p.as_char() == '\'' && p.spacing() == Joint => {
+                let lt_name = expect_tt(
+                    input.next(),
+                    |tt| match tt {
+                        TT::Ident(x) => Some(x),
+                        _ => None,
+                    },
+                    "lifetime name",
+                    p.span(),
+                )?;
+                let arg_span = p.span().join(lt_name.span()).unwrap_or(p.span());
+                self.add_single_arg_def("lifetime", dollar_span, arg_span, out);
+                self.args.extend([TT::Punct(p), TT::Ident(lt_name)]);
+            },
+            TT::Ident(x) => {
+                self.add_single_arg_def("ident", dollar_span, x.span(), out);
+                self.args.push(TT::Ident(x));
+            },
+            TT::Literal(x) => {
+                self.add_single_arg_def("literal", dollar_span, x.span(), out);
+                self.args.push(TT::Literal(x));
+            },
+            TT::Group(g) if g.delimiter() == Parenthesis => {
+                let mut inner = g.stream().into_iter();
+                if let Some(TT::Punct(p)) = inner.next()
+                    && p.as_char() == '@'
+                {
+                    let kind = expect_tt(
+                        inner.next(),
+                        |tt| match tt {
+                            TT::Ident(kind) => Some(kind),
+                            _ => None,
+                        },
+                        "a macro fragment specifier",
+                        p.span(),
+                    )?;
+                    self.add_parenthesized_arg_def(kind, dollar_span, g.span(), out);
+                    self.args.push(TT::Group(group_with_span(Parenthesis, inner.collect(), g.span())))
+                } else {
+                    self.add_multi_arg_def(dollar_span, g.span(), out);
+                    self.args.push(TT::Group(g));
+                }
+            },
+            tt => return Err(make_error("unsupported escape", tt.span())),
+        };
+        Ok(())
+    }
+
+    fn add_sub_args(&mut self, args: Vec<TT>, out: &mut TokenStream) {
+        self.add_multi_arg_def(Span::call_site(), Span::call_site(), out);
+        self.args
+            .extend([TT::Group(Group::new(Parenthesis, TokenStream::from_iter(args)))]);
+    }
+}
+
+#[derive(Default)]
+struct Expander {
+    arm: Option<MacroArm>,
+    expn: TokenStream,
+}
+impl Expander {
+    fn for_arm(idx: usize) -> Self {
+        Self {
+            arm: Some(MacroArm {
+                args_def: TokenStream::from_iter([TT::Literal(Literal::usize_unsuffixed(idx))]),
+                args: Vec::new(),
+            }),
+            expn: TokenStream::new(),
+        }
+    }
+
+    fn write_tt(&mut self, tt: TT, mac: &mut MacWriter) -> Result<()> {
+        match tt {
+            TT::Group(g) => {
+                let outer = mem::take(&mut self.expn);
+                self.expand(g.stream().into_iter(), mac)?;
+                let inner = mem::replace(&mut self.expn, outer);
+                self.expn
+                    .extend([TT::Group(group_with_span(g.delimiter(), inner, g.span()))]);
+            },
+            tt => self.expn.extend([tt]),
+        }
+        Ok(())
+    }
+
+    fn expand(&mut self, input: IntoIter, mac: &mut MacWriter) -> Result<()> {
+        let Some(mut input) = LookaheadIter::new(input) else {
+            return Ok(());
+        };
+        while let Some(tt) = input.next() {
+            if let TT::Punct(p) = &tt
+                && p.as_char() == ESCAPE_CHAR
+                && let Some(arm) = self.arm.as_mut()
+            {
+                arm.add_arg(p.span(), mem::replace(&mut input.tt, tt), &mut input.iter, &mut self.expn)?;
+                if input.next().is_none() {
+                    return Ok(());
+                }
+            } else if let TT::Punct(p) = &input.tt
+                && p.as_char() == '!'
+                && let TT::Ident(name) = &tt
+                && name.to_string() == "inline"
+            {
+                let g = expect_tt(
+                    input.iter.next(),
+                    |tt| match tt {
+                        TT::Group(g) => Some(g),
+                        _ => None,
+                    },
+                    "macro arguments",
+                    p.span(),
+                )?;
+                mac.insert(name.span(), p.span(), g, self)?;
+                if input.next().is_none() {
+                    return Ok(());
+                }
+            } else {
+                self.write_tt(tt, mac)?;
+            }
+        }
+        self.write_tt(input.tt, mac)
+    }
+}
diff --git a/tests/ui/borrow_interior_mutable_const/auxiliary/helper.rs b/tests/ui/borrow_interior_mutable_const/auxiliary/helper.rs
index f13733af3d0..b03c21262c3 100644
--- a/tests/ui/borrow_interior_mutable_const/auxiliary/helper.rs
+++ b/tests/ui/borrow_interior_mutable_const/auxiliary/helper.rs
@@ -1,5 +1,5 @@
 // this file solely exists to test constants defined in foreign crates.
-// As the most common case is the `http` crate, it replicates `http::HeadewrName`'s structure.
+// As the most common case is the `http` crate, it replicates `http::HeaderName`'s structure.
 
 #![allow(clippy::declare_interior_mutable_const)]
 #![allow(unused_tuple_struct_fields)]
diff --git a/tests/ui/crashes/ice-10148.rs b/tests/ui/crashes/ice-10148.rs
index af33b10c693..1ab3570c907 100644
--- a/tests/ui/crashes/ice-10148.rs
+++ b/tests/ui/crashes/ice-10148.rs
@@ -1,8 +1,8 @@
-// aux-build:../../auxiliary/proc_macro_with_span.rs
+// aux-build:../../auxiliary/proc_macros.rs
 
-extern crate proc_macro_with_span;
+extern crate proc_macros;
 
-use proc_macro_with_span::with_span;
+use proc_macros::with_span;
 
 fn main() {
     println!(with_span!(""something ""));
diff --git a/tests/ui/crashes/ice-6254.stderr b/tests/ui/crashes/ice-6254.stderr
index 22d82a30c6a..263c27d3d64 100644
--- a/tests/ui/crashes/ice-6254.stderr
+++ b/tests/ui/crashes/ice-6254.stderr
@@ -6,6 +6,8 @@ LL |         FOO_REF_REF => {},
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/62411>
+   = note: the traits must be derived, manual `impl`s are not sufficient
+   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
    = note: `-D indirect-structural-match` implied by `-D warnings`
 
 error: aborting due to previous error
diff --git a/tests/ui/default_numeric_fallback_f64.fixed b/tests/ui/default_numeric_fallback_f64.fixed
index a9e5fd159af..42c15d6a70b 100644
--- a/tests/ui/default_numeric_fallback_f64.fixed
+++ b/tests/ui/default_numeric_fallback_f64.fixed
@@ -1,5 +1,5 @@
 // run-rustfix
-// aux-build:macro_rules.rs
+// aux-build:proc_macros.rs
 
 #![warn(clippy::default_numeric_fallback)]
 #![allow(
@@ -13,8 +13,8 @@
     clippy::let_with_type_underscore
 )]
 
-#[macro_use]
-extern crate macro_rules;
+extern crate proc_macros;
+use proc_macros::{external, inline_macros};
 
 mod basic_expr {
     fn test() {
@@ -167,20 +167,17 @@ mod method_calls {
 }
 
 mod in_macro {
-    macro_rules! internal_macro {
-        () => {
-            let x = 22.0_f64;
-        };
-    }
+    use super::*;
 
     // Should lint in internal macro.
+    #[inline_macros]
     fn internal() {
-        internal_macro!();
+        inline!(let x = 22.0_f64;);
     }
 
     // Should NOT lint in external macro.
     fn external() {
-        default_numeric_fallback!();
+        external!(let x = 22.;);
     }
 }
 
diff --git a/tests/ui/default_numeric_fallback_f64.rs b/tests/ui/default_numeric_fallback_f64.rs
index 085f8f452b2..7da7ea254e9 100644
--- a/tests/ui/default_numeric_fallback_f64.rs
+++ b/tests/ui/default_numeric_fallback_f64.rs
@@ -1,5 +1,5 @@
 // run-rustfix
-// aux-build:macro_rules.rs
+// aux-build:proc_macros.rs
 
 #![warn(clippy::default_numeric_fallback)]
 #![allow(
@@ -13,8 +13,8 @@
     clippy::let_with_type_underscore
 )]
 
-#[macro_use]
-extern crate macro_rules;
+extern crate proc_macros;
+use proc_macros::{external, inline_macros};
 
 mod basic_expr {
     fn test() {
@@ -167,20 +167,17 @@ mod method_calls {
 }
 
 mod in_macro {
-    macro_rules! internal_macro {
-        () => {
-            let x = 22.;
-        };
-    }
+    use super::*;
 
     // Should lint in internal macro.
+    #[inline_macros]
     fn internal() {
-        internal_macro!();
+        inline!(let x = 22.;);
     }
 
     // Should NOT lint in external macro.
     fn external() {
-        default_numeric_fallback!();
+        external!(let x = 22.;);
     }
 }
 
diff --git a/tests/ui/default_numeric_fallback_f64.stderr b/tests/ui/default_numeric_fallback_f64.stderr
index 44c6f1a9bea..b949cd1d50b 100644
--- a/tests/ui/default_numeric_fallback_f64.stderr
+++ b/tests/ui/default_numeric_fallback_f64.stderr
@@ -139,15 +139,12 @@ LL |         s.generic_arg(1.);
    |                       ^^ help: consider adding suffix: `1.0_f64`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback_f64.rs:172:21
+  --> $DIR/default_numeric_fallback_f64.rs:175:25
    |
-LL |             let x = 22.;
-   |                     ^^^ help: consider adding suffix: `22.0_f64`
-...
-LL |         internal_macro!();
-   |         ----------------- in this macro invocation
+LL |         inline!(let x = 22.;);
+   |                         ^^^ help: consider adding suffix: `22.0_f64`
    |
-   = note: this error originates in the macro `internal_macro` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `__inline_mac_fn_internal` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to 24 previous errors
 
diff --git a/tests/ui/default_numeric_fallback_i32.fixed b/tests/ui/default_numeric_fallback_i32.fixed
index 63ac4d5aeb6..b7485b73dcd 100644
--- a/tests/ui/default_numeric_fallback_i32.fixed
+++ b/tests/ui/default_numeric_fallback_i32.fixed
@@ -1,5 +1,5 @@
 // run-rustfix
-// aux-build:macro_rules.rs
+// aux-build:proc_macros.rs
 
 #![feature(lint_reasons)]
 #![warn(clippy::default_numeric_fallback)]
@@ -13,8 +13,8 @@
     clippy::let_with_type_underscore
 )]
 
-#[macro_use]
-extern crate macro_rules;
+extern crate proc_macros;
+use proc_macros::{external, inline_macros};
 
 mod basic_expr {
     fn test() {
@@ -168,20 +168,17 @@ mod method_calls {
 }
 
 mod in_macro {
-    macro_rules! internal_macro {
-        () => {
-            let x = 22_i32;
-        };
-    }
+    use super::*;
 
     // Should lint in internal macro.
+    #[inline_macros]
     fn internal() {
-        internal_macro!();
+        inline!(let x = 22_i32;);
     }
 
     // Should NOT lint in external macro.
     fn external() {
-        default_numeric_fallback!();
+        external!(let x = 22;);
     }
 }
 
diff --git a/tests/ui/default_numeric_fallback_i32.rs b/tests/ui/default_numeric_fallback_i32.rs
index 28e6eceb80e..7307d31354e 100644
--- a/tests/ui/default_numeric_fallback_i32.rs
+++ b/tests/ui/default_numeric_fallback_i32.rs
@@ -1,5 +1,5 @@
 // run-rustfix
-// aux-build:macro_rules.rs
+// aux-build:proc_macros.rs
 
 #![feature(lint_reasons)]
 #![warn(clippy::default_numeric_fallback)]
@@ -13,8 +13,8 @@
     clippy::let_with_type_underscore
 )]
 
-#[macro_use]
-extern crate macro_rules;
+extern crate proc_macros;
+use proc_macros::{external, inline_macros};
 
 mod basic_expr {
     fn test() {
@@ -168,20 +168,17 @@ mod method_calls {
 }
 
 mod in_macro {
-    macro_rules! internal_macro {
-        () => {
-            let x = 22;
-        };
-    }
+    use super::*;
 
     // Should lint in internal macro.
+    #[inline_macros]
     fn internal() {
-        internal_macro!();
+        inline!(let x = 22;);
     }
 
     // Should NOT lint in external macro.
     fn external() {
-        default_numeric_fallback!();
+        external!(let x = 22;);
     }
 }
 
diff --git a/tests/ui/default_numeric_fallback_i32.stderr b/tests/ui/default_numeric_fallback_i32.stderr
index dd91574d5b3..48cd28102ce 100644
--- a/tests/ui/default_numeric_fallback_i32.stderr
+++ b/tests/ui/default_numeric_fallback_i32.stderr
@@ -151,15 +151,12 @@ LL |         s.generic_arg(1);
    |                       ^ help: consider adding suffix: `1_i32`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback_i32.rs:173:21
+  --> $DIR/default_numeric_fallback_i32.rs:176:25
    |
-LL |             let x = 22;
-   |                     ^^ help: consider adding suffix: `22_i32`
-...
-LL |         internal_macro!();
-   |         ----------------- in this macro invocation
+LL |         inline!(let x = 22;);
+   |                         ^^ help: consider adding suffix: `22_i32`
    |
-   = note: this error originates in the macro `internal_macro` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `__inline_mac_fn_internal` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to 26 previous errors
 
diff --git a/tests/ui/default_trait_access.fixed b/tests/ui/default_trait_access.fixed
index 5640599d48a..7842ef3ec40 100644
--- a/tests/ui/default_trait_access.fixed
+++ b/tests/ui/default_trait_access.fixed
@@ -1,12 +1,12 @@
 // run-rustfix
-// aux-build: proc_macro_with_span.rs
+// aux-build: proc_macros.rs
 #![deny(clippy::default_trait_access)]
 #![allow(dead_code, unused_imports)]
 #![allow(clippy::uninlined_format_args)]
 
-extern crate proc_macro_with_span;
+extern crate proc_macros;
 
-use proc_macro_with_span::with_span;
+use proc_macros::with_span;
 use std::default;
 use std::default::Default as D2;
 use std::string;
diff --git a/tests/ui/default_trait_access.rs b/tests/ui/default_trait_access.rs
index 11d4bc5c5f0..cbb3e59c970 100644
--- a/tests/ui/default_trait_access.rs
+++ b/tests/ui/default_trait_access.rs
@@ -1,12 +1,12 @@
 // run-rustfix
-// aux-build: proc_macro_with_span.rs
+// aux-build: proc_macros.rs
 #![deny(clippy::default_trait_access)]
 #![allow(dead_code, unused_imports)]
 #![allow(clippy::uninlined_format_args)]
 
-extern crate proc_macro_with_span;
+extern crate proc_macros;
 
-use proc_macro_with_span::with_span;
+use proc_macros::with_span;
 use std::default;
 use std::default::Default as D2;
 use std::string;
diff --git a/tests/ui/deref_addrof.fixed b/tests/ui/deref_addrof.fixed
index 2f489deb1ee..ca5c03304c7 100644
--- a/tests/ui/deref_addrof.fixed
+++ b/tests/ui/deref_addrof.fixed
@@ -1,7 +1,12 @@
 // run-rustfix
+// aux-build:proc_macros.rs
+
 #![allow(clippy::return_self_not_must_use)]
 #![warn(clippy::deref_addrof)]
 
+extern crate proc_macros;
+use proc_macros::inline_macros;
+
 fn get_number() -> usize {
     10
 }
@@ -41,28 +46,15 @@ fn main() {
     let _ = unsafe { *core::ptr::addr_of!(a) };
 }
 
-#[rustfmt::skip]
-macro_rules! m {
-    ($visitor: expr) => {
-        $visitor
-    };
-}
-
-#[rustfmt::skip]
-macro_rules! m_mut {
-    ($visitor: expr) => {
-        $visitor
-    };
-}
-
 #[derive(Copy, Clone)]
 pub struct S;
+#[inline_macros]
 impl S {
     pub fn f(&self) -> &Self {
-        m!(self)
+        inline!($(@expr self))
     }
     #[allow(unused_mut)] // mut will be unused, once the macro is fixed
     pub fn f_mut(mut self) -> Self {
-        m_mut!(self)
+        inline!($(@expr self))
     }
 }
diff --git a/tests/ui/deref_addrof.rs b/tests/ui/deref_addrof.rs
index 49f360b9a7f..3db5fafe944 100644
--- a/tests/ui/deref_addrof.rs
+++ b/tests/ui/deref_addrof.rs
@@ -1,7 +1,12 @@
 // run-rustfix
+// aux-build:proc_macros.rs
+
 #![allow(clippy::return_self_not_must_use)]
 #![warn(clippy::deref_addrof)]
 
+extern crate proc_macros;
+use proc_macros::inline_macros;
+
 fn get_number() -> usize {
     10
 }
@@ -41,28 +46,15 @@ fn main() {
     let _ = unsafe { *core::ptr::addr_of!(a) };
 }
 
-#[rustfmt::skip]
-macro_rules! m {
-    ($visitor: expr) => {
-        *& $visitor
-    };
-}
-
-#[rustfmt::skip]
-macro_rules! m_mut {
-    ($visitor: expr) => {
-        *& mut $visitor
-    };
-}
-
 #[derive(Copy, Clone)]
 pub struct S;
+#[inline_macros]
 impl S {
     pub fn f(&self) -> &Self {
-        m!(self)
+        inline!(*& $(@expr self))
     }
     #[allow(unused_mut)] // mut will be unused, once the macro is fixed
     pub fn f_mut(mut self) -> Self {
-        m_mut!(self)
+        inline!(*&mut $(@expr self))
     }
 }
diff --git a/tests/ui/deref_addrof.stderr b/tests/ui/deref_addrof.stderr
index 75371fcdb96..e0287522fc5 100644
--- a/tests/ui/deref_addrof.stderr
+++ b/tests/ui/deref_addrof.stderr
@@ -1,5 +1,5 @@
 error: immediately dereferencing a reference
-  --> $DIR/deref_addrof.rs:19:13
+  --> $DIR/deref_addrof.rs:24:13
    |
 LL |     let b = *&a;
    |             ^^^ help: try this: `a`
@@ -7,68 +7,62 @@ LL |     let b = *&a;
    = note: `-D clippy::deref-addrof` implied by `-D warnings`
 
 error: immediately dereferencing a reference
-  --> $DIR/deref_addrof.rs:21:13
+  --> $DIR/deref_addrof.rs:26:13
    |
 LL |     let b = *&get_number();
    |             ^^^^^^^^^^^^^^ help: try this: `get_number()`
 
 error: immediately dereferencing a reference
-  --> $DIR/deref_addrof.rs:26:13
+  --> $DIR/deref_addrof.rs:31:13
    |
 LL |     let b = *&bytes[1..2][0];
    |             ^^^^^^^^^^^^^^^^ help: try this: `bytes[1..2][0]`
 
 error: immediately dereferencing a reference
-  --> $DIR/deref_addrof.rs:30:13
+  --> $DIR/deref_addrof.rs:35:13
    |
 LL |     let b = *&(a);
    |             ^^^^^ help: try this: `(a)`
 
 error: immediately dereferencing a reference
-  --> $DIR/deref_addrof.rs:32:13
+  --> $DIR/deref_addrof.rs:37:13
    |
 LL |     let b = *(&a);
    |             ^^^^^ help: try this: `a`
 
 error: immediately dereferencing a reference
-  --> $DIR/deref_addrof.rs:35:13
+  --> $DIR/deref_addrof.rs:40:13
    |
 LL |     let b = *((&a));
    |             ^^^^^^^ help: try this: `a`
 
 error: immediately dereferencing a reference
-  --> $DIR/deref_addrof.rs:37:13
+  --> $DIR/deref_addrof.rs:42:13
    |
 LL |     let b = *&&a;
    |             ^^^^ help: try this: `&a`
 
 error: immediately dereferencing a reference
-  --> $DIR/deref_addrof.rs:39:14
+  --> $DIR/deref_addrof.rs:44:14
    |
 LL |     let b = **&aref;
    |              ^^^^^^ help: try this: `aref`
 
 error: immediately dereferencing a reference
-  --> $DIR/deref_addrof.rs:47:9
+  --> $DIR/deref_addrof.rs:54:17
    |
-LL |         *& $visitor
-   |         ^^^^^^^^^^^ help: try this: `$visitor`
-...
-LL |         m!(self)
-   |         -------- in this macro invocation
+LL |         inline!(*& $(@expr self))
+   |                 ^^^^^^^^^^^^^^^^ help: try this: `$(@expr self)`
    |
-   = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `__inline_mac_impl` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: immediately dereferencing a reference
-  --> $DIR/deref_addrof.rs:54:9
+  --> $DIR/deref_addrof.rs:58:17
    |
-LL |         *& mut $visitor
-   |         ^^^^^^^^^^^^^^^ help: try this: `$visitor`
-...
-LL |         m_mut!(self)
-   |         ------------ in this macro invocation
+LL |         inline!(*&mut $(@expr self))
+   |                 ^^^^^^^^^^^^^^^^^^^ help: try this: `$(@expr self)`
    |
-   = note: this error originates in the macro `m_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `__inline_mac_impl` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to 10 previous errors
 
diff --git a/tests/ui/deref_addrof_macro.rs b/tests/ui/deref_addrof_macro.rs
index dcebd6c6e29..57c0be3f51e 100644
--- a/tests/ui/deref_addrof_macro.rs
+++ b/tests/ui/deref_addrof_macro.rs
@@ -1,10 +1,13 @@
-macro_rules! m {
-    ($($x:tt),*) => { &[$(($x, stringify!(x)),)*] };
-}
+// aux-build:proc_macros.rs
+
+#![warn(clippy::deref_addrof)]
+
+extern crate proc_macros;
 
-#[warn(clippy::deref_addrof)]
-fn f() -> [(i32, &'static str); 3] {
-    *m![1, 2, 3] // should be fine
+#[proc_macros::inline_macros]
+fn f() -> i32 {
+    // should be fine
+    *inline!(&$1)
 }
 
 fn main() {}
diff --git a/tests/ui/doc_unsafe.rs b/tests/ui/doc_unsafe.rs
index b91f7aa0dd8..30674ce3708 100644
--- a/tests/ui/doc_unsafe.rs
+++ b/tests/ui/doc_unsafe.rs
@@ -1,9 +1,9 @@
-// aux-build:doc_unsafe_macros.rs
+// aux-build:proc_macros.rs
 
 #![allow(clippy::let_unit_value)]
 
-#[macro_use]
-extern crate doc_unsafe_macros;
+extern crate proc_macros;
+use proc_macros::external;
 
 /// This is not sufficiently documented
 pub unsafe fn destroy_the_planet() {
@@ -105,7 +105,11 @@ macro_rules! very_unsafe {
 very_unsafe!();
 
 // we don't lint code from external macros
-undocd_unsafe!();
+external! {
+    pub unsafe fn oy_vey() {
+        unimplemented!();
+    }
+}
 
 fn main() {
     unsafe {
diff --git a/tests/ui/empty_loop.rs b/tests/ui/empty_loop.rs
index 8fd7697eb3b..6a8e6b550c1 100644
--- a/tests/ui/empty_loop.rs
+++ b/tests/ui/empty_loop.rs
@@ -1,9 +1,9 @@
-// aux-build:macro_rules.rs
+// aux-build:proc_macros.rs
 
 #![warn(clippy::empty_loop)]
 
-#[macro_use]
-extern crate macro_rules;
+extern crate proc_macros;
+use proc_macros::{external, inline_macros};
 
 fn should_trigger() {
     loop {}
@@ -16,6 +16,7 @@ fn should_trigger() {
     }
 }
 
+#[inline_macros]
 fn should_not_trigger() {
     loop {
         panic!("This is fine")
@@ -38,14 +39,10 @@ fn should_not_trigger() {
     loop {}
 
     // We don't lint loops inside macros
-    macro_rules! foo {
-        () => {
-            loop {}
-        };
-    }
+    inline!(loop {});
 
     // We don't lint external macros
-    foofoo!()
+    external!(loop {});
 }
 
 fn main() {}
diff --git a/tests/ui/equatable_if_let.fixed b/tests/ui/equatable_if_let.fixed
index 9af2ba96272..007702ab550 100644
--- a/tests/ui/equatable_if_let.fixed
+++ b/tests/ui/equatable_if_let.fixed
@@ -1,11 +1,11 @@
 // run-rustfix
-// aux-build:macro_rules.rs
+// aux-build:proc_macros.rs
 
 #![allow(unused_variables, dead_code, clippy::derive_partial_eq_without_eq)]
 #![warn(clippy::equatable_if_let)]
 
-#[macro_use]
-extern crate macro_rules;
+extern crate proc_macros;
+use proc_macros::{external, inline_macros};
 
 use std::cmp::Ordering;
 
@@ -44,6 +44,7 @@ impl PartialEq for NotStructuralEq {
     }
 }
 
+#[inline_macros]
 fn main() {
     let a = 2;
     let b = 3;
@@ -78,14 +79,9 @@ fn main() {
     if Some(g) == Some(NotStructuralEq::A) {}
     if matches!(h, NoPartialEqStruct { a: 2, b: false }) {}
 
-    macro_rules! m1 {
-        (x) => {
-            "abc"
-        };
-    }
-    if "abc" == m1!(x) {
+    if "abc" == inline!("abc") {
         println!("OK");
     }
 
-    equatable_if_let!(a);
+    external!({ if let 2 = $a {} });
 }
diff --git a/tests/ui/equatable_if_let.rs b/tests/ui/equatable_if_let.rs
index c3626c081dd..3bda7977645 100644
--- a/tests/ui/equatable_if_let.rs
+++ b/tests/ui/equatable_if_let.rs
@@ -1,11 +1,11 @@
 // run-rustfix
-// aux-build:macro_rules.rs
+// aux-build:proc_macros.rs
 
 #![allow(unused_variables, dead_code, clippy::derive_partial_eq_without_eq)]
 #![warn(clippy::equatable_if_let)]
 
-#[macro_use]
-extern crate macro_rules;
+extern crate proc_macros;
+use proc_macros::{external, inline_macros};
 
 use std::cmp::Ordering;
 
@@ -44,6 +44,7 @@ impl PartialEq for NotStructuralEq {
     }
 }
 
+#[inline_macros]
 fn main() {
     let a = 2;
     let b = 3;
@@ -78,14 +79,9 @@ fn main() {
     if let Some(NotStructuralEq::A) = Some(g) {}
     if let NoPartialEqStruct { a: 2, b: false } = h {}
 
-    macro_rules! m1 {
-        (x) => {
-            "abc"
-        };
-    }
-    if let m1!(x) = "abc" {
+    if let inline!("abc") = "abc" {
         println!("OK");
     }
 
-    equatable_if_let!(a);
+    external!({ if let 2 = $a {} });
 }
diff --git a/tests/ui/equatable_if_let.stderr b/tests/ui/equatable_if_let.stderr
index 40ca75b8da2..a72d87bb7ba 100644
--- a/tests/ui/equatable_if_let.stderr
+++ b/tests/ui/equatable_if_let.stderr
@@ -1,5 +1,5 @@
 error: this pattern matching can be expressed using equality
-  --> $DIR/equatable_if_let.rs:59:8
+  --> $DIR/equatable_if_let.rs:60:8
    |
 LL |     if let 2 = a {}
    |        ^^^^^^^^^ help: try: `a == 2`
@@ -7,82 +7,82 @@ LL |     if let 2 = a {}
    = note: `-D clippy::equatable-if-let` implied by `-D warnings`
 
 error: this pattern matching can be expressed using equality
-  --> $DIR/equatable_if_let.rs:60:8
+  --> $DIR/equatable_if_let.rs:61:8
    |
 LL |     if let Ordering::Greater = a.cmp(&b) {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `a.cmp(&b) == Ordering::Greater`
 
 error: this pattern matching can be expressed using equality
-  --> $DIR/equatable_if_let.rs:61:8
+  --> $DIR/equatable_if_let.rs:62:8
    |
 LL |     if let Some(2) = c {}
    |        ^^^^^^^^^^^^^^^ help: try: `c == Some(2)`
 
 error: this pattern matching can be expressed using equality
-  --> $DIR/equatable_if_let.rs:62:8
+  --> $DIR/equatable_if_let.rs:63:8
    |
 LL |     if let Struct { a: 2, b: false } = d {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `d == (Struct { a: 2, b: false })`
 
 error: this pattern matching can be expressed using equality
-  --> $DIR/equatable_if_let.rs:63:8
+  --> $DIR/equatable_if_let.rs:64:8
    |
 LL |     if let Enum::TupleVariant(32, 64) = e {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `e == Enum::TupleVariant(32, 64)`
 
 error: this pattern matching can be expressed using equality
-  --> $DIR/equatable_if_let.rs:64:8
+  --> $DIR/equatable_if_let.rs:65:8
    |
 LL |     if let Enum::RecordVariant { a: 64, b: 32 } = e {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `e == (Enum::RecordVariant { a: 64, b: 32 })`
 
 error: this pattern matching can be expressed using equality
-  --> $DIR/equatable_if_let.rs:65:8
+  --> $DIR/equatable_if_let.rs:66:8
    |
 LL |     if let Enum::UnitVariant = e {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `e == Enum::UnitVariant`
 
 error: this pattern matching can be expressed using equality
-  --> $DIR/equatable_if_let.rs:66:8
+  --> $DIR/equatable_if_let.rs:67:8
    |
 LL |     if let (Enum::UnitVariant, &Struct { a: 2, b: false }) = (e, &d) {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(e, &d) == (Enum::UnitVariant, &Struct { a: 2, b: false })`
 
 error: this pattern matching can be expressed using `matches!`
-  --> $DIR/equatable_if_let.rs:75:8
+  --> $DIR/equatable_if_let.rs:76:8
    |
 LL |     if let NotPartialEq::A = f {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(f, NotPartialEq::A)`
 
 error: this pattern matching can be expressed using equality
-  --> $DIR/equatable_if_let.rs:76:8
+  --> $DIR/equatable_if_let.rs:77:8
    |
 LL |     if let NotStructuralEq::A = g {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `g == NotStructuralEq::A`
 
 error: this pattern matching can be expressed using `matches!`
-  --> $DIR/equatable_if_let.rs:77:8
+  --> $DIR/equatable_if_let.rs:78:8
    |
 LL |     if let Some(NotPartialEq::A) = Some(f) {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(Some(f), Some(NotPartialEq::A))`
 
 error: this pattern matching can be expressed using equality
-  --> $DIR/equatable_if_let.rs:78:8
+  --> $DIR/equatable_if_let.rs:79:8
    |
 LL |     if let Some(NotStructuralEq::A) = Some(g) {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(g) == Some(NotStructuralEq::A)`
 
 error: this pattern matching can be expressed using `matches!`
-  --> $DIR/equatable_if_let.rs:79:8
+  --> $DIR/equatable_if_let.rs:80:8
    |
 LL |     if let NoPartialEqStruct { a: 2, b: false } = h {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(h, NoPartialEqStruct { a: 2, b: false })`
 
 error: this pattern matching can be expressed using equality
-  --> $DIR/equatable_if_let.rs:86:8
+  --> $DIR/equatable_if_let.rs:82:8
    |
-LL |     if let m1!(x) = "abc" {
-   |        ^^^^^^^^^^^^^^^^^^ help: try: `"abc" == m1!(x)`
+LL |     if let inline!("abc") = "abc" {
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"abc" == inline!("abc")`
 
 error: aborting due to 14 previous errors
 
diff --git a/tests/ui/field_reassign_with_default.rs b/tests/ui/field_reassign_with_default.rs
index 1f989bb1220..0e208b3ed0e 100644
--- a/tests/ui/field_reassign_with_default.rs
+++ b/tests/ui/field_reassign_with_default.rs
@@ -1,12 +1,12 @@
 // aux-build:proc_macro_derive.rs
-// aux-build:macro_rules.rs
+// aux-build:proc_macros.rs
 
 #![warn(clippy::field_reassign_with_default)]
 
 #[macro_use]
 extern crate proc_macro_derive;
-#[macro_use]
-extern crate macro_rules;
+extern crate proc_macros;
+use proc_macros::{external, inline_macros};
 
 // Don't lint on derives that derive `Default`
 // See https://github.com/rust-lang/rust-clippy/issues/6545
@@ -36,14 +36,6 @@ struct D {
     b: Option<i32>,
 }
 
-macro_rules! m {
-    ($key:ident: $value:tt) => {{
-        let mut data = $crate::D::default();
-        data.$key = Some($value);
-        data
-    }};
-}
-
 /// Implements .next() that returns a different number each time.
 struct SideEffect(i32);
 
@@ -57,6 +49,7 @@ impl SideEffect {
     }
 }
 
+#[inline_macros]
 fn main() {
     // wrong, produces first error in stderr
     let mut a: A = Default::default();
@@ -150,7 +143,18 @@ fn main() {
     a.i = vec![1];
 
     // Don't lint in external macros
-    field_reassign_with_default!();
+    external! {
+        #[derive(Default)]
+        struct A {
+            pub i: i32,
+            pub j: i64,
+        }
+        fn lint() {
+            let mut a: A = Default::default();
+            a.i = 42;
+            a;
+        }
+    }
 
     // be sure suggestion is correct with generics
     let mut a: Wrapper<bool> = Default::default();
@@ -160,9 +164,11 @@ fn main() {
     a.i = 42;
 
     // Don't lint in macros
-    m! {
-        a: 42
-    };
+    inline!(
+        let mut data = $crate::D::default();
+        data.$a = Some($42);
+        data
+    );
 }
 
 mod m {
diff --git a/tests/ui/field_reassign_with_default.stderr b/tests/ui/field_reassign_with_default.stderr
index 710bb66a48a..da74f9ef9f7 100644
--- a/tests/ui/field_reassign_with_default.stderr
+++ b/tests/ui/field_reassign_with_default.stderr
@@ -1,132 +1,132 @@
 error: field assignment outside of initializer for an instance created with Default::default()
-  --> $DIR/field_reassign_with_default.rs:63:5
+  --> $DIR/field_reassign_with_default.rs:56:5
    |
 LL |     a.i = 42;
    |     ^^^^^^^^^
    |
 note: consider initializing the variable with `main::A { i: 42, ..Default::default() }` and removing relevant reassignments
-  --> $DIR/field_reassign_with_default.rs:62:5
+  --> $DIR/field_reassign_with_default.rs:55:5
    |
 LL |     let mut a: A = Default::default();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: `-D clippy::field-reassign-with-default` implied by `-D warnings`
 
 error: field assignment outside of initializer for an instance created with Default::default()
-  --> $DIR/field_reassign_with_default.rs:103:5
+  --> $DIR/field_reassign_with_default.rs:96:5
    |
 LL |     a.j = 43;
    |     ^^^^^^^^^
    |
 note: consider initializing the variable with `main::A { j: 43, i: 42 }` and removing relevant reassignments
-  --> $DIR/field_reassign_with_default.rs:102:5
+  --> $DIR/field_reassign_with_default.rs:95:5
    |
 LL |     let mut a: A = Default::default();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: field assignment outside of initializer for an instance created with Default::default()
-  --> $DIR/field_reassign_with_default.rs:108:5
+  --> $DIR/field_reassign_with_default.rs:101:5
    |
 LL |     a.i = 42;
    |     ^^^^^^^^^
    |
 note: consider initializing the variable with `main::A { i: 42, j: 44 }` and removing relevant reassignments
-  --> $DIR/field_reassign_with_default.rs:107:5
+  --> $DIR/field_reassign_with_default.rs:100:5
    |
 LL |     let mut a: A = Default::default();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: field assignment outside of initializer for an instance created with Default::default()
-  --> $DIR/field_reassign_with_default.rs:114:5
+  --> $DIR/field_reassign_with_default.rs:107:5
    |
 LL |     a.i = 42;
    |     ^^^^^^^^^
    |
 note: consider initializing the variable with `main::A { i: 42, ..Default::default() }` and removing relevant reassignments
-  --> $DIR/field_reassign_with_default.rs:113:5
+  --> $DIR/field_reassign_with_default.rs:106:5
    |
 LL |     let mut a = A::default();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: field assignment outside of initializer for an instance created with Default::default()
-  --> $DIR/field_reassign_with_default.rs:124:5
+  --> $DIR/field_reassign_with_default.rs:117:5
    |
 LL |     a.i = Default::default();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: consider initializing the variable with `main::A { i: Default::default(), ..Default::default() }` and removing relevant reassignments
-  --> $DIR/field_reassign_with_default.rs:123:5
+  --> $DIR/field_reassign_with_default.rs:116:5
    |
 LL |     let mut a: A = Default::default();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: field assignment outside of initializer for an instance created with Default::default()
-  --> $DIR/field_reassign_with_default.rs:128:5
+  --> $DIR/field_reassign_with_default.rs:121:5
    |
 LL |     a.i = Default::default();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: consider initializing the variable with `main::A { i: Default::default(), j: 45 }` and removing relevant reassignments
-  --> $DIR/field_reassign_with_default.rs:127:5
+  --> $DIR/field_reassign_with_default.rs:120:5
    |
 LL |     let mut a: A = Default::default();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: field assignment outside of initializer for an instance created with Default::default()
-  --> $DIR/field_reassign_with_default.rs:150:5
+  --> $DIR/field_reassign_with_default.rs:143:5
    |
 LL |     a.i = vec![1];
    |     ^^^^^^^^^^^^^^
    |
 note: consider initializing the variable with `C { i: vec![1], ..Default::default() }` and removing relevant reassignments
-  --> $DIR/field_reassign_with_default.rs:149:5
+  --> $DIR/field_reassign_with_default.rs:142:5
    |
 LL |     let mut a: C = C::default();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: field assignment outside of initializer for an instance created with Default::default()
-  --> $DIR/field_reassign_with_default.rs:157:5
+  --> $DIR/field_reassign_with_default.rs:161:5
    |
 LL |     a.i = true;
    |     ^^^^^^^^^^^
    |
 note: consider initializing the variable with `Wrapper::<bool> { i: true }` and removing relevant reassignments
-  --> $DIR/field_reassign_with_default.rs:156:5
+  --> $DIR/field_reassign_with_default.rs:160:5
    |
 LL |     let mut a: Wrapper<bool> = Default::default();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: field assignment outside of initializer for an instance created with Default::default()
-  --> $DIR/field_reassign_with_default.rs:160:5
+  --> $DIR/field_reassign_with_default.rs:164:5
    |
 LL |     a.i = 42;
    |     ^^^^^^^^^
    |
 note: consider initializing the variable with `WrapperMulti::<i32, i64> { i: 42, ..Default::default() }` and removing relevant reassignments
-  --> $DIR/field_reassign_with_default.rs:159:5
+  --> $DIR/field_reassign_with_default.rs:163:5
    |
 LL |     let mut a: WrapperMulti<i32, i64> = Default::default();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: field assignment outside of initializer for an instance created with Default::default()
-  --> $DIR/field_reassign_with_default.rs:229:13
+  --> $DIR/field_reassign_with_default.rs:235:13
    |
 LL |             f.name = name.len();
    |             ^^^^^^^^^^^^^^^^^^^^
    |
 note: consider initializing the variable with `issue6312::ImplDropAllCopy { name: name.len(), ..Default::default() }` and removing relevant reassignments
-  --> $DIR/field_reassign_with_default.rs:228:13
+  --> $DIR/field_reassign_with_default.rs:234:13
    |
 LL |             let mut f = ImplDropAllCopy::default();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: field assignment outside of initializer for an instance created with Default::default()
-  --> $DIR/field_reassign_with_default.rs:245:13
+  --> $DIR/field_reassign_with_default.rs:251:13
    |
 LL |             f.name = name.len();
    |             ^^^^^^^^^^^^^^^^^^^^
    |
 note: consider initializing the variable with `issue6312::NoDropAllCopy { name: name.len(), ..Default::default() }` and removing relevant reassignments
-  --> $DIR/field_reassign_with_default.rs:244:13
+  --> $DIR/field_reassign_with_default.rs:250:13
    |
 LL |             let mut f = NoDropAllCopy::default();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/ifs_same_cond.rs b/tests/ui/ifs_same_cond.rs
index 9850fc0919e..9ce9a87626a 100644
--- a/tests/ui/ifs_same_cond.rs
+++ b/tests/ui/ifs_same_cond.rs
@@ -43,4 +43,30 @@ fn ifs_same_cond() {
     }
 }
 
+fn issue10272() {
+    let a = String::from("ha");
+    if a.contains("ah") {
+    } else if a.contains("ah") {
+        // Trigger this lint
+    } else if a.contains("ha") {
+    } else if a == "wow" {
+    }
+
+    let p: *mut i8 = std::ptr::null_mut();
+    if p.is_null() {
+    } else if p.align_offset(0) == 0 {
+    } else if p.is_null() {
+        // ok, p is mutable pointer
+    } else {
+    }
+
+    let x = std::cell::Cell::new(true);
+    if x.get() {
+    } else if !x.take() {
+    } else if x.get() {
+        // ok, x is interior mutable type
+    } else {
+    }
+}
+
 fn main() {}
diff --git a/tests/ui/ifs_same_cond.stderr b/tests/ui/ifs_same_cond.stderr
index 4113087327a..9519f6904cb 100644
--- a/tests/ui/ifs_same_cond.stderr
+++ b/tests/ui/ifs_same_cond.stderr
@@ -35,5 +35,17 @@ note: same as this
 LL |     if 2 * a == 1 {
    |        ^^^^^^^^^^
 
-error: aborting due to 3 previous errors
+error: this `if` has the same condition as a previous `if`
+  --> $DIR/ifs_same_cond.rs:49:15
+   |
+LL |     } else if a.contains("ah") {
+   |               ^^^^^^^^^^^^^^^^
+   |
+note: same as this
+  --> $DIR/ifs_same_cond.rs:48:8
+   |
+LL |     if a.contains("ah") {
+   |        ^^^^^^^^^^^^^^^^
+
+error: aborting due to 4 previous errors
 
diff --git a/tests/ui/implicit_hasher.rs b/tests/ui/implicit_hasher.rs
index fd96ca3f466..35d08a07bc3 100644
--- a/tests/ui/implicit_hasher.rs
+++ b/tests/ui/implicit_hasher.rs
@@ -1,9 +1,11 @@
-// aux-build:implicit_hasher_macros.rs
+// aux-build:proc_macros.rs
+
 #![deny(clippy::implicit_hasher)]
 #![allow(unused)]
 
 #[macro_use]
-extern crate implicit_hasher_macros;
+extern crate proc_macros;
+use proc_macros::external;
 
 use std::cmp::Eq;
 use std::collections::{HashMap, HashSet};
@@ -68,22 +70,19 @@ impl<S: BuildHasher + Default> Foo<i64> for HashSet<String, S> {
 
 pub fn foo(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {}
 
-macro_rules! gen {
-    (impl) => {
+#[proc_macros::inline_macros]
+pub mod gen {
+    use super::*;
+    inline! {
         impl<K: Hash + Eq, V> Foo<u8> for HashMap<K, V> {
             fn make() -> (Self, Self) {
                 (HashMap::new(), HashMap::with_capacity(10))
             }
         }
-    };
 
-    (fn $name:ident) => {
-        pub fn $name(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {}
-    };
+        pub fn bar(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {}
+    }
 }
-#[rustfmt::skip]
-gen!(impl);
-gen!(fn bar);
 
 // When the macro is in a different file, the suggestion spans can't be combined properly
 // and should not cause an ICE
@@ -94,7 +93,9 @@ pub mod test_macro;
 __implicit_hasher_test_macro!(impl<K, V> for HashMap<K, V> where V: test_macro::A);
 
 // #4260
-implicit_hasher_fn!();
+external! {
+    pub fn f(input: &HashMap<u32, u32>) {}
+}
 
 // #7712
 pub async fn election_vote(_data: HashMap<i32, i32>) {}
diff --git a/tests/ui/implicit_hasher.stderr b/tests/ui/implicit_hasher.stderr
index 59b0fba2a4c..83b46de2eb5 100644
--- a/tests/ui/implicit_hasher.stderr
+++ b/tests/ui/implicit_hasher.stderr
@@ -1,11 +1,11 @@
 error: impl for `HashMap` should be generalized over different hashers
-  --> $DIR/implicit_hasher.rs:16:35
+  --> $DIR/implicit_hasher.rs:18:35
    |
 LL | impl<K: Hash + Eq, V> Foo<i8> for HashMap<K, V> {
    |                                   ^^^^^^^^^^^^^
    |
 note: the lint level is defined here
-  --> $DIR/implicit_hasher.rs:2:9
+  --> $DIR/implicit_hasher.rs:3:9
    |
 LL | #![deny(clippy::implicit_hasher)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^
@@ -19,7 +19,7 @@ LL |         (HashMap::default(), HashMap::with_capacity_and_hasher(10, Default:
    |          ~~~~~~~~~~~~~~~~~~  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: impl for `HashMap` should be generalized over different hashers
-  --> $DIR/implicit_hasher.rs:25:36
+  --> $DIR/implicit_hasher.rs:27:36
    |
 LL | impl<K: Hash + Eq, V> Foo<i8> for (HashMap<K, V>,) {
    |                                    ^^^^^^^^^^^^^
@@ -34,7 +34,7 @@ LL |         ((HashMap::default(),), (HashMap::with_capacity_and_hasher(10, Defa
    |           ~~~~~~~~~~~~~~~~~~     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: impl for `HashMap` should be generalized over different hashers
-  --> $DIR/implicit_hasher.rs:30:19
+  --> $DIR/implicit_hasher.rs:32:19
    |
 LL | impl Foo<i16> for HashMap<String, String> {
    |                   ^^^^^^^^^^^^^^^^^^^^^^^
@@ -49,7 +49,7 @@ LL |         (HashMap::default(), HashMap::with_capacity_and_hasher(10, Default:
    |          ~~~~~~~~~~~~~~~~~~  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: impl for `HashSet` should be generalized over different hashers
-  --> $DIR/implicit_hasher.rs:47:32
+  --> $DIR/implicit_hasher.rs:49:32
    |
 LL | impl<T: Hash + Eq> Foo<i8> for HashSet<T> {
    |                                ^^^^^^^^^^
@@ -64,7 +64,7 @@ LL |         (HashSet::default(), HashSet::with_capacity_and_hasher(10, Default:
    |          ~~~~~~~~~~~~~~~~~~  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: impl for `HashSet` should be generalized over different hashers
-  --> $DIR/implicit_hasher.rs:52:19
+  --> $DIR/implicit_hasher.rs:54:19
    |
 LL | impl Foo<i16> for HashSet<String> {
    |                   ^^^^^^^^^^^^^^^
@@ -79,7 +79,7 @@ LL |         (HashSet::default(), HashSet::with_capacity_and_hasher(10, Default:
    |          ~~~~~~~~~~~~~~~~~~  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: parameter of type `HashMap` should be generalized over different hashers
-  --> $DIR/implicit_hasher.rs:69:23
+  --> $DIR/implicit_hasher.rs:71:23
    |
 LL | pub fn foo(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {}
    |                       ^^^^^^^^^^^^^^^^^
@@ -90,7 +90,7 @@ LL | pub fn foo<S: ::std::hash::BuildHasher>(_map: &mut HashMap<i32, i32, S>, _s
    |           +++++++++++++++++++++++++++++            ~~~~~~~~~~~~~~~~~~~~
 
 error: parameter of type `HashSet` should be generalized over different hashers
-  --> $DIR/implicit_hasher.rs:69:53
+  --> $DIR/implicit_hasher.rs:71:53
    |
 LL | pub fn foo(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {}
    |                                                     ^^^^^^^^^^^^
@@ -101,15 +101,12 @@ LL | pub fn foo<S: ::std::hash::BuildHasher>(_map: &mut HashMap<i32, i32>, _set:
    |           +++++++++++++++++++++++++++++                                          ~~~~~~~~~~~~~~~
 
 error: impl for `HashMap` should be generalized over different hashers
-  --> $DIR/implicit_hasher.rs:73:43
+  --> $DIR/implicit_hasher.rs:77:43
    |
 LL |         impl<K: Hash + Eq, V> Foo<u8> for HashMap<K, V> {
    |                                           ^^^^^^^^^^^^^
-...
-LL | gen!(impl);
-   | ---------- in this macro invocation
    |
-   = note: this error originates in the macro `gen` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `__inline_mac_mod_gen` (in Nightly builds, run with -Z macro-backtrace for more info)
 help: consider adding a type parameter
    |
 LL |         impl<K: Hash + Eq, V, S: ::std::hash::BuildHasher + Default> Foo<u8> for HashMap<K, V, S> {
@@ -120,37 +117,31 @@ LL |                 (HashMap::default(), HashMap::with_capacity_and_hasher(10,
    |                  ~~~~~~~~~~~~~~~~~~  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: parameter of type `HashMap` should be generalized over different hashers
-  --> $DIR/implicit_hasher.rs:81:33
+  --> $DIR/implicit_hasher.rs:83:31
    |
-LL |         pub fn $name(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {}
-   |                                 ^^^^^^^^^^^^^^^^^
-...
-LL | gen!(fn bar);
-   | ------------ in this macro invocation
+LL |         pub fn bar(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {}
+   |                               ^^^^^^^^^^^^^^^^^
    |
-   = note: this error originates in the macro `gen` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `__inline_mac_mod_gen` (in Nightly builds, run with -Z macro-backtrace for more info)
 help: consider adding a type parameter
    |
-LL |         pub fn $name<S: ::std::hash::BuildHasher>(_map: &mut HashMap<i32, i32, S>, _set: &mut HashSet<i32>) {}
-   |                     +++++++++++++++++++++++++++++            ~~~~~~~~~~~~~~~~~~~~
+LL |         pub fn bar<S: ::std::hash::BuildHasher>(_map: &mut HashMap<i32, i32, S>, _set: &mut HashSet<i32>) {}
+   |                   +++++++++++++++++++++++++++++            ~~~~~~~~~~~~~~~~~~~~
 
 error: parameter of type `HashSet` should be generalized over different hashers
-  --> $DIR/implicit_hasher.rs:81:63
+  --> $DIR/implicit_hasher.rs:83:61
    |
-LL |         pub fn $name(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {}
-   |                                                               ^^^^^^^^^^^^
-...
-LL | gen!(fn bar);
-   | ------------ in this macro invocation
+LL |         pub fn bar(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {}
+   |                                                             ^^^^^^^^^^^^
    |
-   = note: this error originates in the macro `gen` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `__inline_mac_mod_gen` (in Nightly builds, run with -Z macro-backtrace for more info)
 help: consider adding a type parameter
    |
-LL |         pub fn $name<S: ::std::hash::BuildHasher>(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32, S>) {}
-   |                     +++++++++++++++++++++++++++++                                          ~~~~~~~~~~~~~~~
+LL |         pub fn bar<S: ::std::hash::BuildHasher>(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32, S>) {}
+   |                   +++++++++++++++++++++++++++++                                          ~~~~~~~~~~~~~~~
 
 error: parameter of type `HashMap` should be generalized over different hashers
-  --> $DIR/implicit_hasher.rs:100:35
+  --> $DIR/implicit_hasher.rs:101:35
    |
 LL | pub async fn election_vote(_data: HashMap<i32, i32>) {}
    |                                   ^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/inconsistent_struct_constructor.fixed b/tests/ui/inconsistent_struct_constructor.fixed
index 74ba2f1c5e7..5aaa00f8517 100644
--- a/tests/ui/inconsistent_struct_constructor.fixed
+++ b/tests/ui/inconsistent_struct_constructor.fixed
@@ -1,10 +1,14 @@
 // run-rustfix
+// aux-build:proc_macros.rs
+
 #![warn(clippy::inconsistent_struct_constructor)]
 #![allow(clippy::redundant_field_names)]
 #![allow(clippy::unnecessary_operation)]
 #![allow(clippy::no_effect)]
 #![allow(dead_code)]
 
+extern crate proc_macros;
+
 #[derive(Default)]
 struct Foo {
     x: i32,
@@ -12,18 +16,10 @@ struct Foo {
     z: i32,
 }
 
-macro_rules! new_foo {
-    () => {
-        let x = 1;
-        let y = 1;
-        let z = 1;
-        Foo { y, x, z }
-    };
-}
-
 mod without_base {
     use super::Foo;
 
+    #[proc_macros::inline_macros]
     fn test() {
         let x = 1;
         let y = 1;
@@ -34,7 +30,12 @@ mod without_base {
 
         // Should NOT lint.
         // issue #7069.
-        new_foo!();
+        inline!({
+            let x = 1;
+            let y = 1;
+            let z = 1;
+            Foo { y, x, z }
+        });
 
         // Should NOT lint because the order is the same as in the definition.
         Foo { x, y, z };
diff --git a/tests/ui/inconsistent_struct_constructor.rs b/tests/ui/inconsistent_struct_constructor.rs
index ba96e1e330f..2b2dd7f59a4 100644
--- a/tests/ui/inconsistent_struct_constructor.rs
+++ b/tests/ui/inconsistent_struct_constructor.rs
@@ -1,10 +1,14 @@
 // run-rustfix
+// aux-build:proc_macros.rs
+
 #![warn(clippy::inconsistent_struct_constructor)]
 #![allow(clippy::redundant_field_names)]
 #![allow(clippy::unnecessary_operation)]
 #![allow(clippy::no_effect)]
 #![allow(dead_code)]
 
+extern crate proc_macros;
+
 #[derive(Default)]
 struct Foo {
     x: i32,
@@ -12,18 +16,10 @@ struct Foo {
     z: i32,
 }
 
-macro_rules! new_foo {
-    () => {
-        let x = 1;
-        let y = 1;
-        let z = 1;
-        Foo { y, x, z }
-    };
-}
-
 mod without_base {
     use super::Foo;
 
+    #[proc_macros::inline_macros]
     fn test() {
         let x = 1;
         let y = 1;
@@ -34,7 +30,12 @@ mod without_base {
 
         // Should NOT lint.
         // issue #7069.
-        new_foo!();
+        inline!({
+            let x = 1;
+            let y = 1;
+            let z = 1;
+            Foo { y, x, z }
+        });
 
         // Should NOT lint because the order is the same as in the definition.
         Foo { x, y, z };
diff --git a/tests/ui/inconsistent_struct_constructor.stderr b/tests/ui/inconsistent_struct_constructor.stderr
index c90189e964f..785a6dc9d53 100644
--- a/tests/ui/inconsistent_struct_constructor.stderr
+++ b/tests/ui/inconsistent_struct_constructor.stderr
@@ -1,5 +1,5 @@
 error: struct constructor field order is inconsistent with struct definition field order
-  --> $DIR/inconsistent_struct_constructor.rs:33:9
+  --> $DIR/inconsistent_struct_constructor.rs:29:9
    |
 LL |         Foo { y, x, z };
    |         ^^^^^^^^^^^^^^^ help: try: `Foo { x, y, z }`
@@ -7,7 +7,7 @@ LL |         Foo { y, x, z };
    = note: `-D clippy::inconsistent-struct-constructor` implied by `-D warnings`
 
 error: struct constructor field order is inconsistent with struct definition field order
-  --> $DIR/inconsistent_struct_constructor.rs:55:9
+  --> $DIR/inconsistent_struct_constructor.rs:56:9
    |
 LL | /         Foo {
 LL | |             z,
diff --git a/tests/ui/large_enum_variant.rs b/tests/ui/large_enum_variant.rs
index 3b96f09d7b1..f09f8ae0ccc 100644
--- a/tests/ui/large_enum_variant.rs
+++ b/tests/ui/large_enum_variant.rs
@@ -1,11 +1,11 @@
-// aux-build:macro_rules.rs
+// aux-build:proc_macros.rs
 
 #![allow(dead_code)]
 #![allow(unused_variables)]
 #![warn(clippy::large_enum_variant)]
 
-#[macro_use]
-extern crate macro_rules;
+extern crate proc_macros;
+use proc_macros::external;
 
 enum LargeEnum {
     A(i32),
@@ -155,5 +155,10 @@ enum LargeEnumOfConst {
 }
 
 fn main() {
-    large_enum_variant!();
+    external!(
+        enum LargeEnumInMacro {
+            A(i32),
+            B([i32; 8000]),
+        }
+    );
 }
diff --git a/tests/ui/macro_use_imports.fixed b/tests/ui/macro_use_imports.fixed
index e612480d264..15f7a099a7d 100644
--- a/tests/ui/macro_use_imports.fixed
+++ b/tests/ui/macro_use_imports.fixed
@@ -20,7 +20,7 @@ mod a {
     use mac;
     use mini_mac::ClippyMiniMacroTest;
     use mini_mac;
-    use mac::{inner::foofoo, inner::try_err};
+    use mac::{inner::mut_mut, inner::try_err};
     use mac::inner;
     use mac::inner::nested::string_add;
     use mac::inner::nested;
@@ -36,7 +36,7 @@ mod a {
         let v: ty_macro!() = Vec::default();
 
         inner::try_err!();
-        inner::foofoo!();
+        inner::mut_mut!();
         nested::string_add!();
     }
 }
diff --git a/tests/ui/macro_use_imports.rs b/tests/ui/macro_use_imports.rs
index b34817cc3b2..b1a28733294 100644
--- a/tests/ui/macro_use_imports.rs
+++ b/tests/ui/macro_use_imports.rs
@@ -36,7 +36,7 @@ mod a {
         let v: ty_macro!() = Vec::default();
 
         inner::try_err!();
-        inner::foofoo!();
+        inner::mut_mut!();
         nested::string_add!();
     }
 }
diff --git a/tests/ui/macro_use_imports.stderr b/tests/ui/macro_use_imports.stderr
index 61843124ccd..68d558dede0 100644
--- a/tests/ui/macro_use_imports.stderr
+++ b/tests/ui/macro_use_imports.stderr
@@ -16,7 +16,7 @@ error: `macro_use` attributes are no longer needed in the Rust 2018 edition
   --> $DIR/macro_use_imports.rs:23:5
    |
 LL |     #[macro_use]
-   |     ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{inner::foofoo, inner::try_err};`
+   |     ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{inner::mut_mut, inner::try_err};`
 
 error: `macro_use` attributes are no longer needed in the Rust 2018 edition
   --> $DIR/macro_use_imports.rs:19:5
diff --git a/tests/ui/macro_use_imports_expect.rs b/tests/ui/macro_use_imports_expect.rs
index 8a1b05da9ef..5aac5af26db 100644
--- a/tests/ui/macro_use_imports_expect.rs
+++ b/tests/ui/macro_use_imports_expect.rs
@@ -39,7 +39,7 @@ mod a {
         let v: ty_macro!() = Vec::default();
 
         inner::try_err!();
-        inner::foofoo!();
+        inner::mut_mut!();
         nested::string_add!();
     }
 }
diff --git a/tests/ui/manual_async_fn.fixed b/tests/ui/manual_async_fn.fixed
index b7e46a4a8cc..5cc4a43af7e 100644
--- a/tests/ui/manual_async_fn.fixed
+++ b/tests/ui/manual_async_fn.fixed
@@ -107,4 +107,10 @@ mod issue_5765 {
     }
 }
 
+pub async fn issue_10450() -> i32 { 42 }
+
+pub(crate) async fn issue_10450_2() -> i32 { 42 }
+
+pub(self) async fn issue_10450_3() -> i32 { 42 }
+
 fn main() {}
diff --git a/tests/ui/manual_async_fn.rs b/tests/ui/manual_async_fn.rs
index b05429da662..ba504b8a823 100644
--- a/tests/ui/manual_async_fn.rs
+++ b/tests/ui/manual_async_fn.rs
@@ -127,4 +127,16 @@ mod issue_5765 {
     }
 }
 
+pub fn issue_10450() -> impl Future<Output = i32> {
+    async { 42 }
+}
+
+pub(crate) fn issue_10450_2() -> impl Future<Output = i32> {
+    async { 42 }
+}
+
+pub(self) fn issue_10450_3() -> impl Future<Output = i32> {
+    async { 42 }
+}
+
 fn main() {}
diff --git a/tests/ui/manual_async_fn.stderr b/tests/ui/manual_async_fn.stderr
index 0a903ed6fd4..f5ee3eb7ccc 100644
--- a/tests/ui/manual_async_fn.stderr
+++ b/tests/ui/manual_async_fn.stderr
@@ -161,5 +161,50 @@ help: move the body of the async block to the enclosing function
 LL | fn explicit<'a, 'b>(_: &'a i32, _: &'b i32) -> impl Future<Output = i32> + 'a + 'b { 42 }
    |                                                                                    ~~~~~~
 
-error: aborting due to 10 previous errors
+error: this function can be simplified using the `async fn` syntax
+  --> $DIR/manual_async_fn.rs:130:1
+   |
+LL | pub fn issue_10450() -> impl Future<Output = i32> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: make the function `async` and return the output of the future directly
+   |
+LL | pub async fn issue_10450() -> i32 {
+   | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+help: move the body of the async block to the enclosing function
+   |
+LL | pub fn issue_10450() -> impl Future<Output = i32> { 42 }
+   |                                                   ~~~~~~
+
+error: this function can be simplified using the `async fn` syntax
+  --> $DIR/manual_async_fn.rs:134:1
+   |
+LL | pub(crate) fn issue_10450_2() -> impl Future<Output = i32> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: make the function `async` and return the output of the future directly
+   |
+LL | pub(crate) async fn issue_10450_2() -> i32 {
+   | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+help: move the body of the async block to the enclosing function
+   |
+LL | pub(crate) fn issue_10450_2() -> impl Future<Output = i32> { 42 }
+   |                                                            ~~~~~~
+
+error: this function can be simplified using the `async fn` syntax
+  --> $DIR/manual_async_fn.rs:138:1
+   |
+LL | pub(self) fn issue_10450_3() -> impl Future<Output = i32> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: make the function `async` and return the output of the future directly
+   |
+LL | pub(self) async fn issue_10450_3() -> i32 {
+   | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+help: move the body of the async block to the enclosing function
+   |
+LL | pub(self) fn issue_10450_3() -> impl Future<Output = i32> { 42 }
+   |                                                           ~~~~~~
+
+error: aborting due to 13 previous errors
 
diff --git a/tests/ui/manual_clamp.rs b/tests/ui/manual_clamp.rs
index f7902e6fd53..cdfd8e4c3fe 100644
--- a/tests/ui/manual_clamp.rs
+++ b/tests/ui/manual_clamp.rs
@@ -326,3 +326,22 @@ fn msrv_1_50() {
         input
     };
 }
+
+const fn _const() {
+    let (input, min, max) = (0, -1, 2);
+    let _ = if input < min {
+        min
+    } else if input > max {
+        max
+    } else {
+        input
+    };
+
+    let mut x = input;
+    if max < x {
+        let x = max;
+    }
+    if min > x {
+        x = min;
+    }
+}
diff --git a/tests/ui/manual_main_separator_str.fixed b/tests/ui/manual_main_separator_str.fixed
new file mode 100644
index 00000000000..50f46d6b355
--- /dev/null
+++ b/tests/ui/manual_main_separator_str.fixed
@@ -0,0 +1,39 @@
+// run-rustfix
+
+#![allow(unused)]
+#![warn(clippy::manual_main_separator_str)]
+
+use std::path::MAIN_SEPARATOR;
+
+fn len(s: &str) -> usize {
+    s.len()
+}
+
+struct U<'a> {
+    f: &'a str,
+    g: &'a String,
+}
+
+struct V<T> {
+    f: T,
+}
+
+fn main() {
+    // Should lint
+    let _: &str = std::path::MAIN_SEPARATOR_STR;
+    let _ = len(std::path::MAIN_SEPARATOR_STR);
+    let _: Vec<u16> = std::path::MAIN_SEPARATOR_STR.encode_utf16().collect();
+
+    // Should lint for field `f` only
+    let _ = U {
+        f: std::path::MAIN_SEPARATOR_STR,
+        g: &MAIN_SEPARATOR.to_string(),
+    };
+
+    // Should not lint
+    let _: &String = &MAIN_SEPARATOR.to_string();
+    let _ = &MAIN_SEPARATOR.to_string();
+    let _ = V {
+        f: &MAIN_SEPARATOR.to_string(),
+    };
+}
diff --git a/tests/ui/manual_main_separator_str.rs b/tests/ui/manual_main_separator_str.rs
new file mode 100644
index 00000000000..2dbb9e66151
--- /dev/null
+++ b/tests/ui/manual_main_separator_str.rs
@@ -0,0 +1,39 @@
+// run-rustfix
+
+#![allow(unused)]
+#![warn(clippy::manual_main_separator_str)]
+
+use std::path::MAIN_SEPARATOR;
+
+fn len(s: &str) -> usize {
+    s.len()
+}
+
+struct U<'a> {
+    f: &'a str,
+    g: &'a String,
+}
+
+struct V<T> {
+    f: T,
+}
+
+fn main() {
+    // Should lint
+    let _: &str = &MAIN_SEPARATOR.to_string();
+    let _ = len(&MAIN_SEPARATOR.to_string());
+    let _: Vec<u16> = MAIN_SEPARATOR.to_string().encode_utf16().collect();
+
+    // Should lint for field `f` only
+    let _ = U {
+        f: &MAIN_SEPARATOR.to_string(),
+        g: &MAIN_SEPARATOR.to_string(),
+    };
+
+    // Should not lint
+    let _: &String = &MAIN_SEPARATOR.to_string();
+    let _ = &MAIN_SEPARATOR.to_string();
+    let _ = V {
+        f: &MAIN_SEPARATOR.to_string(),
+    };
+}
diff --git a/tests/ui/manual_main_separator_str.stderr b/tests/ui/manual_main_separator_str.stderr
new file mode 100644
index 00000000000..e6cefde66a7
--- /dev/null
+++ b/tests/ui/manual_main_separator_str.stderr
@@ -0,0 +1,28 @@
+error: taking a reference on `std::path::MAIN_SEPARATOR` conversion to `String`
+  --> $DIR/manual_main_separator_str.rs:23:19
+   |
+LL |     let _: &str = &MAIN_SEPARATOR.to_string();
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `std::path::MAIN_SEPARATOR_STR`
+   |
+   = note: `-D clippy::manual-main-separator-str` implied by `-D warnings`
+
+error: taking a reference on `std::path::MAIN_SEPARATOR` conversion to `String`
+  --> $DIR/manual_main_separator_str.rs:24:17
+   |
+LL |     let _ = len(&MAIN_SEPARATOR.to_string());
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `std::path::MAIN_SEPARATOR_STR`
+
+error: taking a reference on `std::path::MAIN_SEPARATOR` conversion to `String`
+  --> $DIR/manual_main_separator_str.rs:25:23
+   |
+LL |     let _: Vec<u16> = MAIN_SEPARATOR.to_string().encode_utf16().collect();
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `std::path::MAIN_SEPARATOR_STR`
+
+error: taking a reference on `std::path::MAIN_SEPARATOR` conversion to `String`
+  --> $DIR/manual_main_separator_str.rs:29:12
+   |
+LL |         f: &MAIN_SEPARATOR.to_string(),
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `std::path::MAIN_SEPARATOR_STR`
+
+error: aborting due to 4 previous errors
+
diff --git a/tests/ui/manual_rem_euclid.fixed b/tests/ui/manual_rem_euclid.fixed
index 6916a284a20..1f6df1b0a86 100644
--- a/tests/ui/manual_rem_euclid.fixed
+++ b/tests/ui/manual_rem_euclid.fixed
@@ -1,19 +1,13 @@
 // run-rustfix
-// aux-build:macro_rules.rs
+// aux-build:proc_macros.rs
 
 #![warn(clippy::manual_rem_euclid)]
 #![allow(clippy::let_with_type_underscore)]
 
-#[macro_use]
-extern crate macro_rules;
-
-macro_rules! internal_rem_euclid {
-    () => {
-        let value: i32 = 5;
-        let _: i32 = value.rem_euclid(4);
-    };
-}
+extern crate proc_macros;
+use proc_macros::{external, inline_macros};
 
+#[inline_macros]
 fn main() {
     let value: i32 = 5;
 
@@ -39,10 +33,16 @@ fn main() {
     let _: i32 = ((4 % value) + 4) % 4;
 
     // Lint in internal macros
-    internal_rem_euclid!();
+    inline!(
+        let value: i32 = 5;
+        let _: i32 = value.rem_euclid(4);
+    );
 
     // Do not lint in external macros
-    manual_rem_euclid!();
+    external!(
+        let value: i32 = 5;
+        let _: i32 = ((value % 4) + 4) % 4;
+    );
 }
 
 // Should lint for params too
diff --git a/tests/ui/manual_rem_euclid.rs b/tests/ui/manual_rem_euclid.rs
index 412dbddb426..b275e8a38d2 100644
--- a/tests/ui/manual_rem_euclid.rs
+++ b/tests/ui/manual_rem_euclid.rs
@@ -1,19 +1,13 @@
 // run-rustfix
-// aux-build:macro_rules.rs
+// aux-build:proc_macros.rs
 
 #![warn(clippy::manual_rem_euclid)]
 #![allow(clippy::let_with_type_underscore)]
 
-#[macro_use]
-extern crate macro_rules;
-
-macro_rules! internal_rem_euclid {
-    () => {
-        let value: i32 = 5;
-        let _: i32 = ((value % 4) + 4) % 4;
-    };
-}
+extern crate proc_macros;
+use proc_macros::{external, inline_macros};
 
+#[inline_macros]
 fn main() {
     let value: i32 = 5;
 
@@ -39,10 +33,16 @@ fn main() {
     let _: i32 = ((4 % value) + 4) % 4;
 
     // Lint in internal macros
-    internal_rem_euclid!();
+    inline!(
+        let value: i32 = 5;
+        let _: i32 = ((value % 4) + 4) % 4;
+    );
 
     // Do not lint in external macros
-    manual_rem_euclid!();
+    external!(
+        let value: i32 = 5;
+        let _: i32 = ((value % 4) + 4) % 4;
+    );
 }
 
 // Should lint for params too
diff --git a/tests/ui/manual_rem_euclid.stderr b/tests/ui/manual_rem_euclid.stderr
index 6d06654638b..a43707f89c4 100644
--- a/tests/ui/manual_rem_euclid.stderr
+++ b/tests/ui/manual_rem_euclid.stderr
@@ -1,5 +1,5 @@
 error: manual `rem_euclid` implementation
-  --> $DIR/manual_rem_euclid.rs:20:18
+  --> $DIR/manual_rem_euclid.rs:14:18
    |
 LL |     let _: i32 = ((value % 4) + 4) % 4;
    |                  ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `value.rem_euclid(4)`
@@ -7,39 +7,36 @@ LL |     let _: i32 = ((value % 4) + 4) % 4;
    = note: `-D clippy::manual-rem-euclid` implied by `-D warnings`
 
 error: manual `rem_euclid` implementation
-  --> $DIR/manual_rem_euclid.rs:21:18
+  --> $DIR/manual_rem_euclid.rs:15:18
    |
 LL |     let _: i32 = (4 + (value % 4)) % 4;
    |                  ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `value.rem_euclid(4)`
 
 error: manual `rem_euclid` implementation
-  --> $DIR/manual_rem_euclid.rs:22:18
+  --> $DIR/manual_rem_euclid.rs:16:18
    |
 LL |     let _: i32 = (value % 4 + 4) % 4;
    |                  ^^^^^^^^^^^^^^^^^^^ help: consider using: `value.rem_euclid(4)`
 
 error: manual `rem_euclid` implementation
-  --> $DIR/manual_rem_euclid.rs:23:18
+  --> $DIR/manual_rem_euclid.rs:17:18
    |
 LL |     let _: i32 = (4 + value % 4) % 4;
    |                  ^^^^^^^^^^^^^^^^^^^ help: consider using: `value.rem_euclid(4)`
 
 error: manual `rem_euclid` implementation
-  --> $DIR/manual_rem_euclid.rs:24:22
+  --> $DIR/manual_rem_euclid.rs:18:22
    |
 LL |     let _: i32 = 1 + (4 + value % 4) % 4;
    |                      ^^^^^^^^^^^^^^^^^^^ help: consider using: `value.rem_euclid(4)`
 
 error: manual `rem_euclid` implementation
-  --> $DIR/manual_rem_euclid.rs:13:22
+  --> $DIR/manual_rem_euclid.rs:38:22
    |
 LL |         let _: i32 = ((value % 4) + 4) % 4;
    |                      ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `value.rem_euclid(4)`
-...
-LL |     internal_rem_euclid!();
-   |     ---------------------- in this macro invocation
    |
-   = note: this error originates in the macro `internal_rem_euclid` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: manual `rem_euclid` implementation
   --> $DIR/manual_rem_euclid.rs:50:5
diff --git a/tests/ui/match_single_binding.fixed b/tests/ui/match_single_binding.fixed
index 6cfb6661a03..201301cc9b7 100644
--- a/tests/ui/match_single_binding.fixed
+++ b/tests/ui/match_single_binding.fixed
@@ -1,7 +1,12 @@
 // run-rustfix
 #![warn(clippy::match_single_binding)]
-#![allow(unused_variables)]
-#![allow(clippy::toplevel_ref_arg, clippy::uninlined_format_args)]
+#![allow(
+    unused,
+    clippy::let_unit_value,
+    clippy::no_effect,
+    clippy::toplevel_ref_arg,
+    clippy::uninlined_format_args
+)]
 
 struct Point {
     x: i32,
@@ -109,10 +114,9 @@ fn main() {
 
     // Lint
     let x = 1;
-    println!("Not an array index start");
+    println!("Not an array index start")
 }
 
-#[allow(dead_code)]
 fn issue_8723() {
     let (mut val, idx) = ("a b", 1);
 
@@ -125,16 +129,15 @@ fn issue_8723() {
     let _ = val;
 }
 
-#[allow(dead_code)]
+fn side_effects() {}
+
 fn issue_9575() {
-    fn side_effects() {}
     let _ = || {
         side_effects();
-        println!("Needs curlies");
+        println!("Needs curlies")
     };
 }
 
-#[allow(dead_code)]
 fn issue_9725(r: Option<u32>) {
     let x = r;
     match x {
@@ -146,3 +149,25 @@ fn issue_9725(r: Option<u32>) {
         },
     };
 }
+
+fn issue_10447() -> usize {
+    ();
+
+    let a = ();
+
+    side_effects();
+
+    let b = side_effects();
+
+    println!("1");
+
+    let c = println!("1");
+
+    let in_expr = [
+        (),
+        side_effects(),
+        println!("1"),
+    ];
+
+    2
+}
diff --git a/tests/ui/match_single_binding.rs b/tests/ui/match_single_binding.rs
index f188aeb5f2f..8b047b19ce9 100644
--- a/tests/ui/match_single_binding.rs
+++ b/tests/ui/match_single_binding.rs
@@ -1,7 +1,12 @@
 // run-rustfix
 #![warn(clippy::match_single_binding)]
-#![allow(unused_variables)]
-#![allow(clippy::toplevel_ref_arg, clippy::uninlined_format_args)]
+#![allow(
+    unused,
+    clippy::let_unit_value,
+    clippy::no_effect,
+    clippy::toplevel_ref_arg,
+    clippy::uninlined_format_args
+)]
 
 struct Point {
     x: i32,
@@ -127,7 +132,6 @@ fn main() {
     }
 }
 
-#[allow(dead_code)]
 fn issue_8723() {
     let (mut val, idx) = ("a b", 1);
 
@@ -141,15 +145,14 @@ fn issue_8723() {
     let _ = val;
 }
 
-#[allow(dead_code)]
+fn side_effects() {}
+
 fn issue_9575() {
-    fn side_effects() {}
     let _ = || match side_effects() {
         _ => println!("Needs curlies"),
     };
 }
 
-#[allow(dead_code)]
 fn issue_9725(r: Option<u32>) {
     match r {
         x => match x {
@@ -162,3 +165,43 @@ fn issue_9725(r: Option<u32>) {
         },
     };
 }
+
+fn issue_10447() -> usize {
+    match 1 {
+        _ => (),
+    }
+
+    let a = match 1 {
+        _ => (),
+    };
+
+    match 1 {
+        _ => side_effects(),
+    }
+
+    let b = match 1 {
+        _ => side_effects(),
+    };
+
+    match 1 {
+        _ => println!("1"),
+    }
+
+    let c = match 1 {
+        _ => println!("1"),
+    };
+
+    let in_expr = [
+        match 1 {
+            _ => (),
+        },
+        match 1 {
+            _ => side_effects(),
+        },
+        match 1 {
+            _ => println!("1"),
+        },
+    ];
+
+    2
+}
diff --git a/tests/ui/match_single_binding.stderr b/tests/ui/match_single_binding.stderr
index e960d64ad2b..9d16af76c6a 100644
--- a/tests/ui/match_single_binding.stderr
+++ b/tests/ui/match_single_binding.stderr
@@ -1,5 +1,5 @@
 error: this match could be written as a `let` statement
-  --> $DIR/match_single_binding.rs:28:5
+  --> $DIR/match_single_binding.rs:33:5
    |
 LL | /     match (a, b, c) {
 LL | |         (x, y, z) => {
@@ -18,7 +18,7 @@ LL +     }
    |
 
 error: this match could be written as a `let` statement
-  --> $DIR/match_single_binding.rs:34:5
+  --> $DIR/match_single_binding.rs:39:5
    |
 LL | /     match (a, b, c) {
 LL | |         (x, y, z) => println!("{} {} {}", x, y, z),
@@ -32,7 +32,7 @@ LL +     println!("{} {} {}", x, y, z);
    |
 
 error: this match could be replaced by its body itself
-  --> $DIR/match_single_binding.rs:51:5
+  --> $DIR/match_single_binding.rs:56:5
    |
 LL | /     match a {
 LL | |         _ => println!("whatever"),
@@ -40,7 +40,7 @@ LL | |     }
    | |_____^ help: consider using the match body instead: `println!("whatever");`
 
 error: this match could be replaced by its body itself
-  --> $DIR/match_single_binding.rs:55:5
+  --> $DIR/match_single_binding.rs:60:5
    |
 LL | /     match a {
 LL | |         _ => {
@@ -59,7 +59,7 @@ LL +     }
    |
 
 error: this match could be replaced by its body itself
-  --> $DIR/match_single_binding.rs:62:5
+  --> $DIR/match_single_binding.rs:67:5
    |
 LL | /     match a {
 LL | |         _ => {
@@ -81,7 +81,7 @@ LL +     }
    |
 
 error: this match could be written as a `let` statement
-  --> $DIR/match_single_binding.rs:72:5
+  --> $DIR/match_single_binding.rs:77:5
    |
 LL | /     match p {
 LL | |         Point { x, y } => println!("Coords: ({}, {})", x, y),
@@ -95,7 +95,7 @@ LL +     println!("Coords: ({}, {})", x, y);
    |
 
 error: this match could be written as a `let` statement
-  --> $DIR/match_single_binding.rs:76:5
+  --> $DIR/match_single_binding.rs:81:5
    |
 LL | /     match p {
 LL | |         Point { x: x1, y: y1 } => println!("Coords: ({}, {})", x1, y1),
@@ -109,7 +109,7 @@ LL +     println!("Coords: ({}, {})", x1, y1);
    |
 
 error: this match could be written as a `let` statement
-  --> $DIR/match_single_binding.rs:81:5
+  --> $DIR/match_single_binding.rs:86:5
    |
 LL | /     match x {
 LL | |         ref r => println!("Got a reference to {}", r),
@@ -123,7 +123,7 @@ LL +     println!("Got a reference to {}", r);
    |
 
 error: this match could be written as a `let` statement
-  --> $DIR/match_single_binding.rs:86:5
+  --> $DIR/match_single_binding.rs:91:5
    |
 LL | /     match x {
 LL | |         ref mut mr => println!("Got a mutable reference to {}", mr),
@@ -137,7 +137,7 @@ LL +     println!("Got a mutable reference to {}", mr);
    |
 
 error: this match could be written as a `let` statement
-  --> $DIR/match_single_binding.rs:90:5
+  --> $DIR/match_single_binding.rs:95:5
    |
 LL | /     let product = match coords() {
 LL | |         Point { x, y } => x * y,
@@ -151,7 +151,7 @@ LL +     let product = x * y;
    |
 
 error: this match could be written as a `let` statement
-  --> $DIR/match_single_binding.rs:98:18
+  --> $DIR/match_single_binding.rs:103:18
    |
 LL |           .map(|i| match i.unwrap() {
    |  __________________^
@@ -168,16 +168,16 @@ LL ~         })
    |
 
 error: this match could be replaced by its body itself
-  --> $DIR/match_single_binding.rs:124:5
+  --> $DIR/match_single_binding.rs:129:5
    |
 LL | /     match x {
 LL | |         // =>
 LL | |         _ => println!("Not an array index start"),
 LL | |     }
-   | |_____^ help: consider using the match body instead: `println!("Not an array index start");`
+   | |_____^ help: consider using the match body instead: `println!("Not an array index start")`
 
 error: this assignment could be simplified
-  --> $DIR/match_single_binding.rs:134:5
+  --> $DIR/match_single_binding.rs:138:5
    |
 LL | /     val = match val.split_at(idx) {
 LL | |         (pre, suf) => {
@@ -197,7 +197,7 @@ LL ~     };
    |
 
 error: this match could be replaced by its scrutinee and body
-  --> $DIR/match_single_binding.rs:147:16
+  --> $DIR/match_single_binding.rs:151:16
    |
 LL |       let _ = || match side_effects() {
    |  ________________^
@@ -209,12 +209,12 @@ help: consider using the scrutinee and body instead
    |
 LL ~     let _ = || {
 LL +         side_effects();
-LL +         println!("Needs curlies");
+LL +         println!("Needs curlies")
 LL ~     };
    |
 
 error: this match could be written as a `let` statement
-  --> $DIR/match_single_binding.rs:154:5
+  --> $DIR/match_single_binding.rs:157:5
    |
 LL | /     match r {
 LL | |         x => match x {
@@ -238,5 +238,80 @@ LL +         },
 LL ~     };
    |
 
-error: aborting due to 15 previous errors
+error: this match could be replaced by its body itself
+  --> $DIR/match_single_binding.rs:170:5
+   |
+LL | /     match 1 {
+LL | |         _ => (),
+LL | |     }
+   | |_____^ help: consider using the match body instead: `();`
+
+error: this match could be replaced by its body itself
+  --> $DIR/match_single_binding.rs:174:13
+   |
+LL |       let a = match 1 {
+   |  _____________^
+LL | |         _ => (),
+LL | |     };
+   | |_____^ help: consider using the match body instead: `()`
+
+error: this match could be replaced by its body itself
+  --> $DIR/match_single_binding.rs:178:5
+   |
+LL | /     match 1 {
+LL | |         _ => side_effects(),
+LL | |     }
+   | |_____^ help: consider using the match body instead: `side_effects();`
+
+error: this match could be replaced by its body itself
+  --> $DIR/match_single_binding.rs:182:13
+   |
+LL |       let b = match 1 {
+   |  _____________^
+LL | |         _ => side_effects(),
+LL | |     };
+   | |_____^ help: consider using the match body instead: `side_effects()`
+
+error: this match could be replaced by its body itself
+  --> $DIR/match_single_binding.rs:186:5
+   |
+LL | /     match 1 {
+LL | |         _ => println!("1"),
+LL | |     }
+   | |_____^ help: consider using the match body instead: `println!("1");`
+
+error: this match could be replaced by its body itself
+  --> $DIR/match_single_binding.rs:190:13
+   |
+LL |       let c = match 1 {
+   |  _____________^
+LL | |         _ => println!("1"),
+LL | |     };
+   | |_____^ help: consider using the match body instead: `println!("1")`
+
+error: this match could be replaced by its body itself
+  --> $DIR/match_single_binding.rs:195:9
+   |
+LL | /         match 1 {
+LL | |             _ => (),
+LL | |         },
+   | |_________^ help: consider using the match body instead: `()`
+
+error: this match could be replaced by its body itself
+  --> $DIR/match_single_binding.rs:198:9
+   |
+LL | /         match 1 {
+LL | |             _ => side_effects(),
+LL | |         },
+   | |_________^ help: consider using the match body instead: `side_effects()`
+
+error: this match could be replaced by its body itself
+  --> $DIR/match_single_binding.rs:201:9
+   |
+LL | /         match 1 {
+LL | |             _ => println!("1"),
+LL | |         },
+   | |_________^ help: consider using the match body instead: `println!("1")`
+
+error: aborting due to 24 previous errors
 
diff --git a/tests/ui/match_single_binding2.fixed b/tests/ui/match_single_binding2.fixed
index 6a7db67e311..e3cf56a4293 100644
--- a/tests/ui/match_single_binding2.fixed
+++ b/tests/ui/match_single_binding2.fixed
@@ -30,7 +30,7 @@ fn main() {
         #[rustfmt::skip]
         Some((first, _second)) => {
             let (a, b) = get_tup();
-            println!("a {:?} and b {:?}", a, b);
+            println!("a {:?} and b {:?}", a, b)
         },
         None => println!("nothing"),
     }
@@ -49,5 +49,5 @@ fn main() {
         0 => 1,
         _ => 2,
     };
-    println!("Single branch");
+    println!("Single branch")
 }
diff --git a/tests/ui/match_single_binding2.stderr b/tests/ui/match_single_binding2.stderr
index 22bf7d8be4a..e180b93e76d 100644
--- a/tests/ui/match_single_binding2.stderr
+++ b/tests/ui/match_single_binding2.stderr
@@ -27,7 +27,7 @@ LL | |             }
 help: consider using a `let` statement
    |
 LL ~             let (a, b) = get_tup();
-LL +             println!("a {:?} and b {:?}", a, b);
+LL +             println!("a {:?} and b {:?}", a, b)
    |
 
 error: this match could be replaced by its scrutinee and body
@@ -61,7 +61,7 @@ LL ~     match x {
 LL +         0 => 1,
 LL +         _ => 2,
 LL +     };
-LL +     println!("Single branch");
+LL +     println!("Single branch")
    |
 
 error: aborting due to 4 previous errors
diff --git a/tests/ui/mem_replace_macro.rs b/tests/ui/mem_replace_macro.rs
index 0c09344b80d..3932e7d00c1 100644
--- a/tests/ui/mem_replace_macro.rs
+++ b/tests/ui/mem_replace_macro.rs
@@ -1,21 +1,12 @@
-// aux-build:macro_rules.rs
+// aux-build:proc_macros.rs
 #![warn(clippy::mem_replace_with_default)]
 
-#[macro_use]
-extern crate macro_rules;
-
-macro_rules! take {
-    ($s:expr) => {
-        std::mem::replace($s, Default::default())
-    };
-}
-
-fn replace_with_default() {
-    let s = &mut String::from("foo");
-    take!(s);
-    take_external!(s);
-}
+extern crate proc_macros;
+use proc_macros::{external, inline_macros};
 
+#[inline_macros]
 fn main() {
-    replace_with_default();
+    let s = &mut String::from("foo");
+    inline!(std::mem::replace($s, Default::default()));
+    external!(std::mem::replace($s, Default::default()));
 }
diff --git a/tests/ui/mem_replace_macro.stderr b/tests/ui/mem_replace_macro.stderr
index dd69ab8b5ef..35dda93da3d 100644
--- a/tests/ui/mem_replace_macro.stderr
+++ b/tests/ui/mem_replace_macro.stderr
@@ -1,14 +1,11 @@
 error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
-  --> $DIR/mem_replace_macro.rs:9:9
+  --> $DIR/mem_replace_macro.rs:10:13
    |
-LL |         std::mem::replace($s, Default::default())
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-...
-LL |     take!(s);
-   |     -------- in this macro invocation
+LL |     inline!(std::mem::replace($s, Default::default()));
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: `-D clippy::mem-replace-with-default` implied by `-D warnings`
-   = note: this error originates in the macro `take` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to previous error
 
diff --git a/tests/ui/missing_const_for_fn/cant_be_const.rs b/tests/ui/missing_const_for_fn/cant_be_const.rs
index 75cace18167..e6f88c6e622 100644
--- a/tests/ui/missing_const_for_fn/cant_be_const.rs
+++ b/tests/ui/missing_const_for_fn/cant_be_const.rs
@@ -3,15 +3,15 @@
 //! The .stderr output of this test should be empty. Otherwise it's a bug somewhere.
 
 // aux-build:helper.rs
-// aux-build:../../auxiliary/proc_macro_with_span.rs
+// aux-build:../../auxiliary/proc_macros.rs
 
 #![warn(clippy::missing_const_for_fn)]
 #![feature(start)]
 
 extern crate helper;
-extern crate proc_macro_with_span;
+extern crate proc_macros;
 
-use proc_macro_with_span::with_span;
+use proc_macros::with_span;
 
 struct Game;
 
diff --git a/tests/ui/missing_doc.rs b/tests/ui/missing_doc.rs
index 590ad63c90b..5752048949c 100644
--- a/tests/ui/missing_doc.rs
+++ b/tests/ui/missing_doc.rs
@@ -1,5 +1,5 @@
 // needs-asm-support
-// aux-build: proc_macro_with_span.rs
+// aux-build: proc_macros.rs
 
 #![warn(clippy::missing_docs_in_private_items)]
 // When denying at the crate level, be sure to not get random warnings from the
@@ -8,9 +8,9 @@
 //! Some garbage docs for the crate here
 #![doc = "More garbage"]
 
-extern crate proc_macro_with_span;
+extern crate proc_macros;
 
-use proc_macro_with_span::with_span;
+use proc_macros::with_span;
 use std::arch::global_asm;
 
 type Typedef = String;
diff --git a/tests/ui/missing_doc_impl.rs b/tests/ui/missing_doc_impl.rs
index 0396d1193ff..e2d49b0907d 100644
--- a/tests/ui/missing_doc_impl.rs
+++ b/tests/ui/missing_doc_impl.rs
@@ -1,4 +1,4 @@
-// aux-build: proc_macro_with_span.rs
+// aux-build: proc_macros.rs
 
 #![warn(clippy::missing_docs_in_private_items)]
 #![allow(dead_code)]
@@ -7,8 +7,8 @@
 //! Some garbage docs for the crate here
 #![doc = "More garbage"]
 
-extern crate proc_macro_with_span;
-use proc_macro_with_span::with_span;
+extern crate proc_macros;
+use proc_macros::with_span;
 
 struct Foo {
     a: isize,
diff --git a/tests/ui/mistyped_literal_suffix.fixed b/tests/ui/mistyped_literal_suffix.fixed
index becb9562a84..9a47d7c56ed 100644
--- a/tests/ui/mistyped_literal_suffix.fixed
+++ b/tests/ui/mistyped_literal_suffix.fixed
@@ -1,5 +1,5 @@
 // run-rustfix
-// aux-build: proc_macro_with_span.rs
+// aux-build: proc_macros.rs
 
 #![allow(
     dead_code,
@@ -10,8 +10,8 @@
     clippy::unusual_byte_groupings
 )]
 
-extern crate proc_macro_with_span;
-use proc_macro_with_span::with_span;
+extern crate proc_macros;
+use proc_macros::with_span;
 
 fn main() {
     let fail14 = 2_i32;
diff --git a/tests/ui/mistyped_literal_suffix.rs b/tests/ui/mistyped_literal_suffix.rs
index ee841bcd7e4..04261cba55a 100644
--- a/tests/ui/mistyped_literal_suffix.rs
+++ b/tests/ui/mistyped_literal_suffix.rs
@@ -1,5 +1,5 @@
 // run-rustfix
-// aux-build: proc_macro_with_span.rs
+// aux-build: proc_macros.rs
 
 #![allow(
     dead_code,
@@ -10,8 +10,8 @@
     clippy::unusual_byte_groupings
 )]
 
-extern crate proc_macro_with_span;
-use proc_macro_with_span::with_span;
+extern crate proc_macros;
+use proc_macros::with_span;
 
 fn main() {
     let fail14 = 2_32;
diff --git a/tests/ui/multiple_unsafe_ops_per_block.rs b/tests/ui/multiple_unsafe_ops_per_block.rs
index 5073685c9f0..9082f1675a8 100644
--- a/tests/ui/multiple_unsafe_ops_per_block.rs
+++ b/tests/ui/multiple_unsafe_ops_per_block.rs
@@ -1,12 +1,12 @@
-// aux-build:macro_rules.rs
+// aux-build:proc_macros.rs
 #![allow(unused)]
 #![allow(deref_nullptr)]
 #![allow(clippy::unnecessary_operation)]
 #![allow(clippy::drop_copy)]
 #![warn(clippy::multiple_unsafe_ops_per_block)]
 
-#[macro_use]
-extern crate macro_rules;
+extern crate proc_macros;
+use proc_macros::external;
 
 use core::arch::asm;
 
@@ -113,7 +113,10 @@ unsafe fn read_char_good(ptr: *const u8) -> char {
 
 // no lint
 fn issue10259() {
-    unsafe_macro!();
+    external!(unsafe {
+        *core::ptr::null::<()>();
+        *core::ptr::null::<()>();
+    });
 }
 
 fn _fn_ptr(x: unsafe fn()) {
diff --git a/tests/ui/multiple_unsafe_ops_per_block.stderr b/tests/ui/multiple_unsafe_ops_per_block.stderr
index e0c1d3801f7..badc284ec42 100644
--- a/tests/ui/multiple_unsafe_ops_per_block.stderr
+++ b/tests/ui/multiple_unsafe_ops_per_block.stderr
@@ -126,7 +126,7 @@ LL |     unsafe { char::from_u32_unchecked(*ptr.cast::<u32>()) }
    |                                       ^^^^^^^^^^^^^^^^^^
 
 error: this `unsafe` block contains 2 unsafe operations, expected only one
-  --> $DIR/multiple_unsafe_ops_per_block.rs:120:5
+  --> $DIR/multiple_unsafe_ops_per_block.rs:123:5
    |
 LL | /     unsafe {
 LL | |         x();
@@ -135,18 +135,18 @@ LL | |     }
    | |_____^
    |
 note: unsafe function call occurs here
-  --> $DIR/multiple_unsafe_ops_per_block.rs:121:9
+  --> $DIR/multiple_unsafe_ops_per_block.rs:124:9
    |
 LL |         x();
    |         ^^^
 note: unsafe function call occurs here
-  --> $DIR/multiple_unsafe_ops_per_block.rs:122:9
+  --> $DIR/multiple_unsafe_ops_per_block.rs:125:9
    |
 LL |         x();
    |         ^^^
 
 error: this `unsafe` block contains 2 unsafe operations, expected only one
-  --> $DIR/multiple_unsafe_ops_per_block.rs:131:9
+  --> $DIR/multiple_unsafe_ops_per_block.rs:134:9
    |
 LL | /         unsafe {
 LL | |             T::X();
@@ -155,18 +155,18 @@ LL | |         }
    | |_________^
    |
 note: unsafe function call occurs here
-  --> $DIR/multiple_unsafe_ops_per_block.rs:132:13
+  --> $DIR/multiple_unsafe_ops_per_block.rs:135:13
    |
 LL |             T::X();
    |             ^^^^^^
 note: unsafe function call occurs here
-  --> $DIR/multiple_unsafe_ops_per_block.rs:133:13
+  --> $DIR/multiple_unsafe_ops_per_block.rs:136:13
    |
 LL |             T::X();
    |             ^^^^^^
 
 error: this `unsafe` block contains 2 unsafe operations, expected only one
-  --> $DIR/multiple_unsafe_ops_per_block.rs:141:5
+  --> $DIR/multiple_unsafe_ops_per_block.rs:144:5
    |
 LL | /     unsafe {
 LL | |         x.0();
@@ -175,12 +175,12 @@ LL | |     }
    | |_____^
    |
 note: unsafe function call occurs here
-  --> $DIR/multiple_unsafe_ops_per_block.rs:142:9
+  --> $DIR/multiple_unsafe_ops_per_block.rs:145:9
    |
 LL |         x.0();
    |         ^^^^^
 note: unsafe function call occurs here
-  --> $DIR/multiple_unsafe_ops_per_block.rs:143:9
+  --> $DIR/multiple_unsafe_ops_per_block.rs:146:9
    |
 LL |         x.0();
    |         ^^^^^
diff --git a/tests/ui/must_use_unit.fixed b/tests/ui/must_use_unit.fixed
index 6c9aa434ac0..b7d375ff80e 100644
--- a/tests/ui/must_use_unit.fixed
+++ b/tests/ui/must_use_unit.fixed
@@ -1,11 +1,11 @@
 //run-rustfix
-// aux-build:macro_rules.rs
+// aux-build:proc_macros.rs
 
 #![warn(clippy::must_use_unit)]
 #![allow(clippy::unused_unit)]
 
-#[macro_use]
-extern crate macro_rules;
+extern crate proc_macros;
+use proc_macros::external;
 
 
 pub fn must_use_default() {}
@@ -22,5 +22,8 @@ fn main() {
     must_use_with_note();
 
     // We should not lint in external macros
-    must_use_unit!();
+    external!(
+        #[must_use]
+        fn foo() {}
+    );
 }
diff --git a/tests/ui/must_use_unit.rs b/tests/ui/must_use_unit.rs
index 8a395dc284d..74d6b4ca865 100644
--- a/tests/ui/must_use_unit.rs
+++ b/tests/ui/must_use_unit.rs
@@ -1,11 +1,11 @@
 //run-rustfix
-// aux-build:macro_rules.rs
+// aux-build:proc_macros.rs
 
 #![warn(clippy::must_use_unit)]
 #![allow(clippy::unused_unit)]
 
-#[macro_use]
-extern crate macro_rules;
+extern crate proc_macros;
+use proc_macros::external;
 
 #[must_use]
 pub fn must_use_default() {}
@@ -22,5 +22,8 @@ fn main() {
     must_use_with_note();
 
     // We should not lint in external macros
-    must_use_unit!();
+    external!(
+        #[must_use]
+        fn foo() {}
+    );
 }
diff --git a/tests/ui/mut_mut.rs b/tests/ui/mut_mut.rs
index ee3a856566c..06bb085442a 100644
--- a/tests/ui/mut_mut.rs
+++ b/tests/ui/mut_mut.rs
@@ -1,10 +1,10 @@
-// aux-build:macro_rules.rs
+// aux-build:proc_macros.rs
 #![warn(clippy::mut_mut)]
 #![allow(unused)]
 #![allow(clippy::no_effect, clippy::uninlined_format_args, clippy::unnecessary_operation)]
 
-#[macro_use]
-extern crate macro_rules;
+extern crate proc_macros;
+use proc_macros::{external, inline_macros};
 
 fn fun(x: &mut &mut u32) -> bool {
     **x > 0
@@ -21,6 +21,7 @@ macro_rules! mut_ptr {
 }
 
 #[allow(unused_mut, unused_variables)]
+#[inline_macros]
 fn main() {
     let mut x = &mut &mut 1u32;
     {
@@ -37,7 +38,7 @@ fn main() {
         ***y + **x;
     }
 
-    let mut z = mut_ptr!(&mut 3u32);
+    let mut z = inline!(&mut $(&mut 3u32));
 }
 
 fn issue939() {
@@ -55,7 +56,7 @@ fn issue939() {
 
 fn issue6922() {
     // do not lint from an external macro
-    mut_mut!();
+    external!(let mut_mut_ty: &mut &mut u32 = &mut &mut 1u32;);
 }
 
 mod issue9035 {
diff --git a/tests/ui/mut_mut.stderr b/tests/ui/mut_mut.stderr
index 6820a85aa54..93b857eb207 100644
--- a/tests/ui/mut_mut.stderr
+++ b/tests/ui/mut_mut.stderr
@@ -7,54 +7,51 @@ LL | fn fun(x: &mut &mut u32) -> bool {
    = note: `-D clippy::mut-mut` implied by `-D warnings`
 
 error: generally you want to avoid `&mut &mut _` if possible
-  --> $DIR/mut_mut.rs:25:17
+  --> $DIR/mut_mut.rs:26:17
    |
 LL |     let mut x = &mut &mut 1u32;
    |                 ^^^^^^^^^^^^^^
 
 error: generally you want to avoid `&mut &mut _` if possible
-  --> $DIR/mut_mut.rs:19:9
+  --> $DIR/mut_mut.rs:41:25
    |
-LL |         &mut $p
-   |         ^^^^^^^
-...
-LL |     let mut z = mut_ptr!(&mut 3u32);
-   |                 ------------------- in this macro invocation
+LL |     let mut z = inline!(&mut $(&mut 3u32));
+   |                         ^
    |
-   = note: this error originates in the macro `mut_ptr` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: this expression mutably borrows a mutable reference. Consider reborrowing
-  --> $DIR/mut_mut.rs:27:21
+  --> $DIR/mut_mut.rs:28:21
    |
 LL |         let mut y = &mut x;
    |                     ^^^^^^
 
 error: generally you want to avoid `&mut &mut _` if possible
-  --> $DIR/mut_mut.rs:31:32
+  --> $DIR/mut_mut.rs:32:32
    |
 LL |         let y: &mut &mut u32 = &mut &mut 2;
    |                                ^^^^^^^^^^^
 
 error: generally you want to avoid `&mut &mut _` if possible
-  --> $DIR/mut_mut.rs:31:16
+  --> $DIR/mut_mut.rs:32:16
    |
 LL |         let y: &mut &mut u32 = &mut &mut 2;
    |                ^^^^^^^^^^^^^
 
 error: generally you want to avoid `&mut &mut _` if possible
-  --> $DIR/mut_mut.rs:36:37
+  --> $DIR/mut_mut.rs:37:37
    |
 LL |         let y: &mut &mut &mut u32 = &mut &mut &mut 2;
    |                                     ^^^^^^^^^^^^^^^^
 
 error: generally you want to avoid `&mut &mut _` if possible
-  --> $DIR/mut_mut.rs:36:16
+  --> $DIR/mut_mut.rs:37:16
    |
 LL |         let y: &mut &mut &mut u32 = &mut &mut &mut 2;
    |                ^^^^^^^^^^^^^^^^^^
 
 error: generally you want to avoid `&mut &mut _` if possible
-  --> $DIR/mut_mut.rs:36:21
+  --> $DIR/mut_mut.rs:37:21
    |
 LL |         let y: &mut &mut &mut u32 = &mut &mut &mut 2;
    |                     ^^^^^^^^^^^^^
diff --git a/tests/ui/needless_late_init.fixed b/tests/ui/needless_late_init.fixed
index 17f2227ba91..86d899bb46c 100644
--- a/tests/ui/needless_late_init.fixed
+++ b/tests/ui/needless_late_init.fixed
@@ -1,4 +1,5 @@
 // run-rustfix
+// aux-build:proc_macros.rs
 #![feature(let_chains)]
 #![allow(unused)]
 #![allow(
@@ -10,6 +11,8 @@
     clippy::uninlined_format_args
 )]
 
+extern crate proc_macros;
+
 use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
 use std::rc::Rc;
 
@@ -138,6 +141,7 @@ const fn in_const() -> &'static str {
     a
 }
 
+#[proc_macros::inline_macros]
 fn does_not_lint() {
     let z;
     if false {
@@ -195,35 +199,27 @@ fn does_not_lint() {
     }
     y = 3;
 
-    macro_rules! assign {
-        ($i:ident) => {
-            $i = 1;
-        };
-    }
     let x;
-    assign!(x);
+    inline!($x = 1;);
 
     let x;
     if true {
-        assign!(x);
+        inline!($x = 1;);
     } else {
         x = 2;
     }
 
-    macro_rules! in_macro {
-        () => {
-            let x;
-            x = 1;
+    inline!({
+        let x;
+        x = 1;
 
-            let x;
-            if true {
-                x = 1;
-            } else {
-                x = 2;
-            }
-        };
-    }
-    in_macro!();
+        let x;
+        if true {
+            x = 1;
+        } else {
+            x = 2;
+        }
+    });
 
     // ignore if-lets - https://github.com/rust-lang/rust-clippy/issues/8613
     let x;
diff --git a/tests/ui/needless_late_init.rs b/tests/ui/needless_late_init.rs
index d84457a2987..969afb38edf 100644
--- a/tests/ui/needless_late_init.rs
+++ b/tests/ui/needless_late_init.rs
@@ -1,4 +1,5 @@
 // run-rustfix
+// aux-build:proc_macros.rs
 #![feature(let_chains)]
 #![allow(unused)]
 #![allow(
@@ -10,6 +11,8 @@
     clippy::uninlined_format_args
 )]
 
+extern crate proc_macros;
+
 use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
 use std::rc::Rc;
 
@@ -138,6 +141,7 @@ const fn in_const() -> &'static str {
     a
 }
 
+#[proc_macros::inline_macros]
 fn does_not_lint() {
     let z;
     if false {
@@ -195,35 +199,27 @@ fn does_not_lint() {
     }
     y = 3;
 
-    macro_rules! assign {
-        ($i:ident) => {
-            $i = 1;
-        };
-    }
     let x;
-    assign!(x);
+    inline!($x = 1;);
 
     let x;
     if true {
-        assign!(x);
+        inline!($x = 1;);
     } else {
         x = 2;
     }
 
-    macro_rules! in_macro {
-        () => {
-            let x;
-            x = 1;
+    inline!({
+        let x;
+        x = 1;
 
-            let x;
-            if true {
-                x = 1;
-            } else {
-                x = 2;
-            }
-        };
-    }
-    in_macro!();
+        let x;
+        if true {
+            x = 1;
+        } else {
+            x = 2;
+        }
+    });
 
     // ignore if-lets - https://github.com/rust-lang/rust-clippy/issues/8613
     let x;
diff --git a/tests/ui/needless_late_init.stderr b/tests/ui/needless_late_init.stderr
index 0a256fb4a13..eff782f8bf1 100644
--- a/tests/ui/needless_late_init.stderr
+++ b/tests/ui/needless_late_init.stderr
@@ -1,5 +1,5 @@
 error: unneeded late initialization
-  --> $DIR/needless_late_init.rs:24:5
+  --> $DIR/needless_late_init.rs:27:5
    |
 LL |     let a;
    |     ^^^^^^ created here
@@ -13,7 +13,7 @@ LL |     let a = "zero";
    |     ~~~~~
 
 error: unneeded late initialization
-  --> $DIR/needless_late_init.rs:27:5
+  --> $DIR/needless_late_init.rs:30:5
    |
 LL |     let b;
    |     ^^^^^^ created here
@@ -27,7 +27,7 @@ LL |     let b = 1;
    |     ~~~~~
 
 error: unneeded late initialization
-  --> $DIR/needless_late_init.rs:28:5
+  --> $DIR/needless_late_init.rs:31:5
    |
 LL |     let c;
    |     ^^^^^^ created here
@@ -41,7 +41,7 @@ LL |     let c = 2;
    |     ~~~~~
 
 error: unneeded late initialization
-  --> $DIR/needless_late_init.rs:32:5
+  --> $DIR/needless_late_init.rs:35:5
    |
 LL |     let d: usize;
    |     ^^^^^^^^^^^^^ created here
@@ -54,7 +54,7 @@ LL |     let d: usize = 1;
    |     ~~~~~~~~~~~~
 
 error: unneeded late initialization
-  --> $DIR/needless_late_init.rs:35:5
+  --> $DIR/needless_late_init.rs:38:5
    |
 LL |     let e;
    |     ^^^^^^ created here
@@ -67,7 +67,7 @@ LL |     let e = format!("{}", d);
    |     ~~~~~
 
 error: unneeded late initialization
-  --> $DIR/needless_late_init.rs:40:5
+  --> $DIR/needless_late_init.rs:43:5
    |
 LL |     let a;
    |     ^^^^^^
@@ -88,7 +88,7 @@ LL |     };
    |      +
 
 error: unneeded late initialization
-  --> $DIR/needless_late_init.rs:49:5
+  --> $DIR/needless_late_init.rs:52:5
    |
 LL |     let b;
    |     ^^^^^^
@@ -109,7 +109,7 @@ LL |     };
    |      +
 
 error: unneeded late initialization
-  --> $DIR/needless_late_init.rs:56:5
+  --> $DIR/needless_late_init.rs:59:5
    |
 LL |     let d;
    |     ^^^^^^
@@ -130,7 +130,7 @@ LL |     };
    |      +
 
 error: unneeded late initialization
-  --> $DIR/needless_late_init.rs:64:5
+  --> $DIR/needless_late_init.rs:67:5
    |
 LL |     let e;
    |     ^^^^^^
@@ -151,7 +151,7 @@ LL |     };
    |      +
 
 error: unneeded late initialization
-  --> $DIR/needless_late_init.rs:71:5
+  --> $DIR/needless_late_init.rs:74:5
    |
 LL |     let f;
    |     ^^^^^^
@@ -167,7 +167,7 @@ LL +         1 => "three",
    |
 
 error: unneeded late initialization
-  --> $DIR/needless_late_init.rs:77:5
+  --> $DIR/needless_late_init.rs:80:5
    |
 LL |     let g: usize;
    |     ^^^^^^^^^^^^^
@@ -187,7 +187,7 @@ LL |     };
    |      +
 
 error: unneeded late initialization
-  --> $DIR/needless_late_init.rs:85:5
+  --> $DIR/needless_late_init.rs:88:5
    |
 LL |     let x;
    |     ^^^^^^ created here
@@ -201,7 +201,7 @@ LL |     let x = 1;
    |     ~~~~~
 
 error: unneeded late initialization
-  --> $DIR/needless_late_init.rs:89:5
+  --> $DIR/needless_late_init.rs:92:5
    |
 LL |     let x;
    |     ^^^^^^ created here
@@ -215,7 +215,7 @@ LL |     let x = SignificantDrop;
    |     ~~~~~
 
 error: unneeded late initialization
-  --> $DIR/needless_late_init.rs:93:5
+  --> $DIR/needless_late_init.rs:96:5
    |
 LL |     let x;
    |     ^^^^^^ created here
@@ -229,7 +229,7 @@ LL |     let x = SignificantDrop;
    |     ~~~~~
 
 error: unneeded late initialization
-  --> $DIR/needless_late_init.rs:112:5
+  --> $DIR/needless_late_init.rs:115:5
    |
 LL |     let a;
    |     ^^^^^^
@@ -250,7 +250,7 @@ LL |     };
    |      +
 
 error: unneeded late initialization
-  --> $DIR/needless_late_init.rs:129:5
+  --> $DIR/needless_late_init.rs:132:5
    |
 LL |     let a;
    |     ^^^^^^
diff --git a/tests/ui/needless_lifetimes.fixed b/tests/ui/needless_lifetimes.fixed
index f0f1f9298ac..e6ead69d148 100644
--- a/tests/ui/needless_lifetimes.fixed
+++ b/tests/ui/needless_lifetimes.fixed
@@ -1,5 +1,5 @@
 // run-rustfix
-// aux-build:macro_rules.rs
+// aux-build:proc_macros.rs
 
 #![warn(clippy::needless_lifetimes)]
 #![allow(
@@ -12,8 +12,8 @@
     clippy::get_first
 )]
 
-#[macro_use]
-extern crate macro_rules;
+extern crate proc_macros;
+use proc_macros::inline_macros;
 
 fn distinct_lifetimes(_x: &u8, _y: &u8, _z: u8) {}
 
@@ -502,30 +502,29 @@ mod pr_9743_output_lifetime_checks {
     }
 }
 
+#[inline_macros]
 mod in_macro {
-    macro_rules! local_one_input_macro {
-        () => {
-            fn one_input(x: &u8) -> &u8 {
-                unimplemented!()
-            }
-        };
-    }
+    use proc_macros::external;
 
     // lint local macro expands to function with needless lifetimes
-    local_one_input_macro!();
+    inline! {
+        fn one_input(x: &u8) -> &u8 {
+            unimplemented!()
+        }
+    }
 
     // no lint on external macro
-    macro_rules::needless_lifetime!();
-
-    macro_rules! expanded_lifetime {
-        ($l:lifetime) => {
-            fn f<$l>(arg: &$l str) -> &$l str {
-                arg
-            }
+    external! {
+        fn needless_lifetime<'a>(x: &'a u8) -> &'a u8 {
+            unimplemented!()
         }
     }
 
-    expanded_lifetime!('a);
+    inline! {
+        fn f<$'a>(arg: &$'a str) -> &$'a str {
+            arg
+        }
+    }
 }
 
 mod issue5787 {
diff --git a/tests/ui/needless_lifetimes.rs b/tests/ui/needless_lifetimes.rs
index ddfd1043003..06eb430506f 100644
--- a/tests/ui/needless_lifetimes.rs
+++ b/tests/ui/needless_lifetimes.rs
@@ -1,5 +1,5 @@
 // run-rustfix
-// aux-build:macro_rules.rs
+// aux-build:proc_macros.rs
 
 #![warn(clippy::needless_lifetimes)]
 #![allow(
@@ -12,8 +12,8 @@
     clippy::get_first
 )]
 
-#[macro_use]
-extern crate macro_rules;
+extern crate proc_macros;
+use proc_macros::inline_macros;
 
 fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) {}
 
@@ -502,30 +502,29 @@ mod pr_9743_output_lifetime_checks {
     }
 }
 
+#[inline_macros]
 mod in_macro {
-    macro_rules! local_one_input_macro {
-        () => {
-            fn one_input<'a>(x: &'a u8) -> &'a u8 {
-                unimplemented!()
-            }
-        };
-    }
+    use proc_macros::external;
 
     // lint local macro expands to function with needless lifetimes
-    local_one_input_macro!();
+    inline! {
+        fn one_input<'a>(x: &'a u8) -> &'a u8 {
+            unimplemented!()
+        }
+    }
 
     // no lint on external macro
-    macro_rules::needless_lifetime!();
-
-    macro_rules! expanded_lifetime {
-        ($l:lifetime) => {
-            fn f<$l>(arg: &$l str) -> &$l str {
-                arg
-            }
+    external! {
+        fn needless_lifetime<'a>(x: &'a u8) -> &'a u8 {
+            unimplemented!()
         }
     }
 
-    expanded_lifetime!('a);
+    inline! {
+        fn f<$'a>(arg: &$'a str) -> &$'a str {
+            arg
+        }
+    }
 }
 
 mod issue5787 {
diff --git a/tests/ui/needless_lifetimes.stderr b/tests/ui/needless_lifetimes.stderr
index 4e3c8f20d8c..86acc4e0046 100644
--- a/tests/ui/needless_lifetimes.stderr
+++ b/tests/ui/needless_lifetimes.stderr
@@ -540,19 +540,16 @@ LL +     fn multiple_inputs_output_not_elided<'b>(x: &u8, y: &'b u8, z: &'b u8)
    |
 
 error: the following explicit lifetimes could be elided: 'a
-  --> $DIR/needless_lifetimes.rs:508:13
+  --> $DIR/needless_lifetimes.rs:511:9
    |
-LL |             fn one_input<'a>(x: &'a u8) -> &'a u8 {
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-...
-LL |     local_one_input_macro!();
-   |     ------------------------ in this macro invocation
+LL |         fn one_input<'a>(x: &'a u8) -> &'a u8 {
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: this error originates in the macro `local_one_input_macro` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `__inline_mac_mod_in_macro` (in Nightly builds, run with -Z macro-backtrace for more info)
 help: elide the lifetimes
    |
-LL -             fn one_input<'a>(x: &'a u8) -> &'a u8 {
-LL +             fn one_input(x: &u8) -> &u8 {
+LL -         fn one_input<'a>(x: &'a u8) -> &'a u8 {
+LL +         fn one_input(x: &u8) -> &u8 {
    |
 
 error: aborting due to 46 previous errors
diff --git a/tests/ui/needless_update.rs b/tests/ui/needless_update.rs
index b93ff048a62..4e8517cad10 100644
--- a/tests/ui/needless_update.rs
+++ b/tests/ui/needless_update.rs
@@ -1,5 +1,5 @@
 #![warn(clippy::needless_update)]
-#![allow(clippy::no_effect)]
+#![allow(clippy::no_effect, clippy::unnecessary_struct_initialization)]
 
 struct S {
     pub a: i32,
diff --git a/tests/ui/no_effect.rs b/tests/ui/no_effect.rs
index ec8a5aa28c5..1e42e1fbabf 100644
--- a/tests/ui/no_effect.rs
+++ b/tests/ui/no_effect.rs
@@ -1,7 +1,12 @@
 #![feature(fn_traits, unboxed_closures)]
 #![warn(clippy::no_effect_underscore_binding)]
 #![allow(dead_code, path_statements)]
-#![allow(clippy::deref_addrof, clippy::redundant_field_names, clippy::uninlined_format_args)]
+#![allow(
+    clippy::deref_addrof,
+    clippy::redundant_field_names,
+    clippy::uninlined_format_args,
+    clippy::unnecessary_struct_initialization
+)]
 
 struct Unit;
 struct Tuple(i32);
diff --git a/tests/ui/no_effect.stderr b/tests/ui/no_effect.stderr
index 92f6dbfbdba..f10f2bcf2a8 100644
--- a/tests/ui/no_effect.stderr
+++ b/tests/ui/no_effect.stderr
@@ -1,5 +1,5 @@
 error: statement with no effect
-  --> $DIR/no_effect.rs:92:5
+  --> $DIR/no_effect.rs:97:5
    |
 LL |     0;
    |     ^^
@@ -7,151 +7,151 @@ LL |     0;
    = note: `-D clippy::no-effect` implied by `-D warnings`
 
 error: statement with no effect
-  --> $DIR/no_effect.rs:93:5
+  --> $DIR/no_effect.rs:98:5
    |
 LL |     s2;
    |     ^^^
 
 error: statement with no effect
-  --> $DIR/no_effect.rs:94:5
+  --> $DIR/no_effect.rs:99:5
    |
 LL |     Unit;
    |     ^^^^^
 
 error: statement with no effect
-  --> $DIR/no_effect.rs:95:5
+  --> $DIR/no_effect.rs:100:5
    |
 LL |     Tuple(0);
    |     ^^^^^^^^^
 
 error: statement with no effect
-  --> $DIR/no_effect.rs:96:5
+  --> $DIR/no_effect.rs:101:5
    |
 LL |     Struct { field: 0 };
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: statement with no effect
-  --> $DIR/no_effect.rs:97:5
+  --> $DIR/no_effect.rs:102:5
    |
 LL |     Struct { ..s };
    |     ^^^^^^^^^^^^^^^
 
 error: statement with no effect
-  --> $DIR/no_effect.rs:98:5
+  --> $DIR/no_effect.rs:103:5
    |
 LL |     Union { a: 0 };
    |     ^^^^^^^^^^^^^^^
 
 error: statement with no effect
-  --> $DIR/no_effect.rs:99:5
+  --> $DIR/no_effect.rs:104:5
    |
 LL |     Enum::Tuple(0);
    |     ^^^^^^^^^^^^^^^
 
 error: statement with no effect
-  --> $DIR/no_effect.rs:100:5
+  --> $DIR/no_effect.rs:105:5
    |
 LL |     Enum::Struct { field: 0 };
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: statement with no effect
-  --> $DIR/no_effect.rs:101:5
+  --> $DIR/no_effect.rs:106:5
    |
 LL |     5 + 6;
    |     ^^^^^^
 
 error: statement with no effect
-  --> $DIR/no_effect.rs:102:5
+  --> $DIR/no_effect.rs:107:5
    |
 LL |     *&42;
    |     ^^^^^
 
 error: statement with no effect
-  --> $DIR/no_effect.rs:103:5
+  --> $DIR/no_effect.rs:108:5
    |
 LL |     &6;
    |     ^^^
 
 error: statement with no effect
-  --> $DIR/no_effect.rs:104:5
+  --> $DIR/no_effect.rs:109:5
    |
 LL |     (5, 6, 7);
    |     ^^^^^^^^^^
 
 error: statement with no effect
-  --> $DIR/no_effect.rs:105:5
+  --> $DIR/no_effect.rs:110:5
    |
 LL |     ..;
    |     ^^^
 
 error: statement with no effect
-  --> $DIR/no_effect.rs:106:5
+  --> $DIR/no_effect.rs:111:5
    |
 LL |     5..;
    |     ^^^^
 
 error: statement with no effect
-  --> $DIR/no_effect.rs:107:5
+  --> $DIR/no_effect.rs:112:5
    |
 LL |     ..5;
    |     ^^^^
 
 error: statement with no effect
-  --> $DIR/no_effect.rs:108:5
+  --> $DIR/no_effect.rs:113:5
    |
 LL |     5..6;
    |     ^^^^^
 
 error: statement with no effect
-  --> $DIR/no_effect.rs:109:5
+  --> $DIR/no_effect.rs:114:5
    |
 LL |     5..=6;
    |     ^^^^^^
 
 error: statement with no effect
-  --> $DIR/no_effect.rs:110:5
+  --> $DIR/no_effect.rs:115:5
    |
 LL |     [42, 55];
    |     ^^^^^^^^^
 
 error: statement with no effect
-  --> $DIR/no_effect.rs:111:5
+  --> $DIR/no_effect.rs:116:5
    |
 LL |     [42, 55][1];
    |     ^^^^^^^^^^^^
 
 error: statement with no effect
-  --> $DIR/no_effect.rs:112:5
+  --> $DIR/no_effect.rs:117:5
    |
 LL |     (42, 55).1;
    |     ^^^^^^^^^^^
 
 error: statement with no effect
-  --> $DIR/no_effect.rs:113:5
+  --> $DIR/no_effect.rs:118:5
    |
 LL |     [42; 55];
    |     ^^^^^^^^^
 
 error: statement with no effect
-  --> $DIR/no_effect.rs:114:5
+  --> $DIR/no_effect.rs:119:5
    |
 LL |     [42; 55][13];
    |     ^^^^^^^^^^^^^
 
 error: statement with no effect
-  --> $DIR/no_effect.rs:116:5
+  --> $DIR/no_effect.rs:121:5
    |
 LL |     || x += 5;
    |     ^^^^^^^^^^
 
 error: statement with no effect
-  --> $DIR/no_effect.rs:118:5
+  --> $DIR/no_effect.rs:123:5
    |
 LL |     FooString { s: s };
    |     ^^^^^^^^^^^^^^^^^^^
 
 error: binding to `_` prefixed variable with no side-effect
-  --> $DIR/no_effect.rs:119:5
+  --> $DIR/no_effect.rs:124:5
    |
 LL |     let _unused = 1;
    |     ^^^^^^^^^^^^^^^^
@@ -159,19 +159,19 @@ LL |     let _unused = 1;
    = note: `-D clippy::no-effect-underscore-binding` implied by `-D warnings`
 
 error: binding to `_` prefixed variable with no side-effect
-  --> $DIR/no_effect.rs:120:5
+  --> $DIR/no_effect.rs:125:5
    |
 LL |     let _penguin = || println!("Some helpful closure");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: binding to `_` prefixed variable with no side-effect
-  --> $DIR/no_effect.rs:121:5
+  --> $DIR/no_effect.rs:126:5
    |
 LL |     let _duck = Struct { field: 0 };
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: binding to `_` prefixed variable with no side-effect
-  --> $DIR/no_effect.rs:122:5
+  --> $DIR/no_effect.rs:127:5
    |
 LL |     let _cat = [2, 4, 6, 8][2];
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/no_mangle_with_rust_abi.fixed b/tests/ui/no_mangle_with_rust_abi.fixed
deleted file mode 100644
index d18dec22a8b..00000000000
--- a/tests/ui/no_mangle_with_rust_abi.fixed
+++ /dev/null
@@ -1,48 +0,0 @@
-// run-rustfix
-
-#![allow(unused)]
-#![warn(clippy::no_mangle_with_rust_abi)]
-
-#[no_mangle]
-extern "C" fn rust_abi_fn_one(arg_one: u32, arg_two: usize) {}
-
-#[no_mangle]
-pub extern "C" fn rust_abi_fn_two(arg_one: u32, arg_two: usize) {}
-
-/// # Safety
-/// This function shouldn't be called unless the horsemen are ready
-#[no_mangle]
-pub unsafe extern "C" fn rust_abi_fn_three(arg_one: u32, arg_two: usize) {}
-
-/// # Safety
-/// This function shouldn't be called unless the horsemen are ready
-#[no_mangle]
-unsafe extern "C" fn rust_abi_fn_four(arg_one: u32, arg_two: usize) {}
-
-#[no_mangle]
-extern "C" fn rust_abi_multiline_function_really_long_name_to_overflow_args_to_multiple_lines(
-    arg_one: u32,
-    arg_two: usize,
-) -> u32 {
-    0
-}
-
-// Must not run on functions that explicitly opt in to Rust ABI with `extern "Rust"`
-#[no_mangle]
-#[rustfmt::skip]
-extern "Rust" fn rust_abi_fn_explicit_opt_in(arg_one: u32, arg_two: usize) {}
-
-fn rust_abi_fn_again(arg_one: u32, arg_two: usize) {}
-
-#[no_mangle]
-extern "C" fn c_abi_fn(arg_one: u32, arg_two: usize) {}
-
-extern "C" fn c_abi_fn_again(arg_one: u32, arg_two: usize) {}
-
-extern "C" {
-    fn c_abi_in_block(arg_one: u32, arg_two: usize);
-}
-
-fn main() {
-    // test code goes here
-}
diff --git a/tests/ui/no_mangle_with_rust_abi.rs b/tests/ui/no_mangle_with_rust_abi.rs
index 481e1b6d961..b32e721110e 100644
--- a/tests/ui/no_mangle_with_rust_abi.rs
+++ b/tests/ui/no_mangle_with_rust_abi.rs
@@ -1,5 +1,3 @@
-// run-rustfix
-
 #![allow(unused)]
 #![warn(clippy::no_mangle_with_rust_abi)]
 
diff --git a/tests/ui/no_mangle_with_rust_abi.stderr b/tests/ui/no_mangle_with_rust_abi.stderr
index 71517d31809..da5d31d8f2d 100644
--- a/tests/ui/no_mangle_with_rust_abi.stderr
+++ b/tests/ui/no_mangle_with_rust_abi.stderr
@@ -1,31 +1,66 @@
-error: attribute #[no_mangle] set on a Rust ABI function
-  --> $DIR/no_mangle_with_rust_abi.rs:7:1
+error: `#[no_mangle]` set on a function with the default (`Rust`) ABI
+  --> $DIR/no_mangle_with_rust_abi.rs:5:1
    |
 LL | fn rust_abi_fn_one(arg_one: u32, arg_two: usize) {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `extern "C" fn rust_abi_fn_one(arg_one: u32, arg_two: usize)`
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: `-D clippy::no-mangle-with-rust-abi` implied by `-D warnings`
+help: set an ABI
+   |
+LL | extern "C" fn rust_abi_fn_one(arg_one: u32, arg_two: usize) {}
+   | ++++++++++
+help: or explicitly set the default
+   |
+LL | extern "Rust" fn rust_abi_fn_one(arg_one: u32, arg_two: usize) {}
+   | +++++++++++++
 
-error: attribute #[no_mangle] set on a Rust ABI function
-  --> $DIR/no_mangle_with_rust_abi.rs:10:1
+error: `#[no_mangle]` set on a function with the default (`Rust`) ABI
+  --> $DIR/no_mangle_with_rust_abi.rs:8:1
    |
 LL | pub fn rust_abi_fn_two(arg_one: u32, arg_two: usize) {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `pub extern "C" fn rust_abi_fn_two(arg_one: u32, arg_two: usize)`
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: set an ABI
+   |
+LL | pub extern "C" fn rust_abi_fn_two(arg_one: u32, arg_two: usize) {}
+   |     ++++++++++
+help: or explicitly set the default
+   |
+LL | pub extern "Rust" fn rust_abi_fn_two(arg_one: u32, arg_two: usize) {}
+   |     +++++++++++++
 
-error: attribute #[no_mangle] set on a Rust ABI function
-  --> $DIR/no_mangle_with_rust_abi.rs:15:1
+error: `#[no_mangle]` set on a function with the default (`Rust`) ABI
+  --> $DIR/no_mangle_with_rust_abi.rs:13:1
    |
 LL | pub unsafe fn rust_abi_fn_three(arg_one: u32, arg_two: usize) {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `pub unsafe extern "C" fn rust_abi_fn_three(arg_one: u32, arg_two: usize)`
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: set an ABI
+   |
+LL | pub unsafe extern "C" fn rust_abi_fn_three(arg_one: u32, arg_two: usize) {}
+   |            ++++++++++
+help: or explicitly set the default
+   |
+LL | pub unsafe extern "Rust" fn rust_abi_fn_three(arg_one: u32, arg_two: usize) {}
+   |            +++++++++++++
 
-error: attribute #[no_mangle] set on a Rust ABI function
-  --> $DIR/no_mangle_with_rust_abi.rs:20:1
+error: `#[no_mangle]` set on a function with the default (`Rust`) ABI
+  --> $DIR/no_mangle_with_rust_abi.rs:18:1
    |
 LL | unsafe fn rust_abi_fn_four(arg_one: u32, arg_two: usize) {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unsafe extern "C" fn rust_abi_fn_four(arg_one: u32, arg_two: usize)`
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: set an ABI
+   |
+LL | unsafe extern "C" fn rust_abi_fn_four(arg_one: u32, arg_two: usize) {}
+   |        ++++++++++
+help: or explicitly set the default
+   |
+LL | unsafe extern "Rust" fn rust_abi_fn_four(arg_one: u32, arg_two: usize) {}
+   |        +++++++++++++
 
-error: attribute #[no_mangle] set on a Rust ABI function
-  --> $DIR/no_mangle_with_rust_abi.rs:23:1
+error: `#[no_mangle]` set on a function with the default (`Rust`) ABI
+  --> $DIR/no_mangle_with_rust_abi.rs:21:1
    |
 LL | / fn rust_abi_multiline_function_really_long_name_to_overflow_args_to_multiple_lines(
 LL | |     arg_one: u32,
@@ -33,13 +68,14 @@ LL | |     arg_two: usize,
 LL | | ) -> u32 {
    | |________^
    |
-help: try
+help: set an ABI
    |
-LL + extern "C" fn rust_abi_multiline_function_really_long_name_to_overflow_args_to_multiple_lines(
-LL +     arg_one: u32,
-LL +     arg_two: usize,
-LL ~ ) -> u32 {
+LL | extern "C" fn rust_abi_multiline_function_really_long_name_to_overflow_args_to_multiple_lines(
+   | ++++++++++
+help: or explicitly set the default
    |
+LL | extern "Rust" fn rust_abi_multiline_function_really_long_name_to_overflow_args_to_multiple_lines(
+   | +++++++++++++
 
 error: aborting due to 5 previous errors
 
diff --git a/tests/ui/nonminimal_bool.rs b/tests/ui/nonminimal_bool.rs
index e9b4367ca65..3b5a374b4a7 100644
--- a/tests/ui/nonminimal_bool.rs
+++ b/tests/ui/nonminimal_bool.rs
@@ -63,3 +63,32 @@ fn issue9428() {
         println!("foo");
     }
 }
+
+fn issue_10523() {
+    macro_rules! a {
+        ($v:expr) => {
+            $v.is_some()
+        };
+    }
+    let x: Option<u32> = None;
+    if !a!(x) {}
+}
+
+fn issue_10523_1() {
+    macro_rules! a {
+        ($v:expr) => {
+            !$v.is_some()
+        };
+    }
+    let x: Option<u32> = None;
+    if a!(x) {}
+}
+
+fn issue_10523_2() {
+    macro_rules! a {
+        () => {
+            !None::<u32>.is_some()
+        };
+    }
+    if a!() {}
+}
diff --git a/tests/ui/option_env_unwrap.rs b/tests/ui/option_env_unwrap.rs
index 0141fb7856d..9a56cf40d8a 100644
--- a/tests/ui/option_env_unwrap.rs
+++ b/tests/ui/option_env_unwrap.rs
@@ -1,24 +1,16 @@
-// aux-build:macro_rules.rs
+// aux-build:proc_macros.rs
 #![warn(clippy::option_env_unwrap)]
 #![allow(clippy::map_flatten)]
 
-#[macro_use]
-extern crate macro_rules;
-
-macro_rules! option_env_unwrap {
-    ($env: expr) => {
-        option_env!($env).unwrap()
-    };
-    ($env: expr, $message: expr) => {
-        option_env!($env).expect($message)
-    };
-}
+extern crate proc_macros;
+use proc_macros::{external, inline_macros};
 
+#[inline_macros]
 fn main() {
     let _ = option_env!("PATH").unwrap();
     let _ = option_env!("PATH").expect("environment variable PATH isn't set");
-    let _ = option_env_unwrap!("PATH");
-    let _ = option_env_unwrap!("PATH", "environment variable PATH isn't set");
-    let _ = option_env_unwrap_external!("PATH");
-    let _ = option_env_unwrap_external!("PATH", "environment variable PATH isn't set");
+    let _ = inline!(option_env!($"PATH").unwrap());
+    let _ = inline!(option_env!($"PATH").expect($"environment variable PATH isn't set"));
+    let _ = external!(option_env!($"PATH").unwrap());
+    let _ = external!(option_env!($"PATH").expect($"environment variable PATH isn't set"));
 }
diff --git a/tests/ui/option_env_unwrap.stderr b/tests/ui/option_env_unwrap.stderr
index bc188a07e9e..7bba62686ee 100644
--- a/tests/ui/option_env_unwrap.stderr
+++ b/tests/ui/option_env_unwrap.stderr
@@ -1,5 +1,5 @@
 error: this will panic at run-time if the environment variable doesn't exist at compile-time
-  --> $DIR/option_env_unwrap.rs:18:13
+  --> $DIR/option_env_unwrap.rs:10:13
    |
 LL |     let _ = option_env!("PATH").unwrap();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -8,7 +8,7 @@ LL |     let _ = option_env!("PATH").unwrap();
    = note: `-D clippy::option-env-unwrap` implied by `-D warnings`
 
 error: this will panic at run-time if the environment variable doesn't exist at compile-time
-  --> $DIR/option_env_unwrap.rs:19:13
+  --> $DIR/option_env_unwrap.rs:11:13
    |
 LL |     let _ = option_env!("PATH").expect("environment variable PATH isn't set");
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -16,46 +16,40 @@ LL |     let _ = option_env!("PATH").expect("environment variable PATH isn't set
    = help: consider using the `env!` macro instead
 
 error: this will panic at run-time if the environment variable doesn't exist at compile-time
-  --> $DIR/option_env_unwrap.rs:10:9
+  --> $DIR/option_env_unwrap.rs:12:21
    |
-LL |         option_env!($env).unwrap()
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
-...
-LL |     let _ = option_env_unwrap!("PATH");
-   |             -------------------------- in this macro invocation
+LL |     let _ = inline!(option_env!($"PATH").unwrap());
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: consider using the `env!` macro instead
-   = note: this error originates in the macro `option_env_unwrap` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: this will panic at run-time if the environment variable doesn't exist at compile-time
-  --> $DIR/option_env_unwrap.rs:13:9
+  --> $DIR/option_env_unwrap.rs:13:21
    |
-LL |         option_env!($env).expect($message)
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-...
-LL |     let _ = option_env_unwrap!("PATH", "environment variable PATH isn't set");
-   |             ----------------------------------------------------------------- in this macro invocation
+LL |     let _ = inline!(option_env!($"PATH").expect($"environment variable PATH isn't set"));
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: consider using the `env!` macro instead
-   = note: this error originates in the macro `option_env_unwrap` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: this will panic at run-time if the environment variable doesn't exist at compile-time
-  --> $DIR/option_env_unwrap.rs:22:13
+  --> $DIR/option_env_unwrap.rs:14:13
    |
-LL |     let _ = option_env_unwrap_external!("PATH");
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     let _ = external!(option_env!($"PATH").unwrap());
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: consider using the `env!` macro instead
-   = note: this error originates in the macro `option_env_unwrap_external` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `external` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: this will panic at run-time if the environment variable doesn't exist at compile-time
-  --> $DIR/option_env_unwrap.rs:23:13
+  --> $DIR/option_env_unwrap.rs:15:13
    |
-LL |     let _ = option_env_unwrap_external!("PATH", "environment variable PATH isn't set");
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     let _ = external!(option_env!($"PATH").expect($"environment variable PATH isn't set"));
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: consider using the `env!` macro instead
-   = note: this error originates in the macro `option_env_unwrap_external` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `external` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to 6 previous errors
 
diff --git a/tests/ui/ptr_as_ptr.fixed b/tests/ui/ptr_as_ptr.fixed
index df36a9b842b..ee7b998a0b2 100644
--- a/tests/ui/ptr_as_ptr.fixed
+++ b/tests/ui/ptr_as_ptr.fixed
@@ -1,16 +1,12 @@
 // run-rustfix
-// aux-build:macro_rules.rs
+// aux-build:proc_macros.rs
 
 #![warn(clippy::ptr_as_ptr)]
 
-extern crate macro_rules;
-
-macro_rules! cast_it {
-    ($ptr: ident) => {
-        $ptr.cast::<i32>()
-    };
-}
+extern crate proc_macros;
+use proc_macros::{external, inline_macros};
 
+#[inline_macros]
 fn main() {
     let ptr: *const u32 = &42_u32;
     let mut_ptr: *mut u32 = &mut 42_u32;
@@ -38,10 +34,10 @@ fn main() {
     let _: *mut i32 = mut_ptr.cast();
 
     // Make sure the lint is triggered inside a macro
-    let _ = cast_it!(ptr);
+    let _ = inline!($ptr.cast::<i32>());
 
     // Do not lint inside macros from external crates
-    let _ = macro_rules::ptr_as_ptr_cast!(ptr);
+    let _ = external!($ptr as *const i32);
 }
 
 #[clippy::msrv = "1.37"]
diff --git a/tests/ui/ptr_as_ptr.rs b/tests/ui/ptr_as_ptr.rs
index 302c66462d9..c88329ce4ec 100644
--- a/tests/ui/ptr_as_ptr.rs
+++ b/tests/ui/ptr_as_ptr.rs
@@ -1,16 +1,12 @@
 // run-rustfix
-// aux-build:macro_rules.rs
+// aux-build:proc_macros.rs
 
 #![warn(clippy::ptr_as_ptr)]
 
-extern crate macro_rules;
-
-macro_rules! cast_it {
-    ($ptr: ident) => {
-        $ptr as *const i32
-    };
-}
+extern crate proc_macros;
+use proc_macros::{external, inline_macros};
 
+#[inline_macros]
 fn main() {
     let ptr: *const u32 = &42_u32;
     let mut_ptr: *mut u32 = &mut 42_u32;
@@ -38,10 +34,10 @@ fn main() {
     let _: *mut i32 = mut_ptr as _;
 
     // Make sure the lint is triggered inside a macro
-    let _ = cast_it!(ptr);
+    let _ = inline!($ptr as *const i32);
 
     // Do not lint inside macros from external crates
-    let _ = macro_rules::ptr_as_ptr_cast!(ptr);
+    let _ = external!($ptr as *const i32);
 }
 
 #[clippy::msrv = "1.37"]
diff --git a/tests/ui/ptr_as_ptr.stderr b/tests/ui/ptr_as_ptr.stderr
index a68e1cab6d3..78d733994ac 100644
--- a/tests/ui/ptr_as_ptr.stderr
+++ b/tests/ui/ptr_as_ptr.stderr
@@ -1,5 +1,5 @@
 error: `as` casting between raw pointers without changing its mutability
-  --> $DIR/ptr_as_ptr.rs:18:13
+  --> $DIR/ptr_as_ptr.rs:14:13
    |
 LL |     let _ = ptr as *const i32;
    |             ^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `ptr.cast::<i32>()`
@@ -7,48 +7,45 @@ LL |     let _ = ptr as *const i32;
    = note: `-D clippy::ptr-as-ptr` implied by `-D warnings`
 
 error: `as` casting between raw pointers without changing its mutability
-  --> $DIR/ptr_as_ptr.rs:19:13
+  --> $DIR/ptr_as_ptr.rs:15:13
    |
 LL |     let _ = mut_ptr as *mut i32;
    |             ^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `mut_ptr.cast::<i32>()`
 
 error: `as` casting between raw pointers without changing its mutability
-  --> $DIR/ptr_as_ptr.rs:24:17
+  --> $DIR/ptr_as_ptr.rs:20:17
    |
 LL |         let _ = *ptr_ptr as *const i32;
    |                 ^^^^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `(*ptr_ptr).cast::<i32>()`
 
 error: `as` casting between raw pointers without changing its mutability
-  --> $DIR/ptr_as_ptr.rs:37:25
+  --> $DIR/ptr_as_ptr.rs:33:25
    |
 LL |     let _: *const i32 = ptr as *const _;
    |                         ^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `ptr.cast()`
 
 error: `as` casting between raw pointers without changing its mutability
-  --> $DIR/ptr_as_ptr.rs:38:23
+  --> $DIR/ptr_as_ptr.rs:34:23
    |
 LL |     let _: *mut i32 = mut_ptr as _;
    |                       ^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `mut_ptr.cast()`
 
 error: `as` casting between raw pointers without changing its mutability
-  --> $DIR/ptr_as_ptr.rs:10:9
+  --> $DIR/ptr_as_ptr.rs:37:21
    |
-LL |         $ptr as *const i32
-   |         ^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `$ptr.cast::<i32>()`
-...
-LL |     let _ = cast_it!(ptr);
-   |             ------------- in this macro invocation
+LL |     let _ = inline!($ptr as *const i32);
+   |                     ^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `$ptr.cast::<i32>()`
    |
-   = note: this error originates in the macro `cast_it` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: `as` casting between raw pointers without changing its mutability
-  --> $DIR/ptr_as_ptr.rs:62:13
+  --> $DIR/ptr_as_ptr.rs:58:13
    |
 LL |     let _ = ptr as *const i32;
    |             ^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `ptr.cast::<i32>()`
 
 error: `as` casting between raw pointers without changing its mutability
-  --> $DIR/ptr_as_ptr.rs:63:13
+  --> $DIR/ptr_as_ptr.rs:59:13
    |
 LL |     let _ = mut_ptr as *mut i32;
    |             ^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `mut_ptr.cast::<i32>()`
diff --git a/tests/ui/redundant_async_block.fixed b/tests/ui/redundant_async_block.fixed
index 5f9931df45e..d26b7a332cb 100644
--- a/tests/ui/redundant_async_block.fixed
+++ b/tests/ui/redundant_async_block.fixed
@@ -3,6 +3,8 @@
 #![allow(unused)]
 #![warn(clippy::redundant_async_block)]
 
+use std::future::Future;
+
 async fn func1(n: usize) -> usize {
     n + 1
 }
@@ -62,3 +64,48 @@ fn main() {
     let fut = async_await_parameter_in_macro!(func2());
     let fut = async_await_in_macro!(std::convert::identity);
 }
+
+#[allow(clippy::let_and_return)]
+fn capture_local() -> impl Future<Output = i32> {
+    // Lint
+    let fut = async { 17 };
+    fut
+}
+
+fn capture_local_closure(s: &str) -> impl Future<Output = &str> {
+    let f = move || std::future::ready(s);
+    // Do not lint: `f` would not live long enough
+    async move { f().await }
+}
+
+#[allow(clippy::let_and_return)]
+fn capture_arg(s: &str) -> impl Future<Output = &str> {
+    // Lint
+    let fut = async move { s };
+    fut
+}
+
+#[derive(Debug, Clone)]
+struct F {}
+
+impl F {
+    async fn run(&self) {}
+}
+
+pub async fn run() {
+    let f = F {};
+    let c = f.clone();
+    // Do not lint: `c` would not live long enough
+    spawn(async move { c.run().await });
+    let _f = f;
+}
+
+fn spawn<F: Future + 'static>(_: F) {}
+
+async fn work(_: &str) {}
+
+fn capture() {
+    let val = "Hello World".to_owned();
+    // Do not lint: `val` would not live long enough
+    spawn(async { work(&{ val }).await });
+}
diff --git a/tests/ui/redundant_async_block.rs b/tests/ui/redundant_async_block.rs
index de3c9970c65..04726e62805 100644
--- a/tests/ui/redundant_async_block.rs
+++ b/tests/ui/redundant_async_block.rs
@@ -3,6 +3,8 @@
 #![allow(unused)]
 #![warn(clippy::redundant_async_block)]
 
+use std::future::Future;
+
 async fn func1(n: usize) -> usize {
     n + 1
 }
@@ -62,3 +64,48 @@ fn main() {
     let fut = async_await_parameter_in_macro!(func2());
     let fut = async_await_in_macro!(std::convert::identity);
 }
+
+#[allow(clippy::let_and_return)]
+fn capture_local() -> impl Future<Output = i32> {
+    // Lint
+    let fut = async { 17 };
+    async move { fut.await }
+}
+
+fn capture_local_closure(s: &str) -> impl Future<Output = &str> {
+    let f = move || std::future::ready(s);
+    // Do not lint: `f` would not live long enough
+    async move { f().await }
+}
+
+#[allow(clippy::let_and_return)]
+fn capture_arg(s: &str) -> impl Future<Output = &str> {
+    // Lint
+    let fut = async move { s };
+    async move { fut.await }
+}
+
+#[derive(Debug, Clone)]
+struct F {}
+
+impl F {
+    async fn run(&self) {}
+}
+
+pub async fn run() {
+    let f = F {};
+    let c = f.clone();
+    // Do not lint: `c` would not live long enough
+    spawn(async move { c.run().await });
+    let _f = f;
+}
+
+fn spawn<F: Future + 'static>(_: F) {}
+
+async fn work(_: &str) {}
+
+fn capture() {
+    let val = "Hello World".to_owned();
+    // Do not lint: `val` would not live long enough
+    spawn(async { work(&{ val }).await });
+}
diff --git a/tests/ui/redundant_async_block.stderr b/tests/ui/redundant_async_block.stderr
index b16d96dce84..1a1c1603e08 100644
--- a/tests/ui/redundant_async_block.stderr
+++ b/tests/ui/redundant_async_block.stderr
@@ -1,5 +1,5 @@
 error: this async expression only awaits a single future
-  --> $DIR/redundant_async_block.rs:13:13
+  --> $DIR/redundant_async_block.rs:15:13
    |
 LL |     let x = async { f.await };
    |             ^^^^^^^^^^^^^^^^^ help: you can reduce it to: `f`
@@ -7,22 +7,34 @@ LL |     let x = async { f.await };
    = note: `-D clippy::redundant-async-block` implied by `-D warnings`
 
 error: this async expression only awaits a single future
-  --> $DIR/redundant_async_block.rs:46:16
+  --> $DIR/redundant_async_block.rs:48:16
    |
 LL |     let fut2 = async { fut1.await };
    |                ^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `fut1`
 
 error: this async expression only awaits a single future
-  --> $DIR/redundant_async_block.rs:49:16
+  --> $DIR/redundant_async_block.rs:51:16
    |
 LL |     let fut2 = async move { fut1.await };
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `fut1`
 
 error: this async expression only awaits a single future
-  --> $DIR/redundant_async_block.rs:51:15
+  --> $DIR/redundant_async_block.rs:53:15
    |
 LL |     let fut = async { async { 42 }.await };
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `async { 42 }`
 
-error: aborting due to 4 previous errors
+error: this async expression only awaits a single future
+  --> $DIR/redundant_async_block.rs:72:5
+   |
+LL |     async move { fut.await }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `fut`
+
+error: this async expression only awaits a single future
+  --> $DIR/redundant_async_block.rs:85:5
+   |
+LL |     async move { fut.await }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `fut`
+
+error: aborting due to 6 previous errors
 
diff --git a/tests/ui/redundant_pattern_matching_result.fixed b/tests/ui/redundant_pattern_matching_result.fixed
index b88c5d0bec8..42348df4480 100644
--- a/tests/ui/redundant_pattern_matching_result.fixed
+++ b/tests/ui/redundant_pattern_matching_result.fixed
@@ -69,8 +69,8 @@ fn issue5504() {
     }
 
     fn try_result_opt() -> Result<i32, i32> {
-        while (r#try!(result_opt())).is_some() {}
-        if (r#try!(result_opt())).is_some() {}
+        while r#try!(result_opt()).is_some() {}
+        if r#try!(result_opt()).is_some() {}
         Ok(42)
     }
 
diff --git a/tests/ui/redundant_pattern_matching_result.stderr b/tests/ui/redundant_pattern_matching_result.stderr
index e6afe9eb78e..d6a46babb77 100644
--- a/tests/ui/redundant_pattern_matching_result.stderr
+++ b/tests/ui/redundant_pattern_matching_result.stderr
@@ -88,13 +88,13 @@ error: redundant pattern matching, consider using `is_some()`
   --> $DIR/redundant_pattern_matching_result.rs:84:19
    |
 LL |         while let Some(_) = r#try!(result_opt()) {}
-   |         ----------^^^^^^^----------------------- help: try this: `while (r#try!(result_opt())).is_some()`
+   |         ----------^^^^^^^----------------------- help: try this: `while r#try!(result_opt()).is_some()`
 
 error: redundant pattern matching, consider using `is_some()`
   --> $DIR/redundant_pattern_matching_result.rs:85:16
    |
 LL |         if let Some(_) = r#try!(result_opt()) {}
-   |         -------^^^^^^^----------------------- help: try this: `if (r#try!(result_opt())).is_some()`
+   |         -------^^^^^^^----------------------- help: try this: `if r#try!(result_opt()).is_some()`
 
 error: redundant pattern matching, consider using `is_some()`
   --> $DIR/redundant_pattern_matching_result.rs:91:12
diff --git a/tests/ui/single_match_else.rs b/tests/ui/single_match_else.rs
index 5d03f77e932..3c86f41f3a6 100644
--- a/tests/ui/single_match_else.rs
+++ b/tests/ui/single_match_else.rs
@@ -1,9 +1,9 @@
-// aux-build: proc_macro_with_span.rs
+// aux-build: proc_macros.rs
 #![warn(clippy::single_match_else)]
 #![allow(clippy::needless_return, clippy::no_effect, clippy::uninlined_format_args)]
 
-extern crate proc_macro_with_span;
-use proc_macro_with_span::with_span;
+extern crate proc_macros;
+use proc_macros::with_span;
 
 enum ExprNode {
     ExprAddrOf,
diff --git a/tests/ui/string_add.rs b/tests/ui/string_add.rs
index 16673c01e63..20edbe31fa9 100644
--- a/tests/ui/string_add.rs
+++ b/tests/ui/string_add.rs
@@ -1,7 +1,7 @@
-// aux-build:macro_rules.rs
+// aux-build:proc_macros.rs
 
-#[macro_use]
-extern crate macro_rules;
+extern crate proc_macros;
+use proc_macros::external;
 
 #[warn(clippy::string_add)]
 #[allow(clippy::string_add_assign, unused)]
@@ -22,5 +22,8 @@ fn main() {
     x = x + 1;
     assert_eq!(2, x);
 
-    string_add!();
+    external!({
+        let y = "".to_owned();
+        let z = y + "...";
+    });
 }
diff --git a/tests/ui/swap.fixed b/tests/ui/swap.fixed
index 04008c0d9b3..9703674d1a4 100644
--- a/tests/ui/swap.fixed
+++ b/tests/ui/swap.fixed
@@ -1,4 +1,5 @@
 // run-rustfix
+// aux-build: macro_rules.rs
 
 #![warn(clippy::all)]
 #![allow(
@@ -8,7 +9,8 @@
     redundant_semicolons,
     dead_code,
     unused_assignments,
-    unused_variables
+    unused_variables,
+    clippy::let_and_return
 )]
 
 struct Foo(u32);
@@ -186,3 +188,14 @@ const fn issue_9864(mut u: u32) -> u32 {
     v = temp;
     u + v
 }
+
+#[macro_use]
+extern crate macro_rules;
+
+const fn issue_10421(x: u32) -> u32 {
+    issue_10421!();
+    let a = x;
+    let a = a;
+    let a = a;
+    a
+}
diff --git a/tests/ui/swap.rs b/tests/ui/swap.rs
index ef8a81c8341..a0228065e46 100644
--- a/tests/ui/swap.rs
+++ b/tests/ui/swap.rs
@@ -1,4 +1,5 @@
 // run-rustfix
+// aux-build: macro_rules.rs
 
 #![warn(clippy::all)]
 #![allow(
@@ -8,7 +9,8 @@
     redundant_semicolons,
     dead_code,
     unused_assignments,
-    unused_variables
+    unused_variables,
+    clippy::let_and_return
 )]
 
 struct Foo(u32);
@@ -215,3 +217,14 @@ const fn issue_9864(mut u: u32) -> u32 {
     v = temp;
     u + v
 }
+
+#[macro_use]
+extern crate macro_rules;
+
+const fn issue_10421(x: u32) -> u32 {
+    issue_10421!();
+    let a = x;
+    let a = a;
+    let a = a;
+    a
+}
diff --git a/tests/ui/swap.stderr b/tests/ui/swap.stderr
index 825c9261e19..0c246268499 100644
--- a/tests/ui/swap.stderr
+++ b/tests/ui/swap.stderr
@@ -1,5 +1,5 @@
 error: this looks like you are swapping `bar.a` and `bar.b` manually
-  --> $DIR/swap.rs:25:5
+  --> $DIR/swap.rs:27:5
    |
 LL | /     let temp = bar.a;
 LL | |     bar.a = bar.b;
@@ -10,7 +10,7 @@ LL | |     bar.b = temp;
    = note: `-D clippy::manual-swap` implied by `-D warnings`
 
 error: this looks like you are swapping elements of `foo` manually
-  --> $DIR/swap.rs:37:5
+  --> $DIR/swap.rs:39:5
    |
 LL | /     let temp = foo[0];
 LL | |     foo[0] = foo[1];
@@ -18,7 +18,7 @@ LL | |     foo[1] = temp;
    | |__________________^ help: try: `foo.swap(0, 1);`
 
 error: this looks like you are swapping elements of `foo` manually
-  --> $DIR/swap.rs:46:5
+  --> $DIR/swap.rs:48:5
    |
 LL | /     let temp = foo[0];
 LL | |     foo[0] = foo[1];
@@ -26,7 +26,7 @@ LL | |     foo[1] = temp;
    | |__________________^ help: try: `foo.swap(0, 1);`
 
 error: this looks like you are swapping elements of `foo` manually
-  --> $DIR/swap.rs:65:5
+  --> $DIR/swap.rs:67:5
    |
 LL | /     let temp = foo[0];
 LL | |     foo[0] = foo[1];
@@ -34,7 +34,7 @@ LL | |     foo[1] = temp;
    | |__________________^ help: try: `foo.swap(0, 1);`
 
 error: this looks like you are swapping `a` and `b` manually
-  --> $DIR/swap.rs:76:5
+  --> $DIR/swap.rs:78:5
    |
 LL | /     a ^= b;
 LL | |     b ^= a;
@@ -42,7 +42,7 @@ LL | |     a ^= b;
    | |___________^ help: try: `std::mem::swap(&mut a, &mut b);`
 
 error: this looks like you are swapping `bar.a` and `bar.b` manually
-  --> $DIR/swap.rs:84:5
+  --> $DIR/swap.rs:86:5
    |
 LL | /     bar.a ^= bar.b;
 LL | |     bar.b ^= bar.a;
@@ -50,7 +50,7 @@ LL | |     bar.a ^= bar.b;
    | |___________________^ help: try: `std::mem::swap(&mut bar.a, &mut bar.b);`
 
 error: this looks like you are swapping elements of `foo` manually
-  --> $DIR/swap.rs:92:5
+  --> $DIR/swap.rs:94:5
    |
 LL | /     foo[0] ^= foo[1];
 LL | |     foo[1] ^= foo[0];
@@ -58,7 +58,7 @@ LL | |     foo[0] ^= foo[1];
    | |_____________________^ help: try: `foo.swap(0, 1);`
 
 error: this looks like you are swapping `foo[0][1]` and `bar[1][0]` manually
-  --> $DIR/swap.rs:121:5
+  --> $DIR/swap.rs:123:5
    |
 LL | /     let temp = foo[0][1];
 LL | |     foo[0][1] = bar[1][0];
@@ -68,7 +68,7 @@ LL | |     bar[1][0] = temp;
    = note: or maybe you should use `std::mem::replace`?
 
 error: this looks like you are swapping `a` and `b` manually
-  --> $DIR/swap.rs:135:7
+  --> $DIR/swap.rs:137:7
    |
 LL |       ; let t = a;
    |  _______^
@@ -79,7 +79,7 @@ LL | |     b = t;
    = note: or maybe you should use `std::mem::replace`?
 
 error: this looks like you are swapping `c.0` and `a` manually
-  --> $DIR/swap.rs:144:7
+  --> $DIR/swap.rs:146:7
    |
 LL |       ; let t = c.0;
    |  _______^
@@ -90,7 +90,7 @@ LL | |     a = t;
    = note: or maybe you should use `std::mem::replace`?
 
 error: this looks like you are swapping `b` and `a` manually
-  --> $DIR/swap.rs:170:5
+  --> $DIR/swap.rs:172:5
    |
 LL | /     let t = b;
 LL | |     b = a;
@@ -100,7 +100,7 @@ LL | |     a = t;
    = note: or maybe you should use `std::mem::replace`?
 
 error: this looks like you are trying to swap `a` and `b`
-  --> $DIR/swap.rs:132:5
+  --> $DIR/swap.rs:134:5
    |
 LL | /     a = b;
 LL | |     b = a;
@@ -110,7 +110,7 @@ LL | |     b = a;
    = note: `-D clippy::almost-swapped` implied by `-D warnings`
 
 error: this looks like you are trying to swap `c.0` and `a`
-  --> $DIR/swap.rs:141:5
+  --> $DIR/swap.rs:143:5
    |
 LL | /     c.0 = a;
 LL | |     a = c.0;
@@ -119,7 +119,7 @@ LL | |     a = c.0;
    = note: or maybe you should use `std::mem::replace`?
 
 error: this looks like you are trying to swap `a` and `b`
-  --> $DIR/swap.rs:148:5
+  --> $DIR/swap.rs:150:5
    |
 LL | /     let a = b;
 LL | |     let b = a;
@@ -128,7 +128,7 @@ LL | |     let b = a;
    = note: or maybe you should use `std::mem::replace`?
 
 error: this looks like you are trying to swap `d` and `c`
-  --> $DIR/swap.rs:153:5
+  --> $DIR/swap.rs:155:5
    |
 LL | /     d = c;
 LL | |     c = d;
@@ -137,7 +137,7 @@ LL | |     c = d;
    = note: or maybe you should use `std::mem::replace`?
 
 error: this looks like you are trying to swap `a` and `b`
-  --> $DIR/swap.rs:157:5
+  --> $DIR/swap.rs:159:5
    |
 LL | /     let a = b;
 LL | |     b = a;
@@ -146,7 +146,7 @@ LL | |     b = a;
    = note: or maybe you should use `std::mem::replace`?
 
 error: this looks like you are swapping `s.0.x` and `s.0.y` manually
-  --> $DIR/swap.rs:205:5
+  --> $DIR/swap.rs:207:5
    |
 LL | /     let t = s.0.x;
 LL | |     s.0.x = s.0.y;
diff --git a/tests/ui/toplevel_ref_arg.fixed b/tests/ui/toplevel_ref_arg.fixed
index 09fb66ca37e..174c858a47d 100644
--- a/tests/ui/toplevel_ref_arg.fixed
+++ b/tests/ui/toplevel_ref_arg.fixed
@@ -1,17 +1,12 @@
 // run-rustfix
-// aux-build:macro_rules.rs
+// aux-build:proc_macros.rs
 #![warn(clippy::toplevel_ref_arg)]
-#![allow(clippy::uninlined_format_args)]
+#![allow(clippy::uninlined_format_args, unused)]
 
-#[macro_use]
-extern crate macro_rules;
-
-macro_rules! gen_binding {
-    () => {
-        let _y = &42;
-    };
-}
+extern crate proc_macros;
+use proc_macros::{external, inline_macros};
 
+#[inline_macros]
 fn main() {
     // Closures should not warn
     let y = |ref x| println!("{:?}", x);
@@ -38,13 +33,8 @@ fn main() {
     for ref _x in 0..10 {}
 
     // lint in macro
-    #[allow(unused)]
-    {
-        gen_binding!();
-    }
+    inline!(let _y = &42;);
 
     // do not lint in external macro
-    {
-        ref_arg_binding!();
-    }
+    external!(let ref _y = 42;);
 }
diff --git a/tests/ui/toplevel_ref_arg.rs b/tests/ui/toplevel_ref_arg.rs
index 9d1f2f81098..4b81a06112f 100644
--- a/tests/ui/toplevel_ref_arg.rs
+++ b/tests/ui/toplevel_ref_arg.rs
@@ -1,17 +1,12 @@
 // run-rustfix
-// aux-build:macro_rules.rs
+// aux-build:proc_macros.rs
 #![warn(clippy::toplevel_ref_arg)]
-#![allow(clippy::uninlined_format_args)]
+#![allow(clippy::uninlined_format_args, unused)]
 
-#[macro_use]
-extern crate macro_rules;
-
-macro_rules! gen_binding {
-    () => {
-        let ref _y = 42;
-    };
-}
+extern crate proc_macros;
+use proc_macros::{external, inline_macros};
 
+#[inline_macros]
 fn main() {
     // Closures should not warn
     let y = |ref x| println!("{:?}", x);
@@ -38,13 +33,8 @@ fn main() {
     for ref _x in 0..10 {}
 
     // lint in macro
-    #[allow(unused)]
-    {
-        gen_binding!();
-    }
+    inline!(let ref _y = 42;);
 
     // do not lint in external macro
-    {
-        ref_arg_binding!();
-    }
+    external!(let ref _y = 42;);
 }
diff --git a/tests/ui/toplevel_ref_arg.stderr b/tests/ui/toplevel_ref_arg.stderr
index 9c853020ab0..407c2d9fcd3 100644
--- a/tests/ui/toplevel_ref_arg.stderr
+++ b/tests/ui/toplevel_ref_arg.stderr
@@ -1,5 +1,5 @@
 error: `ref` on an entire `let` pattern is discouraged, take a reference with `&` instead
-  --> $DIR/toplevel_ref_arg.rs:20:9
+  --> $DIR/toplevel_ref_arg.rs:15:9
    |
 LL |     let ref _x = 1;
    |     ----^^^^^^----- help: try: `let _x = &1;`
@@ -7,39 +7,36 @@ LL |     let ref _x = 1;
    = note: `-D clippy::toplevel-ref-arg` implied by `-D warnings`
 
 error: `ref` on an entire `let` pattern is discouraged, take a reference with `&` instead
-  --> $DIR/toplevel_ref_arg.rs:22:9
+  --> $DIR/toplevel_ref_arg.rs:17:9
    |
 LL |     let ref _y: (&_, u8) = (&1, 2);
    |     ----^^^^^^--------------------- help: try: `let _y: &(&_, u8) = &(&1, 2);`
 
 error: `ref` on an entire `let` pattern is discouraged, take a reference with `&` instead
-  --> $DIR/toplevel_ref_arg.rs:24:9
+  --> $DIR/toplevel_ref_arg.rs:19:9
    |
 LL |     let ref _z = 1 + 2;
    |     ----^^^^^^--------- help: try: `let _z = &(1 + 2);`
 
 error: `ref` on an entire `let` pattern is discouraged, take a reference with `&` instead
-  --> $DIR/toplevel_ref_arg.rs:26:9
+  --> $DIR/toplevel_ref_arg.rs:21:9
    |
 LL |     let ref mut _z = 1 + 2;
    |     ----^^^^^^^^^^--------- help: try: `let _z = &mut (1 + 2);`
 
 error: `ref` on an entire `let` pattern is discouraged, take a reference with `&` instead
-  --> $DIR/toplevel_ref_arg.rs:31:9
+  --> $DIR/toplevel_ref_arg.rs:26:9
    |
 LL |     let ref _x = vec![1, 2, 3];
    |     ----^^^^^^----------------- help: try: `let _x = &vec![1, 2, 3];`
 
 error: `ref` on an entire `let` pattern is discouraged, take a reference with `&` instead
-  --> $DIR/toplevel_ref_arg.rs:11:13
+  --> $DIR/toplevel_ref_arg.rs:36:17
    |
-LL |         let ref _y = 42;
-   |         ----^^^^^^------ help: try: `let _y = &42;`
-...
-LL |         gen_binding!();
-   |         -------------- in this macro invocation
+LL |     inline!(let ref _y = 42;);
+   |             ----^^^^^^------ help: try: `let _y = &42;`
    |
-   = note: this error originates in the macro `gen_binding` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to 6 previous errors
 
diff --git a/tests/ui/toplevel_ref_arg_non_rustfix.rs b/tests/ui/toplevel_ref_arg_non_rustfix.rs
index 1a493fbce0e..2047593e7e4 100644
--- a/tests/ui/toplevel_ref_arg_non_rustfix.rs
+++ b/tests/ui/toplevel_ref_arg_non_rustfix.rs
@@ -1,33 +1,27 @@
-// aux-build:macro_rules.rs
+// aux-build:proc_macros.rs
 
 #![warn(clippy::toplevel_ref_arg)]
 #![allow(unused)]
 
-#[macro_use]
-extern crate macro_rules;
+extern crate proc_macros;
+use proc_macros::{external, inline_macros};
 
 fn the_answer(ref mut x: u8) {
     *x = 42;
 }
 
-macro_rules! gen_function {
-    () => {
-        fn fun_example(ref _x: usize) {}
-    };
-}
-
+#[inline_macros]
 fn main() {
     let mut x = 0;
     the_answer(x);
 
     // lint in macro
-    #[allow(unused)]
-    {
-        gen_function!();
+    inline! {
+        fn fun_example(ref _x: usize) {}
     }
 
     // do not lint in external macro
-    {
-        ref_arg_function!();
+    external! {
+        fn fun_example2(ref _x: usize) {}
     }
 }
diff --git a/tests/ui/toplevel_ref_arg_non_rustfix.stderr b/tests/ui/toplevel_ref_arg_non_rustfix.stderr
index e97011c7fd5..7307bd599d9 100644
--- a/tests/ui/toplevel_ref_arg_non_rustfix.stderr
+++ b/tests/ui/toplevel_ref_arg_non_rustfix.stderr
@@ -7,15 +7,12 @@ LL | fn the_answer(ref mut x: u8) {
    = note: `-D clippy::toplevel-ref-arg` implied by `-D warnings`
 
 error: `ref` directly on a function argument is ignored. Consider using a reference type instead
-  --> $DIR/toplevel_ref_arg_non_rustfix.rs:15:24
+  --> $DIR/toplevel_ref_arg_non_rustfix.rs:20:24
    |
 LL |         fn fun_example(ref _x: usize) {}
    |                        ^^^^^^
-...
-LL |         gen_function!();
-   |         --------------- in this macro invocation
    |
-   = note: this error originates in the macro `gen_function` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/try_err.fixed b/tests/ui/try_err.fixed
index 264194419c7..dc497b1690f 100644
--- a/tests/ui/try_err.fixed
+++ b/tests/ui/try_err.fixed
@@ -1,11 +1,11 @@
 // run-rustfix
-// aux-build:macro_rules.rs
+// aux-build:proc_macros.rs
 
 #![deny(clippy::try_err)]
 #![allow(clippy::unnecessary_wraps, clippy::needless_question_mark)]
 
-#[macro_use]
-extern crate macro_rules;
+extern crate proc_macros;
+use proc_macros::{external, inline_macros};
 
 use std::io;
 use std::task::Poll;
@@ -79,36 +79,22 @@ fn nested_error() -> Result<i32, i32> {
     Ok(1)
 }
 
-// Bad suggestion when in macro (see #6242)
-macro_rules! try_validation {
-    ($e: expr) => {{
-        match $e {
+#[inline_macros]
+fn calling_macro() -> Result<i32, i32> {
+    // macro
+    inline!(
+        match $(Ok::<_, i32>(5)) {
             Ok(_) => 0,
             Err(_) => return Err(1),
         }
-    }};
-}
-
-macro_rules! ret_one {
-    () => {
-        1
-    };
-}
-
-macro_rules! try_validation_in_macro {
-    ($e: expr) => {{
-        match $e {
+    );
+    // `Err` arg is another macro
+    inline!(
+        match $(Ok::<_, i32>(5)) {
             Ok(_) => 0,
-            Err(_) => return Err(ret_one!()),
+            Err(_) => return Err(inline!(1)),
         }
-    }};
-}
-
-fn calling_macro() -> Result<i32, i32> {
-    // macro
-    try_validation!(Ok::<_, i32>(5));
-    // `Err` arg is another macro
-    try_validation_in_macro!(Ok::<_, i32>(5));
+    );
     Ok(5)
 }
 
@@ -121,24 +107,19 @@ fn main() {
     calling_macro().unwrap();
 
     // We don't want to lint in external macros
-    try_err!();
-}
-
-macro_rules! bar {
-    () => {
-        String::from("aasdfasdfasdfa")
-    };
-}
-
-macro_rules! foo {
-    () => {
-        bar!()
-    };
+    external! {
+        pub fn try_err_fn() -> Result<i32, i32> {
+            let err: i32 = 1;
+            // To avoid warnings during rustfix
+            if true { Err(err)? } else { Ok(2) }
+        }
+    }
 }
 
+#[inline_macros]
 pub fn macro_inside(fail: bool) -> Result<i32, String> {
     if fail {
-        return Err(foo!());
+        return Err(inline!(inline!(String::from("aasdfasdfasdfa"))));
     }
     Ok(0)
 }
diff --git a/tests/ui/try_err.rs b/tests/ui/try_err.rs
index bc6979bf457..86aeb75cd96 100644
--- a/tests/ui/try_err.rs
+++ b/tests/ui/try_err.rs
@@ -1,11 +1,11 @@
 // run-rustfix
-// aux-build:macro_rules.rs
+// aux-build:proc_macros.rs
 
 #![deny(clippy::try_err)]
 #![allow(clippy::unnecessary_wraps, clippy::needless_question_mark)]
 
-#[macro_use]
-extern crate macro_rules;
+extern crate proc_macros;
+use proc_macros::{external, inline_macros};
 
 use std::io;
 use std::task::Poll;
@@ -79,36 +79,22 @@ fn nested_error() -> Result<i32, i32> {
     Ok(1)
 }
 
-// Bad suggestion when in macro (see #6242)
-macro_rules! try_validation {
-    ($e: expr) => {{
-        match $e {
+#[inline_macros]
+fn calling_macro() -> Result<i32, i32> {
+    // macro
+    inline!(
+        match $(Ok::<_, i32>(5)) {
             Ok(_) => 0,
             Err(_) => Err(1)?,
         }
-    }};
-}
-
-macro_rules! ret_one {
-    () => {
-        1
-    };
-}
-
-macro_rules! try_validation_in_macro {
-    ($e: expr) => {{
-        match $e {
+    );
+    // `Err` arg is another macro
+    inline!(
+        match $(Ok::<_, i32>(5)) {
             Ok(_) => 0,
-            Err(_) => Err(ret_one!())?,
+            Err(_) => Err(inline!(1))?,
         }
-    }};
-}
-
-fn calling_macro() -> Result<i32, i32> {
-    // macro
-    try_validation!(Ok::<_, i32>(5));
-    // `Err` arg is another macro
-    try_validation_in_macro!(Ok::<_, i32>(5));
+    );
     Ok(5)
 }
 
@@ -121,24 +107,19 @@ fn main() {
     calling_macro().unwrap();
 
     // We don't want to lint in external macros
-    try_err!();
-}
-
-macro_rules! bar {
-    () => {
-        String::from("aasdfasdfasdfa")
-    };
-}
-
-macro_rules! foo {
-    () => {
-        bar!()
-    };
+    external! {
+        pub fn try_err_fn() -> Result<i32, i32> {
+            let err: i32 = 1;
+            // To avoid warnings during rustfix
+            if true { Err(err)? } else { Ok(2) }
+        }
+    }
 }
 
+#[inline_macros]
 pub fn macro_inside(fail: bool) -> Result<i32, String> {
     if fail {
-        Err(foo!())?;
+        Err(inline!(inline!(String::from("aasdfasdfasdfa"))))?;
     }
     Ok(0)
 }
diff --git a/tests/ui/try_err.stderr b/tests/ui/try_err.stderr
index 0cb1328fbfc..4ad0e2e56a4 100644
--- a/tests/ui/try_err.stderr
+++ b/tests/ui/try_err.stderr
@@ -29,53 +29,47 @@ LL |                 Err(err)?;
    |                 ^^^^^^^^^ help: try this: `return Err(err.into())`
 
 error: returning an `Err(_)` with the `?` operator
-  --> $DIR/try_err.rs:87:23
+  --> $DIR/try_err.rs:88:23
    |
 LL |             Err(_) => Err(1)?,
    |                       ^^^^^^^ help: try this: `return Err(1)`
-...
-LL |     try_validation!(Ok::<_, i32>(5));
-   |     -------------------------------- in this macro invocation
    |
-   = note: this error originates in the macro `try_validation` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `__inline_mac_fn_calling_macro` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: returning an `Err(_)` with the `?` operator
-  --> $DIR/try_err.rs:102:23
+  --> $DIR/try_err.rs:95:23
    |
-LL |             Err(_) => Err(ret_one!())?,
-   |                       ^^^^^^^^^^^^^^^^ help: try this: `return Err(ret_one!())`
-...
-LL |     try_validation_in_macro!(Ok::<_, i32>(5));
-   |     ----------------------------------------- in this macro invocation
+LL |             Err(_) => Err(inline!(1))?,
+   |                       ^^^^^^^^^^^^^^^^ help: try this: `return Err(inline!(1))`
    |
-   = note: this error originates in the macro `try_validation_in_macro` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `__inline_mac_fn_calling_macro` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: returning an `Err(_)` with the `?` operator
-  --> $DIR/try_err.rs:141:9
+  --> $DIR/try_err.rs:122:9
    |
-LL |         Err(foo!())?;
-   |         ^^^^^^^^^^^^ help: try this: `return Err(foo!())`
+LL |         Err(inline!(inline!(String::from("aasdfasdfasdfa"))))?;
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `return Err(inline!(inline!(String::from("aasdfasdfasdfa"))))`
 
 error: returning an `Err(_)` with the `?` operator
-  --> $DIR/try_err.rs:148:9
+  --> $DIR/try_err.rs:129:9
    |
 LL |         Err(io::ErrorKind::WriteZero)?
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `return Poll::Ready(Err(io::ErrorKind::WriteZero.into()))`
 
 error: returning an `Err(_)` with the `?` operator
-  --> $DIR/try_err.rs:150:9
+  --> $DIR/try_err.rs:131:9
    |
 LL |         Err(io::Error::new(io::ErrorKind::InvalidInput, "error"))?
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `return Poll::Ready(Err(io::Error::new(io::ErrorKind::InvalidInput, "error")))`
 
 error: returning an `Err(_)` with the `?` operator
-  --> $DIR/try_err.rs:158:9
+  --> $DIR/try_err.rs:139:9
    |
 LL |         Err(io::ErrorKind::NotFound)?
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `return Poll::Ready(Some(Err(io::ErrorKind::NotFound.into())))`
 
 error: returning an `Err(_)` with the `?` operator
-  --> $DIR/try_err.rs:167:16
+  --> $DIR/try_err.rs:148:16
    |
 LL |         return Err(42)?;
    |                ^^^^^^^^ help: try this: `Err(42)`
diff --git a/tests/ui/uninit.rs b/tests/ui/uninit.rs
index 21131731708..412b36b4ee8 100644
--- a/tests/ui/uninit.rs
+++ b/tests/ui/uninit.rs
@@ -3,13 +3,15 @@
 
 use std::mem::{self, MaybeUninit};
 
+union MyOwnMaybeUninit {
+    value: u8,
+    uninit: (),
+}
+
 fn main() {
     let _: usize = unsafe { MaybeUninit::uninit().assume_init() };
 
-    // edge case: For now we lint on empty arrays
-    let _: [u8; 0] = unsafe { MaybeUninit::uninit().assume_init() };
-
-    // edge case: For now we accept unit tuples
+    // This is OK, because ZSTs do not contain data.
     let _: () = unsafe { MaybeUninit::uninit().assume_init() };
 
     // This is OK, because `MaybeUninit` allows uninitialized data.
@@ -21,6 +23,19 @@ fn main() {
     // This is OK, because all constitutent types are uninit-compatible.
     let _: (MaybeUninit<usize>, [MaybeUninit<bool>; 2]) = unsafe { MaybeUninit::uninit().assume_init() };
 
+    // This is OK, because our own MaybeUninit is just as fine as the one from core.
+    let _: MyOwnMaybeUninit = unsafe { MaybeUninit::uninit().assume_init() };
+
+    // This is OK, because empty arrays don't contain data.
+    let _: [u8; 0] = unsafe { MaybeUninit::uninit().assume_init() };
+
     // Was a false negative.
     let _: usize = unsafe { mem::MaybeUninit::uninit().assume_init() };
+
+    polymorphic::<()>();
+
+    fn polymorphic<T>() {
+        // We are conservative around polymorphic types.
+        let _: T = unsafe { mem::MaybeUninit::uninit().assume_init() };
+    }
 }
diff --git a/tests/ui/uninit.stderr b/tests/ui/uninit.stderr
index 15ef2349489..9e01b9a4aa8 100644
--- a/tests/ui/uninit.stderr
+++ b/tests/ui/uninit.stderr
@@ -1,5 +1,5 @@
 error: this call for this type may be undefined behavior
-  --> $DIR/uninit.rs:7:29
+  --> $DIR/uninit.rs:12:29
    |
 LL |     let _: usize = unsafe { MaybeUninit::uninit().assume_init() };
    |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -7,15 +7,15 @@ LL |     let _: usize = unsafe { MaybeUninit::uninit().assume_init() };
    = note: `#[deny(clippy::uninit_assumed_init)]` on by default
 
 error: this call for this type may be undefined behavior
-  --> $DIR/uninit.rs:10:31
+  --> $DIR/uninit.rs:33:29
    |
-LL |     let _: [u8; 0] = unsafe { MaybeUninit::uninit().assume_init() };
-   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     let _: usize = unsafe { mem::MaybeUninit::uninit().assume_init() };
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: this call for this type may be undefined behavior
-  --> $DIR/uninit.rs:25:29
+  --> $DIR/uninit.rs:39:29
    |
-LL |     let _: usize = unsafe { mem::MaybeUninit::uninit().assume_init() };
+LL |         let _: T = unsafe { mem::MaybeUninit::uninit().assume_init() };
    |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 3 previous errors
diff --git a/tests/ui/uninit_vec.rs b/tests/ui/uninit_vec.rs
index 194e4fc157e..59ec64a7ab1 100644
--- a/tests/ui/uninit_vec.rs
+++ b/tests/ui/uninit_vec.rs
@@ -7,6 +7,11 @@ struct MyVec {
     vec: Vec<u8>,
 }
 
+union MyOwnMaybeUninit {
+    value: u8,
+    uninit: (),
+}
+
 fn main() {
     // with_capacity() -> set_len() should be detected
     let mut vec: Vec<u8> = Vec::with_capacity(1000);
@@ -97,4 +102,26 @@ fn main() {
     unsafe {
         vec.set_len(0);
     }
+
+    // ZSTs should not be detected
+    let mut vec: Vec<()> = Vec::with_capacity(1000);
+    unsafe {
+        vec.set_len(10);
+    }
+
+    // unions should not be detected
+    let mut vec: Vec<MyOwnMaybeUninit> = Vec::with_capacity(1000);
+    unsafe {
+        vec.set_len(10);
+    }
+
+    polymorphic::<()>();
+
+    fn polymorphic<T>() {
+        // We are conservative around polymorphic types.
+        let mut vec: Vec<T> = Vec::with_capacity(1000);
+        unsafe {
+            vec.set_len(10);
+        }
+    }
 }
diff --git a/tests/ui/uninit_vec.stderr b/tests/ui/uninit_vec.stderr
index 77fc689f076..9cdf0c95ad9 100644
--- a/tests/ui/uninit_vec.stderr
+++ b/tests/ui/uninit_vec.stderr
@@ -1,5 +1,5 @@
 error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
-  --> $DIR/uninit_vec.rs:12:5
+  --> $DIR/uninit_vec.rs:17:5
    |
 LL |     let mut vec: Vec<u8> = Vec::with_capacity(1000);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -11,7 +11,7 @@ LL |         vec.set_len(200);
    = note: `-D clippy::uninit-vec` implied by `-D warnings`
 
 error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
-  --> $DIR/uninit_vec.rs:18:5
+  --> $DIR/uninit_vec.rs:23:5
    |
 LL |     vec.reserve(1000);
    |     ^^^^^^^^^^^^^^^^^^
@@ -22,7 +22,7 @@ LL |         vec.set_len(200);
    = help: initialize the buffer or wrap the content in `MaybeUninit`
 
 error: calling `set_len()` on empty `Vec` creates out-of-bound values
-  --> $DIR/uninit_vec.rs:24:5
+  --> $DIR/uninit_vec.rs:29:5
    |
 LL |     let mut vec: Vec<u8> = Vec::new();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -31,7 +31,7 @@ LL |         vec.set_len(200);
    |         ^^^^^^^^^^^^^^^^
 
 error: calling `set_len()` on empty `Vec` creates out-of-bound values
-  --> $DIR/uninit_vec.rs:30:5
+  --> $DIR/uninit_vec.rs:35:5
    |
 LL |     let mut vec: Vec<u8> = Default::default();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -40,7 +40,7 @@ LL |         vec.set_len(200);
    |         ^^^^^^^^^^^^^^^^
 
 error: calling `set_len()` on empty `Vec` creates out-of-bound values
-  --> $DIR/uninit_vec.rs:35:5
+  --> $DIR/uninit_vec.rs:40:5
    |
 LL |     let mut vec: Vec<u8> = Vec::default();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -49,7 +49,7 @@ LL |         vec.set_len(200);
    |         ^^^^^^^^^^^^^^^^
 
 error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
-  --> $DIR/uninit_vec.rs:49:5
+  --> $DIR/uninit_vec.rs:54:5
    |
 LL |     let mut vec: Vec<u8> = Vec::with_capacity(1000);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -60,7 +60,7 @@ LL |         vec.set_len(200);
    = help: initialize the buffer or wrap the content in `MaybeUninit`
 
 error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
-  --> $DIR/uninit_vec.rs:58:5
+  --> $DIR/uninit_vec.rs:63:5
    |
 LL |     my_vec.vec.reserve(1000);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -71,7 +71,7 @@ LL |         my_vec.vec.set_len(200);
    = help: initialize the buffer or wrap the content in `MaybeUninit`
 
 error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
-  --> $DIR/uninit_vec.rs:63:5
+  --> $DIR/uninit_vec.rs:68:5
    |
 LL |     my_vec.vec = Vec::with_capacity(1000);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -82,7 +82,7 @@ LL |         my_vec.vec.set_len(200);
    = help: initialize the buffer or wrap the content in `MaybeUninit`
 
 error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
-  --> $DIR/uninit_vec.rs:42:9
+  --> $DIR/uninit_vec.rs:47:9
    |
 LL |         let mut vec: Vec<u8> = Vec::with_capacity(1000);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -92,7 +92,7 @@ LL |         vec.set_len(200);
    = help: initialize the buffer or wrap the content in `MaybeUninit`
 
 error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
-  --> $DIR/uninit_vec.rs:45:9
+  --> $DIR/uninit_vec.rs:50:9
    |
 LL |         vec.reserve(1000);
    |         ^^^^^^^^^^^^^^^^^^
@@ -101,5 +101,16 @@ LL |         vec.set_len(200);
    |
    = help: initialize the buffer or wrap the content in `MaybeUninit`
 
-error: aborting due to 10 previous errors
+error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
+  --> $DIR/uninit_vec.rs:122:9
+   |
+LL |         let mut vec: Vec<T> = Vec::with_capacity(1000);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |         unsafe {
+LL |             vec.set_len(10);
+   |             ^^^^^^^^^^^^^^^
+   |
+   = help: initialize the buffer or wrap the content in `MaybeUninit`
+
+error: aborting due to 11 previous errors
 
diff --git a/tests/ui/uninlined_format_args.fixed b/tests/ui/uninlined_format_args.fixed
index cbd5cc5fcee..1475d781c67 100644
--- a/tests/ui/uninlined_format_args.fixed
+++ b/tests/ui/uninlined_format_args.fixed
@@ -1,11 +1,11 @@
-// aux-build:proc_macro_with_span.rs
+// aux-build:proc_macros.rs
 // run-rustfix
 #![warn(clippy::uninlined_format_args)]
 #![allow(named_arguments_used_positionally, unused_imports, unused_macros, unused_variables)]
 #![allow(clippy::eq_op, clippy::format_in_format_args, clippy::print_literal)]
 
-extern crate proc_macro_with_span;
-use proc_macro_with_span::with_span;
+extern crate proc_macros;
+use proc_macros::with_span;
 
 macro_rules! no_param_str {
     () => {
diff --git a/tests/ui/uninlined_format_args.rs b/tests/ui/uninlined_format_args.rs
index cf0ea5be481..835afac393f 100644
--- a/tests/ui/uninlined_format_args.rs
+++ b/tests/ui/uninlined_format_args.rs
@@ -1,11 +1,11 @@
-// aux-build:proc_macro_with_span.rs
+// aux-build:proc_macros.rs
 // run-rustfix
 #![warn(clippy::uninlined_format_args)]
 #![allow(named_arguments_used_positionally, unused_imports, unused_macros, unused_variables)]
 #![allow(clippy::eq_op, clippy::format_in_format_args, clippy::print_literal)]
 
-extern crate proc_macro_with_span;
-use proc_macro_with_span::with_span;
+extern crate proc_macros;
+use proc_macros::with_span;
 
 macro_rules! no_param_str {
     () => {
diff --git a/tests/ui/unit_arg.rs b/tests/ui/unit_arg.rs
index 07e70873a81..674ae4f1df9 100644
--- a/tests/ui/unit_arg.rs
+++ b/tests/ui/unit_arg.rs
@@ -1,4 +1,4 @@
-// aux-build: proc_macro_with_span.rs
+// aux-build: proc_macros.rs
 #![warn(clippy::unit_arg)]
 #![allow(unused_must_use, unused_variables)]
 #![allow(
@@ -13,9 +13,9 @@
     clippy::unused_unit
 )]
 
-extern crate proc_macro_with_span;
+extern crate proc_macros;
 
-use proc_macro_with_span::with_span;
+use proc_macros::with_span;
 use std::fmt::Debug;
 
 fn foo<T: Debug>(t: T) {
diff --git a/tests/ui/unnecessary_lazy_eval.fixed b/tests/ui/unnecessary_lazy_eval.fixed
index 22e9bd8bdc5..3b93800f8b7 100644
--- a/tests/ui/unnecessary_lazy_eval.fixed
+++ b/tests/ui/unnecessary_lazy_eval.fixed
@@ -1,12 +1,12 @@
 // run-rustfix
-// aux-build: proc_macro_with_span.rs
+// aux-build: proc_macros.rs
 #![warn(clippy::unnecessary_lazy_evaluations)]
 #![allow(clippy::redundant_closure)]
 #![allow(clippy::bind_instead_of_map)]
 #![allow(clippy::map_identity)]
 
-extern crate proc_macro_with_span;
-use proc_macro_with_span::with_span;
+extern crate proc_macros;
+use proc_macros::with_span;
 
 struct Deep(Option<usize>);
 
diff --git a/tests/ui/unnecessary_lazy_eval.rs b/tests/ui/unnecessary_lazy_eval.rs
index 8726d84a23f..2851c0c5190 100644
--- a/tests/ui/unnecessary_lazy_eval.rs
+++ b/tests/ui/unnecessary_lazy_eval.rs
@@ -1,12 +1,12 @@
 // run-rustfix
-// aux-build: proc_macro_with_span.rs
+// aux-build: proc_macros.rs
 #![warn(clippy::unnecessary_lazy_evaluations)]
 #![allow(clippy::redundant_closure)]
 #![allow(clippy::bind_instead_of_map)]
 #![allow(clippy::map_identity)]
 
-extern crate proc_macro_with_span;
-use proc_macro_with_span::with_span;
+extern crate proc_macros;
+use proc_macros::with_span;
 
 struct Deep(Option<usize>);
 
diff --git a/tests/ui/unnecessary_operation.fixed b/tests/ui/unnecessary_operation.fixed
index 65d9c910b82..b046694f8c6 100644
--- a/tests/ui/unnecessary_operation.fixed
+++ b/tests/ui/unnecessary_operation.fixed
@@ -1,6 +1,12 @@
 // run-rustfix
 
-#![allow(clippy::deref_addrof, dead_code, unused, clippy::no_effect)]
+#![allow(
+    clippy::deref_addrof,
+    dead_code,
+    unused,
+    clippy::no_effect,
+    clippy::unnecessary_struct_initialization
+)]
 #![warn(clippy::unnecessary_operation)]
 
 struct Tuple(i32);
diff --git a/tests/ui/unnecessary_operation.rs b/tests/ui/unnecessary_operation.rs
index 4e2acd59f04..9ed9679e938 100644
--- a/tests/ui/unnecessary_operation.rs
+++ b/tests/ui/unnecessary_operation.rs
@@ -1,6 +1,12 @@
 // run-rustfix
 
-#![allow(clippy::deref_addrof, dead_code, unused, clippy::no_effect)]
+#![allow(
+    clippy::deref_addrof,
+    dead_code,
+    unused,
+    clippy::no_effect,
+    clippy::unnecessary_struct_initialization
+)]
 #![warn(clippy::unnecessary_operation)]
 
 struct Tuple(i32);
diff --git a/tests/ui/unnecessary_operation.stderr b/tests/ui/unnecessary_operation.stderr
index 44cf2e01ff7..a1d0d93998a 100644
--- a/tests/ui/unnecessary_operation.stderr
+++ b/tests/ui/unnecessary_operation.stderr
@@ -1,5 +1,5 @@
 error: unnecessary operation
-  --> $DIR/unnecessary_operation.rs:50:5
+  --> $DIR/unnecessary_operation.rs:56:5
    |
 LL |     Tuple(get_number());
    |     ^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();`
@@ -7,103 +7,103 @@ LL |     Tuple(get_number());
    = note: `-D clippy::unnecessary-operation` implied by `-D warnings`
 
 error: unnecessary operation
-  --> $DIR/unnecessary_operation.rs:51:5
+  --> $DIR/unnecessary_operation.rs:57:5
    |
 LL |     Struct { field: get_number() };
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();`
 
 error: unnecessary operation
-  --> $DIR/unnecessary_operation.rs:52:5
+  --> $DIR/unnecessary_operation.rs:58:5
    |
 LL |     Struct { ..get_struct() };
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_struct();`
 
 error: unnecessary operation
-  --> $DIR/unnecessary_operation.rs:53:5
+  --> $DIR/unnecessary_operation.rs:59:5
    |
 LL |     Enum::Tuple(get_number());
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();`
 
 error: unnecessary operation
-  --> $DIR/unnecessary_operation.rs:54:5
+  --> $DIR/unnecessary_operation.rs:60:5
    |
 LL |     Enum::Struct { field: get_number() };
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();`
 
 error: unnecessary operation
-  --> $DIR/unnecessary_operation.rs:55:5
+  --> $DIR/unnecessary_operation.rs:61:5
    |
 LL |     5 + get_number();
    |     ^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `5;get_number();`
 
 error: unnecessary operation
-  --> $DIR/unnecessary_operation.rs:56:5
+  --> $DIR/unnecessary_operation.rs:62:5
    |
 LL |     *&get_number();
    |     ^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();`
 
 error: unnecessary operation
-  --> $DIR/unnecessary_operation.rs:57:5
+  --> $DIR/unnecessary_operation.rs:63:5
    |
 LL |     &get_number();
    |     ^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();`
 
 error: unnecessary operation
-  --> $DIR/unnecessary_operation.rs:58:5
+  --> $DIR/unnecessary_operation.rs:64:5
    |
 LL |     (5, 6, get_number());
    |     ^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `5;6;get_number();`
 
 error: unnecessary operation
-  --> $DIR/unnecessary_operation.rs:59:5
+  --> $DIR/unnecessary_operation.rs:65:5
    |
 LL |     get_number()..;
    |     ^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();`
 
 error: unnecessary operation
-  --> $DIR/unnecessary_operation.rs:60:5
+  --> $DIR/unnecessary_operation.rs:66:5
    |
 LL |     ..get_number();
    |     ^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();`
 
 error: unnecessary operation
-  --> $DIR/unnecessary_operation.rs:61:5
+  --> $DIR/unnecessary_operation.rs:67:5
    |
 LL |     5..get_number();
    |     ^^^^^^^^^^^^^^^^ help: statement can be reduced to: `5;get_number();`
 
 error: unnecessary operation
-  --> $DIR/unnecessary_operation.rs:62:5
+  --> $DIR/unnecessary_operation.rs:68:5
    |
 LL |     [42, get_number()];
    |     ^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `42;get_number();`
 
 error: unnecessary operation
-  --> $DIR/unnecessary_operation.rs:63:5
+  --> $DIR/unnecessary_operation.rs:69:5
    |
 LL |     [42, 55][get_usize()];
    |     ^^^^^^^^^^^^^^^^^^^^^^ help: statement can be written as: `assert!([42, 55].len() > get_usize());`
 
 error: unnecessary operation
-  --> $DIR/unnecessary_operation.rs:64:5
+  --> $DIR/unnecessary_operation.rs:70:5
    |
 LL |     (42, get_number()).1;
    |     ^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `42;get_number();`
 
 error: unnecessary operation
-  --> $DIR/unnecessary_operation.rs:65:5
+  --> $DIR/unnecessary_operation.rs:71:5
    |
 LL |     [get_number(); 55];
    |     ^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();`
 
 error: unnecessary operation
-  --> $DIR/unnecessary_operation.rs:66:5
+  --> $DIR/unnecessary_operation.rs:72:5
    |
 LL |     [42; 55][get_usize()];
    |     ^^^^^^^^^^^^^^^^^^^^^^ help: statement can be written as: `assert!([42; 55].len() > get_usize());`
 
 error: unnecessary operation
-  --> $DIR/unnecessary_operation.rs:67:5
+  --> $DIR/unnecessary_operation.rs:73:5
    |
 LL | /     {
 LL | |         get_number()
@@ -111,7 +111,7 @@ LL | |     };
    | |______^ help: statement can be reduced to: `get_number();`
 
 error: unnecessary operation
-  --> $DIR/unnecessary_operation.rs:70:5
+  --> $DIR/unnecessary_operation.rs:76:5
    |
 LL | /     FooString {
 LL | |         s: String::from("blah"),
diff --git a/tests/ui/unnecessary_struct_initialization.fixed b/tests/ui/unnecessary_struct_initialization.fixed
new file mode 100644
index 00000000000..b47129e4a36
--- /dev/null
+++ b/tests/ui/unnecessary_struct_initialization.fixed
@@ -0,0 +1,73 @@
+// run-rustfix
+
+#![allow(unused)]
+#![warn(clippy::unnecessary_struct_initialization)]
+
+struct S {
+    f: String,
+}
+
+#[derive(Clone, Copy)]
+struct T {
+    f: u32,
+}
+
+struct U {
+    f: u32,
+}
+
+impl Clone for U {
+    fn clone(&self) -> Self {
+        // Do not lint: `Self` does not implement `Copy`
+        Self { ..*self }
+    }
+}
+
+#[derive(Copy)]
+struct V {
+    f: u32,
+}
+
+impl Clone for V {
+    fn clone(&self) -> Self {
+        // Lint: `Self` implements `Copy`
+        *self
+    }
+}
+
+fn main() {
+    // Should lint: `a` would be consumed anyway
+    let a = S { f: String::from("foo") };
+    let mut b = a;
+
+    // Should lint: `b` would be consumed, and is mutable
+    let c = &mut b;
+
+    // Should not lint as `d` is not mutable
+    let d = S { f: String::from("foo") };
+    let e = &mut S { ..d };
+
+    // Should lint as `f` would be consumed anyway
+    let f = S { f: String::from("foo") };
+    let g = &f;
+
+    // Should lint: the result of an expression is mutable
+    let h = &mut *Box::new(S { f: String::from("foo") });
+
+    // Should not lint: `m` would be both alive and borrowed
+    let m = T { f: 17 };
+    let n = &T { ..m };
+
+    // Should not lint: `m` should not be modified
+    let o = &mut T { ..m };
+    o.f = 32;
+    assert_eq!(m.f, 17);
+
+    // Should not lint: `m` should not be modified
+    let o = &mut T { ..m } as *mut T;
+    unsafe { &mut *o }.f = 32;
+    assert_eq!(m.f, 17);
+
+    // Should lint: the result of an expression is mutable and temporary
+    let p = &mut *Box::new(T { f: 5 });
+}
diff --git a/tests/ui/unnecessary_struct_initialization.rs b/tests/ui/unnecessary_struct_initialization.rs
new file mode 100644
index 00000000000..63b11c626e5
--- /dev/null
+++ b/tests/ui/unnecessary_struct_initialization.rs
@@ -0,0 +1,77 @@
+// run-rustfix
+
+#![allow(unused)]
+#![warn(clippy::unnecessary_struct_initialization)]
+
+struct S {
+    f: String,
+}
+
+#[derive(Clone, Copy)]
+struct T {
+    f: u32,
+}
+
+struct U {
+    f: u32,
+}
+
+impl Clone for U {
+    fn clone(&self) -> Self {
+        // Do not lint: `Self` does not implement `Copy`
+        Self { ..*self }
+    }
+}
+
+#[derive(Copy)]
+struct V {
+    f: u32,
+}
+
+impl Clone for V {
+    fn clone(&self) -> Self {
+        // Lint: `Self` implements `Copy`
+        Self { ..*self }
+    }
+}
+
+fn main() {
+    // Should lint: `a` would be consumed anyway
+    let a = S { f: String::from("foo") };
+    let mut b = S { ..a };
+
+    // Should lint: `b` would be consumed, and is mutable
+    let c = &mut S { ..b };
+
+    // Should not lint as `d` is not mutable
+    let d = S { f: String::from("foo") };
+    let e = &mut S { ..d };
+
+    // Should lint as `f` would be consumed anyway
+    let f = S { f: String::from("foo") };
+    let g = &S { ..f };
+
+    // Should lint: the result of an expression is mutable
+    let h = &mut S {
+        ..*Box::new(S { f: String::from("foo") })
+    };
+
+    // Should not lint: `m` would be both alive and borrowed
+    let m = T { f: 17 };
+    let n = &T { ..m };
+
+    // Should not lint: `m` should not be modified
+    let o = &mut T { ..m };
+    o.f = 32;
+    assert_eq!(m.f, 17);
+
+    // Should not lint: `m` should not be modified
+    let o = &mut T { ..m } as *mut T;
+    unsafe { &mut *o }.f = 32;
+    assert_eq!(m.f, 17);
+
+    // Should lint: the result of an expression is mutable and temporary
+    let p = &mut T {
+        ..*Box::new(T { f: 5 })
+    };
+}
diff --git a/tests/ui/unnecessary_struct_initialization.stderr b/tests/ui/unnecessary_struct_initialization.stderr
new file mode 100644
index 00000000000..ca497057702
--- /dev/null
+++ b/tests/ui/unnecessary_struct_initialization.stderr
@@ -0,0 +1,46 @@
+error: unnecessary struct building
+  --> $DIR/unnecessary_struct_initialization.rs:34:9
+   |
+LL |         Self { ..*self }
+   |         ^^^^^^^^^^^^^^^^ help: replace with: `*self`
+   |
+   = note: `-D clippy::unnecessary-struct-initialization` implied by `-D warnings`
+
+error: unnecessary struct building
+  --> $DIR/unnecessary_struct_initialization.rs:41:17
+   |
+LL |     let mut b = S { ..a };
+   |                 ^^^^^^^^^ help: replace with: `a`
+
+error: unnecessary struct building
+  --> $DIR/unnecessary_struct_initialization.rs:44:18
+   |
+LL |     let c = &mut S { ..b };
+   |                  ^^^^^^^^^ help: replace with: `b`
+
+error: unnecessary struct building
+  --> $DIR/unnecessary_struct_initialization.rs:52:14
+   |
+LL |     let g = &S { ..f };
+   |              ^^^^^^^^^ help: replace with: `f`
+
+error: unnecessary struct building
+  --> $DIR/unnecessary_struct_initialization.rs:55:18
+   |
+LL |       let h = &mut S {
+   |  __________________^
+LL | |         ..*Box::new(S { f: String::from("foo") })
+LL | |     };
+   | |_____^ help: replace with: `*Box::new(S { f: String::from("foo") })`
+
+error: unnecessary struct building
+  --> $DIR/unnecessary_struct_initialization.rs:74:18
+   |
+LL |       let p = &mut T {
+   |  __________________^
+LL | |         ..*Box::new(T { f: 5 })
+LL | |     };
+   | |_____^ help: replace with: `*Box::new(T { f: 5 })`
+
+error: aborting due to 6 previous errors
+
diff --git a/tests/ui/unnecessary_unsafety_doc.rs b/tests/ui/unnecessary_unsafety_doc.rs
index c160e31afd3..431093ab369 100644
--- a/tests/ui/unnecessary_unsafety_doc.rs
+++ b/tests/ui/unnecessary_unsafety_doc.rs
@@ -1,10 +1,10 @@
-// aux-build:doc_unsafe_macros.rs
+// aux-build:proc_macros.rs
 
 #![allow(clippy::let_unit_value)]
 #![warn(clippy::unnecessary_safety_doc)]
 
-#[macro_use]
-extern crate doc_unsafe_macros;
+extern crate proc_macros;
+use proc_macros::external;
 
 /// This is has no safety section, and does not need one either
 pub fn destroy_the_planet() {
@@ -129,7 +129,11 @@ macro_rules! very_safe {
 very_safe!();
 
 // we don't lint code from external macros
-undocd_safe!();
+external!(
+    pub fn vey_oy() {
+        unimplemented!();
+    }
+);
 
 fn main() {}
 
diff --git a/tests/ui/unnecessary_unsafety_doc.stderr b/tests/ui/unnecessary_unsafety_doc.stderr
index 72898c93fa1..b0f20fdac5f 100644
--- a/tests/ui/unnecessary_unsafety_doc.stderr
+++ b/tests/ui/unnecessary_unsafety_doc.stderr
@@ -42,7 +42,7 @@ LL | very_safe!();
    = note: this error originates in the macro `very_safe` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: docs for safe trait have unnecessary `# Safety` section
-  --> $DIR/unnecessary_unsafety_doc.rs:147:1
+  --> $DIR/unnecessary_unsafety_doc.rs:151:1
    |
 LL | pub trait DocumentedSafeTraitWithImplementationHeader {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/workspace.rs b/tests/workspace.rs
index 95325e06037..c9cbc50546c 100644
--- a/tests/workspace.rs
+++ b/tests/workspace.rs
@@ -1,4 +1,4 @@
-#![feature(once_cell)]
+#![feature(lazy_cell)]
 
 use std::path::PathBuf;
 use std::process::Command;