#![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 { 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(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() {}