summaryrefslogtreecommitdiffstats
path: root/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs')
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs88
1 files changed, 61 insertions, 27 deletions
diff --git a/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs b/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs
index 8499e050a..c89784065 100644
--- a/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs
@@ -2,17 +2,17 @@ use super::REDUNDANT_PATTERN_MATCHING;
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::snippet;
use clippy_utils::sugg::Sugg;
-use clippy_utils::ty::needs_ordered_drop;
+use clippy_utils::ty::{is_type_diagnostic_item, needs_ordered_drop};
use clippy_utils::visitors::any_temporaries_need_ordered_drop;
-use clippy_utils::{higher, is_lang_ctor, is_trait_method, match_def_path, paths};
+use clippy_utils::{higher, is_lang_ctor, is_trait_method};
use if_chain::if_chain;
use rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
-use rustc_hir::LangItem::{OptionNone, PollPending};
+use rustc_hir::LangItem::{self, OptionSome, OptionNone, PollPending, PollReady, ResultOk, ResultErr};
use rustc_hir::{Arm, Expr, ExprKind, Node, Pat, PatKind, QPath, UnOp};
use rustc_lint::LateContext;
use rustc_middle::ty::{self, subst::GenericArgKind, DefIdTree, Ty};
-use rustc_span::sym;
+use rustc_span::{sym, Symbol};
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
if let Some(higher::WhileLet { let_pat, let_expr, .. }) = higher::WhileLet::hir(expr) {
@@ -75,9 +75,9 @@ fn find_sugg_for_if_let<'tcx>(
("is_some()", op_ty)
} else if Some(id) == lang_items.poll_ready_variant() {
("is_ready()", op_ty)
- } else if match_def_path(cx, id, &paths::IPADDR_V4) {
+ } else if is_pat_variant(cx, check_pat, qpath, Item::Diag(sym::IpAddr, sym!(V4))) {
("is_ipv4()", op_ty)
- } else if match_def_path(cx, id, &paths::IPADDR_V6) {
+ } else if is_pat_variant(cx, check_pat, qpath, Item::Diag(sym::IpAddr, sym!(V6))) {
("is_ipv6()", op_ty)
} else {
return;
@@ -120,7 +120,7 @@ fn find_sugg_for_if_let<'tcx>(
// check that `while_let_on_iterator` lint does not trigger
if_chain! {
if keyword == "while";
- if let ExprKind::MethodCall(method_path, _, _) = let_expr.kind;
+ if let ExprKind::MethodCall(method_path, ..) = let_expr.kind;
if method_path.ident.name == sym::next;
if is_trait_method(cx, let_expr, sym::Iterator);
then {
@@ -187,8 +187,8 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op
arms,
path_left,
path_right,
- &paths::RESULT_OK,
- &paths::RESULT_ERR,
+ Item::Lang(ResultOk),
+ Item::Lang(ResultErr),
"is_ok()",
"is_err()",
)
@@ -198,8 +198,8 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op
arms,
path_left,
path_right,
- &paths::IPADDR_V4,
- &paths::IPADDR_V6,
+ Item::Diag(sym::IpAddr, sym!(V4)),
+ Item::Diag(sym::IpAddr, sym!(V6)),
"is_ipv4()",
"is_ipv6()",
)
@@ -213,13 +213,14 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op
if patterns.len() == 1 =>
{
if let PatKind::Wild = patterns[0].kind {
+
find_good_method_for_match(
cx,
arms,
path_left,
path_right,
- &paths::OPTION_SOME,
- &paths::OPTION_NONE,
+ Item::Lang(OptionSome),
+ Item::Lang(OptionNone),
"is_some()",
"is_none()",
)
@@ -229,8 +230,8 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op
arms,
path_left,
path_right,
- &paths::POLL_READY,
- &paths::POLL_PENDING,
+ Item::Lang(PollReady),
+ Item::Lang(PollPending),
"is_ready()",
"is_pending()",
)
@@ -266,28 +267,61 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op
}
}
+#[derive(Clone, Copy)]
+enum Item {
+ Lang(LangItem),
+ Diag(Symbol, Symbol),
+}
+
+fn is_pat_variant(cx: &LateContext<'_>, pat: &Pat<'_>, path: &QPath<'_>, expected_item: Item) -> bool {
+ let Some(id) = cx.typeck_results().qpath_res(path, pat.hir_id).opt_def_id() else { return false };
+
+ match expected_item {
+ Item::Lang(expected_lang_item) => {
+ let expected_id = cx.tcx.lang_items().require(expected_lang_item).unwrap();
+ cx.tcx.parent(id) == expected_id
+ },
+ Item::Diag(expected_ty, expected_variant) => {
+ let ty = cx.typeck_results().pat_ty(pat);
+
+ if is_type_diagnostic_item(cx, ty, expected_ty) {
+ let variant = ty.ty_adt_def()
+ .expect("struct pattern type is not an ADT")
+ .variant_of_res(cx.qpath_res(path, pat.hir_id));
+
+ return variant.name == expected_variant
+ }
+
+ false
+ }
+ }
+}
+
#[expect(clippy::too_many_arguments)]
fn find_good_method_for_match<'a>(
cx: &LateContext<'_>,
arms: &[Arm<'_>],
path_left: &QPath<'_>,
path_right: &QPath<'_>,
- expected_left: &[&str],
- expected_right: &[&str],
+ expected_item_left: Item,
+ expected_item_right: Item,
should_be_left: &'a str,
should_be_right: &'a str,
) -> Option<&'a str> {
- let left_id = cx
- .typeck_results()
- .qpath_res(path_left, arms[0].pat.hir_id)
- .opt_def_id()?;
- let right_id = cx
- .typeck_results()
- .qpath_res(path_right, arms[1].pat.hir_id)
- .opt_def_id()?;
- let body_node_pair = if match_def_path(cx, left_id, expected_left) && match_def_path(cx, right_id, expected_right) {
+ let pat_left = arms[0].pat;
+ let pat_right = arms[1].pat;
+
+ let body_node_pair = if (
+ is_pat_variant(cx, pat_left, path_left, expected_item_left)
+ ) && (
+ is_pat_variant(cx, pat_right, path_right, expected_item_right)
+ ) {
(&arms[0].body.kind, &arms[1].body.kind)
- } else if match_def_path(cx, right_id, expected_left) && match_def_path(cx, right_id, expected_right) {
+ } else if (
+ is_pat_variant(cx, pat_left, path_left, expected_item_right)
+ ) && (
+ is_pat_variant(cx, pat_right, path_right, expected_item_left)
+ ) {
(&arms[1].body.kind, &arms[0].body.kind)
} else {
return None;