Skip to content

Commit fd53761

Browse files
committed
Move range_zip_with_len into Methods lint pass
1 parent 226f135 commit fd53761

File tree

6 files changed

+77
-70
lines changed

6 files changed

+77
-70
lines changed

clippy_lints/src/lib.register_all.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
196196
LintId::of(methods::OPTION_MAP_OR_NONE),
197197
LintId::of(methods::OR_FUN_CALL),
198198
LintId::of(methods::OR_THEN_UNWRAP),
199+
LintId::of(methods::RANGE_ZIP_WITH_LEN),
199200
LintId::of(methods::RESULT_MAP_OR_INTO_OPTION),
200201
LintId::of(methods::SEARCH_IS_SOME),
201202
LintId::of(methods::SHOULD_IMPLEMENT_TRAIT),
@@ -276,7 +277,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
276277
LintId::of(ptr_offset_with_cast::PTR_OFFSET_WITH_CAST),
277278
LintId::of(question_mark::QUESTION_MARK),
278279
LintId::of(ranges::MANUAL_RANGE_CONTAINS),
279-
LintId::of(ranges::RANGE_ZIP_WITH_LEN),
280280
LintId::of(ranges::REVERSED_EMPTY_RANGES),
281281
LintId::of(rc_clone_in_vec_init::RC_CLONE_IN_VEC_INIT),
282282
LintId::of(read_zero_byte_vec::READ_ZERO_BYTE_VEC),

clippy_lints/src/lib.register_complexity.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec!
5151
LintId::of(methods::OPTION_AS_REF_DEREF),
5252
LintId::of(methods::OPTION_FILTER_MAP),
5353
LintId::of(methods::OR_THEN_UNWRAP),
54+
LintId::of(methods::RANGE_ZIP_WITH_LEN),
5455
LintId::of(methods::SEARCH_IS_SOME),
5556
LintId::of(methods::SKIP_WHILE_NEXT),
5657
LintId::of(methods::UNNECESSARY_FILTER_MAP),
@@ -76,7 +77,6 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec!
7677
LintId::of(partialeq_ne_impl::PARTIALEQ_NE_IMPL),
7778
LintId::of(precedence::PRECEDENCE),
7879
LintId::of(ptr_offset_with_cast::PTR_OFFSET_WITH_CAST),
79-
LintId::of(ranges::RANGE_ZIP_WITH_LEN),
8080
LintId::of(redundant_closure_call::REDUNDANT_CLOSURE_CALL),
8181
LintId::of(redundant_slicing::REDUNDANT_SLICING),
8282
LintId::of(reference::DEREF_ADDROF),

clippy_lints/src/lib.register_lints.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,7 @@ store.register_lints(&[
345345
methods::OR_FUN_CALL,
346346
methods::OR_THEN_UNWRAP,
347347
methods::PATH_BUF_PUSH_OVERWRITE,
348+
methods::RANGE_ZIP_WITH_LEN,
348349
methods::RESULT_MAP_OR_INTO_OPTION,
349350
methods::SEARCH_IS_SOME,
350351
methods::SHOULD_IMPLEMENT_TRAIT,
@@ -473,7 +474,6 @@ store.register_lints(&[
473474
ranges::MANUAL_RANGE_CONTAINS,
474475
ranges::RANGE_MINUS_ONE,
475476
ranges::RANGE_PLUS_ONE,
476-
ranges::RANGE_ZIP_WITH_LEN,
477477
ranges::REVERSED_EMPTY_RANGES,
478478
rc_clone_in_vec_init::RC_CLONE_IN_VEC_INIT,
479479
read_zero_byte_vec::READ_ZERO_BYTE_VEC,

clippy_lints/src/methods/mod.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ mod option_map_unwrap_or;
6464
mod or_fun_call;
6565
mod or_then_unwrap;
6666
mod path_buf_push_overwrite;
67+
mod range_zip_with_len;
6768
mod search_is_some;
6869
mod single_char_add_str;
6970
mod single_char_insert_string;
@@ -2734,6 +2735,31 @@ declare_clippy_lint! {
27342735
"calling `push` with file system root on `PathBuf` can overwrite it"
27352736
}
27362737

2738+
declare_clippy_lint! {
2739+
/// ### What it does
2740+
/// Checks for zipping a collection with the range of
2741+
/// `0.._.len()`.
2742+
///
2743+
/// ### Why is this bad?
2744+
/// The code is better expressed with `.enumerate()`.
2745+
///
2746+
/// ### Example
2747+
/// ```rust
2748+
/// # let x = vec![1];
2749+
/// let _ = x.iter().zip(0..x.len());
2750+
/// ```
2751+
///
2752+
/// Use instead:
2753+
/// ```rust
2754+
/// # let x = vec![1];
2755+
/// let _ = x.iter().enumerate();
2756+
/// ```
2757+
#[clippy::version = "pre 1.29.0"]
2758+
pub RANGE_ZIP_WITH_LEN,
2759+
complexity,
2760+
"zipping iterator with a range when `enumerate()` would do"
2761+
}
2762+
27372763
pub struct Methods {
27382764
avoid_breaking_exported_api: bool,
27392765
msrv: Option<RustcVersion>,
@@ -2848,6 +2874,7 @@ impl_lint_pass!(Methods => [
28482874
MUT_MUTEX_LOCK,
28492875
NONSENSICAL_OPEN_OPTIONS,
28502876
PATH_BUF_PUSH_OVERWRITE,
2877+
RANGE_ZIP_WITH_LEN,
28512878
]);
28522879

28532880
/// Extracts a method call name, args, and `Span` of the method name.
@@ -3304,6 +3331,13 @@ impl Methods {
33043331
("replace" | "replacen", [arg1, arg2] | [arg1, arg2, _]) => {
33053332
no_effect_replace::check(cx, expr, arg1, arg2);
33063333
},
3334+
("zip", [arg]) => {
3335+
if let ExprKind::MethodCall(name, [iter_recv], _) = recv.kind
3336+
&& name.ident.name == sym::iter
3337+
{
3338+
range_zip_with_len::check(cx, expr, iter_recv, arg);
3339+
}
3340+
},
33073341
_ => {},
33083342
}
33093343
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
use clippy_utils::diagnostics::span_lint;
2+
use clippy_utils::source::snippet;
3+
use clippy_utils::{higher, SpanlessEq};
4+
use clippy_utils::{is_integer_const, is_trait_method};
5+
use if_chain::if_chain;
6+
use rustc_hir::{Expr, ExprKind, QPath};
7+
use rustc_lint::LateContext;
8+
use rustc_span::sym;
9+
10+
use super::RANGE_ZIP_WITH_LEN;
11+
12+
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &'tcx Expr<'_>, zip_arg: &'tcx Expr<'_>) {
13+
if_chain! {
14+
if is_trait_method(cx, expr, sym::Iterator);
15+
// range expression in `.zip()` call: `0..x.len()`
16+
if let Some(higher::Range { start: Some(start), end: Some(end), .. }) = higher::Range::hir(zip_arg);
17+
if is_integer_const(cx, start, 0);
18+
// `.len()` call
19+
if let ExprKind::MethodCall(len_path, [len_recv], _) = end.kind;
20+
if len_path.ident.name == sym::len;
21+
// `.iter()` and `.len()` called on same `Path`
22+
if let ExprKind::Path(QPath::Resolved(_, iter_path)) = recv.kind;
23+
if let ExprKind::Path(QPath::Resolved(_, len_path)) = len_recv.kind;
24+
if SpanlessEq::new(cx).eq_path_segments(iter_path.segments, len_path.segments);
25+
then {
26+
span_lint(cx,
27+
RANGE_ZIP_WITH_LEN,
28+
expr.span,
29+
&format!("it is more idiomatic to use `{}.iter().enumerate()`",
30+
snippet(cx, recv.span, "_"))
31+
);
32+
}
33+
}
34+
}

clippy_lints/src/ranges.rs

Lines changed: 6 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,20 @@
11
use clippy_utils::consts::{constant, Constant};
22
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then};
3+
use clippy_utils::higher;
34
use clippy_utils::source::{snippet, snippet_opt, snippet_with_applicability};
45
use clippy_utils::sugg::Sugg;
56
use clippy_utils::{get_parent_expr, in_constant, is_integer_const, meets_msrv, msrvs, path_to_local};
6-
use clippy_utils::{higher, SpanlessEq};
77
use if_chain::if_chain;
88
use rustc_ast::ast::RangeLimits;
99
use rustc_errors::Applicability;
10-
use rustc_hir::{BinOpKind, Expr, ExprKind, HirId, PathSegment, QPath};
10+
use rustc_hir::{BinOpKind, Expr, ExprKind, HirId};
1111
use rustc_lint::{LateContext, LateLintPass};
1212
use rustc_middle::ty;
1313
use rustc_semver::RustcVersion;
1414
use rustc_session::{declare_tool_lint, impl_lint_pass};
1515
use rustc_span::source_map::{Span, Spanned};
16-
use rustc_span::sym;
1716
use std::cmp::Ordering;
1817

19-
declare_clippy_lint! {
20-
/// ### What it does
21-
/// Checks for zipping a collection with the range of
22-
/// `0.._.len()`.
23-
///
24-
/// ### Why is this bad?
25-
/// The code is better expressed with `.enumerate()`.
26-
///
27-
/// ### Example
28-
/// ```rust
29-
/// # let x = vec![1];
30-
/// let _ = x.iter().zip(0..x.len());
31-
/// ```
32-
///
33-
/// Use instead:
34-
/// ```rust
35-
/// # let x = vec![1];
36-
/// let _ = x.iter().enumerate();
37-
/// ```
38-
#[clippy::version = "pre 1.29.0"]
39-
pub RANGE_ZIP_WITH_LEN,
40-
complexity,
41-
"zipping iterator with a range when `enumerate()` would do"
42-
}
43-
4418
declare_clippy_lint! {
4519
/// ### What it does
4620
/// Checks for exclusive ranges where 1 is added to the
@@ -198,7 +172,6 @@ impl Ranges {
198172
}
199173

200174
impl_lint_pass!(Ranges => [
201-
RANGE_ZIP_WITH_LEN,
202175
RANGE_PLUS_ONE,
203176
RANGE_MINUS_ONE,
204177
REVERSED_EMPTY_RANGES,
@@ -207,16 +180,10 @@ impl_lint_pass!(Ranges => [
207180

208181
impl<'tcx> LateLintPass<'tcx> for Ranges {
209182
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
210-
match expr.kind {
211-
ExprKind::MethodCall(path, args, _) => {
212-
check_range_zip_with_len(cx, path, args, expr.span);
213-
},
214-
ExprKind::Binary(ref op, l, r) => {
215-
if meets_msrv(self.msrv, msrvs::RANGE_CONTAINS) {
216-
check_possible_range_contains(cx, op.node, l, r, expr, expr.span);
217-
}
218-
},
219-
_ => {},
183+
if let ExprKind::Binary(ref op, l, r) = expr.kind {
184+
if meets_msrv(self.msrv, msrvs::RANGE_CONTAINS) {
185+
check_possible_range_contains(cx, op.node, l, r, expr, expr.span);
186+
}
220187
}
221188

222189
check_exclusive_range_plus_one(cx, expr);
@@ -380,34 +347,6 @@ fn check_range_bounds<'a>(cx: &'a LateContext<'_>, ex: &'a Expr<'_>) -> Option<R
380347
None
381348
}
382349

383-
fn check_range_zip_with_len(cx: &LateContext<'_>, path: &PathSegment<'_>, args: &[Expr<'_>], span: Span) {
384-
if_chain! {
385-
if path.ident.as_str() == "zip";
386-
if let [iter, zip_arg] = args;
387-
// `.iter()` call
388-
if let ExprKind::MethodCall(iter_path, [iter_caller, ..], _) = iter.kind;
389-
if iter_path.ident.name == sym::iter;
390-
// range expression in `.zip()` call: `0..x.len()`
391-
if let Some(higher::Range { start: Some(start), end: Some(end), .. }) = higher::Range::hir(zip_arg);
392-
if is_integer_const(cx, start, 0);
393-
// `.len()` call
394-
if let ExprKind::MethodCall(len_path, [len_caller], _) = end.kind;
395-
if len_path.ident.name == sym::len;
396-
// `.iter()` and `.len()` called on same `Path`
397-
if let ExprKind::Path(QPath::Resolved(_, iter_path)) = iter_caller.kind;
398-
if let ExprKind::Path(QPath::Resolved(_, len_path)) = len_caller.kind;
399-
if SpanlessEq::new(cx).eq_path_segments(iter_path.segments, len_path.segments);
400-
then {
401-
span_lint(cx,
402-
RANGE_ZIP_WITH_LEN,
403-
span,
404-
&format!("it is more idiomatic to use `{}.iter().enumerate()`",
405-
snippet(cx, iter_caller.span, "_"))
406-
);
407-
}
408-
}
409-
}
410-
411350
// exclusive range plus one: `x..(y+1)`
412351
fn check_exclusive_range_plus_one(cx: &LateContext<'_>, expr: &Expr<'_>) {
413352
if_chain! {

0 commit comments

Comments
 (0)