refactor(obfuscated_if_else): make a bit more type-safe (#15846)

changelog: none
This commit is contained in:
Alex Macleod
2025-10-08 16:58:54 +00:00
committed by GitHub
2 changed files with 42 additions and 24 deletions
+10 -5
View File
@@ -5501,7 +5501,14 @@ fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
option_map_unwrap_or::check(cx, expr, m_recv, m_arg, recv, u_arg, span, self.msrv);
},
Some((then_method @ (sym::then | sym::then_some), t_recv, [t_arg], _, _)) => {
obfuscated_if_else::check(cx, expr, t_recv, t_arg, Some(u_arg), then_method, name);
obfuscated_if_else::check(
cx,
expr,
t_recv,
t_arg,
then_method,
obfuscated_if_else::Unwrap::Or(u_arg),
);
},
_ => {},
}
@@ -5518,9 +5525,8 @@ fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
expr,
t_recv,
t_arg,
None,
then_method,
sym::unwrap_or_default,
obfuscated_if_else::Unwrap::OrDefault,
);
},
_ => {},
@@ -5537,9 +5543,8 @@ fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
expr,
t_recv,
t_arg,
Some(u_arg),
then_method,
sym::unwrap_or_else,
obfuscated_if_else::Unwrap::OrElse(u_arg),
);
},
_ => {
+32 -19
View File
@@ -5,25 +5,24 @@
use clippy_utils::sugg::Sugg;
use clippy_utils::{get_parent_expr, sym};
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_hir::ExprKind;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::LateContext;
use rustc_span::Symbol;
#[expect(clippy::needless_pass_by_value)]
pub(super) fn check<'tcx>(
cx: &LateContext<'tcx>,
expr: &'tcx hir::Expr<'_>,
then_recv: &'tcx hir::Expr<'_>,
then_arg: &'tcx hir::Expr<'_>,
unwrap_arg: Option<&'tcx hir::Expr<'_>>,
expr: &'tcx Expr<'_>,
then_recv: &'tcx Expr<'_>,
then_arg: &'tcx Expr<'_>,
then_method_name: Symbol,
unwrap_method_name: Symbol,
unwrap: Unwrap<'tcx>,
) {
let recv_ty = cx.typeck_results().expr_ty(then_recv);
if recv_ty.is_bool() {
let then_eager = switch_to_eager_eval(cx, then_arg);
let unwrap_eager = unwrap_arg.is_none_or(|arg| switch_to_eager_eval(cx, arg));
let unwrap_eager = unwrap.arg().is_none_or(|arg| switch_to_eager_eval(cx, arg));
let mut applicability = if then_eager && unwrap_eager {
Applicability::MachineApplicable
@@ -40,18 +39,17 @@ pub(super) fn check<'tcx>(
_ => return,
};
// FIXME: Add `unwrap_or_else` and `unwrap_or_default` symbol
let els = match unwrap_method_name {
sym::unwrap_or => snippet_with_applicability(cx, unwrap_arg.unwrap().span, "..", &mut applicability),
sym::unwrap_or_else if let ExprKind::Closure(closure) = unwrap_arg.unwrap().kind => {
let body = cx.tcx.hir_body(closure.body);
snippet_with_applicability(cx, body.value.span, "..", &mut applicability)
let els = match unwrap {
Unwrap::Or(arg) => snippet_with_applicability(cx, arg.span, "..", &mut applicability),
Unwrap::OrElse(arg) => match arg.kind {
ExprKind::Closure(closure) => {
let body = cx.tcx.hir_body(closure.body);
snippet_with_applicability(cx, body.value.span, "..", &mut applicability)
},
ExprKind::Path(_) => snippet_with_applicability(cx, arg.span, "_", &mut applicability) + "()",
_ => return,
},
sym::unwrap_or_else if let ExprKind::Path(_) = unwrap_arg.unwrap().kind => {
snippet_with_applicability(cx, unwrap_arg.unwrap().span, "_", &mut applicability) + "()"
},
sym::unwrap_or_default => "Default::default()".into(),
_ => return,
Unwrap::OrDefault => "Default::default()".into(),
};
let sugg = format!(
@@ -83,3 +81,18 @@ pub(super) fn check<'tcx>(
);
}
}
pub(super) enum Unwrap<'tcx> {
Or(&'tcx Expr<'tcx>),
OrElse(&'tcx Expr<'tcx>),
OrDefault,
}
impl<'tcx> Unwrap<'tcx> {
fn arg(&self) -> Option<&'tcx Expr<'tcx>> {
match self {
Self::Or(a) | Self::OrElse(a) => Some(a),
Self::OrDefault => None,
}
}
}