Skip to content

Commit a994546

Browse files
committed
refactor manual_filter
Move common functions to `manual_utils.rs`, better arm matching, use clippy utils `contains_unsafe_block`
1 parent 0f3f580 commit a994546

File tree

5 files changed

+309
-339
lines changed

5 files changed

+309
-339
lines changed

clippy_lints/src/matches/manual_filter.rs

Lines changed: 26 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,19 @@
11
use clippy_utils::diagnostics::span_lint_and_sugg;
22
use clippy_utils::ty::is_type_diagnostic_item;
3+
use clippy_utils::visitors::contains_unsafe_block;
34
use clippy_utils::{is_lang_ctor, path_to_local_id};
4-
use rustc_hir::intravisit::{walk_expr, Visitor};
55
use rustc_hir::LangItem::OptionSome;
6-
use rustc_hir::{Arm, Block, BlockCheckMode, Expr, ExprKind, HirId, Pat, PatKind, UnsafeSource};
6+
use rustc_hir::{Arm, Expr, ExprKind, HirId, Pat, PatKind};
77
use rustc_lint::LateContext;
88
use rustc_span::{sym, SyntaxContext};
99

10-
use super::manual_map::{check_with, SomeExpr};
10+
use super::manual_utils::{check_with, SomeExpr};
1111
use super::MANUAL_FILTER;
1212

13-
#[derive(Default)]
14-
struct NeedsUnsafeBlock(pub bool);
15-
16-
impl<'tcx> Visitor<'tcx> for NeedsUnsafeBlock {
17-
fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
18-
match expr.kind {
19-
ExprKind::Block(
20-
Block {
21-
rules: BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided),
22-
..
23-
},
24-
_,
25-
) => {
26-
self.0 = true;
27-
},
28-
_ => walk_expr(self, expr),
29-
}
30-
}
31-
}
32-
33-
// Function called on the `expr` of `[&+]Some((ref | ref mut) x) => <expr>`
34-
// Need to check if it's of the `if <cond> {<then_expr>} else {<else_expr>}`
13+
// Function called on the <expr> of `[&+]Some((ref | ref mut) x) => <expr>`
14+
// Need to check if it's of the form `<expr>=if <cond> {<then_expr>} else {<else_expr>}`
3515
// AND that only one `then/else_expr` resolves to `Some(x)` while the other resolves to `None`
36-
// return `cond` if
16+
// return the `cond` expression if so.
3717
fn get_cond_expr<'tcx>(
3818
cx: &LateContext<'tcx>,
3919
pat: &Pat<'_>,
@@ -45,15 +25,13 @@ fn get_cond_expr<'tcx>(
4525
if let ExprKind::If(cond, then_expr, Some(else_expr)) = block_expr.kind;
4626
if let PatKind::Binding(_,target, ..) = pat.kind;
4727
if let (then_visitor, else_visitor)
48-
= (handle_if_or_else_expr(cx, target, ctxt, then_expr),
49-
handle_if_or_else_expr(cx, target, ctxt, else_expr));
28+
= (is_some_expr(cx, target, ctxt, then_expr),
29+
is_some_expr(cx, target, ctxt, else_expr));
5030
if then_visitor != else_visitor; // check that one expr resolves to `Some(x)`, the other to `None`
5131
then {
52-
let mut needs_unsafe_block = NeedsUnsafeBlock::default();
53-
needs_unsafe_block.visit_expr(expr);
5432
return Some(SomeExpr {
5533
expr: peels_blocks_incl_unsafe(cond.peel_drop_temps()),
56-
needs_unsafe_block: needs_unsafe_block.0,
34+
needs_unsafe_block: contains_unsafe_block(cx, expr),
5735
needs_negated: !then_visitor // if the `then_expr` resolves to `None`, need to negate the cond
5836
})
5937
}
@@ -63,7 +41,7 @@ fn get_cond_expr<'tcx>(
6341

6442
fn peels_blocks_incl_unsafe_opt<'a>(expr: &'a Expr<'a>) -> Option<&'a Expr<'a>> {
6543
// we don't want to use `peel_blocks` here because we don't care if the block is unsafe, it's
66-
// checked by `NeedsUnsafeBlock`
44+
// checked by `contains_unsafe_block`
6745
if let ExprKind::Block(block, None) = expr.kind {
6846
if block.stmts.is_empty() {
6947
return block.expr;
@@ -76,20 +54,15 @@ fn peels_blocks_incl_unsafe<'a>(expr: &'a Expr<'a>) -> &'a Expr<'a> {
7654
peels_blocks_incl_unsafe_opt(expr).unwrap_or(expr)
7755
}
7856

79-
// function called for each <ifelse> expression:
57+
// function called for each <expr> expression:
8058
// Some(x) => if <cond> {
81-
// <ifelse>
59+
// <expr>
8260
// } else {
83-
// <ifelse>
61+
// <expr>
8462
// }
85-
// Returns true if <ifelse> resolves to `Some(x)`, `false` otherwise
86-
fn handle_if_or_else_expr<'tcx>(
87-
cx: &LateContext<'_>,
88-
target: HirId,
89-
ctxt: SyntaxContext,
90-
if_or_else_expr: &'tcx Expr<'_>,
91-
) -> bool {
92-
if let Some(inner_expr) = peels_blocks_incl_unsafe_opt(if_or_else_expr) {
63+
// Returns true if <expr> resolves to `Some(x)`, `false` otherwise
64+
fn is_some_expr<'tcx>(cx: &LateContext<'_>, target: HirId, ctxt: SyntaxContext, expr: &'tcx Expr<'_>) -> bool {
65+
if let Some(inner_expr) = peels_blocks_incl_unsafe_opt(expr) {
9366
// there can be not statements in the block as they would be removed when switching to `.filter`
9467
if let ExprKind::Call(
9568
Expr {
@@ -99,9 +72,7 @@ fn handle_if_or_else_expr<'tcx>(
9972
[arg],
10073
) = inner_expr.kind
10174
{
102-
return ctxt == if_or_else_expr.span.ctxt()
103-
&& is_lang_ctor(cx, qpath, OptionSome)
104-
&& path_to_local_id(arg, target);
75+
return ctxt == expr.span.ctxt() && is_lang_ctor(cx, qpath, OptionSome) && path_to_local_id(arg, target);
10576
}
10677
};
10778
false
@@ -126,15 +97,13 @@ pub(super) fn check_match<'tcx>(
12697
expr: &'tcx Expr<'_>,
12798
) {
12899
let ty = cx.typeck_results().expr_ty(expr);
129-
if_chain! {
130-
if is_type_diagnostic_item(cx, ty, sym::Option);
131-
if arms.len() == 2;
132-
if arms[0].guard.is_none();
133-
if arms[1].guard.is_none();
134-
then {
135-
check(cx, expr, scrutinee, arms[0].pat, arms[0].body, Some(arms[1].pat), arms[1].body)
100+
if is_type_diagnostic_item(cx, ty, sym::Option)
101+
&& let [first_arm, second_arm] = arms
102+
&& first_arm.guard.is_none()
103+
&& second_arm.guard.is_none()
104+
{
105+
check(cx, expr, scrutinee, first_arm.pat, first_arm.body, Some(second_arm.pat), second_arm.body)
136106
}
137-
}
138107
}
139108

140109
pub(super) fn check_if_let<'tcx>(
@@ -176,14 +145,11 @@ fn check<'tcx>(
176145
"try this",
177146
if sugg_info.needs_brackets {
178147
format!(
179-
"{{ {}{}.filter({}) }}",
180-
sugg_info.scrutinee_str, sugg_info.as_ref_str, body_str
148+
"{{ {}{}.filter({body_str}) }}",
149+
sugg_info.scrutinee_str, sugg_info.as_ref_str
181150
)
182151
} else {
183-
format!(
184-
"{}{}.filter({})",
185-
sugg_info.scrutinee_str, sugg_info.as_ref_str, body_str
186-
)
152+
format!("{}{}.filter({body_str})", sugg_info.scrutinee_str, sugg_info.as_ref_str)
187153
},
188154
sugg_info.app,
189155
);

0 commit comments

Comments
 (0)