1 use clippy_utils
::diagnostics
::span_lint_and_then
;
2 use clippy_utils
::source
::snippet_opt
;
3 use if_chain
::if_chain
;
4 use rustc_errors
::Applicability
;
5 use rustc_hir
::{BinOpKind, Expr, ExprKind}
;
6 use rustc_lint
::{LateContext, LateLintPass}
;
8 use rustc_session
::{declare_lint_pass, declare_tool_lint}
;
10 declare_clippy_lint
! {
12 /// Checks for uses of bitwise and/or operators between booleans, where performance may be improved by using
15 /// ### Why is this bad?
16 /// The bitwise operators do not support short-circuiting, so it may hinder code performance.
17 /// Additionally, boolean logic "masked" as bitwise logic is not caught by lints like `unnecessary_fold`
19 /// ### Known problems
20 /// This lint evaluates only when the right side is determined to have no side effects. At this time, that
21 /// determination is quite conservative.
25 /// let (x,y) = (true, false);
26 /// if x & !y {} // where both x and y are booleans
30 /// let (x,y) = (true, false);
33 #[clippy::version = "1.54.0"]
34 pub NEEDLESS_BITWISE_BOOL
,
36 "Boolean expressions that use bitwise rather than lazy operators"
39 declare_lint_pass
!(NeedlessBitwiseBool
=> [NEEDLESS_BITWISE_BOOL
]);
41 fn is_bitwise_operation(cx
: &LateContext
<'_
>, expr
: &Expr
<'_
>) -> bool
{
42 let ty
= cx
.typeck_results().expr_ty(expr
);
44 if !expr
.span
.from_expansion();
45 if let (&ExprKind
::Binary(ref op
, _
, right
), &ty
::Bool
) = (&expr
.kind
, &ty
.kind());
46 if op
.node
== BinOpKind
::BitAnd
|| op
.node
== BinOpKind
::BitOr
;
47 if let ExprKind
::Call(..) | ExprKind
::MethodCall(..) | ExprKind
::Binary(..) | ExprKind
::Unary(..) = right
.kind
;
48 if !right
.can_have_side_effects();
56 fn suggesstion_snippet(cx
: &LateContext
<'_
>, expr
: &Expr
<'_
>) -> Option
<String
> {
57 if let ExprKind
::Binary(ref op
, left
, right
) = expr
.kind
{
58 if let (Some(l_snippet
), Some(r_snippet
)) = (snippet_opt(cx
, left
.span
), snippet_opt(cx
, right
.span
)) {
59 let op_snippet
= match op
.node
{
60 BinOpKind
::BitAnd
=> "&&",
63 return Some(format
!("{} {} {}", l_snippet
, op_snippet
, r_snippet
));
69 impl LateLintPass
<'_
> for NeedlessBitwiseBool
{
70 fn check_expr(&mut self, cx
: &LateContext
<'_
>, expr
: &Expr
<'_
>) {
71 if is_bitwise_operation(cx
, expr
) {
74 NEEDLESS_BITWISE_BOOL
,
76 "use of bitwise operator instead of lazy operator between booleans",
78 if let Some(sugg
) = suggesstion_snippet(cx
, expr
) {
79 diag
.span_suggestion(expr
.span
, "try", sugg
, Applicability
::MachineApplicable
);