1 use rustc_hir
::{BinOpKind, Expr, ExprKind}
;
2 use rustc_lint
::LateContext
;
5 use clippy_utils
::comparisons
::{normalize_comparison, Rel}
;
6 use clippy_utils
::consts
::{constant, Constant}
;
7 use clippy_utils
::diagnostics
::span_lint_and_help
;
8 use clippy_utils
::source
::snippet
;
9 use clippy_utils
::ty
::is_isize_or_usize
;
10 use clippy_utils
::{clip, int_bits, unsext}
;
12 use super::ABSURD_EXTREME_COMPARISONS
;
14 pub(super) fn check
<'tcx
>(
15 cx
: &LateContext
<'tcx
>,
21 if let Some((culprit
, result
)) = detect_absurd_comparison(cx
, op
, lhs
, rhs
) {
22 let msg
= "this comparison involving the minimum or maximum element for this \
23 type contains a case that is always true or always false";
25 let conclusion
= match result
{
26 AbsurdComparisonResult
::AlwaysFalse
=> "this comparison is always false".to_owned(),
27 AbsurdComparisonResult
::AlwaysTrue
=> "this comparison is always true".to_owned(),
28 AbsurdComparisonResult
::InequalityImpossible
=> format
!(
29 "the case where the two sides are not equal never occurs, consider using `{} == {}` \
31 snippet(cx
, lhs
.span
, "lhs"),
32 snippet(cx
, rhs
.span
, "rhs")
37 "because `{}` is the {} value for this type, {conclusion}",
38 snippet(cx
, culprit
.expr
.span
, "x"),
40 ExtremeType
::Minimum
=> "minimum",
41 ExtremeType
::Maximum
=> "maximum",
45 span_lint_and_help(cx
, ABSURD_EXTREME_COMPARISONS
, expr
.span
, msg
, None
, &help
);
54 struct ExtremeExpr
<'a
> {
59 enum AbsurdComparisonResult
{
65 fn is_cast_between_fixed_and_target
<'tcx
>(cx
: &LateContext
<'tcx
>, expr
: &'tcx Expr
<'tcx
>) -> bool
{
66 if let ExprKind
::Cast(cast_exp
, _
) = expr
.kind
{
67 let precast_ty
= cx
.typeck_results().expr_ty(cast_exp
);
68 let cast_ty
= cx
.typeck_results().expr_ty(expr
);
70 return is_isize_or_usize(precast_ty
) != is_isize_or_usize(cast_ty
);
76 fn detect_absurd_comparison
<'tcx
>(
77 cx
: &LateContext
<'tcx
>,
81 ) -> Option
<(ExtremeExpr
<'tcx
>, AbsurdComparisonResult
)> {
82 use AbsurdComparisonResult
::{AlwaysFalse, AlwaysTrue, InequalityImpossible}
;
83 use ExtremeType
::{Maximum, Minimum}
;
84 // absurd comparison only makes sense on primitive types
85 // primitive types don't implement comparison operators with each other
86 if cx
.typeck_results().expr_ty(lhs
) != cx
.typeck_results().expr_ty(rhs
) {
90 // comparisons between fix sized types and target sized types are considered unanalyzable
91 if is_cast_between_fixed_and_target(cx
, lhs
) || is_cast_between_fixed_and_target(cx
, rhs
) {
95 let (rel
, normalized_lhs
, normalized_rhs
) = normalize_comparison(op
, lhs
, rhs
)?
;
97 let lx
= detect_extreme_expr(cx
, normalized_lhs
);
98 let rx
= detect_extreme_expr(cx
, normalized_rhs
);
103 (Some(l @ ExtremeExpr { which: Maximum, .. }
), _
) => (l
, AlwaysFalse
), // max < x
104 (_
, Some(r @ ExtremeExpr { which: Minimum, .. }
)) => (r
, AlwaysFalse
), // x < min
110 (Some(l @ ExtremeExpr { which: Minimum, .. }
), _
) => (l
, AlwaysTrue
), // min <= x
111 (Some(l @ ExtremeExpr { which: Maximum, .. }
), _
) => (l
, InequalityImpossible
), // max <= x
112 (_
, Some(r @ ExtremeExpr { which: Minimum, .. }
)) => (r
, InequalityImpossible
), // x <= min
113 (_
, Some(r @ ExtremeExpr { which: Maximum, .. }
)) => (r
, AlwaysTrue
), // x <= max
117 Rel
::Ne
| Rel
::Eq
=> return None
,
121 fn detect_extreme_expr
<'tcx
>(cx
: &LateContext
<'tcx
>, expr
: &'tcx Expr
<'_
>) -> Option
<ExtremeExpr
<'tcx
>> {
122 let ty
= cx
.typeck_results().expr_ty(expr
);
124 let cv
= constant(cx
, cx
.typeck_results(), expr
)?
.0;
126 let which
= match (ty
.kind(), cv
) {
127 (&ty
::Bool
, Constant
::Bool(false)) | (&ty
::Uint(_
), Constant
::Int(0)) => ExtremeType
::Minimum
,
128 (&ty
::Int(ity
), Constant
::Int(i
)) if i
== unsext(cx
.tcx
, i128
::MIN
>> (128 - int_bits(cx
.tcx
, ity
)), ity
) => {
132 (&ty
::Bool
, Constant
::Bool(true)) => ExtremeType
::Maximum
,
133 (&ty
::Int(ity
), Constant
::Int(i
)) if i
== unsext(cx
.tcx
, i128
::MAX
>> (128 - int_bits(cx
.tcx
, ity
)), ity
) => {
136 (&ty
::Uint(uty
), Constant
::Int(i
)) if clip(cx
.tcx
, u128
::MAX
, uty
) == i
=> ExtremeType
::Maximum
,
140 Some(ExtremeExpr { which, expr }
)