Skip to content

Commit 22c986f

Browse files
authored
Merge pull request #1837 from Manishearth/step_by
Replace `Range::step_by` checking with `Iterator::step_by`
2 parents 27727c4 + 38925a5 commit 22c986f

File tree

7 files changed

+70
-31
lines changed

7 files changed

+70
-31
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ All notable changes to this project will be documented in this file.
33

44
## 0.0.141
55
* Rewrite of the `doc_markdown` lint.
6+
* Deprecated [`range_step_by_zero`]
7+
* New lint: [`iterator_step_by_zero`]
68

79
## 0.0.140 - 2017-06-16
810
* Update to *rustc 1.19.0-nightly (258ae6dd9 2017-06-15)*
@@ -439,6 +441,7 @@ All notable changes to this project will be documented in this file.
439441
[`iter_next_loop`]: https://github.com/Manishearth/rust-clippy/wiki#iter_next_loop
440442
[`iter_nth`]: https://github.com/Manishearth/rust-clippy/wiki#iter_nth
441443
[`iter_skip_next`]: https://github.com/Manishearth/rust-clippy/wiki#iter_skip_next
444+
[`iterator_step_by_zero`]: https://github.com/Manishearth/rust-clippy/wiki#iterator_step_by_zero
442445
[`large_enum_variant`]: https://github.com/Manishearth/rust-clippy/wiki#large_enum_variant
443446
[`len_without_is_empty`]: https://github.com/Manishearth/rust-clippy/wiki#len_without_is_empty
444447
[`len_zero`]: https://github.com/Manishearth/rust-clippy/wiki#len_zero

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,7 @@ name
260260
[iter_next_loop](https://github.com/Manishearth/rust-clippy/wiki#iter_next_loop) | warn | for-looping over `_.next()` which is probably not intended
261261
[iter_nth](https://github.com/Manishearth/rust-clippy/wiki#iter_nth) | warn | using `.iter().nth()` on a standard library type with O(1) element access
262262
[iter_skip_next](https://github.com/Manishearth/rust-clippy/wiki#iter_skip_next) | warn | using `.skip(x).next()` on an iterator
263+
[iterator_step_by_zero](https://github.com/Manishearth/rust-clippy/wiki#iterator_step_by_zero) | warn | using `Iterator::step_by(0)`, which produces an infinite iterator
263264
[large_enum_variant](https://github.com/Manishearth/rust-clippy/wiki#large_enum_variant) | warn | large size difference between variants on an enum
264265
[len_without_is_empty](https://github.com/Manishearth/rust-clippy/wiki#len_without_is_empty) | warn | traits or impls with a public `len` method but no corresponding `is_empty` method
265266
[len_zero](https://github.com/Manishearth/rust-clippy/wiki#len_zero) | warn | checking `.len() == 0` or `.len() > 0` (or similar) when `.is_empty()` could be used instead
@@ -321,7 +322,6 @@ name
321322
[print_with_newline](https://github.com/Manishearth/rust-clippy/wiki#print_with_newline) | warn | using `print!()` with a format string that ends in a newline
322323
[ptr_arg](https://github.com/Manishearth/rust-clippy/wiki#ptr_arg) | warn | fn arguments of the type `&Vec<...>` or `&String`, suggesting to use `&[...]` or `&str` instead, respectively
323324
[pub_enum_variant_names](https://github.com/Manishearth/rust-clippy/wiki#pub_enum_variant_names) | allow | enums where all variants share a prefix/postfix
324-
[range_step_by_zero](https://github.com/Manishearth/rust-clippy/wiki#range_step_by_zero) | warn | using `Range::step_by(0)`, which produces an infinite iterator
325325
[range_zip_with_len](https://github.com/Manishearth/rust-clippy/wiki#range_zip_with_len) | warn | zipping iterator with a range when `enumerate()` would do
326326
[redundant_closure](https://github.com/Manishearth/rust-clippy/wiki#redundant_closure) | warn | redundant closures, i.e. `|a| foo(a)` (which can be written as just `foo`)
327327
[redundant_closure_call](https://github.com/Manishearth/rust-clippy/wiki#redundant_closure_call) | warn | throwaway closures called in the expression they are defined

clippy_lints/src/deprecated_lints.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,16 @@ declare_deprecated_lint! {
1414
"`.extend_from_slice(_)` is a faster way to extend a Vec by a slice"
1515
}
1616

17+
/// **What it does:** Nothing. This lint has been deprecated.
18+
///
19+
/// **Deprecation reason:** `Range::step_by(0)` used to be linted since it's
20+
/// an infinite iterator, which is better expressed by `iter::repeat`,
21+
/// but the method has been removed for `Iterator::step_by` which panics
22+
/// if given a zero
23+
declare_deprecated_lint! {
24+
pub RANGE_STEP_BY_ZERO,
25+
"`iterator.step_by(0)` panics nowadays"
26+
}
1727

1828
/// **What it does:** Nothing. This lint has been deprecated.
1929
///

clippy_lints/src/lib.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,10 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
194194
"extend_from_slice",
195195
"`.extend_from_slice(_)` is a faster way to extend a Vec by a slice",
196196
);
197+
store.register_removed(
198+
"range_step_by_zero",
199+
"`iterator.step_by(0)` panics nowadays",
200+
);
197201
store.register_removed(
198202
"unstable_as_slice",
199203
"`Vec::as_slice` has been stabilized in 1.7",
@@ -490,7 +494,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
490494
ptr::CMP_NULL,
491495
ptr::MUT_FROM_REF,
492496
ptr::PTR_ARG,
493-
ranges::RANGE_STEP_BY_ZERO,
497+
ranges::ITERATOR_STEP_BY_ZERO,
494498
ranges::RANGE_ZIP_WITH_LEN,
495499
reference::DEREF_ADDROF,
496500
regex::INVALID_REGEX,

clippy_lints/src/ranges.rs

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
use rustc::lint::*;
22
use rustc::hir::*;
33
use syntax::codemap::Spanned;
4-
use utils::{is_integer_literal, match_type, paths, snippet, span_lint};
5-
use utils::higher;
4+
use utils::{is_integer_literal, paths, snippet, span_lint};
5+
use utils::{higher, implements_trait, get_trait_def_id};
66

7-
/// **What it does:** Checks for iterating over ranges with a `.step_by(0)`,
7+
/// **What it does:** Checks for calling `.step_by(0)` on iterators,
88
/// which never terminates.
99
///
1010
/// **Why is this bad?** This very much looks like an oversight, since with
@@ -17,10 +17,11 @@ use utils::higher;
1717
/// for x in (5..5).step_by(0) { .. }
1818
/// ```
1919
declare_lint! {
20-
pub RANGE_STEP_BY_ZERO,
20+
pub ITERATOR_STEP_BY_ZERO,
2121
Warn,
22-
"using `Range::step_by(0)`, which produces an infinite iterator"
22+
"using `Iterator::step_by(0)`, which produces an infinite iterator"
2323
}
24+
2425
/// **What it does:** Checks for zipping a collection with the range of `0.._.len()`.
2526
///
2627
/// **Why is this bad?** The code is better expressed with `.enumerate()`.
@@ -42,7 +43,7 @@ pub struct StepByZero;
4243

4344
impl LintPass for StepByZero {
4445
fn get_lints(&self) -> LintArray {
45-
lint_array!(RANGE_STEP_BY_ZERO, RANGE_ZIP_WITH_LEN)
46+
lint_array!(ITERATOR_STEP_BY_ZERO, RANGE_ZIP_WITH_LEN)
4647
}
4748
}
4849

@@ -52,12 +53,19 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for StepByZero {
5253
let name = name.as_str();
5354

5455
// Range with step_by(0).
55-
if name == "step_by" && args.len() == 2 && has_step_by(cx, &args[0]) && is_integer_literal(&args[1], 0) {
56-
span_lint(cx,
57-
RANGE_STEP_BY_ZERO,
58-
expr.span,
59-
"Range::step_by(0) produces an infinite iterator. Consider using `std::iter::repeat()` \
60-
instead");
56+
if name == "step_by" && args.len() == 2 && has_step_by(cx, &args[0]) {
57+
use consts::{Constant, constant};
58+
use rustc_const_math::ConstInt::Usize;
59+
if let Some((Constant::Int(Usize(us)), _)) = constant(cx, &args[1]) {
60+
if us.as_u64(cx.sess().target.uint_type) == 0 {
61+
span_lint(
62+
cx,
63+
ITERATOR_STEP_BY_ZERO,
64+
expr.span,
65+
"Iterator::step_by(0) will panic at runtime",
66+
);
67+
}
68+
}
6169
} else if name == "zip" && args.len() == 2 {
6270
let iter = &args[0].node;
6371
let zip_arg = &args[1];
@@ -90,9 +98,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for StepByZero {
9098
fn has_step_by(cx: &LateContext, expr: &Expr) -> bool {
9199
// No need for walk_ptrs_ty here because step_by moves self, so it
92100
// can't be called on a borrowed range.
93-
let ty = cx.tables.expr_ty(expr);
101+
let ty = cx.tables.expr_ty_adjusted(expr);
94102

95-
// Note: `RangeTo`, `RangeToInclusive` and `RangeFull` don't have step_by
96-
match_type(cx, ty, &paths::RANGE) || match_type(cx, ty, &paths::RANGE_FROM) ||
97-
match_type(cx, ty, &paths::RANGE_INCLUSIVE)
103+
get_trait_def_id(cx, &paths::ITERATOR)
104+
.map_or(
105+
false,
106+
|iterator_trait| implements_trait(cx, ty, iterator_trait, &[])
107+
)
98108
}

clippy_tests/examples/range.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#![feature(iterator_step_by)]
12
#![feature(step_by)]
23
#![feature(inclusive_range_syntax)]
34
#![feature(plugin)]
@@ -8,7 +9,7 @@ impl NotARange {
89
fn step_by(&self, _: u32) {}
910
}
1011

11-
#[warn(range_step_by_zero, range_zip_with_len)]
12+
#[warn(iterator_step_by_zero, range_zip_with_len)]
1213
fn main() {
1314
(0..1).step_by(0);
1415
// No warning for non-zero step
@@ -28,4 +29,7 @@ fn main() {
2829
let v2 = vec![4,5];
2930
let _x = v1.iter().zip(0..v1.len());
3031
let _y = v1.iter().zip(0..v2.len()); // No error
32+
33+
// check const eval
34+
let _ = v1.iter().step_by(2/3);
3135
}

clippy_tests/examples/range.stderr

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,59 @@
11
error: use of deprecated item: replaced by `Iterator::step_by`
2-
--> range.rs:13:12
2+
--> range.rs:14:12
33
|
4-
13 | (0..1).step_by(0);
4+
14 | (0..1).step_by(0);
55
| ^^^^^^^
66
|
77
= note: `-D deprecated` implied by `-D warnings`
88

99
error: use of deprecated item: replaced by `Iterator::step_by`
10-
--> range.rs:15:12
10+
--> range.rs:16:12
1111
|
12-
15 | (0..1).step_by(1);
12+
16 | (0..1).step_by(1);
1313
| ^^^^^^^
1414
|
1515
= note: `-D deprecated` implied by `-D warnings`
1616

1717
error: use of deprecated item: replaced by `Iterator::step_by`
18-
--> range.rs:17:11
18+
--> range.rs:18:11
1919
|
20-
17 | (1..).step_by(0);
20+
18 | (1..).step_by(0);
2121
| ^^^^^^^
2222
|
2323
= note: `-D deprecated` implied by `-D warnings`
2424

2525
error: use of deprecated item: replaced by `Iterator::step_by`
26-
--> range.rs:18:13
26+
--> range.rs:19:13
2727
|
28-
18 | (1...2).step_by(0);
28+
19 | (1...2).step_by(0);
2929
| ^^^^^^^
3030
|
3131
= note: `-D deprecated` implied by `-D warnings`
3232

3333
error: use of deprecated item: replaced by `Iterator::step_by`
34-
--> range.rs:21:7
34+
--> range.rs:22:7
3535
|
36-
21 | x.step_by(0);
36+
22 | x.step_by(0);
3737
| ^^^^^^^
3838
|
3939
= note: `-D deprecated` implied by `-D warnings`
4040

4141
error: It is more idiomatic to use v1.iter().enumerate()
42-
--> range.rs:29:14
42+
--> range.rs:30:14
4343
|
44-
29 | let _x = v1.iter().zip(0..v1.len());
44+
30 | let _x = v1.iter().zip(0..v1.len());
4545
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
4646
|
4747
= note: `-D range-zip-with-len` implied by `-D warnings`
4848

49+
error: Iterator::step_by(0) will panic at runtime
50+
--> range.rs:34:13
51+
|
52+
34 | let _ = v1.iter().step_by(2/3);
53+
| ^^^^^^^^^^^^^^^^^^^^^^
54+
|
55+
= note: `-D iterator-step-by-zero` implied by `-D warnings`
56+
4957
error: aborting due to previous error(s)
5058

5159
error: Could not compile `clippy_tests`.

0 commit comments

Comments
 (0)