Skip to content

Commit a2a9b1d

Browse files
committed
Auto merge of #7608 - andrewpollack:7594/while_let_some_result, r=Manishearth
#7594: Adding new 'while_let_some_result' linting Excited for the opportunity to contribute to Clippy! Since the latest Bay Area Rust Meetup, I've been looking for an opportunity and found it 😄 Please let me know how I can improve this PR! Much of it is similar to ``[`if_let_some_result`]``, but I followed the description in the issue to create its own linting rules. Looking forward to feedback, and continuing to work on Clippy in the future! changelog: Renamed Lint: `if_let_some_result` is now called [`match_result_ok`]. Now also handles `while let` case.
2 parents 0c8799d + 17155c8 commit a2a9b1d

8 files changed

+185
-87
lines changed

CHANGELOG.md

+6-2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ document.
88

99
[74d1561...master](https://github.com/rust-lang/rust-clippy/compare/74d1561...master)
1010

11+
### New Lints
12+
13+
* Renamed Lint: `if_let_some_result` is now called [`match_result_ok`]. Now also handles `while let` case.
14+
1115
## Rust 1.55
1216

1317
Current beta, release 2021-09-09
@@ -1491,7 +1495,7 @@ Released 2020-03-12
14911495
* `unknown_clippy_lints` [#4963](https://github.com/rust-lang/rust-clippy/pull/4963)
14921496
* [`explicit_into_iter_loop`] [#4978](https://github.com/rust-lang/rust-clippy/pull/4978)
14931497
* [`useless_attribute`] [#5022](https://github.com/rust-lang/rust-clippy/pull/5022)
1494-
* [`if_let_some_result`] [#5032](https://github.com/rust-lang/rust-clippy/pull/5032)
1498+
* `if_let_some_result` [#5032](https://github.com/rust-lang/rust-clippy/pull/5032)
14951499

14961500
### ICE fixes
14971501

@@ -2685,7 +2689,6 @@ Released 2018-09-13
26852689
[`identity_op`]: https://rust-lang.github.io/rust-clippy/master/index.html#identity_op
26862690
[`if_let_mutex`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_let_mutex
26872691
[`if_let_redundant_pattern_matching`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_let_redundant_pattern_matching
2688-
[`if_let_some_result`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_let_some_result
26892692
[`if_not_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_not_else
26902693
[`if_same_then_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_same_then_else
26912694
[`if_then_panic`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_then_panic
@@ -2775,6 +2778,7 @@ Released 2018-09-13
27752778
[`match_on_vec_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_on_vec_items
27762779
[`match_overlapping_arm`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_overlapping_arm
27772780
[`match_ref_pats`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_ref_pats
2781+
[`match_result_ok`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_result_ok
27782782
[`match_same_arms`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_same_arms
27792783
[`match_single_binding`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_single_binding
27802784
[`match_wild_err_arm`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_wild_err_arm

clippy_lints/src/lib.rs

+6-5
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,6 @@ mod future_not_send;
225225
mod get_last_with_len;
226226
mod identity_op;
227227
mod if_let_mutex;
228-
mod if_let_some_result;
229228
mod if_not_else;
230229
mod if_then_panic;
231230
mod if_then_some_else_none;
@@ -264,6 +263,7 @@ mod map_clone;
264263
mod map_err_ignore;
265264
mod map_unit_fn;
266265
mod match_on_vec_items;
266+
mod match_result_ok;
267267
mod matches;
268268
mod mem_discriminant;
269269
mod mem_forget;
@@ -658,7 +658,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
658658
get_last_with_len::GET_LAST_WITH_LEN,
659659
identity_op::IDENTITY_OP,
660660
if_let_mutex::IF_LET_MUTEX,
661-
if_let_some_result::IF_LET_SOME_RESULT,
662661
if_not_else::IF_NOT_ELSE,
663662
if_then_panic::IF_THEN_PANIC,
664663
if_then_some_else_none::IF_THEN_SOME_ELSE_NONE,
@@ -728,6 +727,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
728727
map_unit_fn::OPTION_MAP_UNIT_FN,
729728
map_unit_fn::RESULT_MAP_UNIT_FN,
730729
match_on_vec_items::MATCH_ON_VEC_ITEMS,
730+
match_result_ok::MATCH_RESULT_OK,
731731
matches::INFALLIBLE_DESTRUCTURING_MATCH,
732732
matches::MATCH_AS_REF,
733733
matches::MATCH_BOOL,
@@ -1259,7 +1259,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
12591259
LintId::of(get_last_with_len::GET_LAST_WITH_LEN),
12601260
LintId::of(identity_op::IDENTITY_OP),
12611261
LintId::of(if_let_mutex::IF_LET_MUTEX),
1262-
LintId::of(if_let_some_result::IF_LET_SOME_RESULT),
12631262
LintId::of(if_then_panic::IF_THEN_PANIC),
12641263
LintId::of(indexing_slicing::OUT_OF_BOUNDS_INDEXING),
12651264
LintId::of(infinite_iter::INFINITE_ITER),
@@ -1303,6 +1302,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
13031302
LintId::of(map_clone::MAP_CLONE),
13041303
LintId::of(map_unit_fn::OPTION_MAP_UNIT_FN),
13051304
LintId::of(map_unit_fn::RESULT_MAP_UNIT_FN),
1305+
LintId::of(match_result_ok::MATCH_RESULT_OK),
13061306
LintId::of(matches::INFALLIBLE_DESTRUCTURING_MATCH),
13071307
LintId::of(matches::MATCH_AS_REF),
13081308
LintId::of(matches::MATCH_LIKE_MATCHES_MACRO),
@@ -1513,7 +1513,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
15131513
LintId::of(functions::DOUBLE_MUST_USE),
15141514
LintId::of(functions::MUST_USE_UNIT),
15151515
LintId::of(functions::RESULT_UNIT_ERR),
1516-
LintId::of(if_let_some_result::IF_LET_SOME_RESULT),
15171516
LintId::of(if_then_panic::IF_THEN_PANIC),
15181517
LintId::of(inherent_to_string::INHERENT_TO_STRING),
15191518
LintId::of(len_zero::COMPARISON_TO_EMPTY),
@@ -1530,6 +1529,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
15301529
LintId::of(manual_map::MANUAL_MAP),
15311530
LintId::of(manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE),
15321531
LintId::of(map_clone::MAP_CLONE),
1532+
LintId::of(match_result_ok::MATCH_RESULT_OK),
15331533
LintId::of(matches::INFALLIBLE_DESTRUCTURING_MATCH),
15341534
LintId::of(matches::MATCH_LIKE_MATCHES_MACRO),
15351535
LintId::of(matches::MATCH_OVERLAPPING_ARM),
@@ -1985,7 +1985,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
19851985
store.register_late_pass(|| Box::new(missing_doc::MissingDoc::new()));
19861986
store.register_late_pass(|| Box::new(missing_inline::MissingInline));
19871987
store.register_late_pass(move || Box::new(exhaustive_items::ExhaustiveItems));
1988-
store.register_late_pass(|| Box::new(if_let_some_result::OkIfLet));
1988+
store.register_late_pass(|| Box::new(match_result_ok::MatchResultOk));
19891989
store.register_late_pass(|| Box::new(partialeq_ne_impl::PartialEqNeImpl));
19901990
store.register_late_pass(|| Box::new(unused_io_amount::UnusedIoAmount));
19911991
let enum_variant_size_threshold = conf.enum_variant_size_threshold;
@@ -2212,6 +2212,7 @@ pub fn register_renamed(ls: &mut rustc_lint::LintStore) {
22122212
ls.register_renamed("clippy::identity_conversion", "clippy::useless_conversion");
22132213
ls.register_renamed("clippy::zero_width_space", "clippy::invisible_characters");
22142214
ls.register_renamed("clippy::single_char_push_str", "clippy::single_char_add_str");
2215+
ls.register_renamed("clippy::if_let_some_result", "clippy::match_result_ok");
22152216

22162217
// uplifted lints
22172218
ls.register_renamed("clippy::invalid_ref", "invalid_value");

clippy_lints/src/if_let_some_result.rs clippy_lints/src/match_result_ok.rs

+32-20
Original file line numberDiff line numberDiff line change
@@ -12,58 +12,70 @@ use rustc_span::sym;
1212

1313
declare_clippy_lint! {
1414
/// ### What it does
15-
///* Checks for unnecessary `ok()` in if let.
15+
/// Checks for unnecessary `ok()` in `while let`.
1616
///
1717
/// ### Why is this bad?
18-
/// Calling `ok()` in if let is unnecessary, instead match
18+
/// Calling `ok()` in `while let` is unnecessary, instead match
1919
/// on `Ok(pat)`
2020
///
2121
/// ### Example
2222
/// ```ignore
23-
/// for i in iter {
24-
/// if let Some(value) = i.parse().ok() {
25-
/// vec.push(value)
26-
/// }
23+
/// while let Some(value) = iter.next().ok() {
24+
/// vec.push(value)
2725
/// }
28-
/// ```
29-
/// Could be written:
3026
///
27+
/// if let Some(valie) = iter.next().ok() {
28+
/// vec.push(value)
29+
/// }
30+
/// ```
31+
/// Use instead:
3132
/// ```ignore
32-
/// for i in iter {
33-
/// if let Ok(value) = i.parse() {
34-
/// vec.push(value)
35-
/// }
33+
/// while let Ok(value) = iter.next() {
34+
/// vec.push(value)
35+
/// }
36+
///
37+
/// if let Ok(value) = iter.next() {
38+
/// vec.push_value)
3639
/// }
3740
/// ```
38-
pub IF_LET_SOME_RESULT,
41+
pub MATCH_RESULT_OK,
3942
style,
40-
"usage of `ok()` in `if let Some(pat)` statements is unnecessary, match on `Ok(pat)` instead"
43+
"usage of `ok()` in `let Some(pat)` statements is unnecessary, match on `Ok(pat)` instead"
4144
}
4245

43-
declare_lint_pass!(OkIfLet => [IF_LET_SOME_RESULT]);
46+
declare_lint_pass!(MatchResultOk => [MATCH_RESULT_OK]);
4447

45-
impl<'tcx> LateLintPass<'tcx> for OkIfLet {
48+
impl<'tcx> LateLintPass<'tcx> for MatchResultOk {
4649
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
47-
if_chain! { //begin checking variables
48-
if let Some(higher::IfLet { let_pat, let_expr, .. }) = higher::IfLet::hir(cx, expr);
50+
let (let_pat, let_expr, ifwhile) = if let Some(higher::IfLet { let_pat, let_expr, .. }) = higher::IfLet::hir(cx, expr) {
51+
(let_pat, let_expr, "if")
52+
} else if let Some(higher::WhileLet { let_pat, let_expr, .. }) = higher::WhileLet::hir(expr) {
53+
(let_pat, let_expr, "while")
54+
} else {
55+
return
56+
};
57+
58+
if_chain! {
4959
if let ExprKind::MethodCall(_, ok_span, [ref result_types_0, ..], _) = let_expr.kind; //check is expr.ok() has type Result<T,E>.ok(, _)
5060
if let PatKind::TupleStruct(QPath::Resolved(_, x), y, _) = let_pat.kind; //get operation
5161
if method_chain_args(let_expr, &["ok"]).is_some(); //test to see if using ok() methoduse std::marker::Sized;
5262
if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(result_types_0), sym::result_type);
5363
if rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_path(x, false)) == "Some";
5464

5565
then {
66+
5667
let mut applicability = Applicability::MachineApplicable;
5768
let some_expr_string = snippet_with_applicability(cx, y[0].span, "", &mut applicability);
5869
let trimmed_ok = snippet_with_applicability(cx, let_expr.span.until(ok_span), "", &mut applicability);
5970
let sugg = format!(
60-
"if let Ok({}) = {}",
71+
"{} let Ok({}) = {}",
72+
ifwhile,
6173
some_expr_string,
6274
trimmed_ok.trim().trim_end_matches('.'),
6375
);
6476
span_lint_and_sugg(
6577
cx,
66-
IF_LET_SOME_RESULT,
78+
MATCH_RESULT_OK,
6779
expr.span.with_hi(let_expr.span.hi()),
6880
"matching on `Some` with `ok()` is redundant",
6981
&format!("consider matching on `Ok({})` and removing the call to `ok` instead", some_expr_string),

tests/ui/if_let_some_result.fixed

-28
This file was deleted.

tests/ui/if_let_some_result.rs

-28
This file was deleted.

tests/ui/match_result_ok.fixed

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// run-rustfix
2+
3+
#![warn(clippy::match_result_ok)]
4+
#![allow(clippy::boxed_local)]
5+
#![allow(dead_code)]
6+
7+
// Checking `if` cases
8+
9+
fn str_to_int(x: &str) -> i32 {
10+
if let Ok(y) = x.parse() { y } else { 0 }
11+
}
12+
13+
fn str_to_int_ok(x: &str) -> i32 {
14+
if let Ok(y) = x.parse() { y } else { 0 }
15+
}
16+
17+
#[rustfmt::skip]
18+
fn strange_some_no_else(x: &str) -> i32 {
19+
{
20+
if let Ok(y) = x . parse() {
21+
return y;
22+
};
23+
0
24+
}
25+
}
26+
27+
// Checking `while` cases
28+
29+
struct Wat {
30+
counter: i32,
31+
}
32+
33+
impl Wat {
34+
fn next(&mut self) -> Result<i32, &str> {
35+
self.counter += 1;
36+
if self.counter < 5 {
37+
Ok(self.counter)
38+
} else {
39+
Err("Oh no")
40+
}
41+
}
42+
}
43+
44+
fn base_1(x: i32) {
45+
let mut wat = Wat { counter: x };
46+
while let Ok(a) = wat.next() {
47+
println!("{}", a);
48+
}
49+
}
50+
51+
fn base_2(x: i32) {
52+
let mut wat = Wat { counter: x };
53+
while let Ok(a) = wat.next() {
54+
println!("{}", a);
55+
}
56+
}
57+
58+
fn base_3(test_func: Box<Result<i32, &str>>) {
59+
// Expected to stay as is
60+
while let Some(_b) = test_func.ok() {}
61+
}
62+
63+
fn main() {}

tests/ui/match_result_ok.rs

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// run-rustfix
2+
3+
#![warn(clippy::match_result_ok)]
4+
#![allow(clippy::boxed_local)]
5+
#![allow(dead_code)]
6+
7+
// Checking `if` cases
8+
9+
fn str_to_int(x: &str) -> i32 {
10+
if let Some(y) = x.parse().ok() { y } else { 0 }
11+
}
12+
13+
fn str_to_int_ok(x: &str) -> i32 {
14+
if let Ok(y) = x.parse() { y } else { 0 }
15+
}
16+
17+
#[rustfmt::skip]
18+
fn strange_some_no_else(x: &str) -> i32 {
19+
{
20+
if let Some(y) = x . parse() . ok () {
21+
return y;
22+
};
23+
0
24+
}
25+
}
26+
27+
// Checking `while` cases
28+
29+
struct Wat {
30+
counter: i32,
31+
}
32+
33+
impl Wat {
34+
fn next(&mut self) -> Result<i32, &str> {
35+
self.counter += 1;
36+
if self.counter < 5 {
37+
Ok(self.counter)
38+
} else {
39+
Err("Oh no")
40+
}
41+
}
42+
}
43+
44+
fn base_1(x: i32) {
45+
let mut wat = Wat { counter: x };
46+
while let Some(a) = wat.next().ok() {
47+
println!("{}", a);
48+
}
49+
}
50+
51+
fn base_2(x: i32) {
52+
let mut wat = Wat { counter: x };
53+
while let Ok(a) = wat.next() {
54+
println!("{}", a);
55+
}
56+
}
57+
58+
fn base_3(test_func: Box<Result<i32, &str>>) {
59+
// Expected to stay as is
60+
while let Some(_b) = test_func.ok() {}
61+
}
62+
63+
fn main() {}

0 commit comments

Comments
 (0)