Auto merge of #11609 - y21:get_first_non_primitives, r=giraffate

[`get_first`]: lint on non-primitive slices

Fixes #11594

I left the issue open for a couple days before making the PR to see if anyone has something to say, but it looks like there aren't any objections to removing this check that prevented linting on non-primitive slices, so here's the PR now.
There's a couple of instances in clippy itself where we now emit the lint. The actual relevant change is in the first commit and fixing the `.get(0)` instances in clippy itself is in the 2nd commit.

changelog: [`get_first`]: lint on non-primitive slices
This commit is contained in:
bors 2023-10-15 23:53:22 +00:00
commit ef95be517c
14 changed files with 45 additions and 27 deletions

View File

@ -185,7 +185,7 @@ fn get_vec_push<'tcx>(
if let StmtKind::Semi(semi_stmt) = &stmt.kind;
if let ExprKind::MethodCall(path, self_expr, args, _) = &semi_stmt.kind;
// Figure out the parameters for the method call
if let Some(pushed_item) = args.get(0);
if let Some(pushed_item) = args.first();
// Check that the method being called is push() on a Vec
if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_expr), sym::Vec);
if path.ident.name.as_str() == "push";

View File

@ -103,9 +103,9 @@ fn get_size_of_ty<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<
if let ExprKind::Path(ref count_func_qpath) = count_func.kind;
if let QPath::Resolved(_, count_func_path) = count_func_qpath;
if let Some(segment_zero) = count_func_path.segments.get(0);
if let Some(segment_zero) = count_func_path.segments.first();
if let Some(args) = segment_zero.args;
if let Some(GenericArg::Type(real_ty)) = args.args.get(0);
if let Some(GenericArg::Type(real_ty)) = args.args.first();
if let Some(def_id) = cx.qpath_res(count_func_qpath, count_func.hir_id).opt_def_id();
if cx.tcx.is_diagnostic_item(sym::mem_size_of, def_id);

View File

@ -1,5 +1,4 @@
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;
@ -20,7 +19,6 @@ pub(super) fn check<'tcx>(
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).instantiate_identity().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;

View File

@ -39,7 +39,7 @@ pub(super) fn check<'tcx>(
if search_method == "find";
if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = search_arg.kind;
let closure_body = cx.tcx.hir().body(body);
if let Some(closure_arg) = closure_body.params.get(0);
if let Some(closure_arg) = closure_body.params.first();
then {
if let hir::PatKind::Ref(..) = closure_arg.pat.kind {
Some(search_snippet.replacen('&', "", 1))

View File

@ -67,7 +67,7 @@ fn has_include(meta: Option<MetaItem>) -> bool {
if_chain! {
if let Some(meta) = meta;
if let MetaItemKind::List(list) = meta.kind;
if let Some(meta) = list.get(0);
if let Some(meta) = list.first();
if let Some(name) = meta.ident();
then {
name.name == sym::include

View File

@ -189,7 +189,7 @@ fn needless_continue_in_else(else_expr: &ast::Expr, label: Option<&ast::Label>)
}
fn is_first_block_stmt_continue(block: &ast::Block, label: Option<&ast::Label>) -> bool {
block.stmts.get(0).map_or(false, |stmt| match stmt.kind {
block.stmts.first().map_or(false, |stmt| match stmt.kind {
ast::StmtKind::Semi(ref e) | ast::StmtKind::Expr(ref e) => {
if let ast::ExprKind::Continue(ref l) = e.kind {
compare_labels(label, l.as_ref())
@ -434,7 +434,7 @@ fn erode_from_back(s: &str) -> String {
}
fn span_of_first_expr_in_block(block: &ast::Block) -> Option<Span> {
block.stmts.get(0).map(|stmt| stmt.span)
block.stmts.first().map(|stmt| stmt.span)
}
#[cfg(test)]

View File

@ -335,7 +335,7 @@ fn visit_stmt(&mut self, stmt: &'tcx Stmt<'_>) {
fn visit_block(&mut self, block: &'tcx Block<'_>) {
if self.initialization_found {
if let Some(s) = block.stmts.get(0) {
if let Some(s) = block.stmts.first() {
self.visit_stmt(s);
}

View File

@ -201,7 +201,7 @@ fn extract_set_len_self<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Opt
let expr = peel_hir_expr_while(expr, |e| {
if let ExprKind::Block(block, _) = e.kind {
// Extract the first statement/expression
match (block.stmts.get(0).map(|stmt| &stmt.kind), block.expr) {
match (block.stmts.first().map(|stmt| &stmt.kind), block.expr) {
(None, Some(expr)) => Some(expr),
(Some(StmtKind::Expr(expr) | StmtKind::Semi(expr)), _) => Some(expr),
_ => None,

View File

@ -40,7 +40,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tc
let (constructor_path, constructor_item) =
if let hir::ExprKind::Call(constructor, constructor_args) = recv.kind
&& let hir::ExprKind::Path(constructor_path) = constructor.kind
&& let Some(arg) = constructor_args.get(0)
&& let Some(arg) = constructor_args.first()
{
if constructor.span.from_expansion() || arg.span.from_expansion() {
return;
@ -66,7 +66,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tc
_ => return,
}
if let Some(map_arg) = args.get(0)
if let Some(map_arg) = args.first()
&& let hir::ExprKind::Path(fun) = map_arg.kind
{
if map_arg.span.from_expansion() {

View File

@ -504,7 +504,7 @@ fn index(&mut self, lhs: &'_ Expr<'_>, index: &'_ Expr<'_>) -> Option<Constant<'
},
(Some(Constant::Vec(vec)), _) => {
if !vec.is_empty() && vec.iter().all(|x| *x == vec[0]) {
match vec.get(0) {
match vec.first() {
Some(Constant::F32(x)) => Some(Constant::F32(*x)),
Some(Constant::F64(x)) => Some(Constant::F64(*x)),
_ => None,

View File

@ -449,7 +449,7 @@ pub fn get_vec_init_kind<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -
} else if name.ident.name == symbol::kw::Default {
return Some(VecInitKind::Default);
} else if name.ident.name.as_str() == "with_capacity" {
let arg = args.get(0)?;
let arg = args.first()?;
return match constant_simple(cx, cx.typeck_results(), arg) {
Some(Constant::Int(num)) => Some(VecInitKind::WithConstCapacity(num)),
_ => Some(VecInitKind::WithExprCapacity(arg.hir_id)),

View File

@ -14,17 +14,20 @@ impl Bar {
fn main() {
let x = vec![2, 3, 5];
let _ = x.first(); // Use x.first()
let _ = x.first();
//~^ ERROR: accessing first element with `x.get(0)`
let _ = x.get(1);
let _ = x[0];
let y = [2, 3, 5];
let _ = y.first(); // Use y.first()
let _ = y.first();
//~^ ERROR: accessing first element with `y.get(0)`
let _ = y.get(1);
let _ = y[0];
let z = &[2, 3, 5];
let _ = z.first(); // Use z.first()
let _ = z.first();
//~^ ERROR: accessing first element with `z.get(0)`
let _ = z.get(1);
let _ = z[0];
@ -37,4 +40,8 @@ fn main() {
let bar = Bar { arr: [0, 1, 2] };
let _ = bar.get(0); // Do not lint, because Bar is struct.
let non_primitives = [vec![1, 2], vec![3, 4]];
let _ = non_primitives.first();
//~^ ERROR: accessing first element with `non_primitives.get(0)`
}

View File

@ -14,17 +14,20 @@ fn get(&self, pos: usize) -> Option<&u32> {
fn main() {
let x = vec![2, 3, 5];
let _ = x.get(0); // Use x.first()
let _ = x.get(0);
//~^ ERROR: accessing first element with `x.get(0)`
let _ = x.get(1);
let _ = x[0];
let y = [2, 3, 5];
let _ = y.get(0); // Use y.first()
let _ = y.get(0);
//~^ ERROR: accessing first element with `y.get(0)`
let _ = y.get(1);
let _ = y[0];
let z = &[2, 3, 5];
let _ = z.get(0); // Use z.first()
let _ = z.get(0);
//~^ ERROR: accessing first element with `z.get(0)`
let _ = z.get(1);
let _ = z[0];
@ -37,4 +40,8 @@ fn main() {
let bar = Bar { arr: [0, 1, 2] };
let _ = bar.get(0); // Do not lint, because Bar is struct.
let non_primitives = [vec![1, 2], vec![3, 4]];
let _ = non_primitives.get(0);
//~^ ERROR: accessing first element with `non_primitives.get(0)`
}

View File

@ -1,23 +1,29 @@
error: accessing first element with `x.get(0)`
--> $DIR/get_first.rs:17:13
|
LL | let _ = x.get(0); // Use x.first()
LL | let _ = x.get(0);
| ^^^^^^^^ help: try: `x.first()`
|
= note: `-D clippy::get-first` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::get_first)]`
error: accessing first element with `y.get(0)`
--> $DIR/get_first.rs:22:13
--> $DIR/get_first.rs:23:13
|
LL | let _ = y.get(0); // Use y.first()
LL | let _ = y.get(0);
| ^^^^^^^^ help: try: `y.first()`
error: accessing first element with `z.get(0)`
--> $DIR/get_first.rs:27:13
--> $DIR/get_first.rs:29:13
|
LL | let _ = z.get(0); // Use z.first()
LL | let _ = z.get(0);
| ^^^^^^^^ help: try: `z.first()`
error: aborting due to 3 previous errors
error: accessing first element with `non_primitives.get(0)`
--> $DIR/get_first.rs:45:13
|
LL | let _ = non_primitives.get(0);
| ^^^^^^^^^^^^^^^^^^^^^ help: try: `non_primitives.first()`
error: aborting due to 4 previous errors