From a8d80d531f1d358c26295eb3d81624594544dd4b Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sun, 5 Jun 2022 13:44:09 -0400 Subject: [PATCH] Move `GetFirst` into `Methods` lint pass --- clippy_lints/src/get_first.rs | 68 -------------------------- clippy_lints/src/lib.register_all.rs | 2 +- clippy_lints/src/lib.register_lints.rs | 2 +- clippy_lints/src/lib.register_style.rs | 2 +- clippy_lints/src/lib.rs | 2 - clippy_lints/src/methods/get_first.rs | 39 +++++++++++++++ clippy_lints/src/methods/mod.rs | 36 +++++++++++++- 7 files changed, 76 insertions(+), 75 deletions(-) delete mode 100644 clippy_lints/src/get_first.rs create mode 100644 clippy_lints/src/methods/get_first.rs diff --git a/clippy_lints/src/get_first.rs b/clippy_lints/src/get_first.rs deleted file mode 100644 index 529f7babaa5..00000000000 --- a/clippy_lints/src/get_first.rs +++ /dev/null @@ -1,68 +0,0 @@ -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 - /// let x = vec![2, 3, 5]; - /// let first_element = x.get(0); - /// ``` - /// - /// Use instead: - /// ```rust - /// 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 f48e542ee41..8ce0a26915f 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -81,7 +81,6 @@ 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(if_let_mutex::IF_LET_MUTEX), LintId::of(indexing_slicing::OUT_OF_BOUNDS_INDEXING), LintId::of(infinite_iter::INFINITE_ITER), @@ -162,6 +161,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(methods::FILTER_MAP_IDENTITY), LintId::of(methods::FILTER_NEXT), LintId::of(methods::FLAT_MAP_IDENTITY), + LintId::of(methods::GET_FIRST), LintId::of(methods::GET_LAST_WITH_LEN), LintId::of(methods::INSPECT_FOR_EACH), LintId::of(methods::INTO_ITER_ON_REF), diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index 10ff1fa1f58..a6224035ec8 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -174,7 +174,6 @@ store.register_lints(&[ functions::TOO_MANY_ARGUMENTS, functions::TOO_MANY_LINES, future_not_send::FUTURE_NOT_SEND, - get_first::GET_FIRST, if_let_mutex::IF_LET_MUTEX, if_not_else::IF_NOT_ELSE, if_then_some_else_none::IF_THEN_SOME_ELSE_NONE, @@ -302,6 +301,7 @@ store.register_lints(&[ methods::FLAT_MAP_IDENTITY, methods::FLAT_MAP_OPTION, methods::FROM_ITER_INSTEAD_OF_COLLECT, + methods::GET_FIRST, methods::GET_LAST_WITH_LEN, methods::GET_UNWRAP, methods::IMPLICIT_CLONE, diff --git a/clippy_lints/src/lib.register_style.rs b/clippy_lints/src/lib.register_style.rs index 6972c75597a..5ddaba2396e 100644 --- a/clippy_lints/src/lib.register_style.rs +++ b/clippy_lints/src/lib.register_style.rs @@ -29,7 +29,6 @@ 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), @@ -62,6 +61,7 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![ LintId::of(methods::CHARS_LAST_CMP), LintId::of(methods::CHARS_NEXT_CMP), LintId::of(methods::ERR_EXPECT), + LintId::of(methods::GET_FIRST), LintId::of(methods::INTO_ITER_ON_REF), LintId::of(methods::IS_DIGIT_ASCII_RADIX), LintId::of(methods::ITER_CLONED_COLLECT), diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 68f69dc64b8..3fcdc84113d 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -233,7 +233,6 @@ mod from_over_into; mod from_str_radix_10; mod functions; mod future_not_send; -mod get_first; mod if_let_mutex; mod if_not_else; mod if_then_some_else_none; @@ -907,7 +906,6 @@ 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)); store.register_early_pass(|| Box::new(unused_rounding::UnusedRounding)); store.register_early_pass(move || Box::new(almost_complete_letter_range::AlmostCompleteLetterRange::new(msrv))); store.register_late_pass(|| Box::new(swap_ptr_to_ref::SwapPtrToRef)); diff --git a/clippy_lints/src/methods/get_first.rs b/clippy_lints/src/methods/get_first.rs new file mode 100644 index 00000000000..4de77de7404 --- /dev/null +++ b/clippy_lints/src/methods/get_first.rs @@ -0,0 +1,39 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_slice_of_primitives; +use clippy_utils::source::snippet_with_applicability; +use if_chain::if_chain; +use rustc_ast::LitKind; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_lint::LateContext; +use rustc_span::source_map::Spanned; + +use super::GET_FIRST; + +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx hir::Expr<'_>, + recv: &'tcx hir::Expr<'_>, + arg: &'tcx hir::Expr<'_>, +) { + if_chain! { + if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); + if let Some(impl_id) = cx.tcx.impl_of_method(method_id); + if cx.tcx.type_of(impl_id).is_slice(); + if let Some(_) = is_slice_of_primitives(cx, recv); + if let hir::ExprKind::Lit(Spanned { node: LitKind::Int(0, _), .. }) = arg.kind; + then { + let mut app = Applicability::MachineApplicable; + let slice_name = snippet_with_applicability(cx, recv.span, "..", &mut app); + span_lint_and_sugg( + cx, + GET_FIRST, + expr.span, + &format!("accessing first element with `{0}.get(0)`", slice_name), + "try", + format!("{}.first()", slice_name), + app, + ); + } + } +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 0bb247c7e81..c3438426985 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -24,6 +24,7 @@ mod filter_next; mod flat_map_identity; mod flat_map_option; mod from_iter_instead_of_collect; +mod get_first; mod get_last_with_len; mod get_unwrap; mod implicit_clone; @@ -2457,6 +2458,32 @@ declare_clippy_lint! { "Checks for calls to ends_with with case-sensitive file extensions" } +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 + /// let x = vec![2, 3, 5]; + /// let first_element = x.get(0); + /// ``` + /// + /// Use instead: + /// ```rust + /// 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" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Option, @@ -2564,6 +2591,7 @@ impl_lint_pass!(Methods => [ NAIVE_BYTECOUNT, BYTES_COUNT_TO_LEN, CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS, + GET_FIRST, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -2833,7 +2861,8 @@ impl Methods { }, ("ends_with", [arg]) => { if let ExprKind::MethodCall(_, _, span) = expr.kind { - case_sensitive_file_extension_comparisons::check(cx, expr, span, recv, arg); + case_sensitive_file_extension_comparisons::check(cx, expr, span, recv, arg); + } }, ("expect", [_]) => match method_call(recv) { Some(("ok", [recv], _)) => ok_expect::check(cx, expr, recv), @@ -2867,7 +2896,10 @@ impl Methods { inspect_for_each::check(cx, expr, span2); } }, - ("get", [arg]) => get_last_with_len::check(cx, expr, recv, arg), + ("get", [arg]) => { + get_first::check(cx, expr, recv, arg); + get_last_with_len::check(cx, expr, recv, arg); + }, ("get_or_insert_with", [arg]) => unnecessary_lazy_eval::check(cx, expr, recv, arg, "get_or_insert"), ("is_file", []) => filetype_is_file::check(cx, expr, recv), ("is_digit", [radix]) => is_digit_ascii_radix::check(cx, expr, recv, radix, self.msrv),