1 use clippy_utils
::diagnostics
::span_lint_and_sugg
;
2 use clippy_utils
::ty
::is_type_diagnostic_item
;
3 use clippy_utils
::{is_res_lang_ctor, path_res, peel_hir_expr_refs, peel_ref_operators, sugg}
;
4 use rustc_errors
::Applicability
;
5 use rustc_hir
::{BinOpKind, Expr, ExprKind, LangItem}
;
6 use rustc_lint
::{LateContext, LateLintPass}
;
7 use rustc_session
::declare_lint_pass
;
10 declare_clippy_lint
! {
13 /// Checks for binary comparisons to a literal `Option::None`.
15 /// ### Why is this bad?
17 /// A programmer checking if some `foo` is `None` via a comparison `foo == None`
18 /// is usually inspired from other programming languages (e.g. `foo is None`
20 /// Checking if a value of type `Option<T>` is (not) equal to `None` in that
21 /// way relies on `T: PartialEq` to do the comparison, which is unneeded.
25 /// fn foo(f: Option<u32>) -> &'static str {
26 /// if f != None { "yay" } else { "nay" }
31 /// fn foo(f: Option<u32>) -> &'static str {
32 /// if f.is_some() { "yay" } else { "nay" }
35 #[clippy::version = "1.65.0"]
36 pub PARTIALEQ_TO_NONE
,
38 "Binary comparison to `Option<T>::None` relies on `T: PartialEq`, which is unneeded"
40 declare_lint_pass
!(PartialeqToNone
=> [PARTIALEQ_TO_NONE
]);
42 impl<'tcx
> LateLintPass
<'tcx
> for PartialeqToNone
{
43 fn check_expr(&mut self, cx
: &LateContext
<'tcx
>, e
: &'tcx Expr
<'_
>) {
44 // Skip expanded code, as we have no control over it anyway...
45 if e
.span
.from_expansion() {
49 // If the expression is of type `Option`
51 |expr
: &Expr
<'_
>| is_type_diagnostic_item(cx
, cx
.typeck_results().expr_ty(expr
).peel_refs(), sym
::Option
);
53 // If the expression is a literal `Option::None`
54 let is_none_ctor
= |expr
: &Expr
<'_
>| {
55 !expr
.span
.from_expansion()
56 && is_res_lang_ctor(cx
, path_res(cx
, peel_hir_expr_refs(expr
).0), LangItem
::OptionNone
)
59 let mut applicability
= Applicability
::MachineApplicable
;
61 if let ExprKind
::Binary(op
, left_side
, right_side
) = e
.kind
{
62 // All other comparisons (e.g. `>= None`) have special meaning wrt T
63 let is_eq
= match op
.node
{
64 BinOpKind
::Eq
=> true,
65 BinOpKind
::Ne
=> false,
69 // We are only interested in comparisons between `Option` and a literal `Option::None`
70 let scrutinee
= match (
71 is_none_ctor(left_side
) && is_ty_option(right_side
),
72 is_none_ctor(right_side
) && is_ty_option(left_side
),
74 (true, false) => right_side
,
75 (false, true) => left_side
,
79 // Peel away refs/derefs (as long as we don't cross manual deref impls), as
80 // autoref/autoderef will take care of those
83 sugg
::Sugg
::hir_with_applicability(cx
, peel_ref_operators(cx
, scrutinee
), "..", &mut applicability
)
85 if is_eq { "is_none()" }
else { "is_some()" }
92 "binary comparison to literal `Option::None`",
94 "use `Option::is_none()` instead"
96 "use `Option::is_some()` instead"