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

Weird warning for needless_range_loop #398

Open
antoyo opened this issue Oct 17, 2015 · 10 comments
Open

Weird warning for needless_range_loop #398

antoyo opened this issue Oct 17, 2015 · 10 comments
Labels
C-bug Category: Clippy is not doing the correct thing

Comments

@antoyo
Copy link

antoyo commented Oct 17, 2015

Hello.

I found a weird warning for a range loop.

In the following code:

#![feature(plugin)]
#![plugin(clippy)]

fn main() {
    let string = "test";
    let vec = vec![0, 1, 2, 3];
    for i in 0 .. string.len() {
        println!("{}", i);
        println!("{}", vec[i]);
    }
}

I get the following warning:

src/main.rs:7:5: 10:6 warning: the loop variable `i` is used to index `vec`. Consider using `for (i, item) in vec.iter().enumerate()` or similar iterators, #[warn(needless_range_loop)] on by default
src/main.rs: 7     for i in 0 .. string.len() {
src/main.rs: 8         println!("{}", i);
src/main.rs: 9         println!("{}", vec[i]);
src/main.rs:10     }
src/main.rs:7:5: 10:6 help: for further information visit https://github.com/Manishearth/rust-clippy/wiki#needless_range_loop

This is wrong since I am iterating over the string, not the vec.

If I remove the line using the vec, the warning is gone.

Thanks to fix this issue.

(By the way, is there an option to span errors instead of warnings in clippy?)

@Manishearth
Copy link
Member

cc @birkenfeld

@Manishearth Manishearth added the C-bug Category: Clippy is not doing the correct thing label Oct 17, 2015
@birkenfeld
Copy link
Contributor

This only looks strange, but this lint doesn't check the range end expression at all. It only sees that you're indexing vec (and only vec) with i and therefore could iterate over it.

In this case, the iteratee could be for (i, item) in vec.iter().enumerate().take(string.len()). Of course we could try to integrate that suggestion into the message.

@Manishearth
Copy link
Member

SGTM

@antoyo
Copy link
Author

antoyo commented Oct 18, 2015

@birkenfeld Well, I made the example simpler, but I my original code, both the clippy suggestion and yours won't work.

Here is my example:

fn levenshtein_distance(string1: &str, string2: &str) -> usize {
    fn distance(i: usize, j: usize, d: &[Vec<usize>], string1: &str, string2: &str) -> usize {
        match (i, j) {
            (i, 0) => i,
            (0, j) => j,
            (i, j) => {
                let delta =
                    if string1.chars().nth(i - 1) == string2.chars().nth(j - 1) {
                        0
                    }
                    else {
                        1
                    };
                *[
                    d[i - 1][j] + 1,
                    d[i][j - 1] + 1,
                    d[i - 1][j - 1] + delta
                ].iter().min().unwrap()
            },
        }
    }

    let mut d = vec![];
    for i in 0 .. string1.len() + 1 {
        d.push(vec![]);
        for j in 0 .. string2.len() + 1 {
            let dist = distance(i, j, &d, string1, string2);
            d[i].push(dist);
        }
    }
    d[string1.len()][string2.len()]
}

clippy gives me this warning on the line:

for i in 0 .. string1.len() + 1 {

but I could not iterate over the vector since it is empty.

@antoyo
Copy link
Author

antoyo commented Oct 25, 2015

Is this a bug?

mcarton added a commit to mcarton/rust-clippy that referenced this issue Jan 14, 2016
@ghost
Copy link

ghost commented Mar 16, 2016

Just adding onto this: I got this error for something along the lines of:

for i in 0..N {
    let var1 = v[i];
    let var2 = v[i + 1];
    // ...
}

And this can't be replaced by a simple enumerate. (Sure, it can be replaced by zip, but the code looks simpler otherwise.)

@mcarton
Copy link
Member

mcarton commented Mar 16, 2016

@Undeterminant do you know about windows?

@ghost
Copy link

ghost commented Apr 3, 2016

@mccarton: I did not at the time, although the point was that the lint's suggestion of just using enumerate wasn't good enough.

@birkenfeld
Copy link
Contributor

@Undeterminant this is possible to write with enumerate, but it isn't pretty at all:

for (i, el) in v.iter().enumerate() {
    let var1 = el;
    let var2 = v[i + 1];
    // ...
}

I'm beginning to think that needless_range_loop should be pruned back quite a bit.

@wfraser
Copy link

wfraser commented Oct 27, 2016

Agree. This lint doesn't seem to check what else you're doing with the range variable in the loop. While it can be replaced by using enumerate, I agree the result looks uglier many times.

Simple example:

fn u32_from_bytes(bytes: &[u8], big_endian: bool) -> u32 {
    let mut out = 0u32;
    for i in 0..4 {
        let shift = if big_endian {
            3 - i
        } else {
            i
        };
        out |= (bytes[i] as u32) << (8 * shift);
    }
    out
}

vs

pub fn u32_from_bytes(bytes: &[u8], big_endian: bool) -> u32 {
    let mut out = 0u32;
    for (i, byte) in bytes[0..4].iter().enumerate() {
        let shift = if big_endian {
            3 - i
        } else {
            i
        };
        out |= (*byte as u32) << (8 * shift);
    }
    out
}

2nd is needlessly more verbose.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-bug Category: Clippy is not doing the correct thing
Projects
None yet
Development

No branches or pull requests

5 participants