-
Notifications
You must be signed in to change notification settings - Fork 1.6k
/
Copy pathobfuscated_if_else.rs
84 lines (76 loc) · 3.07 KB
/
obfuscated_if_else.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
use super::OBFUSCATED_IF_ELSE;
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::eager_or_lazy::switch_to_eager_eval;
use clippy_utils::get_parent_expr;
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::sugg::Sugg;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_hir::ExprKind;
use rustc_lint::LateContext;
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<'_>>,
then_method_name: &str,
unwrap_method_name: &str,
) {
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 mut applicability = if then_eager && unwrap_eager {
Applicability::MachineApplicable
} else {
Applicability::MaybeIncorrect
};
let if_then = match then_method_name {
"then" if let ExprKind::Closure(closure) = then_arg.kind => {
let body = cx.tcx.hir_body(closure.body);
snippet_with_applicability(cx, body.value.span, "..", &mut applicability)
},
"then_some" => snippet_with_applicability(cx, then_arg.span, "..", &mut applicability),
_ => return,
};
// FIXME: Add `unwrap_or_else` and `unwrap_or_default` symbol
let els = match unwrap_method_name {
"unwrap_or" => snippet_with_applicability(cx, unwrap_arg.unwrap().span, "..", &mut applicability),
"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)
},
"unwrap_or_else" if let ExprKind::Path(_) = unwrap_arg.unwrap().kind => {
snippet_with_applicability(cx, unwrap_arg.unwrap().span, "_", &mut applicability) + "()"
},
"unwrap_or_default" => "Default::default()".into(),
_ => return,
};
let sugg = format!(
"if {} {{ {} }} else {{ {} }}",
Sugg::hir_with_applicability(cx, then_recv, "..", &mut applicability),
if_then,
els
);
// To be parsed as an expression, the `if { … } else { … }` as the left operand of a binary operator
// requires parentheses.
let sugg = if let Some(parent_expr) = get_parent_expr(cx, expr)
&& let ExprKind::Binary(_, left, _) = parent_expr.kind
&& left.hir_id == expr.hir_id
{
format!("({sugg})")
} else {
sugg
};
span_lint_and_sugg(
cx,
OBFUSCATED_IF_ELSE,
expr.span,
"this method chain can be written more clearly with `if .. else ..`",
"try",
sugg,
applicability,
);
}
}