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

explicit_counter_loop improvement suggestion #1670

Closed
martinlindhe opened this issue Apr 9, 2017 · 7 comments · Fixed by #5727
Closed

explicit_counter_loop improvement suggestion #1670

martinlindhe opened this issue Apr 9, 2017 · 7 comments · Fixed by #5727
Labels
C-bug Category: Clippy is not doing the correct thing good-first-issue These issues are a good way to get started with Clippy I-suggestion-causes-error Issue: The suggestions provided by this Lint cause an ICE/error when applied L-suggestion Lint: Improving, adding or fixing lint suggestions T-middle Type: Probably requires verifiying types

Comments

@martinlindhe
Copy link
Contributor

martinlindhe commented Apr 9, 2017

Hello! I'm just learning rust and clippy has been a valuable resource for improving my code, thanks!
Today I got confused by one of the clippy suggestions.
I had a look at the source but not sure how to implement proposed improvements.

Consider the following

fn load_rom(&mut self, data: &[u8]) {
    let min = self.get_offset();
    let max = min + data.len();

    let mut rom_pos = 0;
    for i in min..max {
        self.memory[i] = data[rom_pos];
        rom_pos += 1;
    }
}

clippy gives the following warning:

warning: the variable `rom_pos` is used as a loop counter. Consider using `for (rom_pos, item) in min..max.enumerate()` or similar iterators
   --> src/cpu.rs:546:9
    |
546 |           for i in min..max {
    |  _________^ starting here...
547 | |             self.memory[i] = data[rom_pos];
548 | |             rom_pos += 1;
549 | |         }
    | |_________^ ...ending here
    |
    = note: #[warn(explicit_counter_loop)] on by default
    = help: for further information visit https://github.com/Manishearth/rust-clippy/wiki#explicit_counter_loop

attempting to rework the code as suggested:

for (rom_pos, i) in min..max.enumerate() {
    self.memory[i] = data[rom_pos];
}

... does not compile:

error: no method named `enumerate` found for type `usize` in the current scope
   --> src/cpu.rs:552:38
    |
552 |         for (rom_pos, i) in min..max.enumerate() {
    |                                      ^^^^^^^^^
    |
    = note: the method `enumerate` exists but the following trait bounds were not satisfied: `usize : std::iter::Iterator`

error[E0308]: mismatched types
   --> src/cpu.rs:552:13
    |
552 |         for (rom_pos, i) in min..max.enumerate() {
    |             ^^^^^^^^^^^^ expected usize, found tuple
    |
    = note: expected type `usize`
               found type `(_, _)`

Eventually I realized I just need to wrap the min..max in parenthesis to solve it.

I feel an improved error message in check_for_loop_explicit_counter could look like this:

warning: the variable `rom_pos` is used as a loop counter.
Consider using `for (rom_pos, i) in (min..max).enumerate()`

Also it hardcodes "item" rather than using the variable name "i"

@oli-obk
Copy link
Contributor

oli-obk commented Apr 11, 2017

A further suggestion:

self.memory[min..max].copy_from_slice(data)

@oli-obk oli-obk added good-first-issue These issues are a good way to get started with Clippy C-bug Category: Clippy is not doing the correct thing T-middle Type: Probably requires verifiying types labels Apr 11, 2017
@martinlindhe
Copy link
Contributor Author

Even better, thanks for the suggestion!

@phansch phansch added the L-suggestion Lint: Improving, adding or fixing lint suggestions label Dec 7, 2018
@phansch phansch added the I-suggestion-causes-error Issue: The suggestions provided by this Lint cause an ICE/error when applied label Jan 4, 2019
@rail-rain
Copy link
Contributor

Hello.

I would like to try this as my first contribution.

But there are three issues:

  1. explicit_counter_loop suggestion cause error if for loop's argument precedence over method call
  2. Also it hardcodes "item" rather than using the variable name "i"

  3. A further suggestion:

    self.memory[min..max].copy_from_slice(data)

Should I separate PR?

@flip1995
Copy link
Member

flip1995 commented Mar 20, 2019

The first step would be to address 1. and 2. This should be done in one PR. You have to turn this lint into a span_lint_and_sugg here:
https://github.com/rust-lang/rust-clippy/blob/master/clippy_lints/src/loops.rs#L1492-L1502

You can take a look at clippy_lints/src/utils/sugg.rs for the part of the parentheses.

  1. is really specific for this use case, where you just copy from one slice into another and don't do anything else in the for loop. This should be addressed separatly (maybe even a new lint?).

If you have any questions or need help with something, feel free to ask here or open a WIP PR.

@rail-rain
Copy link
Contributor

Thank you. I'll make PR for 1. and 2.

bors added a commit that referenced this issue Apr 8, 2019
Fix `explicit_counter_loop` suggestion

#1670

This code seems to me to work, but I have two question.
* Because range expression desugared in hir, `Sugg::hir` doesn't add parenthesis to range expression.  Which function is better to check range do you think, `check_for_loop_explicit_counter` or `hir_from_snippet`?
* Do you think we need to distinguish between range expression and struct expression that creates `std::ops::Range*`?
@rail-rain

This comment has been minimized.

@rail-rain
Copy link
Contributor

Never mind. I started to work on a PR that addresses 3. as manual_memcpy.

bors added a commit that referenced this issue May 2, 2020
Fix the bugs of `manual_memcpy`, simplify the suggestion and refactor it

While I’m working on the long procrastinated work to expand `manual_memcpy`(#1670), I found a few minor bugs and probably unidiomatic or old coding style. There is a brief explanation of changes to the behaviour this PR will make below. And, I have a questoin: do I need to add tests for the first and second fixed bugs? I thought it might be too rare cases to include the tests for those. I added for the last one though.

* Bug fix
  * It negates resulted offsets (`src/dst_offset`) when `offset` is subtraction by 0. This PR will remove any subtraction by 0 as a part of minification.

    ```rust
    for i in 0..5 {
        dst[i - 0] = src[i];
    }
    ```

    ```diff
     warning: it looks like you're manually copying between slices
       --> src/main.rs:2:14
        |
    LL  |     for i in 0..5 {
    -   |              ^^^^ help: try replacing the loop by: `dst[..-5].clone_from_slice(&src[..5])`
    +   |              ^^^^ help: try replacing the loop by: `dst[..5].clone_from_slice(&src[..5])`
        |
    ```
  * It prints `RangeTo` or `RangeFull` when both of `end` and `offset` are 0, which have different meaning. This PR will print 0. I could reject the cases `end` is 0, but I thought I won’t catch other cases `reverse_range_loop` will trigger, and it’s over to catch every such cases.

    ```rust
    for i in 0..0 {
        dst[i] = src[i];
    }
    ```

    ```diff
     warning: it looks like you're manually copying between slices
       --> src/main.rs:2:14
        |
     LL |     for i in 0..0 {
    -   |              ^^^^ help: try replacing the loop by: `dst.clone_from_slice(&src[..])`
    +   |              ^^^^ help: try replacing the loop by: `dst[..0].clone_from_slice(&src[..0])`
        |
    ```
  * it prints four dots when `end` is `None`. This PR will ignore any `for` loops without `end` because a `for` loop that takes `RangeFrom` as its argument and contains indexing without the statements or the expressions that end loops such as `break` will definitely panic, and `manual_memcpy` should ignore the loops with such control flow.

    ```rust
    fn manual_copy(src: &[u32], dst: &mut [u32]) {
        for i in 0.. {
            dst[i] = src[i];
        }
    }
    ```

    ```diff
    -warning: it looks like you're manually copying between slices
    -  --> src/main.rs:2:14
    -   |
    -LL |     for i in 0.. {
    -   |              ^^^ help: try replacing the loop by: `dst[....].clone_from_slice(&src[....])`
    -   |
    ```
* Simplification of the suggestion

  * It prints 0 when `start` or `end` and `offset` are same (from #3323). This PR will use `RangeTo`

changelog: fixed the bugs of `manual_memcpy` and also simplify the suggestion.
@bors bors closed this as completed in dbc0285 Oct 10, 2020
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 good-first-issue These issues are a good way to get started with Clippy I-suggestion-causes-error Issue: The suggestions provided by this Lint cause an ICE/error when applied L-suggestion Lint: Improving, adding or fixing lint suggestions T-middle Type: Probably requires verifiying types
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants