117 lines
3.3 KiB
Rust
117 lines
3.3 KiB
Rust
use super::manual_utils::{check_with, SomeExpr};
|
|
use super::MANUAL_MAP;
|
|
use clippy_utils::diagnostics::span_lint_and_sugg;
|
|
|
|
use clippy_utils::{is_res_lang_ctor, path_res};
|
|
|
|
use rustc_hir::LangItem::OptionSome;
|
|
use rustc_hir::{Arm, Block, BlockCheckMode, Expr, ExprKind, Pat, UnsafeSource};
|
|
use rustc_lint::LateContext;
|
|
use rustc_span::SyntaxContext;
|
|
|
|
pub(super) fn check_match<'tcx>(
|
|
cx: &LateContext<'tcx>,
|
|
expr: &'tcx Expr<'_>,
|
|
scrutinee: &'tcx Expr<'_>,
|
|
arms: &'tcx [Arm<'_>],
|
|
) {
|
|
if let [arm1, arm2] = arms
|
|
&& arm1.guard.is_none()
|
|
&& arm2.guard.is_none()
|
|
{
|
|
check(cx, expr, scrutinee, arm1.pat, arm1.body, Some(arm2.pat), arm2.body);
|
|
}
|
|
}
|
|
|
|
pub(super) fn check_if_let<'tcx>(
|
|
cx: &LateContext<'tcx>,
|
|
expr: &'tcx Expr<'_>,
|
|
let_pat: &'tcx Pat<'_>,
|
|
let_expr: &'tcx Expr<'_>,
|
|
then_expr: &'tcx Expr<'_>,
|
|
else_expr: &'tcx Expr<'_>,
|
|
) {
|
|
check(cx, expr, let_expr, let_pat, then_expr, None, else_expr);
|
|
}
|
|
|
|
fn check<'tcx>(
|
|
cx: &LateContext<'tcx>,
|
|
expr: &'tcx Expr<'_>,
|
|
scrutinee: &'tcx Expr<'_>,
|
|
then_pat: &'tcx Pat<'_>,
|
|
then_body: &'tcx Expr<'_>,
|
|
else_pat: Option<&'tcx Pat<'_>>,
|
|
else_body: &'tcx Expr<'_>,
|
|
) {
|
|
if let Some(sugg_info) = check_with(
|
|
cx,
|
|
expr,
|
|
scrutinee,
|
|
then_pat,
|
|
then_body,
|
|
else_pat,
|
|
else_body,
|
|
get_some_expr,
|
|
) {
|
|
span_lint_and_sugg(
|
|
cx,
|
|
MANUAL_MAP,
|
|
expr.span,
|
|
"manual implementation of `Option::map`",
|
|
"try this",
|
|
if sugg_info.needs_brackets {
|
|
format!(
|
|
"{{ {}{}.map({}) }}",
|
|
sugg_info.scrutinee_str, sugg_info.as_ref_str, sugg_info.body_str
|
|
)
|
|
} else {
|
|
format!(
|
|
"{}{}.map({})",
|
|
sugg_info.scrutinee_str, sugg_info.as_ref_str, sugg_info.body_str
|
|
)
|
|
},
|
|
sugg_info.app,
|
|
);
|
|
}
|
|
}
|
|
|
|
// Checks for an expression wrapped by the `Some` constructor. Returns the contained expression.
|
|
fn get_some_expr<'tcx>(
|
|
cx: &LateContext<'tcx>,
|
|
_: &'tcx Pat<'_>,
|
|
expr: &'tcx Expr<'_>,
|
|
ctxt: SyntaxContext,
|
|
) -> Option<SomeExpr<'tcx>> {
|
|
fn get_some_expr_internal<'tcx>(
|
|
cx: &LateContext<'tcx>,
|
|
expr: &'tcx Expr<'_>,
|
|
needs_unsafe_block: bool,
|
|
ctxt: SyntaxContext,
|
|
) -> Option<SomeExpr<'tcx>> {
|
|
// TODO: Allow more complex expressions.
|
|
match expr.kind {
|
|
ExprKind::Call(callee, [arg])
|
|
if ctxt == expr.span.ctxt() && is_res_lang_ctor(cx, path_res(cx, callee), OptionSome) =>
|
|
{
|
|
Some(SomeExpr::new_no_negated(arg, needs_unsafe_block))
|
|
},
|
|
ExprKind::Block(
|
|
Block {
|
|
stmts: [],
|
|
expr: Some(expr),
|
|
rules,
|
|
..
|
|
},
|
|
_,
|
|
) => get_some_expr_internal(
|
|
cx,
|
|
expr,
|
|
needs_unsafe_block || *rules == BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided),
|
|
ctxt,
|
|
),
|
|
_ => None,
|
|
}
|
|
}
|
|
get_some_expr_internal(cx, expr, false, ctxt)
|
|
}
|