-/// Lint use of `_.and_then(|x| Some(y))` for `Option`s
-fn lint_option_and_then_some(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
- const LINT_MSG: &str = "using `Option.and_then(|x| Some(y))`, which is more succinctly expressed as `map(|x| y)`";
- const NO_OP_MSG: &str = "using `Option.and_then(Some)`, which is a no-op";
-
- let ty = cx.tables.expr_ty(&args[0]);
- if !match_type(cx, ty, &paths::OPTION) {
- return;
- }
-
- match args[1].kind {
- hir::ExprKind::Closure(_, _, body_id, closure_args_span, _) => {
- let closure_body = cx.tcx.hir().body(body_id);
- let closure_expr = remove_blocks(&closure_body.value);
- if_chain! {
- if let hir::ExprKind::Call(ref some_expr, ref some_args) = closure_expr.kind;
- if let hir::ExprKind::Path(ref qpath) = some_expr.kind;
- if match_qpath(qpath, &paths::OPTION_SOME);
- if some_args.len() == 1;
- then {
- let inner_expr = &some_args[0];
-
- if contains_return(inner_expr) {
- return;
- }
-
- let some_inner_snip = if inner_expr.span.from_expansion() {
- snippet_with_macro_callsite(cx, inner_expr.span, "_")
- } else {
- snippet(cx, inner_expr.span, "_")
- };
-
- let closure_args_snip = snippet(cx, closure_args_span, "..");
- let option_snip = snippet(cx, args[0].span, "..");
- let note = format!("{}.map({} {})", option_snip, closure_args_snip, some_inner_snip);
- span_lint_and_sugg(
- cx,
- OPTION_AND_THEN_SOME,
- expr.span,
- LINT_MSG,
- "try this",
- note,
- Applicability::MachineApplicable,
- );
- }
- }
- },
- // `_.and_then(Some)` case, which is no-op.
- hir::ExprKind::Path(ref qpath) => {
- if match_qpath(qpath, &paths::OPTION_SOME) {
- let option_snip = snippet(cx, args[0].span, "..");
- let note = format!("{}", option_snip);
- span_lint_and_sugg(
- cx,
- OPTION_AND_THEN_SOME,
- expr.span,
- NO_OP_MSG,
- "use the expression directly",
- note,
- Applicability::MachineApplicable,
- );
- }
- },
- _ => {},
- }
-}
-