From 1dd026698d4f6c5848fb88d48b2d4248846bb41c Mon Sep 17 00:00:00 2001 From: kyoto7250 <50972773+kyoto7250@users.noreply.github.com> Date: Tue, 24 May 2022 18:54:49 +0900 Subject: [PATCH 1/4] feat(lint): impl lint about use first() instead of get(0) --- CHANGELOG.md | 1 + clippy_lints/src/get_first.rs | 72 ++++++++++++++++++++++++++ clippy_lints/src/lib.register_all.rs | 1 + clippy_lints/src/lib.register_lints.rs | 1 + clippy_lints/src/lib.register_style.rs | 1 + clippy_lints/src/lib.rs | 2 + clippy_utils/src/paths.rs | 1 + tests/ui/get_first.fixed | 42 +++++++++++++++ tests/ui/get_first.rs | 42 +++++++++++++++ tests/ui/get_first.stderr | 22 ++++++++ 10 files changed, 185 insertions(+) create mode 100644 clippy_lints/src/get_first.rs create mode 100644 tests/ui/get_first.fixed create mode 100644 tests/ui/get_first.rs create mode 100644 tests/ui/get_first.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index f4a362e6c198c..0f6295a45f3fb 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 0000000000000..0f26c19c49eec --- /dev/null +++ b/clippy_lints/src/get_first.rs @@ -0,0 +1,72 @@ +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(_, expr_args, _) = &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) && expr_args.len() == 2; + + if let Some(struct_calling_on) = expr_args.get(0); + if let Some(_) = is_slice_of_primitives(cx, struct_calling_on); + + if let Some(method_arg) = expr_args.get(1); + 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 5aba6040b8c5a..a028b41db7740 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 fea34fe66f4e9..570d736518bde 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 62f26d821a0d6..ea2e1082458c2 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 2f8533723efc5..5f636e5114bdd 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_utils/src/paths.rs b/clippy_utils/src/paths.rs index 9b9cbff2d1462..0064694ff929f 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", "", "get"]; pub const SLICE_INTO_VEC: [&str; 4] = ["alloc", "slice", "", "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/get_first.fixed b/tests/ui/get_first.fixed new file mode 100644 index 0000000000000..def58afa4fbf2 --- /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 = HashMap::from_iter(vec![(0, 'a'), (1, 'b')]); + let btreemap: BTreeMap = 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 0000000000000..85a381854cd3b --- /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 = HashMap::from_iter(vec![(0, 'a'), (1, 'b')]); + let btreemap: BTreeMap = 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 0000000000000..466beff9c92df --- /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 + From b531eb1a7aca3357d2d5fce97f3f07d2a6956bfe Mon Sep 17 00:00:00 2001 From: kyoto7250 <50972773+kyoto7250@users.noreply.github.com> Date: Tue, 24 May 2022 18:55:39 +0900 Subject: [PATCH 2/4] suggest first() instead of get(0) --- clippy_lints/src/methods/iter_next_slice.rs | 9 +++++++-- tests/ui/iter_next_slice.fixed | 8 ++++---- tests/ui/iter_next_slice.rs | 4 ++-- tests/ui/iter_next_slice.stderr | 4 ++-- 4 files changed, 15 insertions(+), 10 deletions(-) diff --git a/clippy_lints/src/methods/iter_next_slice.rs b/clippy_lints/src/methods/iter_next_slice.rs index d053ff567565c..b8d1dabe00764 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/tests/ui/iter_next_slice.fixed b/tests/ui/iter_next_slice.fixed index 11ffc8edb149e..f612d26aaabcc 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 e0d3aabd54acd..5195f1c86675f 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 a78d2c2d5e838..d8b89061ff895 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 From e47c5b0e035c556947fcf3485fd2d1823ed1d1b1 Mon Sep 17 00:00:00 2001 From: kyoto7250 <50972773+kyoto7250@users.noreply.github.com> Date: Tue, 24 May 2022 18:56:37 +0900 Subject: [PATCH 3/4] ignore clippy::get_first --- tests/ui-toml/unwrap_used/unwrap_used.rs | 2 +- tests/ui/debug_assert_with_mut_call.rs | 2 +- tests/ui/get_unwrap.fixed | 2 +- tests/ui/get_unwrap.rs | 2 +- tests/ui/needless_lifetimes.rs | 3 +- tests/ui/needless_lifetimes.stderr | 62 ++++++++++++------------ 6 files changed, 37 insertions(+), 36 deletions(-) diff --git a/tests/ui-toml/unwrap_used/unwrap_used.rs b/tests/ui-toml/unwrap_used/unwrap_used.rs index 74d0d7c2650dd..0e82fb20e4558 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 c5de412556567..46faa0a7b9117 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_unwrap.fixed b/tests/ui/get_unwrap.fixed index 8f165d675890c..5827fc7d76e60 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 786749daa746e..a2a323c14fb7c 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/needless_lifetimes.rs b/tests/ui/needless_lifetimes.rs index 1456204ca8692..fc686b1dac0e1 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 a488bc01fffa2..3c428fd4674ce 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, 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, 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, here: &'a ()) -> &'a () { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ From d0f93c12a2a6f0d693507ff6325fed62720e616b Mon Sep 17 00:00:00 2001 From: kyoto7250 <50972773+kyoto7250@users.noreply.github.com> Date: Wed, 25 May 2022 09:11:29 +0900 Subject: [PATCH 4/4] refactor: get the required variables with MethodCall --- clippy_lints/src/get_first.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/clippy_lints/src/get_first.rs b/clippy_lints/src/get_first.rs index 0f26c19c49eec..0748ab45252ad 100644 --- a/clippy_lints/src/get_first.rs +++ b/clippy_lints/src/get_first.rs @@ -40,14 +40,11 @@ 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(_, expr_args, _) = &expr.kind; + 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) && expr_args.len() == 2; + if match_def_path(cx, expr_def_id, &paths::SLICE_GET); - if let Some(struct_calling_on) = expr_args.get(0); if let Some(_) = is_slice_of_primitives(cx, struct_calling_on); - - if let Some(method_arg) = expr_args.get(1); if let hir::ExprKind::Lit(Spanned { node: LitKind::Int(0, _), .. }) = method_arg.kind; then {