diff --git a/CHANGELOG.md b/CHANGELOG.md index fe9fbd486c9c..23cd7521634b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5913,6 +5913,7 @@ Released 2018-09-13 [`unnecessary_find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_find_map [`unnecessary_fold`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_fold [`unnecessary_get_then_check`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_get_then_check +[`unnecessary_indexing`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_indexing [`unnecessary_join`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_join [`unnecessary_lazy_evaluations`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_lazy_evaluations [`unnecessary_literal_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_literal_unwrap diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 3b3d0db79dcc..9f3e21f7b250 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -728,6 +728,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::unit_types::UNIT_CMP_INFO, crate::unnamed_address::FN_ADDRESS_COMPARISONS_INFO, crate::unnecessary_box_returns::UNNECESSARY_BOX_RETURNS_INFO, + crate::unnecessary_indexing::UNNECESSARY_INDEXING_INFO, crate::unnecessary_map_on_constructor::UNNECESSARY_MAP_ON_CONSTRUCTOR_INFO, crate::unnecessary_owned_empty_strings::UNNECESSARY_OWNED_EMPTY_STRINGS_INFO, crate::unnecessary_self_imports::UNNECESSARY_SELF_IMPORTS_INFO, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 1bd6dfe24617..c5336e763488 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -355,6 +355,7 @@ mod unit_return_expecting_ord; mod unit_types; mod unnamed_address; mod unnecessary_box_returns; +mod unnecessary_indexing; mod unnecessary_map_on_constructor; mod unnecessary_owned_empty_strings; mod unnecessary_self_imports; @@ -1171,6 +1172,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { }); store.register_late_pass(move |_| Box::new(string_patterns::StringPatterns::new(msrv()))); store.register_early_pass(|| Box::new(field_scoped_visibility_modifiers::FieldScopedVisibilityModifiers)); + store.register_late_pass(|_| Box::new(unnecessary_indexing::UnnecessaryIndexing)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/clippy_lints/src/manual_strip.rs b/clippy_lints/src/manual_strip.rs index 45af9f07718d..0cf6908dbb4e 100644 --- a/clippy_lints/src/manual_strip.rs +++ b/clippy_lints/src/manual_strip.rs @@ -95,7 +95,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualStrip { } let strippings = find_stripping(cx, strip_kind, target_res, pattern, then); - if !strippings.is_empty() { + if let Some(first_stripping) = strippings.first() { let kind_word = match strip_kind { StripKind::Prefix => "prefix", StripKind::Suffix => "suffix", @@ -105,7 +105,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualStrip { span_lint_and_then( cx, MANUAL_STRIP, - strippings[0], + *first_stripping, format!("stripping a {kind_word} manually"), |diag| { diag.span_note(test_span, format!("the {kind_word} was tested here")); diff --git a/clippy_lints/src/unnecessary_indexing.rs b/clippy_lints/src/unnecessary_indexing.rs new file mode 100644 index 000000000000..b0ce552b6b0b --- /dev/null +++ b/clippy_lints/src/unnecessary_indexing.rs @@ -0,0 +1,220 @@ +use std::ops::ControlFlow; + +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::source::snippet; +use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::visitors::for_each_expr; +use clippy_utils::{path_to_local, path_to_local_id}; +use rustc_ast::{LitKind, Mutability}; +use rustc_errors::Applicability; +use rustc_hir::{Block, Expr, ExprKind, HirId, LetStmt, Node, UnOp}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::adjustment::{Adjust, AutoBorrow, AutoBorrowMutability}; +use rustc_session::declare_lint_pass; +use rustc_span::sym; + +declare_clippy_lint! { + /// ### What it does + /// Checks for the use of `seq.is_empty()` in an if-conditional where `seq` is a slice, array, or Vec, + /// and in which the first element of the sequence is indexed. + /// + /// ### Why is this bad? + /// This code is unnecessarily complicated and can instead be simplified to the use of an + /// if..let expression which accesses the first element of the sequence. + /// + /// ### Example + /// ```no_run + /// let a: &[i32] = &[1]; + /// if !a.is_empty() { + /// let b = a[0]; + /// } + /// ``` + /// Use instead: + /// ```no_run + /// let a: &[i32] = &[1]; + /// if let Some(b) = a.first() { + /// + /// } + /// ``` + #[clippy::version = "1.78.0"] + pub UNNECESSARY_INDEXING, + complexity, + "unnecessary use of `seq.is_empty()` in a conditional when if..let is more appropriate" +} + +declare_lint_pass!(UnnecessaryIndexing => [UNNECESSARY_INDEXING]); + +impl<'tcx> LateLintPass<'tcx> for UnnecessaryIndexing { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'_ Expr<'tcx>) { + if let Some(if_expr) = clippy_utils::higher::If::hir(expr) + // check for negation + && let ExprKind::Unary(UnOp::Not, unary_inner) = if_expr.cond.kind + // check for call of is_empty + && let ExprKind::MethodCall(method, conditional_receiver, _, _) = unary_inner.kind + && method.ident.as_str() == "is_empty" + && let expr_ty = cx.typeck_results().expr_ty(conditional_receiver) + && let peeled = expr_ty.peel_refs() + && (peeled.is_slice() || peeled.is_array() || is_type_diagnostic_item(cx, peeled, sym::Vec)) + && let ExprKind::Block(block, _) = if_expr.then.kind + // do not lint if conditional receiver is mutable reference + && expr_ty.ref_mutability() != Some(Mutability::Mut) + && let Some(con_path) = path_to_local(conditional_receiver) + && let Some(r) = process_indexing(cx, block, con_path) + && let Some(receiver) = r.index_receiver + { + span_lint_and_then( + cx, + UNNECESSARY_INDEXING, + expr.span, + "condition can be simplified with if..let syntax", + |diag| { + if let Some(first_local) = r.first_local + && first_local.pat.simple_ident().is_some() + { + diag.span_suggestion( + if_expr.cond.span, + "consider using if..let syntax (variable may need to be dereferenced)", + format!( + "let Some({}{}) = {}.first()", + // if we arent borrowing anything then we can pass a reference here for correctness + if r.extra_exprs_borrow.is_empty() { "&" } else { "" }, + snippet(cx, first_local.pat.span, ".."), + snippet(cx, receiver.span, "..") + ), + Applicability::Unspecified, + ); + diag.span_suggestion(first_local.span, "remove this line", "", Applicability::Unspecified); + if !r.extra_exprs_borrow.is_empty() { + let mut index_accesses = r + .extra_exprs_borrow + .iter() + .map(|x| (x.span, snippet(cx, first_local.pat.span, "..").to_string())) + .collect::>(); + + index_accesses.extend( + r.extra_exprs_copy + .iter() + .map(|x| (x.span, snippet(cx, first_local.pat.span, "..").to_string())), + ); + + diag.multipart_suggestion( + "set this indexing to be the `Some` variant (may need dereferencing)", + index_accesses, + Applicability::Unspecified, + ); + } else if !r.extra_exprs_copy.is_empty() { + let index_accesses = r + .extra_exprs_copy + .iter() + .map(|x| (x.span, snippet(cx, first_local.pat.span, "..").to_string())) + .collect::>(); + + diag.multipart_suggestion( + "set this indexing to be the `Some` variant", + index_accesses, + Applicability::Unspecified, + ); + } + } else if r.extra_exprs_borrow.is_empty() { + let mut index_accesses = vec![( + if_expr.cond.span, + format!("let Some(&element) = {}.first()", snippet(cx, receiver.span, "..")), + )]; + index_accesses.extend(r.extra_exprs_copy.iter().map(|x| (x.span, "element".to_owned()))); + + diag.multipart_suggestion( + "consider using if..let syntax", + index_accesses, + Applicability::Unspecified, + ); + } else { + let mut index_accesses = vec![( + if_expr.cond.span, + format!("let Some(element) = {}.first()", snippet(cx, receiver.span, "..")), + )]; + index_accesses.extend(r.extra_exprs_borrow.iter().map(|x| (x.span, "element".to_owned()))); + index_accesses.extend(r.extra_exprs_copy.iter().map(|x| (x.span, "element".to_owned()))); + + diag.multipart_suggestion( + "consider using if..let syntax (variable may need to be dereferenced)", + index_accesses, + Applicability::Unspecified, + ); + } + }, + ); + } + } +} + +struct IndexCheckResult<'a> { + // the receiver for the index operation, only Some in the event the indexing is via a direct primitive + index_receiver: Option<&'a Expr<'a>>, + // first local in the block - used as pattern for `Some(pat)` + first_local: Option<&'a LetStmt<'a>>, + // any other index expressions to replace with `pat` (or "element" if no local exists) + extra_exprs_borrow: Vec<&'a Expr<'a>>, + // copied extra index expressions: if we only have these and no borrows we can provide a correct suggestion of `let + // Some(&a) = ...` + extra_exprs_copy: Vec<&'a Expr<'a>>, +} + +/// Checks the block for any indexing of the conditional receiver. Returns `None` if the block +/// contains code that invalidates the lint, e.g., the receiver is accessed via a mutable reference. +fn process_indexing<'a>( + cx: &LateContext<'a>, + block: &'a Block<'a>, + conditional_receiver_hid: HirId, +) -> Option> { + let mut index_receiver: Option<&Expr<'_>> = None; + let mut first_local: Option<&LetStmt<'_>> = None; + let mut extra_exprs_borrow: Vec<&Expr<'_>> = vec![]; + let mut extra_exprs_copy: Vec<&Expr<'_>> = vec![]; + + // if res == Some(()), then mutation occurred + // & therefore we should not lint on this + let res = for_each_expr(cx, block.stmts, |x| { + let adjustments = cx.typeck_results().expr_adjustments(x); + if let ExprKind::Index(receiver, index, _) = x.kind + && let ExprKind::Lit(lit) = index.kind + && let LitKind::Int(val, _) = lit.node + && path_to_local_id(receiver, conditional_receiver_hid) + && val.0 == 0 + { + index_receiver = Some(receiver); + if let Node::LetStmt(local) = cx.tcx.parent_hir_node(x.hir_id) { + if first_local.is_none() { + first_local = Some(local); + return ControlFlow::Continue::<()>(()); + }; + } + + if let Node::Expr(x) = cx.tcx.parent_hir_node(x.hir_id) + && let ExprKind::AddrOf(_, _, _) = x.kind + { + extra_exprs_borrow.push(x); + } else { + extra_exprs_copy.push(x); + }; + } else if adjustments.iter().any(|adjustment| { + matches!( + adjustment.kind, + Adjust::Borrow(AutoBorrow::Ref(_, AutoBorrowMutability::Mut { .. })) + ) + }) { + // do not lint on mutable auto borrows (https://github.com/rust-lang/rust-clippy/pull/12464#discussion_r1600352696) + return ControlFlow::Break(()); + } else if let ExprKind::AddrOf(_, Mutability::Mut, _) = x.kind { + return ControlFlow::Break(()); + }; + + ControlFlow::Continue::<()>(()) + }); + + res.is_none().then_some(IndexCheckResult { + index_receiver, + first_local, + extra_exprs_borrow, + extra_exprs_copy, + }) +} diff --git a/tests/ui/index_refutable_slice/if_let_slice_binding.fixed b/tests/ui/index_refutable_slice/if_let_slice_binding.fixed index 13f0cbe9cc88..7e2cdac04cca 100644 --- a/tests/ui/index_refutable_slice/if_let_slice_binding.fixed +++ b/tests/ui/index_refutable_slice/if_let_slice_binding.fixed @@ -1,5 +1,6 @@ #![deny(clippy::index_refutable_slice)] #![allow(clippy::uninlined_format_args)] +#![allow(clippy::unnecessary_indexing)] enum SomeEnum { One(T), diff --git a/tests/ui/index_refutable_slice/if_let_slice_binding.rs b/tests/ui/index_refutable_slice/if_let_slice_binding.rs index d8d38c167fa5..9eded7329599 100644 --- a/tests/ui/index_refutable_slice/if_let_slice_binding.rs +++ b/tests/ui/index_refutable_slice/if_let_slice_binding.rs @@ -1,5 +1,6 @@ #![deny(clippy::index_refutable_slice)] #![allow(clippy::uninlined_format_args)] +#![allow(clippy::unnecessary_indexing)] enum SomeEnum { One(T), diff --git a/tests/ui/index_refutable_slice/if_let_slice_binding.stderr b/tests/ui/index_refutable_slice/if_let_slice_binding.stderr index 14e0f931f240..593be58d3f10 100644 --- a/tests/ui/index_refutable_slice/if_let_slice_binding.stderr +++ b/tests/ui/index_refutable_slice/if_let_slice_binding.stderr @@ -1,5 +1,5 @@ error: this binding can be a slice pattern to avoid indexing - --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:14:17 + --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:15:17 | LL | if let Some(slice) = slice { | ^^^^^ @@ -19,7 +19,7 @@ LL | println!("{}", slice_0); | ~~~~~~~ error: this binding can be a slice pattern to avoid indexing - --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:21:17 + --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:22:17 | LL | if let Some(slice) = slice { | ^^^^^ @@ -34,7 +34,7 @@ LL | println!("{}", slice_0); | ~~~~~~~ error: this binding can be a slice pattern to avoid indexing - --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:28:17 + --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:29:17 | LL | if let Some(slice) = slice { | ^^^^^ @@ -50,7 +50,7 @@ LL ~ println!("{}", slice_0); | error: this binding can be a slice pattern to avoid indexing - --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:36:26 + --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:37:26 | LL | if let SomeEnum::One(slice) | SomeEnum::Three(slice) = slice_wrapped { | ^^^^^ @@ -65,7 +65,7 @@ LL | println!("{}", slice_0); | ~~~~~~~ error: this binding can be a slice pattern to avoid indexing - --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:44:29 + --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:45:29 | LL | if let (SomeEnum::Three(a), Some(b)) = (a_wrapped, b_wrapped) { | ^ @@ -80,7 +80,7 @@ LL | println!("{} -> {}", a_2, b[1]); | ~~~ error: this binding can be a slice pattern to avoid indexing - --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:44:38 + --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:45:38 | LL | if let (SomeEnum::Three(a), Some(b)) = (a_wrapped, b_wrapped) { | ^ @@ -95,7 +95,7 @@ LL | println!("{} -> {}", a[2], b_1); | ~~~ error: this binding can be a slice pattern to avoid indexing - --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:53:21 + --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:54:21 | LL | if let Some(ref slice) = slice { | ^^^^^ @@ -110,7 +110,7 @@ LL | println!("{:?}", slice_1); | ~~~~~~~ error: this binding can be a slice pattern to avoid indexing - --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:62:17 + --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:63:17 | LL | if let Some(slice) = &slice { | ^^^^^ @@ -125,7 +125,7 @@ LL | println!("{:?}", slice_0); | ~~~~~~~ error: this binding can be a slice pattern to avoid indexing - --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:132:17 + --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:133:17 | LL | if let Some(slice) = wrap.inner { | ^^^^^ @@ -140,7 +140,7 @@ LL | println!("This is awesome! {}", slice_0); | ~~~~~~~ error: this binding can be a slice pattern to avoid indexing - --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:140:17 + --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:141:17 | LL | if let Some(slice) = wrap.inner { | ^^^^^ diff --git a/tests/ui/unnecessary_indexing.rs b/tests/ui/unnecessary_indexing.rs new file mode 100644 index 000000000000..31d2b2d0433b --- /dev/null +++ b/tests/ui/unnecessary_indexing.rs @@ -0,0 +1,131 @@ +//@no-rustfix +#![allow(unused)] +#![allow(dropping_copy_types)] +#![allow(dropping_references)] +#![warn(clippy::unnecessary_indexing)] + +fn c(x: i32) -> i32 { + println!("{x}"); + 10 +} + +struct Struct; +impl Struct { + pub fn a(x: i32) -> i32 { + println!("{x}"); + 10 + } +} + +fn main() { + // lint on vecs with a call + let a: Vec = vec![1]; + if !a.is_empty() { + let b = c(a[0]); + } + + // lint on vecs with a method call + let a: Vec = vec![1]; + if !a.is_empty() { + let b = Struct::a(a[0]); + } + + // lint on arrays with a call + let a: &[i32] = &[1]; + if !a.is_empty() { + let b = c(a[0]); + } + + // lint on arrays with a method call + let a: &[i32] = &[1]; + if !a.is_empty() { + let b = Struct::a(a[0]); + } + + // lint on vecs with a local access + let a: Vec = vec![1]; + if !a.is_empty() { + let b = a[0]; + } + + // lint on arrays with a local access + let a: &[i32] = &[1]; + if !a.is_empty() { + let b = a[0]; + } + + // lint when access is not first line + let a: &[i32] = &[1]; + if !a.is_empty() { + dbg!(a); + let b = a[0]; + } + + // lint on multiple accesses/locals + let a: &[i32] = &[1]; + if !a.is_empty() { + dbg!(a); + let b = &a[0]; + let c = a[0]; + drop(a[0]); + } + + // lint on multiple accesses + let a: &[i32] = &[1]; + if !a.is_empty() { + dbg!(a); + drop(a[0]); + drop(a[0]); + } + + // dont lint when not accessing [0] + let a: &[i32] = &[1, 2]; + if !a.is_empty() { + let b = a[1]; + } + + // dont lint when access is dynamic + const T: usize = 0; + + let a: &[i32] = &[1]; + if !a.is_empty() { + let b = a[T]; + } + + // dont lint without unary + let a: &[i32] = &[1]; + if a.is_empty() { + let b = a[0]; + } + + // dont lint if we have mutable reference + let mut a: &[i32] = &[1]; + if !a.is_empty() { + drop(&mut a); + let b = a[0]; + } + + // dont lint if we have a mutable reference, even if the mutable reference occurs after what we are + // linting against + let mut a: &[i32] = &[1]; + if !a.is_empty() { + let b = a[0]; + drop(&mut a); + } + + // dont lint on mutable auto borrow + let mut a = vec![1, 2, 3]; + if !a.is_empty() { + a.push(1); + let b = a[0]; + b; + } + + // do not lint if conditional receiver is mutable reference + let a = &mut vec![1, 2, 3]; + if !a.is_empty() { + let b = a[0]; + a; + b; + } +} diff --git a/tests/ui/unnecessary_indexing.stderr b/tests/ui/unnecessary_indexing.stderr new file mode 100644 index 000000000000..15714a5c25e2 --- /dev/null +++ b/tests/ui/unnecessary_indexing.stderr @@ -0,0 +1,160 @@ +error: condition can be simplified with if..let syntax + --> tests/ui/unnecessary_indexing.rs:23:5 + | +LL | / if !a.is_empty() { +LL | | let b = c(a[0]); +LL | | } + | |_____^ + | + = note: `-D clippy::unnecessary-indexing` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unnecessary_indexing)]` +help: consider using if..let syntax + | +LL ~ if let Some(&element) = a.first() { +LL ~ let b = c(element); + | + +error: condition can be simplified with if..let syntax + --> tests/ui/unnecessary_indexing.rs:29:5 + | +LL | / if !a.is_empty() { +LL | | let b = Struct::a(a[0]); +LL | | } + | |_____^ + | +help: consider using if..let syntax + | +LL ~ if let Some(&element) = a.first() { +LL ~ let b = Struct::a(element); + | + +error: condition can be simplified with if..let syntax + --> tests/ui/unnecessary_indexing.rs:35:5 + | +LL | / if !a.is_empty() { +LL | | let b = c(a[0]); +LL | | } + | |_____^ + | +help: consider using if..let syntax + | +LL ~ if let Some(&element) = a.first() { +LL ~ let b = c(element); + | + +error: condition can be simplified with if..let syntax + --> tests/ui/unnecessary_indexing.rs:41:5 + | +LL | / if !a.is_empty() { +LL | | let b = Struct::a(a[0]); +LL | | } + | |_____^ + | +help: consider using if..let syntax + | +LL ~ if let Some(&element) = a.first() { +LL ~ let b = Struct::a(element); + | + +error: condition can be simplified with if..let syntax + --> tests/ui/unnecessary_indexing.rs:47:5 + | +LL | / if !a.is_empty() { +LL | | let b = a[0]; +LL | | } + | |_____^ + | +help: consider using if..let syntax (variable may need to be dereferenced) + | +LL | if let Some(&b) = a.first() { + | ~~~~~~~~~~~~~~~~~~~~~~~~ +help: remove this line + | +LL - let b = a[0]; +LL + + | + +error: condition can be simplified with if..let syntax + --> tests/ui/unnecessary_indexing.rs:53:5 + | +LL | / if !a.is_empty() { +LL | | let b = a[0]; +LL | | } + | |_____^ + | +help: consider using if..let syntax (variable may need to be dereferenced) + | +LL | if let Some(&b) = a.first() { + | ~~~~~~~~~~~~~~~~~~~~~~~~ +help: remove this line + | +LL - let b = a[0]; +LL + + | + +error: condition can be simplified with if..let syntax + --> tests/ui/unnecessary_indexing.rs:59:5 + | +LL | / if !a.is_empty() { +LL | | dbg!(a); +LL | | let b = a[0]; +LL | | } + | |_____^ + | +help: consider using if..let syntax (variable may need to be dereferenced) + | +LL | if let Some(&b) = a.first() { + | ~~~~~~~~~~~~~~~~~~~~~~~~ +help: remove this line + | +LL - let b = a[0]; +LL + + | + +error: condition can be simplified with if..let syntax + --> tests/ui/unnecessary_indexing.rs:66:5 + | +LL | / if !a.is_empty() { +LL | | dbg!(a); +LL | | let b = &a[0]; +LL | | let c = a[0]; +LL | | drop(a[0]); +LL | | } + | |_____^ + | +help: consider using if..let syntax (variable may need to be dereferenced) + | +LL | if let Some(c) = a.first() { + | ~~~~~~~~~~~~~~~~~~~~~~~ +help: remove this line + | +LL - let c = a[0]; +LL + + | +help: set this indexing to be the `Some` variant (may need dereferencing) + | +LL ~ let b = c; +LL | let c = a[0]; +LL ~ drop(c); + | + +error: condition can be simplified with if..let syntax + --> tests/ui/unnecessary_indexing.rs:75:5 + | +LL | / if !a.is_empty() { +LL | | dbg!(a); +LL | | drop(a[0]); +LL | | drop(a[0]); +LL | | } + | |_____^ + | +help: consider using if..let syntax + | +LL ~ if let Some(&element) = a.first() { +LL | dbg!(a); +LL ~ drop(element); +LL ~ drop(element); + | + +error: aborting due to 9 previous errors +