Skip to content

Commit 62831c6

Browse files
committed
Suggest nth(X) instead of skip(X).next()
1 parent 4fbd890 commit 62831c6

File tree

5 files changed

+71
-2
lines changed

5 files changed

+71
-2
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,7 @@ All notable changes to this project will be documented in this file.
266266
[`items_after_statements`]: https://github.com/Manishearth/rust-clippy/wiki#items_after_statements
267267
[`iter_next_loop`]: https://github.com/Manishearth/rust-clippy/wiki#iter_next_loop
268268
[`iter_nth`]: https://github.com/Manishearth/rust-clippy/wiki#iter_nth
269+
[`iter_skip_next`]: https://github.com/Manishearth/rust-clippy/wiki#iter_skip_next
269270
[`len_without_is_empty`]: https://github.com/Manishearth/rust-clippy/wiki#len_without_is_empty
270271
[`len_zero`]: https://github.com/Manishearth/rust-clippy/wiki#len_zero
271272
[`let_and_return`]: https://github.com/Manishearth/rust-clippy/wiki#let_and_return

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ You can check out this great service at [clippy.bashy.io](https://clippy.bashy.i
174174

175175
## Lints
176176

177-
There are 173 lints included in this crate:
177+
There are 174 lints included in this crate:
178178

179179
name | default | triggers on
180180
---------------------------------------------------------------------------------------------------------------------|---------|----------------------------------------------------------------------------------------------------------------------------------
@@ -244,6 +244,7 @@ name
244244
[items_after_statements](https://github.com/Manishearth/rust-clippy/wiki#items_after_statements) | allow | blocks where an item comes after a statement
245245
[iter_next_loop](https://github.com/Manishearth/rust-clippy/wiki#iter_next_loop) | warn | for-looping over `_.next()` which is probably not intended
246246
[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
247+
[iter_skip_next](https://github.com/Manishearth/rust-clippy/wiki#iter_skip_next) | warn | using `.skip(x).next()` on an iterator
247248
[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
248249
[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
249250
[let_and_return](https://github.com/Manishearth/rust-clippy/wiki#let_and_return) | warn | creating a let-binding and then immediately returning it like `let x = expr; x` at the end of a block

clippy_lints/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
372372
methods::EXTEND_FROM_SLICE,
373373
methods::FILTER_NEXT,
374374
methods::ITER_NTH,
375+
methods::ITER_SKIP_NEXT,
375376
methods::NEW_RET_NO_SELF,
376377
methods::OK_EXPECT,
377378
methods::OR_FUN_CALL,

clippy_lints/src/methods.rs

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,31 @@ declare_lint! {
440440
"using `.iter().nth()` on a standard library type with O(1) element access"
441441
}
442442

443+
/// **What it does:** Checks for use of `.skip(x).next()` on iterators.
444+
///
445+
/// **Why is this bad?** `.nth(x)` is cleaner
446+
///
447+
/// **Known problems:** None.
448+
///
449+
/// **Example:**
450+
/// ```rust
451+
/// let some_vec = vec![0, 1, 2, 3];
452+
/// let bad_vec = some_vec.iter().skip(3).next();
453+
/// let bad_slice = &some_vec[..].iter().skip(3).next();
454+
/// ```
455+
/// The correct use would be:
456+
/// ```rust
457+
/// let some_vec = vec![0, 1, 2, 3];
458+
/// let bad_vec = some_vec.iter().nth(3);
459+
/// let bad_slice = &some_vec[..].iter().nth(3);
460+
/// ```
461+
declare_lint! {
462+
pub ITER_SKIP_NEXT,
463+
Warn,
464+
"using `.skip(x).next()` on an iterator"
465+
}
466+
467+
443468
impl LintPass for Pass {
444469
fn get_lints(&self) -> LintArray {
445470
lint_array!(EXTEND_FROM_SLICE,
@@ -461,7 +486,8 @@ impl LintPass for Pass {
461486
TEMPORARY_CSTRING_AS_PTR,
462487
FILTER_NEXT,
463488
FILTER_MAP,
464-
ITER_NTH)
489+
ITER_NTH,
490+
ITER_SKIP_NEXT)
465491
}
466492
}
467493

@@ -506,6 +532,8 @@ impl LateLintPass for Pass {
506532
lint_iter_nth(cx, expr, arglists[0], false);
507533
} else if let Some(arglists) = method_chain_args(expr, &["iter_mut", "nth"]) {
508534
lint_iter_nth(cx, expr, arglists[0], true);
535+
} else if let Some(_) = method_chain_args(expr, &["skip", "next"]) {
536+
lint_iter_skip_next(cx, expr);
509537
}
510538

511539
lint_or_fun_call(cx, expr, &name.node.as_str(), args);
@@ -790,6 +818,18 @@ fn lint_iter_nth(cx: &LateContext, expr: &hir::Expr, iter_args: &MethodArgs, is_
790818
);
791819
}
792820

821+
fn lint_iter_skip_next(cx: &LateContext, expr: &hir::Expr){
822+
// lint if caller of skip is an Iterator
823+
if match_trait_method(cx, expr, &paths::ITERATOR) {
824+
span_lint(
825+
cx,
826+
ITER_SKIP_NEXT,
827+
expr.span,
828+
"called `skip(x).next()` on an iterator. This is more succinctly expressed by calling `nth(x)`"
829+
);
830+
}
831+
}
832+
793833
fn derefs_to_slice(cx: &LateContext, expr: &hir::Expr, ty: ty::Ty) -> Option<sugg::Sugg<'static>> {
794834
fn may_slice(cx: &LateContext, ty: ty::Ty) -> bool {
795835
match ty.sty {

tests/compile-fail/methods.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,10 @@ impl IteratorFalsePositives {
173173
fn nth(self, n: usize) -> Option<u32> {
174174
Some(self.foo)
175175
}
176+
177+
fn skip(self, _: usize) -> IteratorFalsePositives {
178+
self
179+
}
176180
}
177181

178182
/// Checks implementation of `FILTER_NEXT` lint
@@ -363,6 +367,28 @@ fn iter_nth() {
363367
let ok_mut = false_positive.iter_mut().nth(3);
364368
}
365369

370+
/// Checks implementation of `ITER_SKIP_NEXT` lint
371+
fn iter_skip_next() {
372+
let mut some_vec = vec![0, 1, 2, 3];
373+
374+
let _ = some_vec.iter().skip(42).next();
375+
//~^ERROR called `skip(x).next()` on an iterator. This is more succinctly expressed by calling `nth(x)`
376+
377+
let _ = some_vec.iter().cycle().skip(42).next();
378+
//~^ERROR called `skip(x).next()` on an iterator. This is more succinctly expressed by calling `nth(x)`
379+
380+
let _ = (1..10).skip(10).next();
381+
//~^ERROR called `skip(x).next()` on an iterator. This is more succinctly expressed by calling `nth(x)`
382+
383+
let _ = &some_vec[..].iter().skip(3).next();
384+
//~^ERROR called `skip(x).next()` on an iterator. This is more succinctly expressed by calling `nth(x)`
385+
386+
let foo = IteratorFalsePositives { foo : 0 };
387+
let _ = foo.skip(42).next();
388+
let _ = foo.filter().skip(42).next();
389+
}
390+
391+
366392
#[allow(similar_names)]
367393
fn main() {
368394
use std::io;

0 commit comments

Comments
 (0)