new lint iter_skip_zero
This commit is contained in:
parent
ec571555a8
commit
4c79d8ace5
@ -4939,6 +4939,7 @@ Released 2018-09-13
|
||||
[`iter_on_single_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_on_single_items
|
||||
[`iter_overeager_cloned`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_overeager_cloned
|
||||
[`iter_skip_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_skip_next
|
||||
[`iter_skip_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_skip_zero
|
||||
[`iter_with_drain`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_with_drain
|
||||
[`iterator_step_by_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#iterator_step_by_zero
|
||||
[`just_underscores_and_digits`]: https://rust-lang.github.io/rust-clippy/master/index.html#just_underscores_and_digits
|
||||
|
@ -257,7 +257,7 @@ fn is_cast_from_ty_alias<'tcx>(cx: &LateContext<'tcx>, expr: impl Visitable<'tcx
|
||||
// Will this work for more complex types? Probably not!
|
||||
if !snippet
|
||||
.split("->")
|
||||
.skip(0)
|
||||
.skip(1)
|
||||
.map(|s| {
|
||||
s.trim() == cast_from.to_string()
|
||||
|| s.split("where").any(|ty| ty.trim() == cast_from.to_string())
|
||||
|
@ -360,6 +360,7 @@
|
||||
crate::methods::ITER_ON_SINGLE_ITEMS_INFO,
|
||||
crate::methods::ITER_OVEREAGER_CLONED_INFO,
|
||||
crate::methods::ITER_SKIP_NEXT_INFO,
|
||||
crate::methods::ITER_SKIP_ZERO_INFO,
|
||||
crate::methods::ITER_WITH_DRAIN_INFO,
|
||||
crate::methods::MANUAL_FILTER_MAP_INFO,
|
||||
crate::methods::MANUAL_FIND_MAP_INFO,
|
||||
|
34
clippy_lints/src/methods/iter_skip_zero.rs
Normal file
34
clippy_lints/src/methods/iter_skip_zero.rs
Normal file
@ -0,0 +1,34 @@
|
||||
use clippy_utils::consts::{constant, Constant};
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::{is_from_proc_macro, is_trait_method};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::Expr;
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_span::sym;
|
||||
|
||||
use super::ITER_SKIP_ZERO;
|
||||
|
||||
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, arg_expr: &Expr<'_>) {
|
||||
if !expr.span.from_expansion()
|
||||
&& is_trait_method(cx, expr, sym::Iterator)
|
||||
&& let Some(arg) = constant(cx, cx.typeck_results(), arg_expr).and_then(|constant| {
|
||||
if let Constant::Int(arg) = constant {
|
||||
Some(arg)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
&& arg == 0
|
||||
&& !is_from_proc_macro(cx, expr)
|
||||
{
|
||||
span_lint_and_then(cx, ITER_SKIP_ZERO, arg_expr.span, "usage of `.skip(0)`", |diag| {
|
||||
diag.span_suggestion(
|
||||
arg_expr.span,
|
||||
"if you meant to skip the first element, use",
|
||||
"1",
|
||||
Applicability::MaybeIncorrect,
|
||||
)
|
||||
.note("this call to `skip` does nothing and is useless; remove it");
|
||||
});
|
||||
}
|
||||
}
|
@ -45,6 +45,7 @@
|
||||
mod iter_on_single_or_empty_collections;
|
||||
mod iter_overeager_cloned;
|
||||
mod iter_skip_next;
|
||||
mod iter_skip_zero;
|
||||
mod iter_with_drain;
|
||||
mod iterator_step_by_zero;
|
||||
mod manual_next_back;
|
||||
@ -3443,6 +3444,27 @@
|
||||
"`format!`ing every element in a collection, then collecting the strings into a new `String`"
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Checks for usage of `.skip(0)` on iterators.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// This was likely intended to be `.skip(1)` to skip the first element, as `.skip(0)` does
|
||||
/// nothing. If not, the call should be removed.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```rust
|
||||
/// let v = vec![1, 2, 3];
|
||||
/// let x = v.iter().skip(0).collect::<Vec<_>>();
|
||||
/// let y = v.iter().collect::<Vec<_>>();
|
||||
/// assert_eq!(x, y);
|
||||
/// ```
|
||||
#[clippy::version = "1.72.0"]
|
||||
pub ITER_SKIP_ZERO,
|
||||
correctness,
|
||||
"disallows `.skip(0)`"
|
||||
}
|
||||
|
||||
pub struct Methods {
|
||||
avoid_breaking_exported_api: bool,
|
||||
msrv: Msrv,
|
||||
@ -3579,6 +3601,7 @@ pub fn new(
|
||||
MANUAL_TRY_FOLD,
|
||||
FORMAT_COLLECT,
|
||||
STRING_LIT_CHARS_ANY,
|
||||
ITER_SKIP_ZERO,
|
||||
]);
|
||||
|
||||
/// Extracts a method call name, args, and `Span` of the method name.
|
||||
@ -3901,7 +3924,16 @@ fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
unnecessary_join::check(cx, expr, recv, join_arg, span);
|
||||
}
|
||||
},
|
||||
("last", []) | ("skip", [_]) => {
|
||||
("skip", [arg]) => {
|
||||
iter_skip_zero::check(cx, expr, arg);
|
||||
|
||||
if let Some((name2, recv2, args2, _span2, _)) = method_call(recv) {
|
||||
if let ("cloned", []) = (name2, args2) {
|
||||
iter_overeager_cloned::check(cx, expr, recv, recv2, false, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
("last", []) => {
|
||||
if let Some((name2, recv2, args2, _span2, _)) = method_call(recv) {
|
||||
if let ("cloned", []) = (name2, args2) {
|
||||
iter_overeager_cloned::check(cx, expr, recv, recv2, false, false);
|
||||
|
25
tests/ui/iter_skip_zero.fixed
Normal file
25
tests/ui/iter_skip_zero.fixed
Normal file
@ -0,0 +1,25 @@
|
||||
//@run-rustfix
|
||||
//@aux-build:proc_macros.rs:proc-macro
|
||||
#![allow(clippy::useless_vec, unused)]
|
||||
#![warn(clippy::iter_skip_zero)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate proc_macros;
|
||||
|
||||
use std::iter::once;
|
||||
|
||||
fn main() {
|
||||
let _ = [1, 2, 3].iter().skip(1);
|
||||
let _ = vec![1, 2, 3].iter().skip(1);
|
||||
let _ = once([1, 2, 3]).skip(1);
|
||||
let _ = vec![1, 2, 3].iter().chain([1, 2, 3].iter().skip(1)).skip(1);
|
||||
// Don't lint
|
||||
let _ = [1, 2, 3].iter().skip(1);
|
||||
let _ = vec![1, 2, 3].iter().skip(1);
|
||||
external! {
|
||||
let _ = [1, 2, 3].iter().skip(0);
|
||||
}
|
||||
with_span! {
|
||||
let _ = [1, 2, 3].iter().skip(0);
|
||||
}
|
||||
}
|
25
tests/ui/iter_skip_zero.rs
Normal file
25
tests/ui/iter_skip_zero.rs
Normal file
@ -0,0 +1,25 @@
|
||||
//@run-rustfix
|
||||
//@aux-build:proc_macros.rs:proc-macro
|
||||
#![allow(clippy::useless_vec, unused)]
|
||||
#![warn(clippy::iter_skip_zero)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate proc_macros;
|
||||
|
||||
use std::iter::once;
|
||||
|
||||
fn main() {
|
||||
let _ = [1, 2, 3].iter().skip(0);
|
||||
let _ = vec![1, 2, 3].iter().skip(0);
|
||||
let _ = once([1, 2, 3]).skip(0);
|
||||
let _ = vec![1, 2, 3].iter().chain([1, 2, 3].iter().skip(0)).skip(0);
|
||||
// Don't lint
|
||||
let _ = [1, 2, 3].iter().skip(1);
|
||||
let _ = vec![1, 2, 3].iter().skip(1);
|
||||
external! {
|
||||
let _ = [1, 2, 3].iter().skip(0);
|
||||
}
|
||||
with_span! {
|
||||
let _ = [1, 2, 3].iter().skip(0);
|
||||
}
|
||||
}
|
43
tests/ui/iter_skip_zero.stderr
Normal file
43
tests/ui/iter_skip_zero.stderr
Normal file
@ -0,0 +1,43 @@
|
||||
error: usage of `.skip(0)`
|
||||
--> $DIR/iter_skip_zero.rs:12:35
|
||||
|
|
||||
LL | let _ = [1, 2, 3].iter().skip(0);
|
||||
| ^ help: if you meant to skip the first element, use: `1`
|
||||
|
|
||||
= note: this call to `skip` does nothing and is useless; remove it
|
||||
= note: `-D clippy::iter-skip-zero` implied by `-D warnings`
|
||||
|
||||
error: usage of `.skip(0)`
|
||||
--> $DIR/iter_skip_zero.rs:13:39
|
||||
|
|
||||
LL | let _ = vec![1, 2, 3].iter().skip(0);
|
||||
| ^ help: if you meant to skip the first element, use: `1`
|
||||
|
|
||||
= note: this call to `skip` does nothing and is useless; remove it
|
||||
|
||||
error: usage of `.skip(0)`
|
||||
--> $DIR/iter_skip_zero.rs:14:34
|
||||
|
|
||||
LL | let _ = once([1, 2, 3]).skip(0);
|
||||
| ^ help: if you meant to skip the first element, use: `1`
|
||||
|
|
||||
= note: this call to `skip` does nothing and is useless; remove it
|
||||
|
||||
error: usage of `.skip(0)`
|
||||
--> $DIR/iter_skip_zero.rs:15:71
|
||||
|
|
||||
LL | let _ = vec![1, 2, 3].iter().chain([1, 2, 3].iter().skip(0)).skip(0);
|
||||
| ^ help: if you meant to skip the first element, use: `1`
|
||||
|
|
||||
= note: this call to `skip` does nothing and is useless; remove it
|
||||
|
||||
error: usage of `.skip(0)`
|
||||
--> $DIR/iter_skip_zero.rs:15:62
|
||||
|
|
||||
LL | let _ = vec![1, 2, 3].iter().chain([1, 2, 3].iter().skip(0)).skip(0);
|
||||
| ^ help: if you meant to skip the first element, use: `1`
|
||||
|
|
||||
= note: this call to `skip` does nothing and is useless; remove it
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
|
Loading…
Reference in New Issue
Block a user