From 9035264a8febac258d1def1d27978ab8cd1ff121 Mon Sep 17 00:00:00 2001 From: Yuki Okushi <huyuumi.dev@gmail.com> Date: Fri, 10 Jan 2020 08:34:13 +0900 Subject: [PATCH 1/7] Add suggestion in `if_let_some_result` --- clippy_lints/src/ok_if_let.rs | 33 ++++++++++++++++++++++++++------- tests/ui/ok_if_let.fixed | 35 +++++++++++++++++++++++++++++++++++ tests/ui/ok_if_let.rs | 20 ++++++++++++++++---- tests/ui/ok_if_let.stderr | 28 +++++++++++++++++++++++++--- 4 files changed, 102 insertions(+), 14 deletions(-) create mode 100644 tests/ui/ok_if_let.fixed diff --git a/clippy_lints/src/ok_if_let.rs b/clippy_lints/src/ok_if_let.rs index 6145fae3156..9696951ac0c 100644 --- a/clippy_lints/src/ok_if_let.rs +++ b/clippy_lints/src/ok_if_let.rs @@ -1,5 +1,6 @@ -use crate::utils::{match_type, method_chain_args, paths, snippet, span_help_and_lint}; +use crate::utils::{match_type, method_chain_args, paths, snippet, snippet_with_applicability, span_lint_and_sugg}; use if_chain::if_chain; +use rustc_errors::Applicability; use rustc_hir::*; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -40,18 +41,36 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for OkIfLet { fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) { if_chain! { //begin checking variables if let ExprKind::Match(ref op, ref body, ref source) = expr.kind; //test if expr is a match - if let MatchSource::IfLetDesugar { .. } = *source; //test if it is an If Let - if let ExprKind::MethodCall(_, _, ref result_types) = op.kind; //check is expr.ok() has type Result<T,E>.ok() + if let MatchSource::IfLetDesugar { contains_else_clause } = *source; //test if it is an If Let + if let ExprKind::MethodCall(_, ok_span, ref result_types) = op.kind; //check is expr.ok() has type Result<T,E>.ok() if let PatKind::TupleStruct(QPath::Resolved(_, ref x), ref y, _) = body[0].pat.kind; //get operation if method_chain_args(op, &["ok"]).is_some(); //test to see if using ok() methoduse std::marker::Sized; then { let is_result_type = match_type(cx, cx.tables.expr_ty(&result_types[0]), &paths::RESULT); - let some_expr_string = snippet(cx, y[0].span, ""); + let mut applicability = Applicability::MachineApplicable; + let some_expr_string = snippet_with_applicability(cx, y[0].span, "", &mut applicability); + let trimmed_ok = snippet_with_applicability(cx, op.span.until(ok_span), "", &mut applicability); + let mut sugg = format!( + "if let Ok({}) = {} {}", + some_expr_string, + // FIXME(JohnTitor): this trimming is hacky, probably can improve it + trimmed_ok.trim_matches('.'), + snippet(cx, body[0].span, ".."), + ); + if contains_else_clause { + sugg = format!("{} else {}", sugg, snippet(cx, body[1].span, "..")); + } if print::to_string(print::NO_ANN, |s| s.print_path(x, false)) == "Some" && is_result_type { - span_help_and_lint(cx, IF_LET_SOME_RESULT, expr.span, - "Matching on `Some` with `ok()` is redundant", - &format!("Consider matching on `Ok({})` and removing the call to `ok` instead", some_expr_string)); + span_lint_and_sugg( + cx, + IF_LET_SOME_RESULT, + expr.span, + "Matching on `Some` with `ok()` is redundant", + &format!("Consider matching on `Ok({})` and removing the call to `ok` instead", some_expr_string), + sugg, + applicability, + ); } } } diff --git a/tests/ui/ok_if_let.fixed b/tests/ui/ok_if_let.fixed new file mode 100644 index 00000000000..e7fdc972a19 --- /dev/null +++ b/tests/ui/ok_if_let.fixed @@ -0,0 +1,35 @@ +// run-rustfix + +#![warn(clippy::if_let_some_result)] + +fn str_to_int(x: &str) -> i32 { + if let Ok(y) = x.parse() { + y + } else { + 0 + } +} + +fn str_to_int_ok(x: &str) -> i32 { + if let Ok(y) = x.parse() { + y + } else { + 0 + } +} + +fn nested_some_no_else(x: &str) -> i32 { + { + if let Ok(y) = x.parse() { + return y; + }; + 0 + } +} + +fn main() { + let x = str_to_int("1"); + let y = str_to_int_ok("2"); + let z = nested_some_no_else("3"); + println!("{}{}{}", x, y, z); +} diff --git a/tests/ui/ok_if_let.rs b/tests/ui/ok_if_let.rs index 61db3113052..becadf3644f 100644 --- a/tests/ui/ok_if_let.rs +++ b/tests/ui/ok_if_let.rs @@ -1,3 +1,5 @@ +// run-rustfix + #![warn(clippy::if_let_some_result)] fn str_to_int(x: &str) -> i32 { @@ -16,8 +18,18 @@ fn str_to_int_ok(x: &str) -> i32 { } } -fn main() { - let y = str_to_int("1"); - let z = str_to_int_ok("2"); - println!("{}{}", y, z); +fn nested_some_no_else(x: &str) -> i32 { + { + if let Some(y) = x.parse().ok() { + return y; + }; + 0 + } +} + +fn main() { + let x = str_to_int("1"); + let y = str_to_int_ok("2"); + let z = nested_some_no_else("3"); + println!("{}{}{}", x, y, z); } diff --git a/tests/ui/ok_if_let.stderr b/tests/ui/ok_if_let.stderr index e3e6c5c4634..4aa6057ba47 100644 --- a/tests/ui/ok_if_let.stderr +++ b/tests/ui/ok_if_let.stderr @@ -1,5 +1,5 @@ error: Matching on `Some` with `ok()` is redundant - --> $DIR/ok_if_let.rs:4:5 + --> $DIR/ok_if_let.rs:6:5 | LL | / if let Some(y) = x.parse().ok() { LL | | y @@ -9,7 +9,29 @@ LL | | } | |_____^ | = note: `-D clippy::if-let-some-result` implied by `-D warnings` - = help: Consider matching on `Ok(y)` and removing the call to `ok` instead +help: Consider matching on `Ok(y)` and removing the call to `ok` instead + | +LL | if let Ok(y) = x.parse() { +LL | y +LL | } else { +LL | 0 +LL | } + | -error: aborting due to previous error +error: Matching on `Some` with `ok()` is redundant + --> $DIR/ok_if_let.rs:23:9 + | +LL | / if let Some(y) = x.parse().ok() { +LL | | return y; +LL | | }; + | |_________^ + | +help: Consider matching on `Ok(y)` and removing the call to `ok` instead + | +LL | if let Ok(y) = x.parse() { +LL | return y; +LL | }; + | + +error: aborting due to 2 previous errors From 9e55424bdc4b837e38a7f52139ad6158d7818102 Mon Sep 17 00:00:00 2001 From: Yuki Okushi <huyuumi.dev@gmail.com> Date: Sat, 11 Jan 2020 03:05:10 +0900 Subject: [PATCH 2/7] Apply review comments --- clippy_lints/src/ok_if_let.rs | 11 ++++++----- tests/ui/ok_if_let.fixed | 7 +++---- tests/ui/ok_if_let.rs | 7 +++---- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/clippy_lints/src/ok_if_let.rs b/clippy_lints/src/ok_if_let.rs index 9696951ac0c..dc129a28e37 100644 --- a/clippy_lints/src/ok_if_let.rs +++ b/clippy_lints/src/ok_if_let.rs @@ -4,6 +4,7 @@ use rustc_errors::Applicability; use rustc_hir::*; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::BytePos; declare_clippy_lint! { /// **What it does:*** Checks for unnecessary `ok()` in if let. @@ -40,8 +41,8 @@ declare_lint_pass!(OkIfLet => [IF_LET_SOME_RESULT]); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for OkIfLet { fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) { if_chain! { //begin checking variables - if let ExprKind::Match(ref op, ref body, ref source) = expr.kind; //test if expr is a match - if let MatchSource::IfLetDesugar { contains_else_clause } = *source; //test if it is an If Let + if let ExprKind::Match(ref op, ref body, source) = expr.kind; //test if expr is a match + if let MatchSource::IfLetDesugar { contains_else_clause } = source; //test if it is an If Let if let ExprKind::MethodCall(_, ok_span, ref result_types) = op.kind; //check is expr.ok() has type Result<T,E>.ok() if let PatKind::TupleStruct(QPath::Resolved(_, ref x), ref y, _) = body[0].pat.kind; //get operation if method_chain_args(op, &["ok"]).is_some(); //test to see if using ok() methoduse std::marker::Sized; @@ -49,13 +50,13 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for OkIfLet { then { let is_result_type = match_type(cx, cx.tables.expr_ty(&result_types[0]), &paths::RESULT); let mut applicability = Applicability::MachineApplicable; + let trimed_ok_span = op.span.until(op.span.with_lo(ok_span.lo() - BytePos(1))); let some_expr_string = snippet_with_applicability(cx, y[0].span, "", &mut applicability); - let trimmed_ok = snippet_with_applicability(cx, op.span.until(ok_span), "", &mut applicability); + let trimmed_ok = snippet_with_applicability(cx, trimed_ok_span, "", &mut applicability); let mut sugg = format!( "if let Ok({}) = {} {}", some_expr_string, - // FIXME(JohnTitor): this trimming is hacky, probably can improve it - trimmed_ok.trim_matches('.'), + trimmed_ok, snippet(cx, body[0].span, ".."), ); if contains_else_clause { diff --git a/tests/ui/ok_if_let.fixed b/tests/ui/ok_if_let.fixed index e7fdc972a19..439c749f995 100644 --- a/tests/ui/ok_if_let.fixed +++ b/tests/ui/ok_if_let.fixed @@ -28,8 +28,7 @@ fn nested_some_no_else(x: &str) -> i32 { } fn main() { - let x = str_to_int("1"); - let y = str_to_int_ok("2"); - let z = nested_some_no_else("3"); - println!("{}{}{}", x, y, z); + let _ = str_to_int("1"); + let _ = str_to_int_ok("2"); + let _ = nested_some_no_else("3"); } diff --git a/tests/ui/ok_if_let.rs b/tests/ui/ok_if_let.rs index becadf3644f..83f6ce1d330 100644 --- a/tests/ui/ok_if_let.rs +++ b/tests/ui/ok_if_let.rs @@ -28,8 +28,7 @@ fn nested_some_no_else(x: &str) -> i32 { } fn main() { - let x = str_to_int("1"); - let y = str_to_int_ok("2"); - let z = nested_some_no_else("3"); - println!("{}{}{}", x, y, z); + let _ = str_to_int("1"); + let _ = str_to_int_ok("2"); + let _ = nested_some_no_else("3"); } From ae872fe1c74d68d7d1e88079cc77c858268fcdbf Mon Sep 17 00:00:00 2001 From: Yuki Okushi <huyuumi.dev@gmail.com> Date: Sat, 11 Jan 2020 03:29:55 +0900 Subject: [PATCH 3/7] Rename `ok_if_let` to `if_let_some_result` --- .../src/{ok_if_let.rs => if_let_some_result.rs} | 0 clippy_lints/src/lib.rs | 10 +++++----- src/lintlist/mod.rs | 2 +- tests/ui/{ok_if_let.fixed => if_let_some_result.fixed} | 0 tests/ui/{ok_if_let.rs => if_let_some_result.rs} | 0 .../ui/{ok_if_let.stderr => if_let_some_result.stderr} | 4 ++-- 6 files changed, 8 insertions(+), 8 deletions(-) rename clippy_lints/src/{ok_if_let.rs => if_let_some_result.rs} (100%) rename tests/ui/{ok_if_let.fixed => if_let_some_result.fixed} (100%) rename tests/ui/{ok_if_let.rs => if_let_some_result.rs} (100%) rename tests/ui/{ok_if_let.stderr => if_let_some_result.stderr} (91%) diff --git a/clippy_lints/src/ok_if_let.rs b/clippy_lints/src/if_let_some_result.rs similarity index 100% rename from clippy_lints/src/ok_if_let.rs rename to clippy_lints/src/if_let_some_result.rs diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 5fe0d937f2f..8a90e39f2e9 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -210,6 +210,7 @@ pub mod functions; pub mod get_last_with_len; pub mod identity_conversion; pub mod identity_op; +pub mod if_let_some_result; pub mod if_not_else; pub mod implicit_return; pub mod indexing_slicing; @@ -263,7 +264,6 @@ pub mod new_without_default; pub mod no_effect; pub mod non_copy_const; pub mod non_expressive_names; -pub mod ok_if_let; pub mod open_options; pub mod overflow_check_conditional; pub mod panic_unimplemented; @@ -703,7 +703,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &non_expressive_names::JUST_UNDERSCORES_AND_DIGITS, &non_expressive_names::MANY_SINGLE_CHAR_NAMES, &non_expressive_names::SIMILAR_NAMES, - &ok_if_let::IF_LET_SOME_RESULT, + &if_let_some_result::IF_LET_SOME_RESULT, &open_options::NONSENSICAL_OPEN_OPTIONS, &overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL, &panic_unimplemented::PANIC, @@ -904,7 +904,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box eval_order_dependence::EvalOrderDependence); store.register_late_pass(|| box missing_doc::MissingDoc::new()); store.register_late_pass(|| box missing_inline::MissingInline); - store.register_late_pass(|| box ok_if_let::OkIfLet); + store.register_late_pass(|| box if_let_some_result::OkIfLet); store.register_late_pass(|| box redundant_pattern_matching::RedundantPatternMatching); store.register_late_pass(|| box partialeq_ne_impl::PartialEqNeImpl); store.register_late_pass(|| box unused_io_amount::UnusedIoAmount); @@ -1265,7 +1265,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST), LintId::of(&non_expressive_names::JUST_UNDERSCORES_AND_DIGITS), LintId::of(&non_expressive_names::MANY_SINGLE_CHAR_NAMES), - LintId::of(&ok_if_let::IF_LET_SOME_RESULT), + LintId::of(&if_let_some_result::IF_LET_SOME_RESULT), LintId::of(&open_options::NONSENSICAL_OPEN_OPTIONS), LintId::of(&overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL), LintId::of(&panic_unimplemented::PANIC_PARAMS), @@ -1413,7 +1413,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&new_without_default::NEW_WITHOUT_DEFAULT), LintId::of(&non_expressive_names::JUST_UNDERSCORES_AND_DIGITS), LintId::of(&non_expressive_names::MANY_SINGLE_CHAR_NAMES), - LintId::of(&ok_if_let::IF_LET_SOME_RESULT), + LintId::of(&if_let_some_result::IF_LET_SOME_RESULT), LintId::of(&panic_unimplemented::PANIC_PARAMS), LintId::of(&ptr::CMP_NULL), LintId::of(&ptr::PTR_ARG), diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index eee16fcd312..c6339daf2eb 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -705,7 +705,7 @@ pub const ALL_LINTS: [Lint; 347] = [ group: "style", desc: "usage of `ok()` in `if let Some(pat)` statements is unnecessary, match on `Ok(pat)` instead", deprecation: None, - module: "ok_if_let", + module: "if_let_some_result", }, Lint { name: "if_not_else", diff --git a/tests/ui/ok_if_let.fixed b/tests/ui/if_let_some_result.fixed similarity index 100% rename from tests/ui/ok_if_let.fixed rename to tests/ui/if_let_some_result.fixed diff --git a/tests/ui/ok_if_let.rs b/tests/ui/if_let_some_result.rs similarity index 100% rename from tests/ui/ok_if_let.rs rename to tests/ui/if_let_some_result.rs diff --git a/tests/ui/ok_if_let.stderr b/tests/ui/if_let_some_result.stderr similarity index 91% rename from tests/ui/ok_if_let.stderr rename to tests/ui/if_let_some_result.stderr index 4aa6057ba47..6925dfa0bf9 100644 --- a/tests/ui/ok_if_let.stderr +++ b/tests/ui/if_let_some_result.stderr @@ -1,5 +1,5 @@ error: Matching on `Some` with `ok()` is redundant - --> $DIR/ok_if_let.rs:6:5 + --> $DIR/if_let_some_result.rs:6:5 | LL | / if let Some(y) = x.parse().ok() { LL | | y @@ -19,7 +19,7 @@ LL | } | error: Matching on `Some` with `ok()` is redundant - --> $DIR/ok_if_let.rs:23:9 + --> $DIR/if_let_some_result.rs:23:9 | LL | / if let Some(y) = x.parse().ok() { LL | | return y; From aab64a21cca6e73cee0a7d6c203aa3ac14a8ea8d Mon Sep 17 00:00:00 2001 From: Yuki Okushi <huyuumi.dev@gmail.com> Date: Sat, 11 Jan 2020 04:34:01 +0900 Subject: [PATCH 4/7] Reduce span range --- clippy_lints/src/if_let_some_result.rs | 25 +++++++++++++------------ tests/ui/if_let_some_result.stderr | 10 ++-------- 2 files changed, 15 insertions(+), 20 deletions(-) diff --git a/clippy_lints/src/if_let_some_result.rs b/clippy_lints/src/if_let_some_result.rs index dc129a28e37..860caad2858 100644 --- a/clippy_lints/src/if_let_some_result.rs +++ b/clippy_lints/src/if_let_some_result.rs @@ -1,4 +1,4 @@ -use crate::utils::{match_type, method_chain_args, paths, snippet, snippet_with_applicability, span_lint_and_sugg}; +use crate::utils::{match_type, method_chain_args, paths, snippet_with_applicability, span_lint_and_then}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::*; @@ -42,7 +42,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for OkIfLet { fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) { if_chain! { //begin checking variables if let ExprKind::Match(ref op, ref body, source) = expr.kind; //test if expr is a match - if let MatchSource::IfLetDesugar { contains_else_clause } = source; //test if it is an If Let + if let MatchSource::IfLetDesugar { .. } = source; //test if it is an If Let if let ExprKind::MethodCall(_, ok_span, ref result_types) = op.kind; //check is expr.ok() has type Result<T,E>.ok() if let PatKind::TupleStruct(QPath::Resolved(_, ref x), ref y, _) = body[0].pat.kind; //get operation if method_chain_args(op, &["ok"]).is_some(); //test to see if using ok() methoduse std::marker::Sized; @@ -53,24 +53,25 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for OkIfLet { let trimed_ok_span = op.span.until(op.span.with_lo(ok_span.lo() - BytePos(1))); let some_expr_string = snippet_with_applicability(cx, y[0].span, "", &mut applicability); let trimmed_ok = snippet_with_applicability(cx, trimed_ok_span, "", &mut applicability); - let mut sugg = format!( - "if let Ok({}) = {} {}", + let sugg = format!( + "if let Ok({}) = {}", some_expr_string, trimmed_ok, - snippet(cx, body[0].span, ".."), ); - if contains_else_clause { - sugg = format!("{} else {}", sugg, snippet(cx, body[1].span, "..")); - } if print::to_string(print::NO_ANN, |s| s.print_path(x, false)) == "Some" && is_result_type { - span_lint_and_sugg( + span_lint_and_then( cx, IF_LET_SOME_RESULT, expr.span, "Matching on `Some` with `ok()` is redundant", - &format!("Consider matching on `Ok({})` and removing the call to `ok` instead", some_expr_string), - sugg, - applicability, + |db| { + db.span_suggestion( + expr.span.shrink_to_lo().to(ok_span.with_hi(ok_span.hi() + BytePos(2))), + &format!("Consider matching on `Ok({})` and removing the call to `ok` instead", some_expr_string), + sugg, + applicability, + ); + }, ); } } diff --git a/tests/ui/if_let_some_result.stderr b/tests/ui/if_let_some_result.stderr index 6925dfa0bf9..0084260b22a 100644 --- a/tests/ui/if_let_some_result.stderr +++ b/tests/ui/if_let_some_result.stderr @@ -12,11 +12,7 @@ LL | | } help: Consider matching on `Ok(y)` and removing the call to `ok` instead | LL | if let Ok(y) = x.parse() { -LL | y -LL | } else { -LL | 0 -LL | } - | + | ^^^^^^^^^^^^^^^^^^^^^^^^ error: Matching on `Some` with `ok()` is redundant --> $DIR/if_let_some_result.rs:23:9 @@ -29,9 +25,7 @@ LL | | }; help: Consider matching on `Ok(y)` and removing the call to `ok` instead | LL | if let Ok(y) = x.parse() { -LL | return y; -LL | }; - | + | ^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors From ce06ba3d30c2331c00596317284a0e1049b79929 Mon Sep 17 00:00:00 2001 From: Yuki Okushi <huyuumi.dev@gmail.com> Date: Sat, 11 Jan 2020 06:02:02 +0900 Subject: [PATCH 5/7] Run `update_lints` --- clippy_lints/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 8a90e39f2e9..497146772a5 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -545,6 +545,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &get_last_with_len::GET_LAST_WITH_LEN, &identity_conversion::IDENTITY_CONVERSION, &identity_op::IDENTITY_OP, + &if_let_some_result::IF_LET_SOME_RESULT, &if_not_else::IF_NOT_ELSE, &implicit_return::IMPLICIT_RETURN, &indexing_slicing::INDEXING_SLICING, @@ -703,7 +704,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &non_expressive_names::JUST_UNDERSCORES_AND_DIGITS, &non_expressive_names::MANY_SINGLE_CHAR_NAMES, &non_expressive_names::SIMILAR_NAMES, - &if_let_some_result::IF_LET_SOME_RESULT, &open_options::NONSENSICAL_OPEN_OPTIONS, &overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL, &panic_unimplemented::PANIC, @@ -1153,6 +1153,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&get_last_with_len::GET_LAST_WITH_LEN), LintId::of(&identity_conversion::IDENTITY_CONVERSION), LintId::of(&identity_op::IDENTITY_OP), + LintId::of(&if_let_some_result::IF_LET_SOME_RESULT), LintId::of(&indexing_slicing::OUT_OF_BOUNDS_INDEXING), LintId::of(&infallible_destructuring_match::INFALLIBLE_DESTRUCTURING_MATCH), LintId::of(&infinite_iter::INFINITE_ITER), @@ -1265,7 +1266,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST), LintId::of(&non_expressive_names::JUST_UNDERSCORES_AND_DIGITS), LintId::of(&non_expressive_names::MANY_SINGLE_CHAR_NAMES), - LintId::of(&if_let_some_result::IF_LET_SOME_RESULT), LintId::of(&open_options::NONSENSICAL_OPEN_OPTIONS), LintId::of(&overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL), LintId::of(&panic_unimplemented::PANIC_PARAMS), @@ -1367,6 +1367,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&formatting::SUSPICIOUS_UNARY_OP_FORMATTING), LintId::of(&functions::DOUBLE_MUST_USE), LintId::of(&functions::MUST_USE_UNIT), + LintId::of(&if_let_some_result::IF_LET_SOME_RESULT), LintId::of(&infallible_destructuring_match::INFALLIBLE_DESTRUCTURING_MATCH), LintId::of(&inherent_to_string::INHERENT_TO_STRING), LintId::of(&len_zero::LEN_WITHOUT_IS_EMPTY), @@ -1413,7 +1414,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&new_without_default::NEW_WITHOUT_DEFAULT), LintId::of(&non_expressive_names::JUST_UNDERSCORES_AND_DIGITS), LintId::of(&non_expressive_names::MANY_SINGLE_CHAR_NAMES), - LintId::of(&if_let_some_result::IF_LET_SOME_RESULT), LintId::of(&panic_unimplemented::PANIC_PARAMS), LintId::of(&ptr::CMP_NULL), LintId::of(&ptr::PTR_ARG), From 7e76a196649e1675e9c210f659074499e37fb353 Mon Sep 17 00:00:00 2001 From: Yuki Okushi <huyuumi.dev@gmail.com> Date: Sun, 19 Jan 2020 10:00:34 +0900 Subject: [PATCH 6/7] Apply review comments --- clippy_lints/src/if_let_some_result.rs | 27 +++++++++++++------------- tests/ui/if_let_some_result.fixed | 7 ++++--- tests/ui/if_let_some_result.rs | 7 ++++--- tests/ui/if_let_some_result.stderr | 20 +++++++------------ 4 files changed, 28 insertions(+), 33 deletions(-) diff --git a/clippy_lints/src/if_let_some_result.rs b/clippy_lints/src/if_let_some_result.rs index 860caad2858..8a3dcb7b6e9 100644 --- a/clippy_lints/src/if_let_some_result.rs +++ b/clippy_lints/src/if_let_some_result.rs @@ -1,4 +1,4 @@ -use crate::utils::{match_type, method_chain_args, paths, snippet_with_applicability, span_lint_and_then}; +use crate::utils::{match_type, method_chain_args, paths, snippet_with_applicability, span_lint_and_sugg}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::*; @@ -50,28 +50,27 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for OkIfLet { then { let is_result_type = match_type(cx, cx.tables.expr_ty(&result_types[0]), &paths::RESULT); let mut applicability = Applicability::MachineApplicable; - let trimed_ok_span = op.span.until(op.span.with_lo(ok_span.lo() - BytePos(1))); + // ok_span = `ok` + // op.span = `x.parse() . ok()` + // op.span.until(op.span.with_lo(ok_span.lo() - BytePos(1))) = `x.parse() .` + // op.span.with_lo(ok_span.lo() - BytePos(1)) = ` ok()` + // op.span.with_hi(ok_span.hi() - BytePos(1)) = `x.parse() . o` let some_expr_string = snippet_with_applicability(cx, y[0].span, "", &mut applicability); - let trimmed_ok = snippet_with_applicability(cx, trimed_ok_span, "", &mut applicability); + let trimmed_ok = snippet_with_applicability(cx, op.span.until(ok_span), "", &mut applicability); let sugg = format!( "if let Ok({}) = {}", some_expr_string, - trimmed_ok, + trimmed_ok.trim().trim_end_matches('.'), ); if print::to_string(print::NO_ANN, |s| s.print_path(x, false)) == "Some" && is_result_type { - span_lint_and_then( + span_lint_and_sugg( cx, IF_LET_SOME_RESULT, - expr.span, + expr.span.with_hi(ok_span.hi() + BytePos(2)), "Matching on `Some` with `ok()` is redundant", - |db| { - db.span_suggestion( - expr.span.shrink_to_lo().to(ok_span.with_hi(ok_span.hi() + BytePos(2))), - &format!("Consider matching on `Ok({})` and removing the call to `ok` instead", some_expr_string), - sugg, - applicability, - ); - }, + &format!("Consider matching on `Ok({})` and removing the call to `ok` instead", some_expr_string), + sugg, + applicability, ); } } diff --git a/tests/ui/if_let_some_result.fixed b/tests/ui/if_let_some_result.fixed index 439c749f995..80505fd997f 100644 --- a/tests/ui/if_let_some_result.fixed +++ b/tests/ui/if_let_some_result.fixed @@ -18,9 +18,10 @@ fn str_to_int_ok(x: &str) -> i32 { } } -fn nested_some_no_else(x: &str) -> i32 { +#[rustfmt::skip] +fn strange_some_no_else(x: &str) -> i32 { { - if let Ok(y) = x.parse() { + if let Ok(y) = x . parse() { return y; }; 0 @@ -30,5 +31,5 @@ fn nested_some_no_else(x: &str) -> i32 { fn main() { let _ = str_to_int("1"); let _ = str_to_int_ok("2"); - let _ = nested_some_no_else("3"); + let _ = strange_some_no_else("3"); } diff --git a/tests/ui/if_let_some_result.rs b/tests/ui/if_let_some_result.rs index 83f6ce1d330..bee8156e084 100644 --- a/tests/ui/if_let_some_result.rs +++ b/tests/ui/if_let_some_result.rs @@ -18,9 +18,10 @@ fn str_to_int_ok(x: &str) -> i32 { } } -fn nested_some_no_else(x: &str) -> i32 { +#[rustfmt::skip] +fn strange_some_no_else(x: &str) -> i32 { { - if let Some(y) = x.parse().ok() { + if let Some(y) = x . parse() . ok() { return y; }; 0 @@ -30,5 +31,5 @@ fn nested_some_no_else(x: &str) -> i32 { fn main() { let _ = str_to_int("1"); let _ = str_to_int_ok("2"); - let _ = nested_some_no_else("3"); + let _ = strange_some_no_else("3"); } diff --git a/tests/ui/if_let_some_result.stderr b/tests/ui/if_let_some_result.stderr index 0084260b22a..b4adc526efa 100644 --- a/tests/ui/if_let_some_result.stderr +++ b/tests/ui/if_let_some_result.stderr @@ -1,12 +1,8 @@ error: Matching on `Some` with `ok()` is redundant --> $DIR/if_let_some_result.rs:6:5 | -LL | / if let Some(y) = x.parse().ok() { -LL | | y -LL | | } else { -LL | | 0 -LL | | } - | |_____^ +LL | if let Some(y) = x.parse().ok() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::if-let-some-result` implied by `-D warnings` help: Consider matching on `Ok(y)` and removing the call to `ok` instead @@ -15,17 +11,15 @@ LL | if let Ok(y) = x.parse() { | ^^^^^^^^^^^^^^^^^^^^^^^^ error: Matching on `Some` with `ok()` is redundant - --> $DIR/if_let_some_result.rs:23:9 + --> $DIR/if_let_some_result.rs:24:9 | -LL | / if let Some(y) = x.parse().ok() { -LL | | return y; -LL | | }; - | |_________^ +LL | if let Some(y) = x . parse() . ok() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: Consider matching on `Ok(y)` and removing the call to `ok` instead | -LL | if let Ok(y) = x.parse() { - | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | if let Ok(y) = x . parse() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors From c9f8d03f42f8ce0617992e6375d8c9a39ab1ca01 Mon Sep 17 00:00:00 2001 From: Yuki Okushi <huyuumi.dev@gmail.com> Date: Sun, 19 Jan 2020 21:14:47 +0900 Subject: [PATCH 7/7] Treat more strange pattern --- clippy_lints/src/if_let_some_result.rs | 29 ++++++++++---------------- tests/ui/if_let_some_result.rs | 2 +- tests/ui/if_let_some_result.stderr | 4 ++-- 3 files changed, 14 insertions(+), 21 deletions(-) diff --git a/clippy_lints/src/if_let_some_result.rs b/clippy_lints/src/if_let_some_result.rs index 8a3dcb7b6e9..a9826d58633 100644 --- a/clippy_lints/src/if_let_some_result.rs +++ b/clippy_lints/src/if_let_some_result.rs @@ -4,7 +4,6 @@ use rustc_errors::Applicability; use rustc_hir::*; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::BytePos; declare_clippy_lint! { /// **What it does:*** Checks for unnecessary `ok()` in if let. @@ -46,15 +45,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for OkIfLet { if let ExprKind::MethodCall(_, ok_span, ref result_types) = op.kind; //check is expr.ok() has type Result<T,E>.ok() if let PatKind::TupleStruct(QPath::Resolved(_, ref x), ref y, _) = body[0].pat.kind; //get operation if method_chain_args(op, &["ok"]).is_some(); //test to see if using ok() methoduse std::marker::Sized; + let is_result_type = match_type(cx, cx.tables.expr_ty(&result_types[0]), &paths::RESULT); + if print::to_string(print::NO_ANN, |s| s.print_path(x, false)) == "Some" && is_result_type; then { - let is_result_type = match_type(cx, cx.tables.expr_ty(&result_types[0]), &paths::RESULT); let mut applicability = Applicability::MachineApplicable; - // ok_span = `ok` - // op.span = `x.parse() . ok()` - // op.span.until(op.span.with_lo(ok_span.lo() - BytePos(1))) = `x.parse() .` - // op.span.with_lo(ok_span.lo() - BytePos(1)) = ` ok()` - // op.span.with_hi(ok_span.hi() - BytePos(1)) = `x.parse() . o` let some_expr_string = snippet_with_applicability(cx, y[0].span, "", &mut applicability); let trimmed_ok = snippet_with_applicability(cx, op.span.until(ok_span), "", &mut applicability); let sugg = format!( @@ -62,17 +57,15 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for OkIfLet { some_expr_string, trimmed_ok.trim().trim_end_matches('.'), ); - if print::to_string(print::NO_ANN, |s| s.print_path(x, false)) == "Some" && is_result_type { - span_lint_and_sugg( - cx, - IF_LET_SOME_RESULT, - expr.span.with_hi(ok_span.hi() + BytePos(2)), - "Matching on `Some` with `ok()` is redundant", - &format!("Consider matching on `Ok({})` and removing the call to `ok` instead", some_expr_string), - sugg, - applicability, - ); - } + span_lint_and_sugg( + cx, + IF_LET_SOME_RESULT, + expr.span.with_hi(op.span.hi()), + "Matching on `Some` with `ok()` is redundant", + &format!("Consider matching on `Ok({})` and removing the call to `ok` instead", some_expr_string), + sugg, + applicability, + ); } } } diff --git a/tests/ui/if_let_some_result.rs b/tests/ui/if_let_some_result.rs index bee8156e084..ecac1357445 100644 --- a/tests/ui/if_let_some_result.rs +++ b/tests/ui/if_let_some_result.rs @@ -21,7 +21,7 @@ fn str_to_int_ok(x: &str) -> i32 { #[rustfmt::skip] fn strange_some_no_else(x: &str) -> i32 { { - if let Some(y) = x . parse() . ok() { + if let Some(y) = x . parse() . ok () { return y; }; 0 diff --git a/tests/ui/if_let_some_result.stderr b/tests/ui/if_let_some_result.stderr index b4adc526efa..334ccb01016 100644 --- a/tests/ui/if_let_some_result.stderr +++ b/tests/ui/if_let_some_result.stderr @@ -13,8 +13,8 @@ LL | if let Ok(y) = x.parse() { error: Matching on `Some` with `ok()` is redundant --> $DIR/if_let_some_result.rs:24:9 | -LL | if let Some(y) = x . parse() . ok() { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | if let Some(y) = x . parse() . ok () { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: Consider matching on `Ok(y)` and removing the call to `ok` instead |