about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-05-25 01:35:55 +0000
committerbors <bors@rust-lang.org>2022-05-25 01:35:55 +0000
commit3cc50a4a0816efd4e1964025e7abdeba3a661275 (patch)
tree16c31c0dcc35d3ce530bc20bfd6b917b6124d4bd
parentb97784fd07b1981292703fb136cf6e4f7cddc113 (diff)
parentd0f93c12a2a6f0d693507ff6325fed62720e616b (diff)
downloadrust-3cc50a4a0816efd4e1964025e7abdeba3a661275.tar.gz
rust-3cc50a4a0816efd4e1964025e7abdeba3a661275.zip
Auto merge of #8882 - kyoto7250:get_first, r=llogiq
feat(lint): impl lint about use first() instead of get(0)

close #8851

This PR adds new lint about considering replacing .get(0) with .first().

Thank you in advance.

changelog: adds new lint [`get_first`] to consider replacing .get(0) with .first()
-rw-r--r--CHANGELOG.md1
-rw-r--r--clippy_lints/src/get_first.rs69
-rw-r--r--clippy_lints/src/lib.register_all.rs1
-rw-r--r--clippy_lints/src/lib.register_lints.rs1
-rw-r--r--clippy_lints/src/lib.register_style.rs1
-rw-r--r--clippy_lints/src/lib.rs2
-rw-r--r--clippy_lints/src/methods/iter_next_slice.rs9
-rw-r--r--clippy_utils/src/paths.rs1
-rw-r--r--tests/ui-toml/unwrap_used/unwrap_used.rs2
-rw-r--r--tests/ui/debug_assert_with_mut_call.rs2
-rw-r--r--tests/ui/get_first.fixed42
-rw-r--r--tests/ui/get_first.rs42
-rw-r--r--tests/ui/get_first.stderr22
-rw-r--r--tests/ui/get_unwrap.fixed2
-rw-r--r--tests/ui/get_unwrap.rs2
-rw-r--r--tests/ui/iter_next_slice.fixed8
-rw-r--r--tests/ui/iter_next_slice.rs4
-rw-r--r--tests/ui/iter_next_slice.stderr4
-rw-r--r--tests/ui/needless_lifetimes.rs3
-rw-r--r--tests/ui/needless_lifetimes.stderr62
20 files changed, 234 insertions, 46 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f4a362e6c19..0f6295a45f3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3435,6 +3435,7 @@ Released 2018-09-13
 [`from_over_into`]: https://rust-lang.github.io/rust-clippy/master/index.html#from_over_into
 [`from_str_radix_10`]: https://rust-lang.github.io/rust-clippy/master/index.html#from_str_radix_10
 [`future_not_send`]: https://rust-lang.github.io/rust-clippy/master/index.html#future_not_send
+[`get_first`]: https://rust-lang.github.io/rust-clippy/master/index.html#get_first
 [`get_last_with_len`]: https://rust-lang.github.io/rust-clippy/master/index.html#get_last_with_len
 [`get_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#get_unwrap
 [`identity_conversion`]: https://rust-lang.github.io/rust-clippy/master/index.html#identity_conversion
diff --git a/clippy_lints/src/get_first.rs b/clippy_lints/src/get_first.rs
new file mode 100644
index 00000000000..0748ab45252
--- /dev/null
+++ b/clippy_lints/src/get_first.rs
@@ -0,0 +1,69 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::{is_slice_of_primitives, match_def_path, paths};
+use if_chain::if_chain;
+use rustc_ast::LitKind;
+use rustc_errors::Applicability;
+use rustc_hir as hir;
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::source_map::Spanned;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for using `x.get(0)` instead of
+    /// `x.first()`.
+    ///
+    /// ### Why is this bad?
+    /// Using `x.first()` is easier to read and has the same
+    /// result.
+    ///
+    /// ### Example
+    /// ```rust
+    /// // Bad
+    /// let x = vec![2, 3, 5];
+    /// let first_element = x.get(0);
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// // Good
+    /// let x = vec![2, 3, 5];
+    /// let first_element = x.first();
+    /// ```
+    #[clippy::version = "1.63.0"]
+    pub GET_FIRST,
+    style,
+    "Using `x.get(0)` when `x.first()` is simpler"
+}
+declare_lint_pass!(GetFirst => [GET_FIRST]);
+
+impl<'tcx> LateLintPass<'tcx> for GetFirst {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
+        if_chain! {
+            if let hir::ExprKind::MethodCall(_, [struct_calling_on, method_arg], _) = &expr.kind;
+            if let Some(expr_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
+            if match_def_path(cx, expr_def_id, &paths::SLICE_GET);
+
+            if let Some(_) = is_slice_of_primitives(cx, struct_calling_on);
+            if let hir::ExprKind::Lit(Spanned { node: LitKind::Int(0, _), .. }) = method_arg.kind;
+
+            then {
+                let mut applicability = Applicability::MachineApplicable;
+                let slice_name = snippet_with_applicability(
+                    cx,
+                    struct_calling_on.span, "..",
+                    &mut applicability,
+                );
+                span_lint_and_sugg(
+                    cx,
+                    GET_FIRST,
+                    expr.span,
+                    &format!("accessing first element with `{0}.get(0)`", slice_name),
+                    "try",
+                    format!("{}.first()", slice_name),
+                    applicability,
+                );
+            }
+        }
+    }
+}
diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs
index 5aba6040b8c..a028b41db77 100644
--- a/clippy_lints/src/lib.register_all.rs
+++ b/clippy_lints/src/lib.register_all.rs
@@ -91,6 +91,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
     LintId::of(functions::NOT_UNSAFE_PTR_ARG_DEREF),
     LintId::of(functions::RESULT_UNIT_ERR),
     LintId::of(functions::TOO_MANY_ARGUMENTS),
+    LintId::of(get_first::GET_FIRST),
     LintId::of(identity_op::IDENTITY_OP),
     LintId::of(if_let_mutex::IF_LET_MUTEX),
     LintId::of(indexing_slicing::OUT_OF_BOUNDS_INDEXING),
diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs
index fea34fe66f4..570d736518b 100644
--- a/clippy_lints/src/lib.register_lints.rs
+++ b/clippy_lints/src/lib.register_lints.rs
@@ -183,6 +183,7 @@ store.register_lints(&[
     functions::TOO_MANY_ARGUMENTS,
     functions::TOO_MANY_LINES,
     future_not_send::FUTURE_NOT_SEND,
+    get_first::GET_FIRST,
     identity_op::IDENTITY_OP,
     if_let_mutex::IF_LET_MUTEX,
     if_not_else::IF_NOT_ELSE,
diff --git a/clippy_lints/src/lib.register_style.rs b/clippy_lints/src/lib.register_style.rs
index 62f26d821a0..ea2e1082458 100644
--- a/clippy_lints/src/lib.register_style.rs
+++ b/clippy_lints/src/lib.register_style.rs
@@ -31,6 +31,7 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![
     LintId::of(functions::DOUBLE_MUST_USE),
     LintId::of(functions::MUST_USE_UNIT),
     LintId::of(functions::RESULT_UNIT_ERR),
+    LintId::of(get_first::GET_FIRST),
     LintId::of(inherent_to_string::INHERENT_TO_STRING),
     LintId::of(init_numbered_fields::INIT_NUMBERED_FIELDS),
     LintId::of(len_zero::COMPARISON_TO_EMPTY),
diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs
index 2f8533723ef..5f636e5114b 100644
--- a/clippy_lints/src/lib.rs
+++ b/clippy_lints/src/lib.rs
@@ -242,6 +242,7 @@ mod from_over_into;
 mod from_str_radix_10;
 mod functions;
 mod future_not_send;
+mod get_first;
 mod identity_op;
 mod if_let_mutex;
 mod if_not_else;
@@ -904,6 +905,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|| Box::new(strings::TrimSplitWhitespace));
     store.register_late_pass(|| Box::new(rc_clone_in_vec_init::RcCloneInVecInit));
     store.register_early_pass(|| Box::new(duplicate_mod::DuplicateMod::default()));
+    store.register_late_pass(|| Box::new(get_first::GetFirst));
     // add lints here, do not remove this comment, it's used in `new_lint`
 }
 
diff --git a/clippy_lints/src/methods/iter_next_slice.rs b/clippy_lints/src/methods/iter_next_slice.rs
index d053ff56756..b8d1dabe007 100644
--- a/clippy_lints/src/methods/iter_next_slice.rs
+++ b/clippy_lints/src/methods/iter_next_slice.rs
@@ -34,13 +34,18 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, cal
             if let ast::LitKind::Int(start_idx, _) = start_lit.node;
             then {
                 let mut applicability = Applicability::MachineApplicable;
+                let suggest = if start_idx == 0 {
+                    format!("{}.first()", snippet_with_applicability(cx, caller_var.span, "..", &mut applicability))
+                } else {
+                    format!("{}.get({})", snippet_with_applicability(cx, caller_var.span, "..", &mut applicability), start_idx)
+                };
                 span_lint_and_sugg(
                     cx,
                     ITER_NEXT_SLICE,
                     expr.span,
                     "using `.iter().next()` on a Slice without end index",
                     "try calling",
-                    format!("{}.get({})", snippet_with_applicability(cx, caller_var.span, "..", &mut applicability), start_idx),
+                    suggest,
                     applicability,
                 );
             }
@@ -55,7 +60,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, cal
             "using `.iter().next()` on an array",
             "try calling",
             format!(
-                "{}.get(0)",
+                "{}.first()",
                 snippet_with_applicability(cx, caller_expr.span, "..", &mut applicability)
             ),
             applicability,
diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs
index 9b9cbff2d14..0064694ff92 100644
--- a/clippy_utils/src/paths.rs
+++ b/clippy_utils/src/paths.rs
@@ -141,6 +141,7 @@ pub const SERDE_DESERIALIZE: [&str; 3] = ["serde", "de", "Deserialize"];
 pub const SERDE_DE_VISITOR: [&str; 3] = ["serde", "de", "Visitor"];
 pub const SLICE_FROM_RAW_PARTS: [&str; 4] = ["core", "slice", "raw", "from_raw_parts"];
 pub const SLICE_FROM_RAW_PARTS_MUT: [&str; 4] = ["core", "slice", "raw", "from_raw_parts_mut"];
+pub const SLICE_GET: [&str; 4] = ["core", "slice", "<impl [T]>", "get"];
 pub const SLICE_INTO_VEC: [&str; 4] = ["alloc", "slice", "<impl [T]>", "into_vec"];
 pub const SLICE_ITER: [&str; 4] = ["core", "slice", "iter", "Iter"];
 pub const STDERR: [&str; 4] = ["std", "io", "stdio", "stderr"];
diff --git a/tests/ui-toml/unwrap_used/unwrap_used.rs b/tests/ui-toml/unwrap_used/unwrap_used.rs
index 74d0d7c2650..0e82fb20e45 100644
--- a/tests/ui-toml/unwrap_used/unwrap_used.rs
+++ b/tests/ui-toml/unwrap_used/unwrap_used.rs
@@ -1,6 +1,6 @@
 // compile-flags: --test
 
-#![allow(unused_mut, clippy::from_iter_instead_of_collect)]
+#![allow(unused_mut, clippy::get_first, clippy::from_iter_instead_of_collect)]
 #![warn(clippy::unwrap_used)]
 #![deny(clippy::get_unwrap)]
 
diff --git a/tests/ui/debug_assert_with_mut_call.rs b/tests/ui/debug_assert_with_mut_call.rs
index c5de4125565..46faa0a7b91 100644
--- a/tests/ui/debug_assert_with_mut_call.rs
+++ b/tests/ui/debug_assert_with_mut_call.rs
@@ -1,7 +1,7 @@
 #![feature(custom_inner_attributes)]
 #![rustfmt::skip]
 #![warn(clippy::debug_assert_with_mut_call)]
-#![allow(clippy::redundant_closure_call)]
+#![allow(clippy::redundant_closure_call, clippy::get_first)]
 
 
 struct S;
diff --git a/tests/ui/get_first.fixed b/tests/ui/get_first.fixed
new file mode 100644
index 00000000000..def58afa4fb
--- /dev/null
+++ b/tests/ui/get_first.fixed
@@ -0,0 +1,42 @@
+// run-rustfix
+#![warn(clippy::get_first)]
+use std::collections::BTreeMap;
+use std::collections::HashMap;
+use std::collections::VecDeque;
+
+struct Bar {
+    arr: [u32; 3],
+}
+
+impl Bar {
+    fn get(&self, pos: usize) -> Option<&u32> {
+        self.arr.get(pos)
+    }
+}
+
+fn main() {
+    let x = vec![2, 3, 5];
+    let _ = x.first(); // Use x.first()
+    let _ = x.get(1);
+    let _ = x[0];
+
+    let y = [2, 3, 5];
+    let _ = y.first(); // Use y.first()
+    let _ = y.get(1);
+    let _ = y[0];
+
+    let z = &[2, 3, 5];
+    let _ = z.first(); // Use z.first()
+    let _ = z.get(1);
+    let _ = z[0];
+
+    let vecdeque: VecDeque<_> = x.iter().cloned().collect();
+    let hashmap: HashMap<u8, char> = HashMap::from_iter(vec![(0, 'a'), (1, 'b')]);
+    let btreemap: BTreeMap<u8, char> = BTreeMap::from_iter(vec![(0, 'a'), (1, 'b')]);
+    let _ = vecdeque.get(0); // Do not lint, because VecDeque is not slice.
+    let _ = hashmap.get(&0); // Do not lint, because HashMap is not slice.
+    let _ = btreemap.get(&0); // Do not lint, because BTreeMap is not slice.
+
+    let bar = Bar { arr: [0, 1, 2] };
+    let _ = bar.get(0); // Do not lint, because Bar is struct.
+}
diff --git a/tests/ui/get_first.rs b/tests/ui/get_first.rs
new file mode 100644
index 00000000000..85a381854cd
--- /dev/null
+++ b/tests/ui/get_first.rs
@@ -0,0 +1,42 @@
+// run-rustfix
+#![warn(clippy::get_first)]
+use std::collections::BTreeMap;
+use std::collections::HashMap;
+use std::collections::VecDeque;
+
+struct Bar {
+    arr: [u32; 3],
+}
+
+impl Bar {
+    fn get(&self, pos: usize) -> Option<&u32> {
+        self.arr.get(pos)
+    }
+}
+
+fn main() {
+    let x = vec![2, 3, 5];
+    let _ = x.get(0); // Use x.first()
+    let _ = x.get(1);
+    let _ = x[0];
+
+    let y = [2, 3, 5];
+    let _ = y.get(0); // Use y.first()
+    let _ = y.get(1);
+    let _ = y[0];
+
+    let z = &[2, 3, 5];
+    let _ = z.get(0); // Use z.first()
+    let _ = z.get(1);
+    let _ = z[0];
+
+    let vecdeque: VecDeque<_> = x.iter().cloned().collect();
+    let hashmap: HashMap<u8, char> = HashMap::from_iter(vec![(0, 'a'), (1, 'b')]);
+    let btreemap: BTreeMap<u8, char> = BTreeMap::from_iter(vec![(0, 'a'), (1, 'b')]);
+    let _ = vecdeque.get(0); // Do not lint, because VecDeque is not slice.
+    let _ = hashmap.get(&0); // Do not lint, because HashMap is not slice.
+    let _ = btreemap.get(&0); // Do not lint, because BTreeMap is not slice.
+
+    let bar = Bar { arr: [0, 1, 2] };
+    let _ = bar.get(0); // Do not lint, because Bar is struct.
+}
diff --git a/tests/ui/get_first.stderr b/tests/ui/get_first.stderr
new file mode 100644
index 00000000000..466beff9c92
--- /dev/null
+++ b/tests/ui/get_first.stderr
@@ -0,0 +1,22 @@
+error: accessing first element with `x.get(0)`
+  --> $DIR/get_first.rs:19:13
+   |
+LL |     let _ = x.get(0); // Use x.first()
+   |             ^^^^^^^^ help: try: `x.first()`
+   |
+   = note: `-D clippy::get-first` implied by `-D warnings`
+
+error: accessing first element with `y.get(0)`
+  --> $DIR/get_first.rs:24:13
+   |
+LL |     let _ = y.get(0); // Use y.first()
+   |             ^^^^^^^^ help: try: `y.first()`
+
+error: accessing first element with `z.get(0)`
+  --> $DIR/get_first.rs:29:13
+   |
+LL |     let _ = z.get(0); // Use z.first()
+   |             ^^^^^^^^ help: try: `z.first()`
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/get_unwrap.fixed b/tests/ui/get_unwrap.fixed
index 8f165d67589..5827fc7d76e 100644
--- a/tests/ui/get_unwrap.fixed
+++ b/tests/ui/get_unwrap.fixed
@@ -1,6 +1,6 @@
 // run-rustfix
 
-#![allow(unused_mut, clippy::from_iter_instead_of_collect)]
+#![allow(unused_mut, clippy::from_iter_instead_of_collect, clippy::get_first)]
 #![warn(clippy::unwrap_used)]
 #![deny(clippy::get_unwrap)]
 
diff --git a/tests/ui/get_unwrap.rs b/tests/ui/get_unwrap.rs
index 786749daa74..a2a323c14fb 100644
--- a/tests/ui/get_unwrap.rs
+++ b/tests/ui/get_unwrap.rs
@@ -1,6 +1,6 @@
 // run-rustfix
 
-#![allow(unused_mut, clippy::from_iter_instead_of_collect)]
+#![allow(unused_mut, clippy::from_iter_instead_of_collect, clippy::get_first)]
 #![warn(clippy::unwrap_used)]
 #![deny(clippy::get_unwrap)]
 
diff --git a/tests/ui/iter_next_slice.fixed b/tests/ui/iter_next_slice.fixed
index 11ffc8edb14..f612d26aaab 100644
--- a/tests/ui/iter_next_slice.fixed
+++ b/tests/ui/iter_next_slice.fixed
@@ -6,8 +6,8 @@ fn main() {
     let s = [1, 2, 3];
     let v = vec![1, 2, 3];
 
-    let _ = s.get(0);
-    // Should be replaced by s.get(0)
+    let _ = s.first();
+    // Should be replaced by s.first()
 
     let _ = s.get(2);
     // Should be replaced by s.get(2)
@@ -15,8 +15,8 @@ fn main() {
     let _ = v.get(5);
     // Should be replaced by v.get(5)
 
-    let _ = v.get(0);
-    // Should be replaced by v.get(0)
+    let _ = v.first();
+    // Should be replaced by v.first()
 
     let o = Some(5);
     o.iter().next();
diff --git a/tests/ui/iter_next_slice.rs b/tests/ui/iter_next_slice.rs
index e0d3aabd54a..5195f1c8667 100644
--- a/tests/ui/iter_next_slice.rs
+++ b/tests/ui/iter_next_slice.rs
@@ -7,7 +7,7 @@ fn main() {
     let v = vec![1, 2, 3];
 
     let _ = s.iter().next();
-    // Should be replaced by s.get(0)
+    // Should be replaced by s.first()
 
     let _ = s[2..].iter().next();
     // Should be replaced by s.get(2)
@@ -16,7 +16,7 @@ fn main() {
     // Should be replaced by v.get(5)
 
     let _ = v.iter().next();
-    // Should be replaced by v.get(0)
+    // Should be replaced by v.first()
 
     let o = Some(5);
     o.iter().next();
diff --git a/tests/ui/iter_next_slice.stderr b/tests/ui/iter_next_slice.stderr
index a78d2c2d5e8..d8b89061ff8 100644
--- a/tests/ui/iter_next_slice.stderr
+++ b/tests/ui/iter_next_slice.stderr
@@ -2,7 +2,7 @@ error: using `.iter().next()` on an array
   --> $DIR/iter_next_slice.rs:9:13
    |
 LL |     let _ = s.iter().next();
-   |             ^^^^^^^^^^^^^^^ help: try calling: `s.get(0)`
+   |             ^^^^^^^^^^^^^^^ help: try calling: `s.first()`
    |
    = note: `-D clippy::iter-next-slice` implied by `-D warnings`
 
@@ -22,7 +22,7 @@ error: using `.iter().next()` on an array
   --> $DIR/iter_next_slice.rs:18:13
    |
 LL |     let _ = v.iter().next();
-   |             ^^^^^^^^^^^^^^^ help: try calling: `v.get(0)`
+   |             ^^^^^^^^^^^^^^^ help: try calling: `v.first()`
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/needless_lifetimes.rs b/tests/ui/needless_lifetimes.rs
index 1456204ca86..fc686b1dac0 100644
--- a/tests/ui/needless_lifetimes.rs
+++ b/tests/ui/needless_lifetimes.rs
@@ -4,7 +4,8 @@
     clippy::boxed_local,
     clippy::needless_pass_by_value,
     clippy::unnecessary_wraps,
-    dyn_drop
+    dyn_drop,
+    clippy::get_first
 )]
 
 fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) {}
diff --git a/tests/ui/needless_lifetimes.stderr b/tests/ui/needless_lifetimes.stderr
index a488bc01fff..3c428fd4674 100644
--- a/tests/ui/needless_lifetimes.stderr
+++ b/tests/ui/needless_lifetimes.stderr
@@ -1,5 +1,5 @@
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:10:1
+  --> $DIR/needless_lifetimes.rs:11:1
    |
 LL | fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -7,181 +7,181 @@ LL | fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) {}
    = note: `-D clippy::needless-lifetimes` implied by `-D warnings`
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:12:1
+  --> $DIR/needless_lifetimes.rs:13:1
    |
 LL | fn distinct_and_static<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: &'static u8) {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:22:1
+  --> $DIR/needless_lifetimes.rs:23:1
    |
 LL | fn in_and_out<'a>(x: &'a u8, _y: u8) -> &'a u8 {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:56:1
+  --> $DIR/needless_lifetimes.rs:57:1
    |
 LL | fn deep_reference_3<'a>(x: &'a u8, _y: u8) -> Result<&'a u8, ()> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:61:1
+  --> $DIR/needless_lifetimes.rs:62:1
    |
 LL | fn where_clause_without_lt<'a, T>(x: &'a u8, _y: u8) -> Result<&'a u8, ()>
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:73:1
+  --> $DIR/needless_lifetimes.rs:74:1
    |
 LL | fn lifetime_param_2<'a, 'b>(_x: Ref<'a>, _y: &'b u8) {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:97:1
+  --> $DIR/needless_lifetimes.rs:98:1
    |
 LL | fn fn_bound_2<'a, F, I>(_m: Lt<'a, I>, _f: F) -> Lt<'a, I>
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:127:5
+  --> $DIR/needless_lifetimes.rs:128:5
    |
 LL |     fn self_and_out<'s>(&'s self) -> &'s u8 {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:136:5
+  --> $DIR/needless_lifetimes.rs:137:5
    |
 LL |     fn distinct_self_and_in<'s, 't>(&'s self, _x: &'t u8) {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:155:1
+  --> $DIR/needless_lifetimes.rs:156:1
    |
 LL | fn struct_with_lt<'a>(_foo: Foo<'a>) -> &'a str {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:185:1
+  --> $DIR/needless_lifetimes.rs:186:1
    |
 LL | fn trait_obj_elided2<'a>(_arg: &'a dyn Drop) -> &'a str {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:191:1
+  --> $DIR/needless_lifetimes.rs:192:1
    |
 LL | fn alias_with_lt<'a>(_foo: FooAlias<'a>) -> &'a str {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:210:1
+  --> $DIR/needless_lifetimes.rs:211:1
    |
 LL | fn named_input_elided_output<'a>(_arg: &'a str) -> &str {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:218:1
+  --> $DIR/needless_lifetimes.rs:219:1
    |
 LL | fn trait_bound_ok<'a, T: WithLifetime<'static>>(_: &'a u8, _: T) {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:254:1
+  --> $DIR/needless_lifetimes.rs:255:1
    |
 LL | fn out_return_type_lts<'a>(e: &'a str) -> Cow<'a> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:261:9
+  --> $DIR/needless_lifetimes.rs:262:9
    |
 LL |         fn needless_lt<'a>(x: &'a u8) {}
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:265:9
+  --> $DIR/needless_lifetimes.rs:266:9
    |
 LL |         fn needless_lt<'a>(_x: &'a u8) {}
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:278:9
+  --> $DIR/needless_lifetimes.rs:279:9
    |
 LL |         fn baz<'a>(&'a self) -> impl Foo + 'a {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:310:5
+  --> $DIR/needless_lifetimes.rs:311:5
    |
 LL |     fn impl_trait_elidable_nested_anonymous_lifetimes<'a>(i: &'a i32, f: impl Fn(&i32) -> &i32) -> &'a i32 {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:319:5
+  --> $DIR/needless_lifetimes.rs:320:5
    |
 LL |     fn generics_elidable<'a, T: Fn(&i32) -> &i32>(i: &'a i32, f: T) -> &'a i32 {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:331:5
+  --> $DIR/needless_lifetimes.rs:332:5
    |
 LL |     fn where_clause_elidadable<'a, T>(i: &'a i32, f: T) -> &'a i32
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:346:5
+  --> $DIR/needless_lifetimes.rs:347:5
    |
 LL |     fn pointer_fn_elidable<'a>(i: &'a i32, f: fn(&i32) -> &i32) -> &'a i32 {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:359:5
+  --> $DIR/needless_lifetimes.rs:360:5
    |
 LL |     fn nested_fn_pointer_3<'a>(_: &'a i32) -> fn(fn(&i32) -> &i32) -> i32 {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:362:5
+  --> $DIR/needless_lifetimes.rs:363:5
    |
 LL |     fn nested_fn_pointer_4<'a>(_: &'a i32) -> impl Fn(fn(&i32)) {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:384:9
+  --> $DIR/needless_lifetimes.rs:385:9
    |
 LL |         fn implicit<'a>(&'a self) -> &'a () {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:387:9
+  --> $DIR/needless_lifetimes.rs:388:9
    |
 LL |         fn implicit_mut<'a>(&'a mut self) -> &'a () {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:398:9
+  --> $DIR/needless_lifetimes.rs:399:9
    |
 LL |         fn lifetime_elsewhere<'a>(self: Box<Self>, here: &'a ()) -> &'a () {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:404:9
+  --> $DIR/needless_lifetimes.rs:405:9
    |
 LL |         fn implicit<'a>(&'a self) -> &'a ();
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:405:9
+  --> $DIR/needless_lifetimes.rs:406:9
    |
 LL |         fn implicit_provided<'a>(&'a self) -> &'a () {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:414:9
+  --> $DIR/needless_lifetimes.rs:415:9
    |
 LL |         fn lifetime_elsewhere<'a>(self: Box<Self>, here: &'a ()) -> &'a ();
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:415:9
+  --> $DIR/needless_lifetimes.rs:416:9
    |
 LL |         fn lifetime_elsewhere_provided<'a>(self: Box<Self>, here: &'a ()) -> &'a () {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^