Skip to content

Commit 763a7bd

Browse files
Extend manual_is_variant_and lint to check for boolean map comparisons
1 parent 3927a61 commit 763a7bd

File tree

2 files changed

+65
-6
lines changed

2 files changed

+65
-6
lines changed

clippy_lints/src/methods/manual_is_variant_and.rs

Lines changed: 64 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,22 @@
11
use clippy_utils::diagnostics::span_lint_and_sugg;
2+
use clippy_utils::get_parent_expr;
23
use clippy_utils::msrvs::{self, Msrv};
3-
use clippy_utils::source::snippet;
4+
use clippy_utils::source::{snippet, snippet_opt};
45
use clippy_utils::ty::is_type_diagnostic_item;
56
use rustc_errors::Applicability;
7+
use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
8+
use rustc_hir::{BinOpKind, Expr, ExprKind, QPath};
69
use rustc_lint::LateContext;
7-
use rustc_span::{Span, sym};
10+
use rustc_middle::ty;
11+
use rustc_span::{BytePos, Span, sym};
812

913
use super::MANUAL_IS_VARIANT_AND;
1014

11-
pub(super) fn check<'tcx>(
15+
pub(super) fn check(
1216
cx: &LateContext<'_>,
13-
expr: &'tcx rustc_hir::Expr<'_>,
14-
map_recv: &'tcx rustc_hir::Expr<'_>,
15-
map_arg: &'tcx rustc_hir::Expr<'_>,
17+
expr: &Expr<'_>,
18+
map_recv: &Expr<'_>,
19+
map_arg: &Expr<'_>,
1620
map_span: Span,
1721
msrv: Msrv,
1822
) {
@@ -57,3 +61,57 @@ pub(super) fn check<'tcx>(
5761
Applicability::MachineApplicable,
5862
);
5963
}
64+
65+
fn emit_lint(cx: &LateContext<'_>, op: BinOpKind, parent: &Expr<'_>, method_span: Span, is_option: bool) {
66+
if let Some(before_map_snippet) = snippet_opt(cx, parent.span.with_hi(method_span.lo()))
67+
&& let Some(after_map_snippet) = snippet_opt(cx, method_span.with_lo(method_span.lo() + BytePos(3)))
68+
{
69+
span_lint_and_sugg(
70+
cx,
71+
MANUAL_IS_VARIANT_AND,
72+
parent.span,
73+
format!(
74+
"called `.map() {}= {}()`",
75+
if op == BinOpKind::Eq { '=' } else { '!' },
76+
if is_option { "Some" } else { "Ok" },
77+
),
78+
"use",
79+
if is_option && op == BinOpKind::Ne {
80+
format!("{before_map_snippet}is_none_or{after_map_snippet}",)
81+
} else {
82+
format!(
83+
"{}{before_map_snippet}{}{after_map_snippet}",
84+
if op == BinOpKind::Eq { "" } else { "!" },
85+
if is_option { "is_some_and" } else { "is_ok_and" },
86+
)
87+
},
88+
Applicability::MachineApplicable,
89+
);
90+
}
91+
}
92+
93+
pub(super) fn check_map(cx: &LateContext<'_>, expr: &Expr<'_>) {
94+
if let Some(parent_expr) = get_parent_expr(cx, expr)
95+
&& let ExprKind::Binary(op, left, right) = parent_expr.kind
96+
&& matches!(op.node, BinOpKind::Eq | BinOpKind::Ne)
97+
&& op.span.eq_ctxt(expr.span)
98+
{
99+
// Check `left` and `right` expression in any order, and for `Option` and `Result`
100+
for (expr1, expr2) in [(left, right), (right, left)] {
101+
for item in [sym::Option, sym::Result] {
102+
if let ExprKind::Call(call, ..) = expr1.kind
103+
&& let ExprKind::Path(QPath::Resolved(_, path)) = call.kind
104+
&& let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Fn), _) = path.res
105+
&& let ty = cx.typeck_results().expr_ty(expr1)
106+
&& let ty::Adt(adt, args) = ty.kind()
107+
&& cx.tcx.is_diagnostic_item(item, adt.did())
108+
&& args.type_at(0).is_bool()
109+
&& let ExprKind::MethodCall(_, recv, _, span) = expr2.kind
110+
&& is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), item)
111+
{
112+
return emit_lint(cx, op.node, parent_expr, span, item == sym::Option);
113+
}
114+
}
115+
}
116+
}
117+
}

clippy_lints/src/methods/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5203,6 +5203,7 @@ impl Methods {
52035203
unused_enumerate_index::check(cx, expr, recv, m_arg);
52045204
map_clone::check(cx, expr, recv, m_arg, self.msrv);
52055205
map_with_unused_argument_over_ranges::check(cx, expr, recv, m_arg, self.msrv, span);
5206+
manual_is_variant_and::check_map(cx, expr);
52065207
match method_call(recv) {
52075208
Some((map_name @ (sym::iter | sym::into_iter), recv2, _, _, _)) => {
52085209
iter_kv_map::check(cx, map_name, expr, recv2, m_arg, self.msrv);

0 commit comments

Comments
 (0)