Skip to content

Commit 5577e42

Browse files
authored
Rollup merge of #99696 - WaffleLapkin:uplift, r=fee1-dead
Uplift `clippy::for_loops_over_fallibles` lint into rustc This PR, as the title suggests, uplifts [`clippy::for_loops_over_fallibles`] lint into rustc. This lint warns for code like this: ```rust for _ in Some(1) {} for _ in Ok::<_, ()>(1) {} ``` i.e. directly iterating over `Option` and `Result` using `for` loop. There are a number of suggestions that this PR adds (on top of what clippy suggested): 1. If the argument (? is there a better name for that expression) of a `for` loop is a `.next()` call, then we can suggest removing it (or rather replacing with `.by_ref()` to allow iterator being used later) ```rust for _ in iter.next() {} // turns into for _ in iter.by_ref() {} ``` 2. (otherwise) We can suggest using `while let`, this is useful for non-iterator, iterator-like things like [async] channels ```rust for _ in rx.recv() {} // turns into while let Some(_) = rx.recv() {} ``` 3. If the argument type is `Result<impl IntoIterator, _>` and the body has a `Result<_, _>` type, we can suggest using `?` ```rust for _ in f() {} // turns into for _ in f()? {} ``` 4. To preserve the original behavior and clear intent, we can suggest using `if let` ```rust for _ in f() {} // turns into if let Some(_) = f() {} ``` (P.S. `Some` and `Ok` are interchangeable depending on the type) I still feel that the lint wording/look is somewhat off, so I'll be happy to hear suggestions (on how to improve suggestions :D)! Resolves #99272 [`clippy::for_loops_over_fallibles`]: https://rust-lang.github.io/rust-clippy/master/index.html#for_loops_over_fallibles
2 parents e7a5249 + 7cfc6fa commit 5577e42

18 files changed

+36
-351
lines changed

clippy_lints/src/lib.register_all.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
109109
LintId::of(loops::EMPTY_LOOP),
110110
LintId::of(loops::EXPLICIT_COUNTER_LOOP),
111111
LintId::of(loops::FOR_KV_MAP),
112-
LintId::of(loops::FOR_LOOPS_OVER_FALLIBLES),
113112
LintId::of(loops::ITER_NEXT_LOOP),
114113
LintId::of(loops::MANUAL_FIND),
115114
LintId::of(loops::MANUAL_FLATTEN),

clippy_lints/src/lib.register_lints.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,6 @@ store.register_lints(&[
227227
loops::EXPLICIT_INTO_ITER_LOOP,
228228
loops::EXPLICIT_ITER_LOOP,
229229
loops::FOR_KV_MAP,
230-
loops::FOR_LOOPS_OVER_FALLIBLES,
231230
loops::ITER_NEXT_LOOP,
232231
loops::MANUAL_FIND,
233232
loops::MANUAL_FLATTEN,

clippy_lints/src/lib.register_suspicious.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), vec!
2121
LintId::of(formatting::SUSPICIOUS_ELSE_FORMATTING),
2222
LintId::of(formatting::SUSPICIOUS_UNARY_OP_FORMATTING),
2323
LintId::of(loops::EMPTY_LOOP),
24-
LintId::of(loops::FOR_LOOPS_OVER_FALLIBLES),
2524
LintId::of(loops::MUT_RANGE_BOUND),
2625
LintId::of(methods::NO_EFFECT_REPLACE),
2726
LintId::of(methods::SUSPICIOUS_MAP),

clippy_lints/src/loops/for_loops_over_fallibles.rs

Lines changed: 0 additions & 65 deletions
This file was deleted.

clippy_lints/src/loops/iter_next_loop.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use rustc_hir::Expr;
55
use rustc_lint::LateContext;
66
use rustc_span::sym;
77

8-
pub(super) fn check(cx: &LateContext<'_>, arg: &Expr<'_>) -> bool {
8+
pub(super) fn check(cx: &LateContext<'_>, arg: &Expr<'_>) {
99
if is_trait_method(cx, arg, sym::Iterator) {
1010
span_lint(
1111
cx,
@@ -14,8 +14,5 @@ pub(super) fn check(cx: &LateContext<'_>, arg: &Expr<'_>) -> bool {
1414
"you are iterating over `Iterator::next()` which is an Option; this will compile but is \
1515
probably not what you want",
1616
);
17-
true
18-
} else {
19-
false
2017
}
2118
}

clippy_lints/src/loops/mod.rs

Lines changed: 2 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ mod explicit_counter_loop;
33
mod explicit_into_iter_loop;
44
mod explicit_iter_loop;
55
mod for_kv_map;
6-
mod for_loops_over_fallibles;
76
mod iter_next_loop;
87
mod manual_find;
98
mod manual_flatten;
@@ -173,49 +172,6 @@ declare_clippy_lint! {
173172
"for-looping over `_.next()` which is probably not intended"
174173
}
175174

176-
declare_clippy_lint! {
177-
/// ### What it does
178-
/// Checks for `for` loops over `Option` or `Result` values.
179-
///
180-
/// ### Why is this bad?
181-
/// Readability. This is more clearly expressed as an `if
182-
/// let`.
183-
///
184-
/// ### Example
185-
/// ```rust
186-
/// # let opt = Some(1);
187-
/// # let res: Result<i32, std::io::Error> = Ok(1);
188-
/// for x in opt {
189-
/// // ..
190-
/// }
191-
///
192-
/// for x in &res {
193-
/// // ..
194-
/// }
195-
///
196-
/// for x in res.iter() {
197-
/// // ..
198-
/// }
199-
/// ```
200-
///
201-
/// Use instead:
202-
/// ```rust
203-
/// # let opt = Some(1);
204-
/// # let res: Result<i32, std::io::Error> = Ok(1);
205-
/// if let Some(x) = opt {
206-
/// // ..
207-
/// }
208-
///
209-
/// if let Ok(x) = res {
210-
/// // ..
211-
/// }
212-
/// ```
213-
#[clippy::version = "1.45.0"]
214-
pub FOR_LOOPS_OVER_FALLIBLES,
215-
suspicious,
216-
"for-looping over an `Option` or a `Result`, which is more clearly expressed as an `if let`"
217-
}
218-
219175
declare_clippy_lint! {
220176
/// ### What it does
221177
/// Detects `loop + match` combinations that are easier
@@ -648,7 +604,6 @@ declare_lint_pass!(Loops => [
648604
EXPLICIT_ITER_LOOP,
649605
EXPLICIT_INTO_ITER_LOOP,
650606
ITER_NEXT_LOOP,
651-
FOR_LOOPS_OVER_FALLIBLES,
652607
WHILE_LET_LOOP,
653608
NEEDLESS_COLLECT,
654609
EXPLICIT_COUNTER_LOOP,
@@ -739,30 +694,22 @@ fn check_for_loop<'tcx>(
739694
manual_find::check(cx, pat, arg, body, span, expr);
740695
}
741696

742-
fn check_for_loop_arg(cx: &LateContext<'_>, pat: &Pat<'_>, arg: &Expr<'_>) {
743-
let mut next_loop_linted = false; // whether or not ITER_NEXT_LOOP lint was used
744-
697+
fn check_for_loop_arg(cx: &LateContext<'_>, _: &Pat<'_>, arg: &Expr<'_>) {
745698
if let ExprKind::MethodCall(method, self_arg, [], _) = arg.kind {
746699
let method_name = method.ident.as_str();
747700
// check for looping over x.iter() or x.iter_mut(), could use &x or &mut x
748701
match method_name {
749702
"iter" | "iter_mut" => {
750703
explicit_iter_loop::check(cx, self_arg, arg, method_name);
751-
for_loops_over_fallibles::check(cx, pat, self_arg, Some(method_name));
752704
},
753705
"into_iter" => {
754706
explicit_iter_loop::check(cx, self_arg, arg, method_name);
755707
explicit_into_iter_loop::check(cx, self_arg, arg);
756-
for_loops_over_fallibles::check(cx, pat, self_arg, Some(method_name));
757708
},
758709
"next" => {
759-
next_loop_linted = iter_next_loop::check(cx, arg);
710+
iter_next_loop::check(cx, arg);
760711
},
761712
_ => {},
762713
}
763714
}
764-
765-
if !next_loop_linted {
766-
for_loops_over_fallibles::check(cx, pat, arg, None);
767-
}
768715
}

clippy_lints/src/renamed_lints.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ pub static RENAMED_LINTS: &[(&str, &str)] = &[
1111
("clippy::disallowed_method", "clippy::disallowed_methods"),
1212
("clippy::disallowed_type", "clippy::disallowed_types"),
1313
("clippy::eval_order_dependence", "clippy::mixed_read_write_in_expression"),
14-
("clippy::for_loop_over_option", "clippy::for_loops_over_fallibles"),
15-
("clippy::for_loop_over_result", "clippy::for_loops_over_fallibles"),
14+
("clippy::for_loop_over_option", "for_loops_over_fallibles"),
15+
("clippy::for_loop_over_result", "for_loops_over_fallibles"),
1616
("clippy::identity_conversion", "clippy::useless_conversion"),
1717
("clippy::if_let_some_result", "clippy::match_result_ok"),
1818
("clippy::logic_bug", "clippy::overly_complex_bool_expr"),
@@ -31,6 +31,7 @@ pub static RENAMED_LINTS: &[(&str, &str)] = &[
3131
("clippy::to_string_in_display", "clippy::recursive_format_impl"),
3232
("clippy::zero_width_space", "clippy::invisible_characters"),
3333
("clippy::drop_bounds", "drop_bounds"),
34+
("clippy::for_loops_over_fallibles", "for_loops_over_fallibles"),
3435
("clippy::into_iter_on_array", "array_into_iter"),
3536
("clippy::invalid_atomic_ordering", "invalid_atomic_ordering"),
3637
("clippy::invalid_ref", "invalid_value"),

src/docs.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,6 @@ docs! {
170170
"fn_to_numeric_cast_any",
171171
"fn_to_numeric_cast_with_truncation",
172172
"for_kv_map",
173-
"for_loops_over_fallibles",
174173
"forget_copy",
175174
"forget_non_drop",
176175
"forget_ref",

src/docs/for_loops_over_fallibles.txt

Lines changed: 0 additions & 32 deletions
This file was deleted.

tests/ui/for_loop_unfixable.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
clippy::for_kv_map
99
)]
1010
#[allow(clippy::linkedlist, clippy::unnecessary_mut_passed, clippy::similar_names)]
11+
#[allow(for_loops_over_fallibles)]
1112
fn main() {
1213
let vec = vec![1, 2, 3, 4];
1314

tests/ui/for_loop_unfixable.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: you are iterating over `Iterator::next()` which is an Option; this will compile but is probably not what you want
2-
--> $DIR/for_loop_unfixable.rs:14:15
2+
--> $DIR/for_loop_unfixable.rs:15:15
33
|
44
LL | for _v in vec.iter().next() {}
55
| ^^^^^^^^^^^^^^^^^

tests/ui/for_loops_over_fallibles.rs

Lines changed: 0 additions & 73 deletions
This file was deleted.

0 commit comments

Comments
 (0)