rust/tests/ui/index_refutable_slice/if_let_slice_binding.rs

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