Skip to content
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

Warn when iterating an array of ranges #7125

Closed
teor2345 opened this issue Apr 22, 2021 · 11 comments
Closed

Warn when iterating an array of ranges #7125

teor2345 opened this issue Apr 22, 2021 · 11 comments
Labels
A-lint Area: New lints C-enhancement Category: Enhancement of lints, like adding more cases or adding help messages good-first-issue These issues are a good way to get started with Clippy

Comments

@teor2345
Copy link
Contributor

teor2345 commented Apr 22, 2021

What it does

Warns users if they accidentally iterate range struct items, rather than iterating through the indexes in the range:

Suggests:

  • iterating through the indexes in the range, or
  • disambiguating the range struct iteration by providing a range type.

This lint will become more important once rustc allows iterating arrays by value, because that allows code like:

for _ in [0..5] {} // iterates through 1 range, not 5 indexes

For context, see rust-lang/rust#84147 (comment)

Categories (optional)

  • Kind: clippy::correctness

What is the advantage of the recommended code over the original code

The recommended code either:

  • does what the user actually intended, or
  • makes it clear that the user intended something really unusual (iterating ranges themselves, not their indexes).

Drawbacks

Expressing iterating through an array of ranges becomes more verbose. But this disambiguation makes the intent of the code much clearer.

Example

for _ in [0..5] {} // iterates through 1 range, clippy warning

Is probably intended to be:

for _ in 0..5 {} // iterates through 5 indexes

And if range iteration is genuinely intended, it could be disambiguated as:

for _: Range<_> in [0..5] {} // iterates through 1 range, no clippy warning
@scottmcm
Copy link
Member

nit: you can't actually annotate a type for the pattern in a for loop -- it's not supported in the grammar.

@matthiaskrgr
Copy link
Member

i guess this should only lint on arrays of len 1?

what about code like this:

pub fn main() {
    for r in [0..7, 8..5, 37..42] {
        println!("{:?}",r);
    }
}

@llogiq
Copy link
Contributor

llogiq commented Apr 25, 2021

Shouldn't that one be caught by single_element_loop?

@llogiq
Copy link
Contributor

llogiq commented Apr 25, 2021

Looking into that, it catches for r in &[0..5], but not (yet) for r in [0..5].iter(). for r in [0..5] is currently caught by the compiler, because [Range; 1] does not implement IntoIterator in this edition.

@llogiq
Copy link
Contributor

llogiq commented Apr 25, 2021

I'll extend single_element_loop to also catch the .iter() variant.

bors added a commit that referenced this issue Apr 25, 2021
extend `single_element_loop` to match `.iter()`

This extends `single_element_loop` to also match `[..].iter()` in the loop argument. Related to #7125, but not completely fixing it due to the lint only firing if the array expression contains a local variable.

---

changelog: none
bors added a commit that referenced this issue Apr 26, 2021
extend `single_element_loop` to match `.iter()`

This extends `single_element_loop` to also match `[..].iter()` in the loop argument. Related to #7125, but not completely fixing it due to the lint only firing if the array expression contains a local variable.

---

changelog: none
@camsteffen
Copy link
Contributor

camsteffen commented May 2, 2021

What if we just lint for _ in [any_single_element] since that is never really useful. Oh we already have that.

@llogiq
Copy link
Contributor

llogiq commented May 2, 2021

Yes, but that appears to only work if the element is an ExprPath for some reason.

@camsteffen camsteffen added C-enhancement Category: Enhancement of lints, like adding more cases or adding help messages good-first-issue These issues are a good way to get started with Clippy and removed A-lint Area: New lints labels May 3, 2021
@pitaj
Copy link
Contributor

pitaj commented Apr 1, 2022

It appears that, actually, single_element_loop won't do anything with a straight array passed in. I've made some changes in #8616 that should cover that case. It also expands coverage to .iter_mut() and .into_iter(), and wraps in parens if necessary.

@pitaj
Copy link
Contributor

pitaj commented Apr 1, 2022

We probably still want to cover the range case specially at some point, to at least give a better diagnostic.

@christophbeberweil
Copy link
Contributor

Hi, @ThinkerDreamer and myself worked on a pull request #11862 that lints the array itself, if it contains exactly one range. In this case, the lint suggests that the user wanted to iterate over the single range instead and suggests to rewrite the for loop accordingly.

bors added a commit that referenced this issue Nov 24, 2023
…er-range, r=llogiq

suggest alternatives to iterate an array of ranges

works towards #7125
changelog: [`single_element_loop`]: suggest better syntax when iterating over an array of a single range

`@thinkerdreamer` and myself worked on this issue during a workshop by `@llogiq` at the RustLab 2023 conference. It is our first contribution to clippy.

When iterating over an array of only one element, _which is a range_, our change suggests to replace the array with the contained range itself. Additionally, a hint is printed stating that the user probably intended to iterate over the range and not the array. If the single element in the array is not a range, the previous suggestion in the form of `let {pat_snip} = {prefix}{arg_snip};{block_str}`is used.

This change lints the array with the single range directly, so any prefixes or suffixes are covered as well.
@teor2345
Copy link
Contributor Author

I think we can call this closed by #11862.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-lint Area: New lints C-enhancement Category: Enhancement of lints, like adding more cases or adding help messages good-first-issue These issues are a good way to get started with Clippy
Projects
None yet
Development

No branches or pull requests

7 participants