180 lines
5.5 KiB
Rust
180 lines
5.5 KiB
Rust
#![deny(clippy::index_refutable_slice)]
|
|
#![allow(clippy::uninlined_format_args, clippy::needless_lifetimes)]
|
|
|
|
//@no-rustfix: need to change the suggestion to a multipart suggestion
|
|
|
|
enum SomeEnum<T> {
|
|
One(T),
|
|
Two(T),
|
|
Three(T),
|
|
Four(T),
|
|
}
|
|
|
|
fn lintable_examples() {
|
|
// Try with reference
|
|
let slice: Option<&[u32]> = Some(&[1, 2, 3]);
|
|
if let Some(slice) = slice {
|
|
//~^ ERROR: this binding can be a slice pattern to avoid indexing
|
|
println!("{}", slice[0]);
|
|
}
|
|
|
|
// Try with copy
|
|
let slice: Option<[u32; 3]> = Some([1, 2, 3]);
|
|
if let Some(slice) = slice {
|
|
//~^ ERROR: this binding can be a slice pattern to avoid indexing
|
|
println!("{}", slice[0]);
|
|
}
|
|
|
|
// Try with long slice and small indices
|
|
let slice: Option<[u32; 9]> = Some([1, 2, 3, 4, 5, 6, 7, 8, 9]);
|
|
if let Some(slice) = slice {
|
|
//~^ ERROR: this binding can be a slice pattern to avoid indexing
|
|
println!("{}", slice[2]);
|
|
println!("{}", slice[0]);
|
|
}
|
|
|
|
// Multiple bindings
|
|
let slice_wrapped: SomeEnum<[u32; 3]> = SomeEnum::One([5, 6, 7]);
|
|
if let SomeEnum::One(slice) | SomeEnum::Three(slice) = slice_wrapped {
|
|
//~^ ERROR: this binding can be a slice pattern to avoid indexing
|
|
println!("{}", slice[0]);
|
|
}
|
|
|
|
// Two lintable slices in one if let
|
|
let a_wrapped: SomeEnum<[u32; 3]> = SomeEnum::One([9, 5, 1]);
|
|
let b_wrapped: Option<[u32; 2]> = Some([4, 6]);
|
|
if let (SomeEnum::Three(a), Some(b)) = (a_wrapped, b_wrapped) {
|
|
//~^ ERROR: this binding can be a slice pattern to avoid indexing
|
|
//~| ERROR: this binding can be a slice pattern to avoid indexing
|
|
println!("{} -> {}", a[2], b[1]);
|
|
}
|
|
|
|
// This requires the slice values to be borrowed as the slice values can only be
|
|
// borrowed and `String` doesn't implement copy
|
|
let slice: Option<[String; 2]> = Some([String::from("1"), String::from("2")]);
|
|
if let Some(ref slice) = slice {
|
|
//~^ ERROR: this binding can be a slice pattern to avoid indexing
|
|
println!("{:?}", slice[1]);
|
|
}
|
|
println!("{:?}", slice);
|
|
|
|
// This should not suggest using the `ref` keyword as the scrutinee is already
|
|
// a reference
|
|
let slice: Option<[String; 2]> = Some([String::from("1"), String::from("2")]);
|
|
if let Some(slice) = &slice {
|
|
//~^ ERROR: this binding can be a slice pattern to avoid indexing
|
|
println!("{:?}", slice[0]);
|
|
}
|
|
println!("{:?}", slice);
|
|
}
|
|
|
|
fn slice_index_above_limit() {
|
|
let slice: Option<&[u32]> = Some(&[1, 2, 3]);
|
|
|
|
if let Some(slice) = slice {
|
|
// Would cause a panic, IDK
|
|
println!("{}", slice[7]);
|
|
}
|
|
}
|
|
|
|
fn slice_is_used() {
|
|
let slice: Option<&[u32]> = Some(&[1, 2, 3]);
|
|
if let Some(slice) = slice {
|
|
println!("{:?}", slice.len());
|
|
}
|
|
|
|
let slice: Option<&[u32]> = Some(&[1, 2, 3]);
|
|
if let Some(slice) = slice {
|
|
println!("{:?}", slice.to_vec());
|
|
}
|
|
|
|
let opt: Option<[String; 2]> = Some([String::from("Hello"), String::from("world")]);
|
|
if let Some(slice) = opt {
|
|
if !slice.is_empty() {
|
|
println!("first: {}", slice[0]);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// The slice is used by an external function and should therefore not be linted
|
|
fn check_slice_as_arg() {
|
|
fn is_interesting<T>(slice: &[T; 2]) -> bool {
|
|
!slice.is_empty()
|
|
}
|
|
|
|
let slice_wrapped: Option<[String; 2]> = Some([String::from("Hello"), String::from("world")]);
|
|
if let Some(slice) = &slice_wrapped {
|
|
if is_interesting(slice) {
|
|
println!("This is interesting {}", slice[0]);
|
|
}
|
|
}
|
|
println!("{:?}", slice_wrapped);
|
|
}
|
|
|
|
fn check_slice_in_struct() {
|
|
#[derive(Debug)]
|
|
struct Wrapper<'a> {
|
|
inner: Option<&'a [String]>,
|
|
is_awesome: bool,
|
|
}
|
|
|
|
impl<'a> Wrapper<'a> {
|
|
fn is_super_awesome(&self) -> bool {
|
|
self.is_awesome
|
|
}
|
|
}
|
|
|
|
let inner = &[String::from("New"), String::from("World")];
|
|
let wrap = Wrapper {
|
|
inner: Some(inner),
|
|
is_awesome: true,
|
|
};
|
|
|
|
// Test 1: Field access
|
|
if let Some(slice) = wrap.inner {
|
|
//~^ ERROR: this binding can be a slice pattern to avoid indexing
|
|
if wrap.is_awesome {
|
|
println!("This is awesome! {}", slice[0]);
|
|
}
|
|
}
|
|
|
|
// Test 2: function access
|
|
if let Some(slice) = wrap.inner {
|
|
//~^ ERROR: this binding can be a slice pattern to avoid indexing
|
|
if wrap.is_super_awesome() {
|
|
println!("This is super awesome! {}", slice[0]);
|
|
}
|
|
}
|
|
println!("Complete wrap: {:?}", wrap);
|
|
}
|
|
|
|
/// This would be a nice additional feature to have in the future, but adding it
|
|
/// now would make the PR too large. This is therefore only a test that we don't
|
|
/// lint cases we can't make a reasonable suggestion for
|
|
fn mutable_slice_index() {
|
|
// Mut access
|
|
let mut slice: Option<[String; 1]> = Some([String::from("Penguin")]);
|
|
if let Some(ref mut slice) = slice {
|
|
slice[0] = String::from("Mr. Penguin");
|
|
}
|
|
println!("Use after modification: {:?}", slice);
|
|
|
|
// Mut access on reference
|
|
let mut slice: Option<[String; 1]> = Some([String::from("Cat")]);
|
|
if let Some(slice) = &mut slice {
|
|
slice[0] = String::from("Lord Meow Meow");
|
|
}
|
|
println!("Use after modification: {:?}", slice);
|
|
}
|
|
|
|
/// The lint will ignore bindings with sub patterns as it would be hard
|
|
/// to build correct suggestions for these instances :)
|
|
fn binding_with_sub_pattern() {
|
|
let slice: Option<&[u32]> = Some(&[1, 2, 3]);
|
|
if let Some(slice @ [_, _, _]) = slice {
|
|
println!("{:?}", slice[2]);
|
|
}
|
|
}
|
|
|
|
fn main() {}
|