about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-02-24 13:43:34 +0000
committerbors <bors@rust-lang.org>2024-02-24 13:43:34 +0000
commita2c1d565e576efb5f3abce367723711afe65c8cd (patch)
tree99580a6f6b41c6be8612cd4872b66f0d90b20928
parent64054693eb35cd0b80d3eee598f723a2b2df2e8f (diff)
parent762448bc55f034aba15a62245b24a5fcd48166b9 (diff)
downloadrust-a2c1d565e576efb5f3abce367723711afe65c8cd.tar.gz
rust-a2c1d565e576efb5f3abce367723711afe65c8cd.zip
Auto merge of #12259 - GuillaumeGomez:multiple-bound-locations, r=llogiq
Add new `multiple_bound_locations` lint

Fixes #7181.

r? `@llogiq`

changelog: Add new `multiple_bound_locations` lint
-rw-r--r--CHANGELOG.md1
-rw-r--r--clippy_lints/src/declared_lints.rs1
-rw-r--r--clippy_lints/src/lib.rs2
-rw-r--r--clippy_lints/src/multiple_bound_locations.rs84
-rw-r--r--tests/ui/multiple_bound_locations.rs60
-rw-r--r--tests/ui/multiple_bound_locations.stderr59
-rw-r--r--tests/ui/trait_duplication_in_bounds_unfixable.rs1
-rw-r--r--tests/ui/trait_duplication_in_bounds_unfixable.stderr16
-rw-r--r--tests/ui/type_repetition_in_bounds.rs2
-rw-r--r--tests/ui/unnecessary_cast.fixed1
-rw-r--r--tests/ui/unnecessary_cast.rs1
-rw-r--r--tests/ui/unnecessary_cast.stderr80
12 files changed, 259 insertions, 49 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c2f47ad9720..5805511c70f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5430,6 +5430,7 @@ Released 2018-09-13
 [`modulo_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#modulo_arithmetic
 [`modulo_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#modulo_one
 [`multi_assignments`]: https://rust-lang.github.io/rust-clippy/master/index.html#multi_assignments
+[`multiple_bound_locations`]: https://rust-lang.github.io/rust-clippy/master/index.html#multiple_bound_locations
 [`multiple_crate_versions`]: https://rust-lang.github.io/rust-clippy/master/index.html#multiple_crate_versions
 [`multiple_inherent_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#multiple_inherent_impl
 [`multiple_unsafe_ops_per_block`]: https://rust-lang.github.io/rust-clippy/master/index.html#multiple_unsafe_ops_per_block
diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs
index 76595e2e26e..79fd7639307 100644
--- a/clippy_lints/src/declared_lints.rs
+++ b/clippy_lints/src/declared_lints.rs
@@ -499,6 +499,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::module_style::MOD_MODULE_FILES_INFO,
     crate::module_style::SELF_NAMED_MODULE_FILES_INFO,
     crate::multi_assignments::MULTI_ASSIGNMENTS_INFO,
+    crate::multiple_bound_locations::MULTIPLE_BOUND_LOCATIONS_INFO,
     crate::multiple_unsafe_ops_per_block::MULTIPLE_UNSAFE_OPS_PER_BLOCK_INFO,
     crate::mut_key::MUTABLE_KEY_TYPE_INFO,
     crate::mut_mut::MUT_MUT_INFO,
diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs
index 1bca1f2bd6f..77b6775eb77 100644
--- a/clippy_lints/src/lib.rs
+++ b/clippy_lints/src/lib.rs
@@ -231,6 +231,7 @@ mod missing_trait_methods;
 mod mixed_read_write_in_expression;
 mod module_style;
 mod multi_assignments;
+mod multiple_bound_locations;
 mod multiple_unsafe_ops_per_block;
 mod mut_key;
 mod mut_mut;
@@ -1116,6 +1117,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
     });
     store.register_late_pass(move |_| Box::new(incompatible_msrv::IncompatibleMsrv::new(msrv())));
     store.register_late_pass(|_| Box::new(to_string_trait_impl::ToStringTraitImpl));
+    store.register_early_pass(|| Box::new(multiple_bound_locations::MultipleBoundLocations));
     // add lints here, do not remove this comment, it's used in `new_lint`
 }
 
diff --git a/clippy_lints/src/multiple_bound_locations.rs b/clippy_lints/src/multiple_bound_locations.rs
new file mode 100644
index 00000000000..191b32408ef
--- /dev/null
+++ b/clippy_lints/src/multiple_bound_locations.rs
@@ -0,0 +1,84 @@
+use rustc_ast::visit::FnKind;
+use rustc_ast::{NodeId, WherePredicate};
+use rustc_data_structures::fx::FxHashMap;
+use rustc_lint::{EarlyContext, EarlyLintPass};
+use rustc_session::declare_lint_pass;
+use rustc_span::Span;
+
+use clippy_utils::diagnostics::span_lint;
+use clippy_utils::source::snippet_opt;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Check if a generic is defined both in the bound predicate and in the `where` clause.
+    ///
+    /// ### Why is this bad?
+    /// It can be confusing for developers when seeing bounds for a generic in multiple places.
+    ///
+    /// ### Example
+    /// ```no_run
+    /// fn ty<F: std::fmt::Debug>(a: F)
+    /// where
+    ///     F: Sized,
+    /// {}
+    /// ```
+    /// Use instead:
+    /// ```no_run
+    /// fn ty<F>(a: F)
+    /// where
+    ///     F: Sized + std::fmt::Debug,
+    /// {}
+    /// ```
+    #[clippy::version = "1.77.0"]
+    pub MULTIPLE_BOUND_LOCATIONS,
+    suspicious,
+    "defining generic bounds in multiple locations"
+}
+
+declare_lint_pass!(MultipleBoundLocations => [MULTIPLE_BOUND_LOCATIONS]);
+
+impl EarlyLintPass for MultipleBoundLocations {
+    fn check_fn(&mut self, cx: &EarlyContext<'_>, kind: FnKind<'_>, _: Span, _: NodeId) {
+        if let FnKind::Fn(_, _, _, _, generics, _) = kind
+            && !generics.params.is_empty()
+            && !generics.where_clause.predicates.is_empty()
+        {
+            let mut generic_params_with_bounds = FxHashMap::default();
+
+            for param in &generics.params {
+                if !param.bounds.is_empty() {
+                    generic_params_with_bounds.insert(param.ident.name.as_str(), param.ident.span);
+                }
+            }
+            for clause in &generics.where_clause.predicates {
+                match clause {
+                    WherePredicate::BoundPredicate(pred) => {
+                        if (!pred.bound_generic_params.is_empty() || !pred.bounds.is_empty())
+                            && let Some(name) = snippet_opt(cx, pred.bounded_ty.span)
+                            && let Some(bound_span) = generic_params_with_bounds.get(name.as_str())
+                        {
+                            emit_lint(cx, *bound_span, pred.bounded_ty.span);
+                        }
+                    },
+                    WherePredicate::RegionPredicate(pred) => {
+                        if !pred.bounds.is_empty()
+                            && let Some(bound_span) = generic_params_with_bounds.get(&pred.lifetime.ident.name.as_str())
+                        {
+                            emit_lint(cx, *bound_span, pred.lifetime.ident.span);
+                        }
+                    },
+                    WherePredicate::EqPredicate(_) => {},
+                }
+            }
+        }
+    }
+}
+
+fn emit_lint(cx: &EarlyContext<'_>, bound_span: Span, where_span: Span) {
+    span_lint(
+        cx,
+        MULTIPLE_BOUND_LOCATIONS,
+        vec![bound_span, where_span],
+        "bound is defined in more than one place",
+    );
+}
diff --git a/tests/ui/multiple_bound_locations.rs b/tests/ui/multiple_bound_locations.rs
new file mode 100644
index 00000000000..de9d994782e
--- /dev/null
+++ b/tests/ui/multiple_bound_locations.rs
@@ -0,0 +1,60 @@
+#![warn(clippy::multiple_bound_locations)]
+
+fn ty<F: std::fmt::Debug>(a: F)
+//~^ ERROR: bound is defined in more than one place
+where
+    F: Sized,
+{
+}
+
+fn lifetime<'a, 'b: 'a, 'c>(a: &'b str, b: &'a str, c: &'c str)
+//~^ ERROR: bound is defined in more than one place
+where
+    'b: 'c,
+{
+}
+
+fn ty_pred<F: Sized>()
+//~^ ERROR: bound is defined in more than one place
+where
+    for<'a> F: Send + 'a,
+{
+}
+
+struct B;
+
+impl B {
+    fn ty<F: std::fmt::Debug>(a: F)
+    //~^ ERROR: bound is defined in more than one place
+    where
+        F: Sized,
+    {
+    }
+
+    fn lifetime<'a, 'b: 'a, 'c>(a: &'b str, b: &'a str, c: &'c str)
+    //~^ ERROR: bound is defined in more than one place
+    where
+        'b: 'c,
+    {
+    }
+
+    fn ty_pred<F: Sized>()
+    //~^ ERROR: bound is defined in more than one place
+    where
+        for<'a> F: Send + 'a,
+    {
+    }
+}
+
+struct C<F>(F);
+
+impl<F> C<F> {
+    fn foo(_f: F) -> Self
+    where
+        F: std::fmt::Display,
+    {
+        todo!()
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/multiple_bound_locations.stderr b/tests/ui/multiple_bound_locations.stderr
new file mode 100644
index 00000000000..22dd2e0a552
--- /dev/null
+++ b/tests/ui/multiple_bound_locations.stderr
@@ -0,0 +1,59 @@
+error: bound is defined in more than one place
+  --> tests/ui/multiple_bound_locations.rs:3:7
+   |
+LL | fn ty<F: std::fmt::Debug>(a: F)
+   |       ^
+...
+LL |     F: Sized,
+   |     ^
+   |
+   = note: `-D clippy::multiple-bound-locations` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::multiple_bound_locations)]`
+
+error: bound is defined in more than one place
+  --> tests/ui/multiple_bound_locations.rs:10:17
+   |
+LL | fn lifetime<'a, 'b: 'a, 'c>(a: &'b str, b: &'a str, c: &'c str)
+   |                 ^^
+...
+LL |     'b: 'c,
+   |     ^^
+
+error: bound is defined in more than one place
+  --> tests/ui/multiple_bound_locations.rs:17:12
+   |
+LL | fn ty_pred<F: Sized>()
+   |            ^
+...
+LL |     for<'a> F: Send + 'a,
+   |             ^
+
+error: bound is defined in more than one place
+  --> tests/ui/multiple_bound_locations.rs:27:11
+   |
+LL |     fn ty<F: std::fmt::Debug>(a: F)
+   |           ^
+...
+LL |         F: Sized,
+   |         ^
+
+error: bound is defined in more than one place
+  --> tests/ui/multiple_bound_locations.rs:34:21
+   |
+LL |     fn lifetime<'a, 'b: 'a, 'c>(a: &'b str, b: &'a str, c: &'c str)
+   |                     ^^
+...
+LL |         'b: 'c,
+   |         ^^
+
+error: bound is defined in more than one place
+  --> tests/ui/multiple_bound_locations.rs:41:16
+   |
+LL |     fn ty_pred<F: Sized>()
+   |                ^
+...
+LL |         for<'a> F: Send + 'a,
+   |                 ^
+
+error: aborting due to 6 previous errors
+
diff --git a/tests/ui/trait_duplication_in_bounds_unfixable.rs b/tests/ui/trait_duplication_in_bounds_unfixable.rs
index effed3a2693..b0095bb77b5 100644
--- a/tests/ui/trait_duplication_in_bounds_unfixable.rs
+++ b/tests/ui/trait_duplication_in_bounds_unfixable.rs
@@ -1,4 +1,5 @@
 #![deny(clippy::trait_duplication_in_bounds)]
+#![allow(clippy::multiple_bound_locations)]
 
 use std::collections::BTreeMap;
 use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign};
diff --git a/tests/ui/trait_duplication_in_bounds_unfixable.stderr b/tests/ui/trait_duplication_in_bounds_unfixable.stderr
index 1d87e50e8a5..41029007a98 100644
--- a/tests/ui/trait_duplication_in_bounds_unfixable.stderr
+++ b/tests/ui/trait_duplication_in_bounds_unfixable.stderr
@@ -1,5 +1,5 @@
 error: this trait bound is already specified in the where clause
-  --> tests/ui/trait_duplication_in_bounds_unfixable.rs:6:15
+  --> tests/ui/trait_duplication_in_bounds_unfixable.rs:7:15
    |
 LL | fn bad_foo<T: Clone + Default, Z: Copy>(arg0: T, arg1: Z)
    |               ^^^^^
@@ -12,7 +12,7 @@ LL | #![deny(clippy::trait_duplication_in_bounds)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: this trait bound is already specified in the where clause
-  --> tests/ui/trait_duplication_in_bounds_unfixable.rs:6:23
+  --> tests/ui/trait_duplication_in_bounds_unfixable.rs:7:23
    |
 LL | fn bad_foo<T: Clone + Default, Z: Copy>(arg0: T, arg1: Z)
    |                       ^^^^^^^
@@ -20,7 +20,7 @@ LL | fn bad_foo<T: Clone + Default, Z: Copy>(arg0: T, arg1: Z)
    = help: consider removing this trait bound
 
 error: this trait bound is already specified in trait declaration
-  --> tests/ui/trait_duplication_in_bounds_unfixable.rs:37:15
+  --> tests/ui/trait_duplication_in_bounds_unfixable.rs:38:15
    |
 LL |         Self: Default;
    |               ^^^^^^^
@@ -28,7 +28,7 @@ LL |         Self: Default;
    = help: consider removing this trait bound
 
 error: this trait bound is already specified in trait declaration
-  --> tests/ui/trait_duplication_in_bounds_unfixable.rs:52:15
+  --> tests/ui/trait_duplication_in_bounds_unfixable.rs:53:15
    |
 LL |         Self: Default + Clone;
    |               ^^^^^^^
@@ -36,7 +36,7 @@ LL |         Self: Default + Clone;
    = help: consider removing this trait bound
 
 error: this trait bound is already specified in trait declaration
-  --> tests/ui/trait_duplication_in_bounds_unfixable.rs:59:15
+  --> tests/ui/trait_duplication_in_bounds_unfixable.rs:60:15
    |
 LL |         Self: Default + Clone;
    |               ^^^^^^^
@@ -44,7 +44,7 @@ LL |         Self: Default + Clone;
    = help: consider removing this trait bound
 
 error: this trait bound is already specified in trait declaration
-  --> tests/ui/trait_duplication_in_bounds_unfixable.rs:59:25
+  --> tests/ui/trait_duplication_in_bounds_unfixable.rs:60:25
    |
 LL |         Self: Default + Clone;
    |                         ^^^^^
@@ -52,7 +52,7 @@ LL |         Self: Default + Clone;
    = help: consider removing this trait bound
 
 error: this trait bound is already specified in trait declaration
-  --> tests/ui/trait_duplication_in_bounds_unfixable.rs:64:15
+  --> tests/ui/trait_duplication_in_bounds_unfixable.rs:65:15
    |
 LL |         Self: Default;
    |               ^^^^^^^
@@ -60,7 +60,7 @@ LL |         Self: Default;
    = help: consider removing this trait bound
 
 error: this trait bound is already specified in trait declaration
-  --> tests/ui/trait_duplication_in_bounds_unfixable.rs:100:15
+  --> tests/ui/trait_duplication_in_bounds_unfixable.rs:101:15
    |
 LL |         Self: Iterator<Item = Foo>,
    |               ^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/type_repetition_in_bounds.rs b/tests/ui/type_repetition_in_bounds.rs
index 504a0039405..0039c805b7d 100644
--- a/tests/ui/type_repetition_in_bounds.rs
+++ b/tests/ui/type_repetition_in_bounds.rs
@@ -1,5 +1,5 @@
 #![deny(clippy::type_repetition_in_bounds)]
-#![allow(clippy::extra_unused_type_parameters)]
+#![allow(clippy::extra_unused_type_parameters, clippy::multiple_bound_locations)]
 
 use serde::Deserialize;
 use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign};
diff --git a/tests/ui/unnecessary_cast.fixed b/tests/ui/unnecessary_cast.fixed
index 18dd53bf2b4..f52d3250339 100644
--- a/tests/ui/unnecessary_cast.fixed
+++ b/tests/ui/unnecessary_cast.fixed
@@ -2,6 +2,7 @@
 #![warn(clippy::unnecessary_cast)]
 #![allow(
     clippy::borrow_as_ptr,
+    clippy::multiple_bound_locations,
     clippy::no_effect,
     clippy::nonstandard_macro_braces,
     clippy::unnecessary_operation,
diff --git a/tests/ui/unnecessary_cast.rs b/tests/ui/unnecessary_cast.rs
index fcdd4c60ccd..dfd8b454e6c 100644
--- a/tests/ui/unnecessary_cast.rs
+++ b/tests/ui/unnecessary_cast.rs
@@ -2,6 +2,7 @@
 #![warn(clippy::unnecessary_cast)]
 #![allow(
     clippy::borrow_as_ptr,
+    clippy::multiple_bound_locations,
     clippy::no_effect,
     clippy::nonstandard_macro_braces,
     clippy::unnecessary_operation,
diff --git a/tests/ui/unnecessary_cast.stderr b/tests/ui/unnecessary_cast.stderr
index 9456c5acde3..935bb71da32 100644
--- a/tests/ui/unnecessary_cast.stderr
+++ b/tests/ui/unnecessary_cast.stderr
@@ -1,5 +1,5 @@
 error: casting raw pointers to the same type and constness is unnecessary (`*const T` -> `*const T`)
-  --> tests/ui/unnecessary_cast.rs:18:5
+  --> tests/ui/unnecessary_cast.rs:19:5
    |
 LL |     ptr as *const T
    |     ^^^^^^^^^^^^^^^ help: try: `ptr`
@@ -8,235 +8,235 @@ LL |     ptr as *const T
    = help: to override `-D warnings` add `#[allow(clippy::unnecessary_cast)]`
 
 error: casting integer literal to `i32` is unnecessary
-  --> tests/ui/unnecessary_cast.rs:53:5
+  --> tests/ui/unnecessary_cast.rs:54:5
    |
 LL |     1i32 as i32;
    |     ^^^^^^^^^^^ help: try: `1_i32`
 
 error: casting float literal to `f32` is unnecessary
-  --> tests/ui/unnecessary_cast.rs:54:5
+  --> tests/ui/unnecessary_cast.rs:55:5
    |
 LL |     1f32 as f32;
    |     ^^^^^^^^^^^ help: try: `1_f32`
 
 error: casting to the same type is unnecessary (`bool` -> `bool`)
-  --> tests/ui/unnecessary_cast.rs:55:5
+  --> tests/ui/unnecessary_cast.rs:56:5
    |
 LL |     false as bool;
    |     ^^^^^^^^^^^^^ help: try: `false`
 
 error: casting integer literal to `i32` is unnecessary
-  --> tests/ui/unnecessary_cast.rs:58:5
+  --> tests/ui/unnecessary_cast.rs:59:5
    |
 LL |     -1_i32 as i32;
    |     ^^^^^^^^^^^^^ help: try: `-1_i32`
 
 error: casting integer literal to `i32` is unnecessary
-  --> tests/ui/unnecessary_cast.rs:59:5
+  --> tests/ui/unnecessary_cast.rs:60:5
    |
 LL |     - 1_i32 as i32;
    |     ^^^^^^^^^^^^^^ help: try: `- 1_i32`
 
 error: casting float literal to `f32` is unnecessary
-  --> tests/ui/unnecessary_cast.rs:60:5
+  --> tests/ui/unnecessary_cast.rs:61:5
    |
 LL |     -1f32 as f32;
    |     ^^^^^^^^^^^^ help: try: `-1_f32`
 
 error: casting integer literal to `i32` is unnecessary
-  --> tests/ui/unnecessary_cast.rs:61:5
+  --> tests/ui/unnecessary_cast.rs:62:5
    |
 LL |     1_i32 as i32;
    |     ^^^^^^^^^^^^ help: try: `1_i32`
 
 error: casting float literal to `f32` is unnecessary
-  --> tests/ui/unnecessary_cast.rs:62:5
+  --> tests/ui/unnecessary_cast.rs:63:5
    |
 LL |     1_f32 as f32;
    |     ^^^^^^^^^^^^ help: try: `1_f32`
 
 error: casting raw pointers to the same type and constness is unnecessary (`*const u8` -> `*const u8`)
-  --> tests/ui/unnecessary_cast.rs:64:22
+  --> tests/ui/unnecessary_cast.rs:65:22
    |
 LL |     let _: *mut u8 = [1u8, 2].as_ptr() as *const u8 as *mut u8;
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `[1u8, 2].as_ptr()`
 
 error: casting raw pointers to the same type and constness is unnecessary (`*const u8` -> `*const u8`)
-  --> tests/ui/unnecessary_cast.rs:66:5
+  --> tests/ui/unnecessary_cast.rs:67:5
    |
 LL |     [1u8, 2].as_ptr() as *const u8;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `[1u8, 2].as_ptr()`
 
 error: casting raw pointers to the same type and constness is unnecessary (`*mut u8` -> `*mut u8`)
-  --> tests/ui/unnecessary_cast.rs:68:5
+  --> tests/ui/unnecessary_cast.rs:69:5
    |
 LL |     [1u8, 2].as_mut_ptr() as *mut u8;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `[1u8, 2].as_mut_ptr()`
 
 error: casting raw pointers to the same type and constness is unnecessary (`*const u32` -> `*const u32`)
-  --> tests/ui/unnecessary_cast.rs:79:5
+  --> tests/ui/unnecessary_cast.rs:80:5
    |
 LL |     owo::<u32>([1u32].as_ptr()) as *const u32;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `owo::<u32>([1u32].as_ptr())`
 
 error: casting raw pointers to the same type and constness is unnecessary (`*const u8` -> `*const u8`)
-  --> tests/ui/unnecessary_cast.rs:80:5
+  --> tests/ui/unnecessary_cast.rs:81:5
    |
 LL |     uwu::<u32, u8>([1u32].as_ptr()) as *const u8;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `uwu::<u32, u8>([1u32].as_ptr())`
 
 error: casting raw pointers to the same type and constness is unnecessary (`*const u32` -> `*const u32`)
-  --> tests/ui/unnecessary_cast.rs:82:5
+  --> tests/ui/unnecessary_cast.rs:83:5
    |
 LL |     uwu::<u32, u32>([1u32].as_ptr()) as *const u32;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `uwu::<u32, u32>([1u32].as_ptr())`
 
 error: casting to the same type is unnecessary (`u32` -> `u32`)
-  --> tests/ui/unnecessary_cast.rs:117:5
+  --> tests/ui/unnecessary_cast.rs:118:5
    |
 LL |     aaa() as u32;
    |     ^^^^^^^^^^^^ help: try: `aaa()`
 
 error: casting to the same type is unnecessary (`u32` -> `u32`)
-  --> tests/ui/unnecessary_cast.rs:119:5
+  --> tests/ui/unnecessary_cast.rs:120:5
    |
 LL |     aaa() as u32;
    |     ^^^^^^^^^^^^ help: try: `aaa()`
 
 error: casting integer literal to `f32` is unnecessary
-  --> tests/ui/unnecessary_cast.rs:155:9
+  --> tests/ui/unnecessary_cast.rs:156:9
    |
 LL |         100 as f32;
    |         ^^^^^^^^^^ help: try: `100_f32`
 
 error: casting integer literal to `f64` is unnecessary
-  --> tests/ui/unnecessary_cast.rs:156:9
+  --> tests/ui/unnecessary_cast.rs:157:9
    |
 LL |         100 as f64;
    |         ^^^^^^^^^^ help: try: `100_f64`
 
 error: casting integer literal to `f64` is unnecessary
-  --> tests/ui/unnecessary_cast.rs:157:9
+  --> tests/ui/unnecessary_cast.rs:158:9
    |
 LL |         100_i32 as f64;
    |         ^^^^^^^^^^^^^^ help: try: `100_f64`
 
 error: casting integer literal to `f32` is unnecessary
-  --> tests/ui/unnecessary_cast.rs:158:17
+  --> tests/ui/unnecessary_cast.rs:159:17
    |
 LL |         let _ = -100 as f32;
    |                 ^^^^^^^^^^^ help: try: `-100_f32`
 
 error: casting integer literal to `f64` is unnecessary
-  --> tests/ui/unnecessary_cast.rs:159:17
+  --> tests/ui/unnecessary_cast.rs:160:17
    |
 LL |         let _ = -100 as f64;
    |                 ^^^^^^^^^^^ help: try: `-100_f64`
 
 error: casting integer literal to `f64` is unnecessary
-  --> tests/ui/unnecessary_cast.rs:160:17
+  --> tests/ui/unnecessary_cast.rs:161:17
    |
 LL |         let _ = -100_i32 as f64;
    |                 ^^^^^^^^^^^^^^^ help: try: `-100_f64`
 
 error: casting float literal to `f32` is unnecessary
-  --> tests/ui/unnecessary_cast.rs:161:9
+  --> tests/ui/unnecessary_cast.rs:162:9
    |
 LL |         100. as f32;
    |         ^^^^^^^^^^^ help: try: `100_f32`
 
 error: casting float literal to `f64` is unnecessary
-  --> tests/ui/unnecessary_cast.rs:162:9
+  --> tests/ui/unnecessary_cast.rs:163:9
    |
 LL |         100. as f64;
    |         ^^^^^^^^^^^ help: try: `100_f64`
 
 error: casting integer literal to `u32` is unnecessary
-  --> tests/ui/unnecessary_cast.rs:174:9
+  --> tests/ui/unnecessary_cast.rs:175:9
    |
 LL |         1 as u32;
    |         ^^^^^^^^ help: try: `1_u32`
 
 error: casting integer literal to `i32` is unnecessary
-  --> tests/ui/unnecessary_cast.rs:175:9
+  --> tests/ui/unnecessary_cast.rs:176:9
    |
 LL |         0x10 as i32;
    |         ^^^^^^^^^^^ help: try: `0x10_i32`
 
 error: casting integer literal to `usize` is unnecessary
-  --> tests/ui/unnecessary_cast.rs:176:9
+  --> tests/ui/unnecessary_cast.rs:177:9
    |
 LL |         0b10 as usize;
    |         ^^^^^^^^^^^^^ help: try: `0b10_usize`
 
 error: casting integer literal to `u16` is unnecessary
-  --> tests/ui/unnecessary_cast.rs:177:9
+  --> tests/ui/unnecessary_cast.rs:178:9
    |
 LL |         0o73 as u16;
    |         ^^^^^^^^^^^ help: try: `0o73_u16`
 
 error: casting integer literal to `u32` is unnecessary
-  --> tests/ui/unnecessary_cast.rs:178:9
+  --> tests/ui/unnecessary_cast.rs:179:9
    |
 LL |         1_000_000_000 as u32;
    |         ^^^^^^^^^^^^^^^^^^^^ help: try: `1_000_000_000_u32`
 
 error: casting float literal to `f64` is unnecessary
-  --> tests/ui/unnecessary_cast.rs:180:9
+  --> tests/ui/unnecessary_cast.rs:181:9
    |
 LL |         1.0 as f64;
    |         ^^^^^^^^^^ help: try: `1.0_f64`
 
 error: casting float literal to `f32` is unnecessary
-  --> tests/ui/unnecessary_cast.rs:181:9
+  --> tests/ui/unnecessary_cast.rs:182:9
    |
 LL |         0.5 as f32;
    |         ^^^^^^^^^^ help: try: `0.5_f32`
 
 error: casting integer literal to `i32` is unnecessary
-  --> tests/ui/unnecessary_cast.rs:185:17
+  --> tests/ui/unnecessary_cast.rs:186:17
    |
 LL |         let _ = -1 as i32;
    |                 ^^^^^^^^^ help: try: `-1_i32`
 
 error: casting float literal to `f32` is unnecessary
-  --> tests/ui/unnecessary_cast.rs:186:17
+  --> tests/ui/unnecessary_cast.rs:187:17
    |
 LL |         let _ = -1.0 as f32;
    |                 ^^^^^^^^^^^ help: try: `-1.0_f32`
 
 error: casting to the same type is unnecessary (`i32` -> `i32`)
-  --> tests/ui/unnecessary_cast.rs:192:18
+  --> tests/ui/unnecessary_cast.rs:193:18
    |
 LL |         let _ = &(x as i32);
    |                  ^^^^^^^^^^ help: try: `{ x }`
 
 error: casting integer literal to `i32` is unnecessary
-  --> tests/ui/unnecessary_cast.rs:198:22
+  --> tests/ui/unnecessary_cast.rs:199:22
    |
 LL |         let _: i32 = -(1) as i32;
    |                      ^^^^^^^^^^^ help: try: `-1_i32`
 
 error: casting integer literal to `i64` is unnecessary
-  --> tests/ui/unnecessary_cast.rs:200:22
+  --> tests/ui/unnecessary_cast.rs:201:22
    |
 LL |         let _: i64 = -(1) as i64;
    |                      ^^^^^^^^^^^ help: try: `-1_i64`
 
 error: casting float literal to `f64` is unnecessary
-  --> tests/ui/unnecessary_cast.rs:207:22
+  --> tests/ui/unnecessary_cast.rs:208:22
    |
 LL |         let _: f64 = (-8.0 as f64).exp();
    |                      ^^^^^^^^^^^^^ help: try: `(-8.0_f64)`
 
 error: casting float literal to `f64` is unnecessary
-  --> tests/ui/unnecessary_cast.rs:209:23
+  --> tests/ui/unnecessary_cast.rs:210:23
    |
 LL |         let _: f64 = -(8.0 as f64).exp(); // should suggest `-8.0_f64.exp()` here not to change code behavior
    |                       ^^^^^^^^^^^^ help: try: `8.0_f64`
 
 error: casting to the same type is unnecessary (`f32` -> `f32`)
-  --> tests/ui/unnecessary_cast.rs:217:20
+  --> tests/ui/unnecessary_cast.rs:218:20
    |
 LL |         let _num = foo() as f32;
    |                    ^^^^^^^^^^^^ help: try: `foo()`