Skip to content

new lint: unnecessary_indexing #14058

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -6160,6 +6160,7 @@ Released 2018-09-13
[`unnecessary_first_then_check`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_first_then_check
[`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_bound`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_literal_bound
1 change: 1 addition & 0 deletions clippy_lints/src/declared_lints.rs
Original file line number Diff line number Diff line change
@@ -753,6 +753,7 @@ pub static LINTS: &[&crate::LintInfo] = &[
crate::unit_types::UNIT_ARG_INFO,
crate::unit_types::UNIT_CMP_INFO,
crate::unnecessary_box_returns::UNNECESSARY_BOX_RETURNS_INFO,
crate::unnecessary_indexing::UNNECESSARY_INDEXING_INFO,
crate::unnecessary_literal_bound::UNNECESSARY_LITERAL_BOUND_INFO,
crate::unnecessary_map_on_constructor::UNNECESSARY_MAP_ON_CONSTRUCTOR_INFO,
crate::unnecessary_owned_empty_strings::UNNECESSARY_OWNED_EMPTY_STRINGS_INFO,
2 changes: 2 additions & 0 deletions clippy_lints/src/lib.rs
Original file line number Diff line number Diff line change
@@ -368,6 +368,7 @@ mod uninit_vec;
mod unit_return_expecting_ord;
mod unit_types;
mod unnecessary_box_returns;
mod unnecessary_indexing;
mod unnecessary_literal_bound;
mod unnecessary_map_on_constructor;
mod unnecessary_owned_empty_strings;
@@ -974,5 +975,6 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
store.register_late_pass(move |_| Box::new(arbitrary_source_item_ordering::ArbitrarySourceItemOrdering::new(conf)));
store.register_late_pass(|_| Box::new(unneeded_struct_pattern::UnneededStructPattern));
store.register_late_pass(|_| Box::new(unnecessary_semicolon::UnnecessarySemicolon));
store.register_late_pass(|_| Box::new(unnecessary_indexing::UnnecessaryIndexing));
// add lints here, do not remove this comment, it's used in `new_lint`
}
4 changes: 2 additions & 2 deletions clippy_lints/src/manual_strip.rs
Original file line number Diff line number Diff line change
@@ -96,7 +96,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",
@@ -106,7 +106,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"));
190 changes: 190 additions & 0 deletions clippy_lints/src/unnecessary_indexing.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
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::{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() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that you can generate even simplier expressions:

  • If a is a slice ref, use: if let [b, ..] = a
  • If a is an array, use: if let [b, ..] = &a
  • If a derefs to a slice, use: if let [b, ..] = &a[..]

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can add it as an alternate suggestion, which one is more preferable though?

///
/// }
/// ```
#[clippy::version = "1.86.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)
&& !if_expr.cond.span.from_expansion()
// 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_span) = r.index_receiver_span
{
let receiver = snippet(cx, receiver_span, "..");
let mut suggestions: Vec<(Span, String)> = vec![];
let mut message = "consider using `if..let` syntax instead of indexing".to_string();
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
&& let Some(name) = first_local.pat.simple_ident().map(|ident| ident.name)
{
suggestions.push((
if_expr.cond.span,
format!(
"let Some({}{name}) = {receiver}.first()",
// if we arent borrowing anything then we can pass a reference here for correctness
if r.extra_exprs_borrow.is_empty() { "&" } else { "" },
),
));
suggestions.push((first_local.span, String::new()));

if !r.extra_exprs_borrow.is_empty() {
suggestions.extend(
r.extra_exprs_borrow
.iter()
.chain(r.extra_exprs_copy.iter())
.map(|x| (x.span, name.to_string())),
);

message.push_str(", and replacing indexing expression(s) with the value in `Some` variant");
} else if !r.extra_exprs_copy.is_empty() {
suggestions.extend(r.extra_exprs_copy.iter().map(|x| (x.span, name.to_string())));
}
} else if r.extra_exprs_borrow.is_empty() {
suggestions.push((if_expr.cond.span, format!("let Some(&element) = {receiver}.first()")));
suggestions.extend(r.extra_exprs_copy.iter().map(|x| (x.span, "element".to_owned())));
} else {
suggestions.push((if_expr.cond.span, format!("let Some(element) = {receiver}.first()")));
suggestions.extend(
r.extra_exprs_borrow
.iter()
.chain(r.extra_exprs_copy.iter())
.map(|x| (x.span, "element".to_owned())),
);
}

diag.multipart_suggestion(message, suggestions, Applicability::MaybeIncorrect);
},
);
}
}
}

struct IndexCheckResult<'a> {
// span of the receiver for the index operation, only Some in the event the indexing is via a direct primitive
index_receiver_span: Option<Span>,
// 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<IndexCheckResult<'a>> {
let mut index_receiver_span: Option<Span> = 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, |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_span = Some(receiver.span);
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_span,
first_local,
extra_exprs_borrow,
extra_exprs_copy,
})
}
1 change: 1 addition & 0 deletions tests/ui/index_refutable_slice/if_let_slice_binding.fixed
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#![deny(clippy::index_refutable_slice)]
#![allow(clippy::uninlined_format_args, clippy::needless_lifetimes)]
#![allow(clippy::unnecessary_indexing)]

enum SomeEnum<T> {
One(T),
1 change: 1 addition & 0 deletions tests/ui/index_refutable_slice/if_let_slice_binding.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#![deny(clippy::index_refutable_slice)]
#![allow(clippy::uninlined_format_args, clippy::needless_lifetimes)]
#![allow(clippy::unnecessary_indexing)]

enum SomeEnum<T> {
One(T),
20 changes: 10 additions & 10 deletions tests/ui/index_refutable_slice/if_let_slice_binding.stderr
Original file line number Diff line number Diff line change
@@ -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 {
| ^^^^^
@@ -17,7 +17,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 {
| ^^^^^
@@ -30,7 +30,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 {
| ^^^^^
@@ -44,7 +44,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 {
| ^^^^^
@@ -57,7 +57,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) {
| ^
@@ -71,7 +71,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) {
| ^
@@ -85,7 +85,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 {
| ^^^^^
@@ -98,7 +98,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 {
| ^^^^^
@@ -111,7 +111,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 {
| ^^^^^
@@ -125,7 +125,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 {
| ^^^^^
157 changes: 157 additions & 0 deletions tests/ui/unnecessary_indexing.fixed
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
#![allow(unused)]
#![allow(dropping_copy_types)]
#![allow(dropping_references)]
#![warn(clippy::unnecessary_indexing)]

macro_rules! not_empty {
($seq:ident) => {
!$seq.is_empty()
};
}

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<i32> = vec![1];
if let Some(&element) = a.first() {
//~^ ERROR: condition can be simplified with `if..let` syntax
let b = c(element);
}

// lint on vecs with a method call
let a: Vec<i32> = vec![1];
if let Some(&element) = a.first() {
//~^ ERROR: condition can be simplified with `if..let` syntax
let b = Struct::a(element);
}

// lint on arrays with a call
let a: &[i32] = &[1];
if let Some(&element) = a.first() {
//~^ ERROR: condition can be simplified with `if..let` syntax
let b = c(element);
}

// lint on arrays with a method call
let a: &[i32] = &[1];
if let Some(&element) = a.first() {
//~^ ERROR: condition can be simplified with `if..let` syntax
let b = Struct::a(element);
}

// lint on vecs with a local access
let a: Vec<i32> = vec![1];
if let Some(&b) = a.first() {
//~^ ERROR: condition can be simplified with `if..let` syntax

}

// lint on arrays with a local access
let a: &[i32] = &[1];
if let Some(&b) = a.first() {
//~^ ERROR: condition can be simplified with `if..let` syntax

}

// lint when access is not first line
let a: &[i32] = &[1];
if let Some(&b) = a.first() {
//~^ ERROR: condition can be simplified with `if..let` syntax
dbg!(a);

}

// lint on multiple accesses/locals
let a: &[i32] = &[1];
if let Some(c) = a.first() {
//~^ ERROR: condition can be simplified with `if..let` syntax
dbg!(a);
let b = c;

drop(c);
}

// lint on multiple accesses
let a: &[i32] = &[1];
if let Some(&element) = a.first() {
//~^ ERROR: condition can be simplified with `if..let` syntax
dbg!(a);
drop(element);
drop(element);
}

let _first = if let Some(&element) = a.first() {
//~^ ERROR: condition can be simplified with `if..let` syntax
element
} else {
1
};

// don't lint when the condition is from expansion
if not_empty!(a) {
let b = 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;
}
}
157 changes: 157 additions & 0 deletions tests/ui/unnecessary_indexing.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
#![allow(unused)]
#![allow(dropping_copy_types)]
#![allow(dropping_references)]
#![warn(clippy::unnecessary_indexing)]

macro_rules! not_empty {
($seq:ident) => {
!$seq.is_empty()
};
}

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<i32> = vec![1];
if !a.is_empty() {
//~^ ERROR: condition can be simplified with `if..let` syntax
let b = c(a[0]);
}

// lint on vecs with a method call
let a: Vec<i32> = vec![1];
if !a.is_empty() {
//~^ ERROR: condition can be simplified with `if..let` syntax
let b = Struct::a(a[0]);
}

// lint on arrays with a call
let a: &[i32] = &[1];
if !a.is_empty() {
//~^ ERROR: condition can be simplified with `if..let` syntax
let b = c(a[0]);
}

// lint on arrays with a method call
let a: &[i32] = &[1];
if !a.is_empty() {
//~^ ERROR: condition can be simplified with `if..let` syntax
let b = Struct::a(a[0]);
}

// lint on vecs with a local access
let a: Vec<i32> = vec![1];
if !a.is_empty() {
//~^ ERROR: condition can be simplified with `if..let` syntax
let b = a[0];
}

// lint on arrays with a local access
let a: &[i32] = &[1];
if !a.is_empty() {
//~^ ERROR: condition can be simplified with `if..let` syntax
let b = a[0];
}

// lint when access is not first line
let a: &[i32] = &[1];
if !a.is_empty() {
//~^ ERROR: condition can be simplified with `if..let` syntax
dbg!(a);
let b = a[0];
}

// lint on multiple accesses/locals
let a: &[i32] = &[1];
if !a.is_empty() {
//~^ ERROR: condition can be simplified with `if..let` syntax
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() {
//~^ ERROR: condition can be simplified with `if..let` syntax
dbg!(a);
drop(a[0]);
drop(a[0]);
}

let _first = if !a.is_empty() {
//~^ ERROR: condition can be simplified with `if..let` syntax
a[0]
} else {
1
};

// don't lint when the condition is from expansion
if not_empty!(a) {
let b = 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;
}
}
179 changes: 179 additions & 0 deletions tests/ui/unnecessary_indexing.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
error: condition can be simplified with `if..let` syntax
--> tests/ui/unnecessary_indexing.rs:28:5
|
LL | / if !a.is_empty() {
LL | |
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 instead of indexing
|
LL ~ if let Some(&element) = a.first() {
LL |
LL ~ let b = c(element);
|

error: condition can be simplified with `if..let` syntax
--> tests/ui/unnecessary_indexing.rs:35:5
|
LL | / if !a.is_empty() {
LL | |
LL | | let b = Struct::a(a[0]);
LL | | }
| |_____^
|
help: consider using `if..let` syntax instead of indexing
|
LL ~ if let Some(&element) = a.first() {
LL |
LL ~ let b = Struct::a(element);
|

error: condition can be simplified with `if..let` syntax
--> tests/ui/unnecessary_indexing.rs:42:5
|
LL | / if !a.is_empty() {
LL | |
LL | | let b = c(a[0]);
LL | | }
| |_____^
|
help: consider using `if..let` syntax instead of indexing
|
LL ~ if let Some(&element) = a.first() {
LL |
LL ~ let b = c(element);
|

error: condition can be simplified with `if..let` syntax
--> tests/ui/unnecessary_indexing.rs:49:5
|
LL | / if !a.is_empty() {
LL | |
LL | | let b = Struct::a(a[0]);
LL | | }
| |_____^
|
help: consider using `if..let` syntax instead of indexing
|
LL ~ if let Some(&element) = a.first() {
LL |
LL ~ let b = Struct::a(element);
|

error: condition can be simplified with `if..let` syntax
--> tests/ui/unnecessary_indexing.rs:56:5
|
LL | / if !a.is_empty() {
LL | |
LL | | let b = a[0];
LL | | }
| |_____^
|
help: consider using `if..let` syntax instead of indexing
|
LL ~ if let Some(&b) = a.first() {
LL |
LL ~
|

error: condition can be simplified with `if..let` syntax
--> tests/ui/unnecessary_indexing.rs:63:5
|
LL | / if !a.is_empty() {
LL | |
LL | | let b = a[0];
LL | | }
| |_____^
|
help: consider using `if..let` syntax instead of indexing
|
LL ~ if let Some(&b) = a.first() {
LL |
LL ~
|

error: condition can be simplified with `if..let` syntax
--> tests/ui/unnecessary_indexing.rs:70:5
|
LL | / if !a.is_empty() {
LL | |
LL | | dbg!(a);
LL | | let b = a[0];
LL | | }
| |_____^
|
help: consider using `if..let` syntax instead of indexing
|
LL ~ if let Some(&b) = a.first() {
LL |
LL | dbg!(a);
LL ~
|

error: condition can be simplified with `if..let` syntax
--> tests/ui/unnecessary_indexing.rs:78:5
|
LL | / if !a.is_empty() {
LL | |
LL | | dbg!(a);
LL | | let b = &a[0];
LL | | let c = a[0];
LL | | drop(a[0]);
LL | | }
| |_____^
|
help: consider using `if..let` syntax instead of indexing, and replacing indexing expression(s) with the value in `Some` variant
|
LL ~ if let Some(c) = a.first() {
LL |
LL | dbg!(a);
LL ~ let b = c;
LL ~
LL ~ drop(c);
|

error: condition can be simplified with `if..let` syntax
--> tests/ui/unnecessary_indexing.rs:88:5
|
LL | / if !a.is_empty() {
LL | |
LL | | dbg!(a);
LL | | drop(a[0]);
LL | | drop(a[0]);
LL | | }
| |_____^
|
help: consider using `if..let` syntax instead of indexing
|
LL ~ if let Some(&element) = a.first() {
LL |
LL | dbg!(a);
LL ~ drop(element);
LL ~ drop(element);
|

error: condition can be simplified with `if..let` syntax
--> tests/ui/unnecessary_indexing.rs:95:18
|
LL | let _first = if !a.is_empty() {
| __________________^
LL | |
LL | | a[0]
LL | | } else {
LL | | 1
LL | | };
| |_____^
|
help: consider using `if..let` syntax instead of indexing
|
LL ~ let _first = if let Some(&element) = a.first() {
LL |
LL ~ element
|

error: aborting due to 10 previous errors