Skip to content

Commit b89ac0c

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

File tree

5 files changed

+311
-333
lines changed

5 files changed

+311
-333
lines changed

clippy_lints/src/matches/manual_filter.rs

Lines changed: 24 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,20 @@
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_res_lang_ctor, path_res, path_to_local_id};
4-
use rustc_hir::intravisit::{walk_expr, Visitor};
5+
56
use rustc_hir::LangItem::OptionSome;
6-
use rustc_hir::{Arm, Block, BlockCheckMode, Expr, ExprKind, HirId, Pat, PatKind, UnsafeSource};
7+
use rustc_hir::{Arm, Expr, ExprKind, HirId, Pat, PatKind};
78
use rustc_lint::LateContext;
89
use rustc_span::{sym, SyntaxContext};
910

10-
use super::manual_map::{check_with, SomeExpr};
11+
use super::manual_utils::{check_with, SomeExpr};
1112
use super::MANUAL_FILTER;
1213

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>}`
14+
// Function called on the <expr> of `[&+]Some((ref | ref mut) x) => <expr>`
15+
// Need to check if it's of the form `<expr>=if <cond> {<then_expr>} else {<else_expr>}`
3516
// AND that only one `then/else_expr` resolves to `Some(x)` while the other resolves to `None`
36-
// return `cond` if
17+
// return the `cond` expression if so.
3718
fn get_cond_expr<'tcx>(
3819
cx: &LateContext<'tcx>,
3920
pat: &Pat<'_>,
@@ -45,15 +26,13 @@ fn get_cond_expr<'tcx>(
4526
if let ExprKind::If(cond, then_expr, Some(else_expr)) = block_expr.kind;
4627
if let PatKind::Binding(_,target, ..) = pat.kind;
4728
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));
29+
= (is_some_expr(cx, target, ctxt, then_expr),
30+
is_some_expr(cx, target, ctxt, else_expr));
5031
if then_visitor != else_visitor; // check that one expr resolves to `Some(x)`, the other to `None`
5132
then {
52-
let mut needs_unsafe_block = NeedsUnsafeBlock::default();
53-
needs_unsafe_block.visit_expr(expr);
5433
return Some(SomeExpr {
5534
expr: peels_blocks_incl_unsafe(cond.peel_drop_temps()),
56-
needs_unsafe_block: needs_unsafe_block.0,
35+
needs_unsafe_block: contains_unsafe_block(cx, expr),
5736
needs_negated: !then_visitor // if the `then_expr` resolves to `None`, need to negate the cond
5837
})
5938
}
@@ -63,7 +42,7 @@ fn get_cond_expr<'tcx>(
6342

6443
fn peels_blocks_incl_unsafe_opt<'a>(expr: &'a Expr<'a>) -> Option<&'a Expr<'a>> {
6544
// 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`
45+
// checked by `contains_unsafe_block`
6746
if let ExprKind::Block(block, None) = expr.kind {
6847
if block.stmts.is_empty() {
6948
return block.expr;
@@ -76,23 +55,18 @@ fn peels_blocks_incl_unsafe<'a>(expr: &'a Expr<'a>) -> &'a Expr<'a> {
7655
peels_blocks_incl_unsafe_opt(expr).unwrap_or(expr)
7756
}
7857

79-
// function called for each <ifelse> expression:
58+
// function called for each <expr> expression:
8059
// Some(x) => if <cond> {
81-
// <ifelse>
60+
// <expr>
8261
// } else {
83-
// <ifelse>
62+
// <expr>
8463
// }
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) {
64+
// Returns true if <expr> resolves to `Some(x)`, `false` otherwise
65+
fn is_some_expr<'tcx>(cx: &LateContext<'_>, target: HirId, ctxt: SyntaxContext, expr: &'tcx Expr<'_>) -> bool {
66+
if let Some(inner_expr) = peels_blocks_incl_unsafe_opt(expr) {
9367
// there can be not statements in the block as they would be removed when switching to `.filter`
9468
if let ExprKind::Call(callee, [arg]) = inner_expr.kind {
95-
return ctxt == if_or_else_expr.span.ctxt()
69+
return ctxt == expr.span.ctxt()
9670
&& is_res_lang_ctor(cx, path_res(cx, callee), OptionSome)
9771
&& path_to_local_id(arg, target);
9872
}
@@ -119,15 +93,13 @@ pub(super) fn check_match<'tcx>(
11993
expr: &'tcx Expr<'_>,
12094
) {
12195
let ty = cx.typeck_results().expr_ty(expr);
122-
if_chain! {
123-
if is_type_diagnostic_item(cx, ty, sym::Option);
124-
if arms.len() == 2;
125-
if arms[0].guard.is_none();
126-
if arms[1].guard.is_none();
127-
then {
128-
check(cx, expr, scrutinee, arms[0].pat, arms[0].body, Some(arms[1].pat), arms[1].body)
96+
if is_type_diagnostic_item(cx, ty, sym::Option)
97+
&& let [first_arm, second_arm] = arms
98+
&& first_arm.guard.is_none()
99+
&& second_arm.guard.is_none()
100+
{
101+
check(cx, expr, scrutinee, first_arm.pat, first_arm.body, Some(second_arm.pat), second_arm.body);
129102
}
130-
}
131103
}
132104

133105
pub(super) fn check_if_let<'tcx>(

0 commit comments

Comments
 (0)