Move GetFirst into Methods lint pass

This commit is contained in:
Jason Newcomb 2022-06-05 13:44:09 -04:00
parent e3b77974d0
commit a8d80d531f
7 changed files with 76 additions and 75 deletions

View File

@ -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,
);
}
}
}
}

View File

@ -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),

View File

@ -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,

View File

@ -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),

View File

@ -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));

View File

@ -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,
);
}
}
}

View File

@ -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<RustcVersion>,
@ -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),