Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit dc75695

Browse files
committed
Split out match_wild_err_arm
1 parent 2a70439 commit dc75695

File tree

2 files changed

+55
-49
lines changed

2 files changed

+55
-49
lines changed
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
use clippy_utils::diagnostics::span_lint_and_note;
2+
use clippy_utils::macros::{is_panic, root_macro_call};
3+
use clippy_utils::ty::is_type_diagnostic_item;
4+
use clippy_utils::visitors::is_local_used;
5+
use clippy_utils::{is_wild, peel_blocks_with_stmt};
6+
use rustc_hir::{Arm, Expr, PatKind};
7+
use rustc_lint::LateContext;
8+
use rustc_span::symbol::{kw, sym};
9+
10+
use super::MATCH_WILD_ERR_ARM;
11+
12+
pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, ex: &Expr<'tcx>, arms: &[Arm<'tcx>]) {
13+
let ex_ty = cx.typeck_results().expr_ty(ex).peel_refs();
14+
if is_type_diagnostic_item(cx, ex_ty, sym::Result) {
15+
for arm in arms {
16+
if let PatKind::TupleStruct(ref path, inner, _) = arm.pat.kind {
17+
let path_str = rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_qpath(path, false));
18+
if path_str == "Err" {
19+
let mut matching_wild = inner.iter().any(is_wild);
20+
let mut ident_bind_name = kw::Underscore;
21+
if !matching_wild {
22+
// Looking for unused bindings (i.e.: `_e`)
23+
for pat in inner.iter() {
24+
if let PatKind::Binding(_, id, ident, None) = pat.kind {
25+
if ident.as_str().starts_with('_') && !is_local_used(cx, arm.body, id) {
26+
ident_bind_name = ident.name;
27+
matching_wild = true;
28+
}
29+
}
30+
}
31+
}
32+
if_chain! {
33+
if matching_wild;
34+
if let Some(macro_call) = root_macro_call(peel_blocks_with_stmt(arm.body).span);
35+
if is_panic(cx, macro_call.def_id);
36+
then {
37+
// `Err(_)` or `Err(_e)` arm with `panic!` found
38+
span_lint_and_note(cx,
39+
MATCH_WILD_ERR_ARM,
40+
arm.pat.span,
41+
&format!("`Err({})` matches all errors", ident_bind_name),
42+
None,
43+
"match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable",
44+
);
45+
}
46+
}
47+
}
48+
}
49+
}
50+
}
51+
}

clippy_lints/src/matches/mod.rs

Lines changed: 4 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,7 @@
1-
use clippy_utils::diagnostics::{
2-
multispan_sugg, span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then,
3-
};
4-
use clippy_utils::macros::{is_panic, root_macro_call};
5-
use clippy_utils::peel_blocks_with_stmt;
1+
use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_help, span_lint_and_sugg, span_lint_and_then};
62
use clippy_utils::source::{indent_of, snippet, snippet_block, snippet_opt, snippet_with_applicability};
73
use clippy_utils::sugg::Sugg;
84
use clippy_utils::ty::is_type_diagnostic_item;
9-
use clippy_utils::visitors::is_local_used;
105
use clippy_utils::{
116
get_parent_expr, is_lang_ctor, is_refutable, is_wild, meets_msrv, msrvs, path_to_local_id, peel_blocks,
127
peel_hir_pat_refs, recurse_or_patterns, strip_pat_refs,
@@ -24,11 +19,12 @@ use rustc_lint::{LateContext, LateLintPass};
2419
use rustc_middle::ty::{self, VariantDef};
2520
use rustc_semver::RustcVersion;
2621
use rustc_session::{declare_tool_lint, impl_lint_pass};
27-
use rustc_span::{sym, symbol::kw};
22+
use rustc_span::sym;
2823

2924
mod match_bool;
3025
mod match_like_matches;
3126
mod match_same_arms;
27+
mod match_wild_err_arm;
3228
mod overlapping_arms;
3329
mod redundant_pattern_match;
3430
mod single_match;
@@ -632,7 +628,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
632628
single_match::check(cx, ex, arms, expr);
633629
match_bool::check(cx, ex, arms, expr);
634630
overlapping_arms::check(cx, ex, arms);
635-
check_wild_err_arm(cx, ex, arms);
631+
match_wild_err_arm::check(cx, ex, arms);
636632
check_wild_enum_match(cx, ex, arms);
637633
check_match_as_ref(cx, ex, arms, expr);
638634
check_wild_in_or_pats(cx, arms);
@@ -709,47 +705,6 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
709705
extract_msrv_attr!(LateContext);
710706
}
711707

712-
fn check_wild_err_arm<'tcx>(cx: &LateContext<'tcx>, ex: &Expr<'tcx>, arms: &[Arm<'tcx>]) {
713-
let ex_ty = cx.typeck_results().expr_ty(ex).peel_refs();
714-
if is_type_diagnostic_item(cx, ex_ty, sym::Result) {
715-
for arm in arms {
716-
if let PatKind::TupleStruct(ref path, inner, _) = arm.pat.kind {
717-
let path_str = rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_qpath(path, false));
718-
if path_str == "Err" {
719-
let mut matching_wild = inner.iter().any(is_wild);
720-
let mut ident_bind_name = kw::Underscore;
721-
if !matching_wild {
722-
// Looking for unused bindings (i.e.: `_e`)
723-
for pat in inner.iter() {
724-
if let PatKind::Binding(_, id, ident, None) = pat.kind {
725-
if ident.as_str().starts_with('_') && !is_local_used(cx, arm.body, id) {
726-
ident_bind_name = ident.name;
727-
matching_wild = true;
728-
}
729-
}
730-
}
731-
}
732-
if_chain! {
733-
if matching_wild;
734-
if let Some(macro_call) = root_macro_call(peel_blocks_with_stmt(arm.body).span);
735-
if is_panic(cx, macro_call.def_id);
736-
then {
737-
// `Err(_)` or `Err(_e)` arm with `panic!` found
738-
span_lint_and_note(cx,
739-
MATCH_WILD_ERR_ARM,
740-
arm.pat.span,
741-
&format!("`Err({})` matches all errors", ident_bind_name),
742-
None,
743-
"match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable",
744-
);
745-
}
746-
}
747-
}
748-
}
749-
}
750-
}
751-
}
752-
753708
enum CommonPrefixSearcher<'a> {
754709
None,
755710
Path(&'a [PathSegment<'a>]),

0 commit comments

Comments
 (0)