Skip to content

Add an manual_slice_match lint #17492

Description

@CommanderStorm

What it does

This suggestion builds upon #17400 (comment)

We should detect match or if statements that check the .len() of a slice and subsequently index into it, suggesting a rewrite to use slice patterns.

Advantage

  • Destructuring assigns meaning to the elements (e.g., [_, second, _, _]) instead of requiring the reader to parse and track raw integer indices across a block of code.
  • removes panic sites by guaranteeing the check, though I suspect that llvm can optimsie this away. Needs a double check if llvm can do this in all cases though.

-> so a stylistic lint I think.

Drawbacks

None that I can think off.

Example

// Bad
fn foo(slice: &[u8]) -> u8 {
    match slice.len() {
        3 => slice[0] + slice[1] + slice[2],
        4 => slice[1],
        _ => 42,
    }
}

Could be written as:

// Good
fn foo(slice: &[u8]) -> u8 {
    match slice.len() {
        [a, b, c] => a + b + c,
        [_, b, _, _] => b,
        _ => 42,
    }
}

Comparison with existing lints

  • clippy::len_zero targets len == 0
  • clippy::get_first targets len == 1
  • not sure why clippy::get_last does not exist
  • clippy::get_last_with_len targets x.get(x.len() - 1)
  • rustc::unconditional_panic targets bad indexings
  • clippy::missing_asserts_for_indexing targets indexing without len checks

Additional Context

At first, this should be done with these additional constraints:

  • slices with copy-able T (given that derfs might be seen as ugly)
  • operation inside does not require mut
  • up to index 5 (since adding something like 25 here might be fairly ugly).
    • Also goes for match-or patterns.
      Allow such a rewrite again, only if sum(idx for idx in match_or) <= 5, due to complexity.
  • if the whole match is not actually .first(), .last(), 0 or impossible (no rustc::unconditional_panic)

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-lintArea: New lints

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions