move iter_next_slice to its own module
This commit is contained in:
parent
db91d9cf9a
commit
3fe099ba8d
2 changed files with 73 additions and 61 deletions
68
clippy_lints/src/methods/iter_next_slice.rs
Normal file
68
clippy_lints/src/methods/iter_next_slice.rs
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
use crate::methods::derefs_to_slice;
|
||||||
|
use crate::utils::{get_parent_expr, higher, is_type_diagnostic_item, snippet_with_applicability, span_lint_and_sugg};
|
||||||
|
use if_chain::if_chain;
|
||||||
|
use rustc_ast::ast;
|
||||||
|
use rustc_errors::Applicability;
|
||||||
|
use rustc_hir as hir;
|
||||||
|
use rustc_lint::LateContext;
|
||||||
|
use rustc_middle::ty;
|
||||||
|
use rustc_span::symbol::sym;
|
||||||
|
|
||||||
|
use super::ITER_NEXT_SLICE;
|
||||||
|
|
||||||
|
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, iter_args: &'tcx [hir::Expr<'_>]) {
|
||||||
|
let caller_expr = &iter_args[0];
|
||||||
|
|
||||||
|
// Skip lint if the `iter().next()` expression is a for loop argument,
|
||||||
|
// since it is already covered by `&loops::ITER_NEXT_LOOP`
|
||||||
|
let mut parent_expr_opt = get_parent_expr(cx, expr);
|
||||||
|
while let Some(parent_expr) = parent_expr_opt {
|
||||||
|
if higher::for_loop(parent_expr).is_some() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
parent_expr_opt = get_parent_expr(cx, parent_expr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if derefs_to_slice(cx, caller_expr, cx.typeck_results().expr_ty(caller_expr)).is_some() {
|
||||||
|
// caller is a Slice
|
||||||
|
if_chain! {
|
||||||
|
if let hir::ExprKind::Index(ref caller_var, ref index_expr) = &caller_expr.kind;
|
||||||
|
if let Some(higher::Range { start: Some(start_expr), end: None, limits: ast::RangeLimits::HalfOpen })
|
||||||
|
= higher::range(index_expr);
|
||||||
|
if let hir::ExprKind::Lit(ref start_lit) = &start_expr.kind;
|
||||||
|
if let ast::LitKind::Int(start_idx, _) = start_lit.node;
|
||||||
|
then {
|
||||||
|
let mut applicability = Applicability::MachineApplicable;
|
||||||
|
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),
|
||||||
|
applicability,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(caller_expr), sym::vec_type)
|
||||||
|
|| matches!(
|
||||||
|
&cx.typeck_results().expr_ty(caller_expr).peel_refs().kind(),
|
||||||
|
ty::Array(_, _)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
// caller is a Vec or an Array
|
||||||
|
let mut applicability = Applicability::MachineApplicable;
|
||||||
|
span_lint_and_sugg(
|
||||||
|
cx,
|
||||||
|
ITER_NEXT_SLICE,
|
||||||
|
expr.span,
|
||||||
|
"using `.iter().next()` on an array",
|
||||||
|
"try calling",
|
||||||
|
format!(
|
||||||
|
"{}.get(0)",
|
||||||
|
snippet_with_applicability(cx, caller_expr.span, "..", &mut applicability)
|
||||||
|
),
|
||||||
|
applicability,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,6 +10,7 @@ mod inefficient_to_string;
|
||||||
mod inspect_for_each;
|
mod inspect_for_each;
|
||||||
mod iter_cloned_collect;
|
mod iter_cloned_collect;
|
||||||
mod iter_count;
|
mod iter_count;
|
||||||
|
mod iter_next_slice;
|
||||||
mod manual_saturating_arithmetic;
|
mod manual_saturating_arithmetic;
|
||||||
mod map_collect_result_unit;
|
mod map_collect_result_unit;
|
||||||
mod ok_expect;
|
mod ok_expect;
|
||||||
|
@ -46,9 +47,9 @@ use crate::consts::{constant, Constant};
|
||||||
use crate::utils::eager_or_lazy::is_lazyness_candidate;
|
use crate::utils::eager_or_lazy::is_lazyness_candidate;
|
||||||
use crate::utils::usage::mutated_variables;
|
use crate::utils::usage::mutated_variables;
|
||||||
use crate::utils::{
|
use crate::utils::{
|
||||||
contains_return, contains_ty, get_parent_expr, get_trait_def_id, has_iter_method, higher, implements_trait,
|
contains_return, contains_ty, get_parent_expr, get_trait_def_id, has_iter_method, implements_trait, in_macro,
|
||||||
in_macro, is_copy, is_expn_of, is_type_diagnostic_item, iter_input_pats, last_path_segment, match_def_path,
|
is_copy, is_expn_of, is_type_diagnostic_item, iter_input_pats, last_path_segment, match_def_path, match_qpath,
|
||||||
match_qpath, match_trait_method, match_type, meets_msrv, method_calls, method_chain_args, path_to_local_id, paths,
|
match_trait_method, match_type, meets_msrv, method_calls, method_chain_args, path_to_local_id, paths,
|
||||||
remove_blocks, return_ty, single_segment_path, snippet, snippet_with_applicability, snippet_with_macro_callsite,
|
remove_blocks, return_ty, single_segment_path, snippet, snippet_with_applicability, snippet_with_macro_callsite,
|
||||||
span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then, strip_pat_refs, sugg, walk_ptrs_ty_depth,
|
span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then, strip_pat_refs, sugg, walk_ptrs_ty_depth,
|
||||||
SpanlessEq,
|
SpanlessEq,
|
||||||
|
@ -1688,7 +1689,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
|
||||||
},
|
},
|
||||||
["next", "filter"] => filter_next::check(cx, expr, arg_lists[1]),
|
["next", "filter"] => filter_next::check(cx, expr, arg_lists[1]),
|
||||||
["next", "skip_while"] => skip_while_next::check(cx, expr, arg_lists[1]),
|
["next", "skip_while"] => skip_while_next::check(cx, expr, arg_lists[1]),
|
||||||
["next", "iter"] => lint_iter_next(cx, expr, arg_lists[1]),
|
["next", "iter"] => iter_next_slice::check(cx, expr, arg_lists[1]),
|
||||||
["map", "filter"] => lint_filter_map(cx, expr, false),
|
["map", "filter"] => lint_filter_map(cx, expr, false),
|
||||||
["map", "filter_map"] => lint_filter_map_map(cx, expr, arg_lists[1], arg_lists[0]),
|
["map", "filter_map"] => lint_filter_map_map(cx, expr, arg_lists[1], arg_lists[0]),
|
||||||
["next", "filter_map"] => lint_filter_map_next(cx, expr, arg_lists[1], self.msrv.as_ref()),
|
["next", "filter_map"] => lint_filter_map_next(cx, expr, arg_lists[1], self.msrv.as_ref()),
|
||||||
|
@ -2598,63 +2599,6 @@ fn lint_step_by<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, args: &'tcx
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lint_iter_next<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, iter_args: &'tcx [hir::Expr<'_>]) {
|
|
||||||
let caller_expr = &iter_args[0];
|
|
||||||
|
|
||||||
// Skip lint if the `iter().next()` expression is a for loop argument,
|
|
||||||
// since it is already covered by `&loops::ITER_NEXT_LOOP`
|
|
||||||
let mut parent_expr_opt = get_parent_expr(cx, expr);
|
|
||||||
while let Some(parent_expr) = parent_expr_opt {
|
|
||||||
if higher::for_loop(parent_expr).is_some() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
parent_expr_opt = get_parent_expr(cx, parent_expr);
|
|
||||||
}
|
|
||||||
|
|
||||||
if derefs_to_slice(cx, caller_expr, cx.typeck_results().expr_ty(caller_expr)).is_some() {
|
|
||||||
// caller is a Slice
|
|
||||||
if_chain! {
|
|
||||||
if let hir::ExprKind::Index(ref caller_var, ref index_expr) = &caller_expr.kind;
|
|
||||||
if let Some(higher::Range { start: Some(start_expr), end: None, limits: ast::RangeLimits::HalfOpen })
|
|
||||||
= higher::range(index_expr);
|
|
||||||
if let hir::ExprKind::Lit(ref start_lit) = &start_expr.kind;
|
|
||||||
if let ast::LitKind::Int(start_idx, _) = start_lit.node;
|
|
||||||
then {
|
|
||||||
let mut applicability = Applicability::MachineApplicable;
|
|
||||||
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),
|
|
||||||
applicability,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(caller_expr), sym::vec_type)
|
|
||||||
|| matches!(
|
|
||||||
&cx.typeck_results().expr_ty(caller_expr).peel_refs().kind(),
|
|
||||||
ty::Array(_, _)
|
|
||||||
)
|
|
||||||
{
|
|
||||||
// caller is a Vec or an Array
|
|
||||||
let mut applicability = Applicability::MachineApplicable;
|
|
||||||
span_lint_and_sugg(
|
|
||||||
cx,
|
|
||||||
ITER_NEXT_SLICE,
|
|
||||||
expr.span,
|
|
||||||
"using `.iter().next()` on an array",
|
|
||||||
"try calling",
|
|
||||||
format!(
|
|
||||||
"{}.get(0)",
|
|
||||||
snippet_with_applicability(cx, caller_expr.span, "..", &mut applicability)
|
|
||||||
),
|
|
||||||
applicability,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn lint_iter_nth<'tcx>(
|
fn lint_iter_nth<'tcx>(
|
||||||
cx: &LateContext<'tcx>,
|
cx: &LateContext<'tcx>,
|
||||||
expr: &hir::Expr<'_>,
|
expr: &hir::Expr<'_>,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue