|
| 1 | +use clippy_utils::diagnostics::span_lint_and_sugg; |
| 2 | +use clippy_utils::path_to_local_id; |
| 3 | +use clippy_utils::source::snippet; |
| 4 | +use clippy_utils::ty::is_type_diagnostic_item; |
| 5 | +use rustc_ast::LitKind::Bool; |
| 6 | +use rustc_errors::Applicability; |
| 7 | +use rustc_hir::{BinOpKind, Expr, ExprKind, PatKind}; |
| 8 | +use rustc_lint::LateContext; |
| 9 | +use rustc_span::sym; |
| 10 | + |
| 11 | +use super::UNNECESSARY_PATTERN_MATCHING; |
| 12 | + |
| 13 | +// Only checking map_or for now |
| 14 | +pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, def: &Expr<'_>, map: &Expr<'_>) { |
| 15 | + if let ExprKind::Lit(def_kind) = def.kind |
| 16 | + // only works on Result and Option |
| 17 | + && let recv_ty = cx.typeck_results().expr_ty(recv) |
| 18 | + && (is_type_diagnostic_item(cx, recv_ty, sym::Option) |
| 19 | + || is_type_diagnostic_item(cx, recv_ty, sym::Result)) |
| 20 | + // check we are dealing with boolean map_or |
| 21 | + && let Bool(def_bool) = def_kind.node |
| 22 | + && def_bool == false |
| 23 | + && let ExprKind::Closure(map_closure) = map.kind |
| 24 | + && let closure_body = cx.tcx.hir().body(map_closure.body) |
| 25 | + && let closure_body_value = closure_body.value.peel_blocks() |
| 26 | + // check we are dealing with equality statement in the closure |
| 27 | + && let ExprKind::Binary(op, l, r) = closure_body_value.kind |
| 28 | + && let Some(param) = closure_body.params.first() |
| 29 | + && let PatKind::Binding(_, hir_id, _, _) = param.pat.kind |
| 30 | + && BinOpKind::Eq == op.node |
| 31 | + && (path_to_local_id(l, hir_id) || path_to_local_id(r, hir_id)) |
| 32 | + { |
| 33 | + let wrap = if is_type_diagnostic_item(cx, recv_ty, sym::Option) { |
| 34 | + "Some" |
| 35 | + } else { |
| 36 | + "Result" |
| 37 | + }; |
| 38 | + |
| 39 | + // we already checked either l or r is the local id earlier |
| 40 | + let non_binding_location = if path_to_local_id(l, hir_id) { r } else { l }; |
| 41 | + |
| 42 | + span_lint_and_sugg( |
| 43 | + cx, |
| 44 | + UNNECESSARY_PATTERN_MATCHING, |
| 45 | + expr.span, |
| 46 | + "`map_or` here is redundant, use typical equality instead", |
| 47 | + "try", |
| 48 | + format!( |
| 49 | + "{} == {}({})", |
| 50 | + snippet(cx, recv.span, ".."), |
| 51 | + wrap, |
| 52 | + snippet(cx, non_binding_location.span.source_callsite(), "..") |
| 53 | + ), |
| 54 | + Applicability::Unspecified, |
| 55 | + ) |
| 56 | + } |
| 57 | +} |
0 commit comments