Auto merge of #10843 - MortenLohne:feat/double-const-comparisons, r=Centri3
New lints: `impossible_comparisons` and `redundant_comparisons` Inspired by a bug we had in production, like all good lints ;) Adds two lints for "double" comparisons, specifically when the same expression is being compared against two different constants. `impossible_comparisons` checks for expressions that can never be true at all. Example: ```rust status_code <= 400 && status_code > 500 ``` Presumably, the programmer intended to write `status_code >= 400 && status_code < 500` in this case. `redundant_comparisons` checks for expressions where either half has no effect. Example: ```rust status_code <= 400 && status_code < 500 ``` Works with other literal types like floats and strings, and *some* cases where the constant is more complex than a literal, see the tests for more. **Limitations and/or future work:** * Doesn't work if the LHS can have side-effects at all, for example by being a function call * Only works for exactly two comparison expressions, so `x > y && x > z && x < w` won't get checked * Doesn't check for comparison expressions combined with `||`. Very similar logic could be applied there. changelog: New lints [`impossible_comparisons`] and [`redundant_comparisons`]
This commit is contained in:
commit
6a2c8a1e7b
10 changed files with 601 additions and 22 deletions
|
|
@ -4897,6 +4897,7 @@ Released 2018-09-13
|
|||
[`implicit_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_return
|
||||
[`implicit_saturating_add`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_saturating_add
|
||||
[`implicit_saturating_sub`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_saturating_sub
|
||||
[`impossible_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#impossible_comparisons
|
||||
[`imprecise_flops`]: https://rust-lang.github.io/rust-clippy/master/index.html#imprecise_flops
|
||||
[`inconsistent_digit_grouping`]: https://rust-lang.github.io/rust-clippy/master/index.html#inconsistent_digit_grouping
|
||||
[`inconsistent_struct_constructor`]: https://rust-lang.github.io/rust-clippy/master/index.html#inconsistent_struct_constructor
|
||||
|
|
@ -5191,6 +5192,7 @@ Released 2018-09-13
|
|||
[`redundant_closure`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure
|
||||
[`redundant_closure_call`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure_call
|
||||
[`redundant_closure_for_method_calls`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure_for_method_calls
|
||||
[`redundant_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_comparisons
|
||||
[`redundant_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_else
|
||||
[`redundant_feature_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_feature_names
|
||||
[`redundant_field_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_field_names
|
||||
|
|
|
|||
|
|
@ -518,6 +518,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
|
|||
crate::operators::FLOAT_CMP_CONST_INFO,
|
||||
crate::operators::FLOAT_EQUALITY_WITHOUT_ABS_INFO,
|
||||
crate::operators::IDENTITY_OP_INFO,
|
||||
crate::operators::IMPOSSIBLE_COMPARISONS_INFO,
|
||||
crate::operators::INEFFECTIVE_BIT_MASK_INFO,
|
||||
crate::operators::INTEGER_DIVISION_INFO,
|
||||
crate::operators::MISREFACTORED_ASSIGN_OP_INFO,
|
||||
|
|
@ -526,6 +527,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
|
|||
crate::operators::NEEDLESS_BITWISE_BOOL_INFO,
|
||||
crate::operators::OP_REF_INFO,
|
||||
crate::operators::PTR_EQ_INFO,
|
||||
crate::operators::REDUNDANT_COMPARISONS_INFO,
|
||||
crate::operators::SELF_ASSIGNMENT_INFO,
|
||||
crate::operators::VERBOSE_BIT_MASK_INFO,
|
||||
crate::option_env_unwrap::OPTION_ENV_UNWRAP_INFO,
|
||||
|
|
|
|||
207
clippy_lints/src/operators/const_comparisons.rs
Normal file
207
clippy_lints/src/operators/const_comparisons.rs
Normal file
|
|
@ -0,0 +1,207 @@
|
|||
#![allow(clippy::match_same_arms)]
|
||||
|
||||
use std::cmp::Ordering;
|
||||
|
||||
use clippy_utils::consts::{constant, Constant};
|
||||
use if_chain::if_chain;
|
||||
use rustc_hir::{BinOpKind, Expr, ExprKind};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::ty::layout::HasTyCtxt;
|
||||
use rustc_middle::ty::{Ty, TypeckResults};
|
||||
use rustc_span::source_map::{Span, Spanned};
|
||||
|
||||
use clippy_utils::diagnostics::span_lint_and_note;
|
||||
use clippy_utils::source::snippet;
|
||||
use clippy_utils::SpanlessEq;
|
||||
|
||||
use super::{IMPOSSIBLE_COMPARISONS, REDUNDANT_COMPARISONS};
|
||||
|
||||
// Extract a comparison between a const and non-const
|
||||
// Flip yoda conditionals, turnings expressions like `42 < x` into `x > 42`
|
||||
fn comparison_to_const<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
typeck: &TypeckResults<'tcx>,
|
||||
expr: &'tcx Expr<'tcx>,
|
||||
) -> Option<(CmpOp, &'tcx Expr<'tcx>, &'tcx Expr<'tcx>, Constant<'tcx>, Ty<'tcx>)> {
|
||||
if_chain! {
|
||||
if let ExprKind::Binary(operator, left, right) = expr.kind;
|
||||
if let Ok(cmp_op) = CmpOp::try_from(operator.node);
|
||||
then {
|
||||
match (constant(cx, typeck, left), constant(cx, typeck, right)) {
|
||||
(Some(_), Some(_)) => None,
|
||||
(_, Some(con)) => Some((cmp_op, left, right, con, typeck.expr_ty(right))),
|
||||
(Some(con), _) => Some((cmp_op.reverse(), right, left, con, typeck.expr_ty(left))),
|
||||
_ => None,
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn check<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
and_op: Spanned<BinOpKind>,
|
||||
left_cond: &'tcx Expr<'tcx>,
|
||||
right_cond: &'tcx Expr<'tcx>,
|
||||
span: Span,
|
||||
) {
|
||||
if_chain! {
|
||||
// Ensure that the binary operator is &&
|
||||
if and_op.node == BinOpKind::And;
|
||||
|
||||
// Check that both operands to '&&' are themselves a binary operation
|
||||
// The `comparison_to_const` step also checks this, so this step is just an optimization
|
||||
if let ExprKind::Binary(_, _, _) = left_cond.kind;
|
||||
if let ExprKind::Binary(_, _, _) = right_cond.kind;
|
||||
|
||||
let typeck = cx.typeck_results();
|
||||
|
||||
// Check that both operands to '&&' compare a non-literal to a literal
|
||||
if let Some((left_cmp_op, left_expr, left_const_expr, left_const, left_type)) =
|
||||
comparison_to_const(cx, typeck, left_cond);
|
||||
if let Some((right_cmp_op, right_expr, right_const_expr, right_const, right_type)) =
|
||||
comparison_to_const(cx, typeck, right_cond);
|
||||
|
||||
if left_type == right_type;
|
||||
|
||||
// Check that the same expression is compared in both comparisons
|
||||
if SpanlessEq::new(cx).eq_expr(left_expr, right_expr);
|
||||
|
||||
if !left_expr.can_have_side_effects();
|
||||
|
||||
// Compare the two constant expressions
|
||||
if let Some(ordering) = Constant::partial_cmp(cx.tcx(), left_type, &left_const, &right_const);
|
||||
|
||||
// Rule out the `x >= 42 && x <= 42` corner case immediately
|
||||
// Mostly to simplify the implementation, but it is also covered by `clippy::double_comparisons`
|
||||
if !matches!(
|
||||
(&left_cmp_op, &right_cmp_op, ordering),
|
||||
(CmpOp::Le | CmpOp::Ge, CmpOp::Le | CmpOp::Ge, Ordering::Equal)
|
||||
);
|
||||
|
||||
then {
|
||||
if left_cmp_op.direction() == right_cmp_op.direction() {
|
||||
let lhs_str = snippet(cx, left_cond.span, "<lhs>");
|
||||
let rhs_str = snippet(cx, right_cond.span, "<rhs>");
|
||||
// We already know that either side of `&&` has no effect,
|
||||
// but emit a different error message depending on which side it is
|
||||
if left_side_is_useless(left_cmp_op, ordering) {
|
||||
span_lint_and_note(
|
||||
cx,
|
||||
REDUNDANT_COMPARISONS,
|
||||
span,
|
||||
"left-hand side of `&&` operator has no effect",
|
||||
Some(left_cond.span.until(right_cond.span)),
|
||||
&format!("`if `{rhs_str}` evaluates to true, {lhs_str}` will always evaluate to true as well"),
|
||||
);
|
||||
} else {
|
||||
span_lint_and_note(
|
||||
cx,
|
||||
REDUNDANT_COMPARISONS,
|
||||
span,
|
||||
"right-hand side of `&&` operator has no effect",
|
||||
Some(and_op.span.to(right_cond.span)),
|
||||
&format!("`if `{lhs_str}` evaluates to true, {rhs_str}` will always evaluate to true as well"),
|
||||
);
|
||||
}
|
||||
// We could autofix this error but choose not to,
|
||||
// because code triggering this lint probably not behaving correctly in the first place
|
||||
}
|
||||
else if !comparison_is_possible(left_cmp_op.direction(), ordering) {
|
||||
let expr_str = snippet(cx, left_expr.span, "..");
|
||||
let lhs_str = snippet(cx, left_const_expr.span, "<lhs>");
|
||||
let rhs_str = snippet(cx, right_const_expr.span, "<rhs>");
|
||||
let note = match ordering {
|
||||
Ordering::Less => format!("since `{lhs_str}` < `{rhs_str}`, the expression evaluates to false for any value of `{expr_str}`"),
|
||||
Ordering::Equal => format!("`{expr_str}` cannot simultaneously be greater than and less than `{lhs_str}`"),
|
||||
Ordering::Greater => format!("since `{lhs_str}` > `{rhs_str}`, the expression evaluates to false for any value of `{expr_str}`"),
|
||||
};
|
||||
span_lint_and_note(
|
||||
cx,
|
||||
IMPOSSIBLE_COMPARISONS,
|
||||
span,
|
||||
"boolean expression will never evaluate to 'true'",
|
||||
None,
|
||||
¬e,
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn left_side_is_useless(left_cmp_op: CmpOp, ordering: Ordering) -> bool {
|
||||
// Special-case for equal constants with an inclusive comparison
|
||||
if ordering == Ordering::Equal {
|
||||
match left_cmp_op {
|
||||
CmpOp::Lt | CmpOp::Gt => false,
|
||||
CmpOp::Le | CmpOp::Ge => true,
|
||||
}
|
||||
} else {
|
||||
match (left_cmp_op.direction(), ordering) {
|
||||
(CmpOpDirection::Lesser, Ordering::Less) => false,
|
||||
(CmpOpDirection::Lesser, Ordering::Equal) => false,
|
||||
(CmpOpDirection::Lesser, Ordering::Greater) => true,
|
||||
(CmpOpDirection::Greater, Ordering::Less) => true,
|
||||
(CmpOpDirection::Greater, Ordering::Equal) => false,
|
||||
(CmpOpDirection::Greater, Ordering::Greater) => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn comparison_is_possible(left_cmp_direction: CmpOpDirection, ordering: Ordering) -> bool {
|
||||
match (left_cmp_direction, ordering) {
|
||||
(CmpOpDirection::Lesser, Ordering::Less | Ordering::Equal) => false,
|
||||
(CmpOpDirection::Lesser, Ordering::Greater) => true,
|
||||
(CmpOpDirection::Greater, Ordering::Greater | Ordering::Equal) => false,
|
||||
(CmpOpDirection::Greater, Ordering::Less) => true,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Clone, Copy)]
|
||||
enum CmpOpDirection {
|
||||
Lesser,
|
||||
Greater,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
enum CmpOp {
|
||||
Lt,
|
||||
Le,
|
||||
Ge,
|
||||
Gt,
|
||||
}
|
||||
|
||||
impl CmpOp {
|
||||
fn reverse(self) -> Self {
|
||||
match self {
|
||||
CmpOp::Lt => CmpOp::Gt,
|
||||
CmpOp::Le => CmpOp::Ge,
|
||||
CmpOp::Ge => CmpOp::Le,
|
||||
CmpOp::Gt => CmpOp::Lt,
|
||||
}
|
||||
}
|
||||
|
||||
fn direction(self) -> CmpOpDirection {
|
||||
match self {
|
||||
CmpOp::Lt => CmpOpDirection::Lesser,
|
||||
CmpOp::Le => CmpOpDirection::Lesser,
|
||||
CmpOp::Ge => CmpOpDirection::Greater,
|
||||
CmpOp::Gt => CmpOpDirection::Greater,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<BinOpKind> for CmpOp {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(bin_op: BinOpKind) -> Result<Self, Self::Error> {
|
||||
match bin_op {
|
||||
BinOpKind::Lt => Ok(CmpOp::Lt),
|
||||
BinOpKind::Le => Ok(CmpOp::Le),
|
||||
BinOpKind::Ge => Ok(CmpOp::Ge),
|
||||
BinOpKind::Gt => Ok(CmpOp::Gt),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@ mod absurd_extreme_comparisons;
|
|||
mod assign_op_pattern;
|
||||
mod bit_mask;
|
||||
mod cmp_owned;
|
||||
mod const_comparisons;
|
||||
mod double_comparison;
|
||||
mod duration_subsec;
|
||||
mod eq_op;
|
||||
|
|
@ -298,6 +299,45 @@ declare_clippy_lint! {
|
|||
"unnecessary double comparisons that can be simplified"
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Checks for double comparisons that can never succeed
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// The whole expression can be replaced by `false`,
|
||||
/// which is probably not the programmer's intention
|
||||
///
|
||||
/// ### Example
|
||||
/// ```rust
|
||||
/// # let status_code = 200;
|
||||
/// if status_code <= 400 && status_code > 500 {}
|
||||
/// ```
|
||||
#[clippy::version = "1.71.0"]
|
||||
pub IMPOSSIBLE_COMPARISONS,
|
||||
correctness,
|
||||
"double comparisons that will never evaluate to `true`"
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Checks for ineffective double comparisons against constants.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// Only one of the comparisons has any effect on the result, the programmer
|
||||
/// probably intended to flip one of the comparison operators, or compare a
|
||||
/// different value entirely.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```rust
|
||||
/// # let status_code = 200;
|
||||
/// if status_code <= 400 && status_code < 500 {}
|
||||
/// ```
|
||||
#[clippy::version = "1.71.0"]
|
||||
pub REDUNDANT_COMPARISONS,
|
||||
correctness,
|
||||
"double comparisons where one of them can be removed"
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Checks for calculation of subsecond microseconds or milliseconds
|
||||
|
|
@ -742,6 +782,8 @@ impl_lint_pass!(Operators => [
|
|||
INEFFECTIVE_BIT_MASK,
|
||||
VERBOSE_BIT_MASK,
|
||||
DOUBLE_COMPARISONS,
|
||||
IMPOSSIBLE_COMPARISONS,
|
||||
REDUNDANT_COMPARISONS,
|
||||
DURATION_SUBSEC,
|
||||
EQ_OP,
|
||||
OP_REF,
|
||||
|
|
@ -786,6 +828,7 @@ impl<'tcx> LateLintPass<'tcx> for Operators {
|
|||
bit_mask::check(cx, e, op.node, lhs, rhs);
|
||||
verbose_bit_mask::check(cx, e, op.node, lhs, rhs, self.verbose_bit_mask_threshold);
|
||||
double_comparison::check(cx, op.node, lhs, rhs, e.span);
|
||||
const_comparisons::check(cx, op, lhs, rhs, e.span);
|
||||
duration_subsec::check(cx, e, op.node, lhs, rhs);
|
||||
float_equality_without_abs::check(cx, e, op.node, lhs, rhs);
|
||||
integer_division::check(cx, e, op.node, lhs, rhs);
|
||||
|
|
|
|||
|
|
@ -329,7 +329,7 @@ pub struct ConstEvalLateContext<'a, 'tcx> {
|
|||
}
|
||||
|
||||
impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
|
||||
fn new(lcx: &'a LateContext<'tcx>, typeck_results: &'a ty::TypeckResults<'tcx>) -> Self {
|
||||
pub fn new(lcx: &'a LateContext<'tcx>, typeck_results: &'a ty::TypeckResults<'tcx>) -> Self {
|
||||
Self {
|
||||
lcx,
|
||||
typeck_results,
|
||||
|
|
|
|||
93
tests/ui/const_comparisons.rs
Normal file
93
tests/ui/const_comparisons.rs
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
#![allow(unused)]
|
||||
#![warn(clippy::impossible_comparisons)]
|
||||
#![warn(clippy::redundant_comparisons)]
|
||||
#![allow(clippy::no_effect)]
|
||||
#![allow(clippy::short_circuit_statement)]
|
||||
#![allow(clippy::manual_range_contains)]
|
||||
|
||||
const STATUS_BAD_REQUEST: u16 = 400;
|
||||
const STATUS_SERVER_ERROR: u16 = 500;
|
||||
|
||||
struct Status {
|
||||
code: u16,
|
||||
}
|
||||
|
||||
impl PartialEq<u16> for Status {
|
||||
fn eq(&self, other: &u16) -> bool {
|
||||
self.code == *other
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd<u16> for Status {
|
||||
fn partial_cmp(&self, other: &u16) -> Option<std::cmp::Ordering> {
|
||||
self.code.partial_cmp(other)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<Status> for u16 {
|
||||
fn eq(&self, other: &Status) -> bool {
|
||||
*self == other.code
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd<Status> for u16 {
|
||||
fn partial_cmp(&self, other: &Status) -> Option<std::cmp::Ordering> {
|
||||
self.partial_cmp(&other.code)
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let status_code = 500; // Value doesn't matter for the lint
|
||||
let status = Status { code: status_code };
|
||||
|
||||
status_code >= 400 && status_code < 500; // Correct
|
||||
status_code <= 400 && status_code > 500;
|
||||
status_code > 500 && status_code < 400;
|
||||
status_code < 500 && status_code > 500;
|
||||
|
||||
// More complex expressions
|
||||
status_code < { 400 } && status_code > { 500 };
|
||||
status_code < STATUS_BAD_REQUEST && status_code > STATUS_SERVER_ERROR;
|
||||
status_code <= u16::MIN + 1 && status_code > STATUS_SERVER_ERROR;
|
||||
status_code < STATUS_SERVER_ERROR && status_code > STATUS_SERVER_ERROR;
|
||||
|
||||
// Comparing two different types, via the `impl PartialOrd<u16> for Status`
|
||||
status < { 400 } && status > { 500 };
|
||||
status < STATUS_BAD_REQUEST && status > STATUS_SERVER_ERROR;
|
||||
status <= u16::MIN + 1 && status > STATUS_SERVER_ERROR;
|
||||
status < STATUS_SERVER_ERROR && status > STATUS_SERVER_ERROR;
|
||||
|
||||
// Yoda conditions
|
||||
500 <= status_code && 600 > status_code; // Correct
|
||||
500 <= status_code && status_code <= 600; // Correct
|
||||
500 >= status_code && 600 < status_code; // Incorrect
|
||||
500 >= status_code && status_code > 600; // Incorrect
|
||||
|
||||
// Yoda conditions, comparing two different types
|
||||
500 <= status && 600 > status; // Correct
|
||||
500 <= status && status <= 600; // Correct
|
||||
500 >= status && 600 < status; // Incorrect
|
||||
500 >= status && status > 600; // Incorrect
|
||||
|
||||
// Expressions where one of the sides has no effect
|
||||
status_code < 200 && status_code <= 299;
|
||||
status_code > 200 && status_code >= 299;
|
||||
|
||||
status_code >= 500 && status_code > 500; // Useless left
|
||||
status_code > 500 && status_code >= 500; // Useless right
|
||||
status_code <= 500 && status_code < 500; // Useless left
|
||||
status_code < 500 && status_code <= 500; // Useless right
|
||||
|
||||
// Other types
|
||||
let name = "Steve";
|
||||
name < "Jennifer" && name > "Shannon";
|
||||
|
||||
let numbers = [1, 2];
|
||||
numbers < [3, 4] && numbers > [5, 6];
|
||||
|
||||
let letter = 'a';
|
||||
letter < 'b' && letter > 'c';
|
||||
|
||||
let area = 42.0;
|
||||
area < std::f32::consts::E && area > std::f32::consts::PI;
|
||||
}
|
||||
228
tests/ui/const_comparisons.stderr
Normal file
228
tests/ui/const_comparisons.stderr
Normal file
|
|
@ -0,0 +1,228 @@
|
|||
error: boolean expression will never evaluate to 'true'
|
||||
--> $DIR/const_comparisons.rs:44:5
|
||||
|
|
||||
LL | status_code <= 400 && status_code > 500;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: since `400` < `500`, the expression evaluates to false for any value of `status_code`
|
||||
= note: `-D clippy::impossible-comparisons` implied by `-D warnings`
|
||||
|
||||
error: boolean expression will never evaluate to 'true'
|
||||
--> $DIR/const_comparisons.rs:45:5
|
||||
|
|
||||
LL | status_code > 500 && status_code < 400;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: since `500` > `400`, the expression evaluates to false for any value of `status_code`
|
||||
|
||||
error: boolean expression will never evaluate to 'true'
|
||||
--> $DIR/const_comparisons.rs:46:5
|
||||
|
|
||||
LL | status_code < 500 && status_code > 500;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `status_code` cannot simultaneously be greater than and less than `500`
|
||||
|
||||
error: boolean expression will never evaluate to 'true'
|
||||
--> $DIR/const_comparisons.rs:49:5
|
||||
|
|
||||
LL | status_code < { 400 } && status_code > { 500 };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: since `{ 400 }` < `{ 500 }`, the expression evaluates to false for any value of `status_code`
|
||||
|
||||
error: boolean expression will never evaluate to 'true'
|
||||
--> $DIR/const_comparisons.rs:50:5
|
||||
|
|
||||
LL | status_code < STATUS_BAD_REQUEST && status_code > STATUS_SERVER_ERROR;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: since `STATUS_BAD_REQUEST` < `STATUS_SERVER_ERROR`, the expression evaluates to false for any value of `status_code`
|
||||
|
||||
error: boolean expression will never evaluate to 'true'
|
||||
--> $DIR/const_comparisons.rs:51:5
|
||||
|
|
||||
LL | status_code <= u16::MIN + 1 && status_code > STATUS_SERVER_ERROR;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: since `u16::MIN + 1` < `STATUS_SERVER_ERROR`, the expression evaluates to false for any value of `status_code`
|
||||
|
||||
error: boolean expression will never evaluate to 'true'
|
||||
--> $DIR/const_comparisons.rs:52:5
|
||||
|
|
||||
LL | status_code < STATUS_SERVER_ERROR && status_code > STATUS_SERVER_ERROR;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `status_code` cannot simultaneously be greater than and less than `STATUS_SERVER_ERROR`
|
||||
|
||||
error: boolean expression will never evaluate to 'true'
|
||||
--> $DIR/const_comparisons.rs:55:5
|
||||
|
|
||||
LL | status < { 400 } && status > { 500 };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: since `{ 400 }` < `{ 500 }`, the expression evaluates to false for any value of `status`
|
||||
|
||||
error: boolean expression will never evaluate to 'true'
|
||||
--> $DIR/const_comparisons.rs:56:5
|
||||
|
|
||||
LL | status < STATUS_BAD_REQUEST && status > STATUS_SERVER_ERROR;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: since `STATUS_BAD_REQUEST` < `STATUS_SERVER_ERROR`, the expression evaluates to false for any value of `status`
|
||||
|
||||
error: boolean expression will never evaluate to 'true'
|
||||
--> $DIR/const_comparisons.rs:57:5
|
||||
|
|
||||
LL | status <= u16::MIN + 1 && status > STATUS_SERVER_ERROR;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: since `u16::MIN + 1` < `STATUS_SERVER_ERROR`, the expression evaluates to false for any value of `status`
|
||||
|
||||
error: boolean expression will never evaluate to 'true'
|
||||
--> $DIR/const_comparisons.rs:58:5
|
||||
|
|
||||
LL | status < STATUS_SERVER_ERROR && status > STATUS_SERVER_ERROR;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `status` cannot simultaneously be greater than and less than `STATUS_SERVER_ERROR`
|
||||
|
||||
error: boolean expression will never evaluate to 'true'
|
||||
--> $DIR/const_comparisons.rs:63:5
|
||||
|
|
||||
LL | 500 >= status_code && 600 < status_code; // Incorrect
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: since `500` < `600`, the expression evaluates to false for any value of `status_code`
|
||||
|
||||
error: boolean expression will never evaluate to 'true'
|
||||
--> $DIR/const_comparisons.rs:64:5
|
||||
|
|
||||
LL | 500 >= status_code && status_code > 600; // Incorrect
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: since `500` < `600`, the expression evaluates to false for any value of `status_code`
|
||||
|
||||
error: boolean expression will never evaluate to 'true'
|
||||
--> $DIR/const_comparisons.rs:69:5
|
||||
|
|
||||
LL | 500 >= status && 600 < status; // Incorrect
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: since `500` < `600`, the expression evaluates to false for any value of `status`
|
||||
|
||||
error: boolean expression will never evaluate to 'true'
|
||||
--> $DIR/const_comparisons.rs:70:5
|
||||
|
|
||||
LL | 500 >= status && status > 600; // Incorrect
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: since `500` < `600`, the expression evaluates to false for any value of `status`
|
||||
|
||||
error: right-hand side of `&&` operator has no effect
|
||||
--> $DIR/const_comparisons.rs:73:5
|
||||
|
|
||||
LL | status_code < 200 && status_code <= 299;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: `if `status_code < 200` evaluates to true, status_code <= 299` will always evaluate to true as well
|
||||
--> $DIR/const_comparisons.rs:73:23
|
||||
|
|
||||
LL | status_code < 200 && status_code <= 299;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
= note: `-D clippy::redundant-comparisons` implied by `-D warnings`
|
||||
|
||||
error: left-hand side of `&&` operator has no effect
|
||||
--> $DIR/const_comparisons.rs:74:5
|
||||
|
|
||||
LL | status_code > 200 && status_code >= 299;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: `if `status_code >= 299` evaluates to true, status_code > 200` will always evaluate to true as well
|
||||
--> $DIR/const_comparisons.rs:74:5
|
||||
|
|
||||
LL | status_code > 200 && status_code >= 299;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: left-hand side of `&&` operator has no effect
|
||||
--> $DIR/const_comparisons.rs:76:5
|
||||
|
|
||||
LL | status_code >= 500 && status_code > 500; // Useless left
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: `if `status_code > 500` evaluates to true, status_code >= 500` will always evaluate to true as well
|
||||
--> $DIR/const_comparisons.rs:76:5
|
||||
|
|
||||
LL | status_code >= 500 && status_code > 500; // Useless left
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: right-hand side of `&&` operator has no effect
|
||||
--> $DIR/const_comparisons.rs:77:5
|
||||
|
|
||||
LL | status_code > 500 && status_code >= 500; // Useless right
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: `if `status_code > 500` evaluates to true, status_code >= 500` will always evaluate to true as well
|
||||
--> $DIR/const_comparisons.rs:77:23
|
||||
|
|
||||
LL | status_code > 500 && status_code >= 500; // Useless right
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: left-hand side of `&&` operator has no effect
|
||||
--> $DIR/const_comparisons.rs:78:5
|
||||
|
|
||||
LL | status_code <= 500 && status_code < 500; // Useless left
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: `if `status_code < 500` evaluates to true, status_code <= 500` will always evaluate to true as well
|
||||
--> $DIR/const_comparisons.rs:78:5
|
||||
|
|
||||
LL | status_code <= 500 && status_code < 500; // Useless left
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: right-hand side of `&&` operator has no effect
|
||||
--> $DIR/const_comparisons.rs:79:5
|
||||
|
|
||||
LL | status_code < 500 && status_code <= 500; // Useless right
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: `if `status_code < 500` evaluates to true, status_code <= 500` will always evaluate to true as well
|
||||
--> $DIR/const_comparisons.rs:79:23
|
||||
|
|
||||
LL | status_code < 500 && status_code <= 500; // Useless right
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: boolean expression will never evaluate to 'true'
|
||||
--> $DIR/const_comparisons.rs:83:5
|
||||
|
|
||||
LL | name < "Jennifer" && name > "Shannon";
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: since `"Jennifer"` < `"Shannon"`, the expression evaluates to false for any value of `name`
|
||||
|
||||
error: boolean expression will never evaluate to 'true'
|
||||
--> $DIR/const_comparisons.rs:86:5
|
||||
|
|
||||
LL | numbers < [3, 4] && numbers > [5, 6];
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: since `[3, 4]` < `[5, 6]`, the expression evaluates to false for any value of `numbers`
|
||||
|
||||
error: boolean expression will never evaluate to 'true'
|
||||
--> $DIR/const_comparisons.rs:89:5
|
||||
|
|
||||
LL | letter < 'b' && letter > 'c';
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: since `'b'` < `'c'`, the expression evaluates to false for any value of `letter`
|
||||
|
||||
error: boolean expression will never evaluate to 'true'
|
||||
--> $DIR/const_comparisons.rs:92:5
|
||||
|
|
||||
LL | area < std::f32::consts::E && area > std::f32::consts::PI;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: since `std::f32::consts::E` < `std::f32::consts::PI`, the expression evaluates to false for any value of `area`
|
||||
|
||||
error: aborting due to 25 previous errors
|
||||
|
||||
|
|
@ -5,6 +5,8 @@
|
|||
#![allow(clippy::no_effect)]
|
||||
#![allow(clippy::short_circuit_statement)]
|
||||
#![allow(clippy::unnecessary_operation)]
|
||||
#![allow(clippy::impossible_comparisons)]
|
||||
#![allow(clippy::redundant_comparisons)]
|
||||
|
||||
fn main() {
|
||||
let x = 9_i32;
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@
|
|||
#![allow(clippy::no_effect)]
|
||||
#![allow(clippy::short_circuit_statement)]
|
||||
#![allow(clippy::unnecessary_operation)]
|
||||
#![allow(clippy::impossible_comparisons)]
|
||||
#![allow(clippy::redundant_comparisons)]
|
||||
|
||||
fn main() {
|
||||
let x = 9_i32;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
error: manual `Range::contains` implementation
|
||||
--> $DIR/range_contains.rs:13:5
|
||||
--> $DIR/range_contains.rs:15:5
|
||||
|
|
||||
LL | x >= 8 && x < 12;
|
||||
| ^^^^^^^^^^^^^^^^ help: use: `(8..12).contains(&x)`
|
||||
|
|
@ -7,121 +7,121 @@ LL | x >= 8 && x < 12;
|
|||
= note: `-D clippy::manual-range-contains` implied by `-D warnings`
|
||||
|
||||
error: manual `Range::contains` implementation
|
||||
--> $DIR/range_contains.rs:14:5
|
||||
--> $DIR/range_contains.rs:16:5
|
||||
|
|
||||
LL | x < 42 && x >= 21;
|
||||
| ^^^^^^^^^^^^^^^^^ help: use: `(21..42).contains(&x)`
|
||||
|
||||
error: manual `Range::contains` implementation
|
||||
--> $DIR/range_contains.rs:15:5
|
||||
--> $DIR/range_contains.rs:17:5
|
||||
|
|
||||
LL | 100 > x && 1 <= x;
|
||||
| ^^^^^^^^^^^^^^^^^ help: use: `(1..100).contains(&x)`
|
||||
|
||||
error: manual `RangeInclusive::contains` implementation
|
||||
--> $DIR/range_contains.rs:18:5
|
||||
--> $DIR/range_contains.rs:20:5
|
||||
|
|
||||
LL | x >= 9 && x <= 99;
|
||||
| ^^^^^^^^^^^^^^^^^ help: use: `(9..=99).contains(&x)`
|
||||
|
||||
error: manual `RangeInclusive::contains` implementation
|
||||
--> $DIR/range_contains.rs:19:5
|
||||
--> $DIR/range_contains.rs:21:5
|
||||
|
|
||||
LL | x <= 33 && x >= 1;
|
||||
| ^^^^^^^^^^^^^^^^^ help: use: `(1..=33).contains(&x)`
|
||||
|
||||
error: manual `RangeInclusive::contains` implementation
|
||||
--> $DIR/range_contains.rs:20:5
|
||||
--> $DIR/range_contains.rs:22:5
|
||||
|
|
||||
LL | 999 >= x && 1 <= x;
|
||||
| ^^^^^^^^^^^^^^^^^^ help: use: `(1..=999).contains(&x)`
|
||||
|
||||
error: manual `!Range::contains` implementation
|
||||
--> $DIR/range_contains.rs:23:5
|
||||
--> $DIR/range_contains.rs:25:5
|
||||
|
|
||||
LL | x < 8 || x >= 12;
|
||||
| ^^^^^^^^^^^^^^^^ help: use: `!(8..12).contains(&x)`
|
||||
|
||||
error: manual `!Range::contains` implementation
|
||||
--> $DIR/range_contains.rs:24:5
|
||||
--> $DIR/range_contains.rs:26:5
|
||||
|
|
||||
LL | x >= 42 || x < 21;
|
||||
| ^^^^^^^^^^^^^^^^^ help: use: `!(21..42).contains(&x)`
|
||||
|
||||
error: manual `!Range::contains` implementation
|
||||
--> $DIR/range_contains.rs:25:5
|
||||
--> $DIR/range_contains.rs:27:5
|
||||
|
|
||||
LL | 100 <= x || 1 > x;
|
||||
| ^^^^^^^^^^^^^^^^^ help: use: `!(1..100).contains(&x)`
|
||||
|
||||
error: manual `!RangeInclusive::contains` implementation
|
||||
--> $DIR/range_contains.rs:28:5
|
||||
--> $DIR/range_contains.rs:30:5
|
||||
|
|
||||
LL | x < 9 || x > 99;
|
||||
| ^^^^^^^^^^^^^^^ help: use: `!(9..=99).contains(&x)`
|
||||
|
||||
error: manual `!RangeInclusive::contains` implementation
|
||||
--> $DIR/range_contains.rs:29:5
|
||||
--> $DIR/range_contains.rs:31:5
|
||||
|
|
||||
LL | x > 33 || x < 1;
|
||||
| ^^^^^^^^^^^^^^^ help: use: `!(1..=33).contains(&x)`
|
||||
|
||||
error: manual `!RangeInclusive::contains` implementation
|
||||
--> $DIR/range_contains.rs:30:5
|
||||
--> $DIR/range_contains.rs:32:5
|
||||
|
|
||||
LL | 999 < x || 1 > x;
|
||||
| ^^^^^^^^^^^^^^^^ help: use: `!(1..=999).contains(&x)`
|
||||
|
||||
error: manual `Range::contains` implementation
|
||||
--> $DIR/range_contains.rs:45:5
|
||||
--> $DIR/range_contains.rs:47:5
|
||||
|
|
||||
LL | y >= 0. && y < 1.;
|
||||
| ^^^^^^^^^^^^^^^^^ help: use: `(0. ..1.).contains(&y)`
|
||||
|
||||
error: manual `!RangeInclusive::contains` implementation
|
||||
--> $DIR/range_contains.rs:46:5
|
||||
--> $DIR/range_contains.rs:48:5
|
||||
|
|
||||
LL | y < 0. || y > 1.;
|
||||
| ^^^^^^^^^^^^^^^^ help: use: `!(0. ..=1.).contains(&y)`
|
||||
|
||||
error: manual `RangeInclusive::contains` implementation
|
||||
--> $DIR/range_contains.rs:49:5
|
||||
--> $DIR/range_contains.rs:51:5
|
||||
|
|
||||
LL | x >= -10 && x <= 10;
|
||||
| ^^^^^^^^^^^^^^^^^^^ help: use: `(-10..=10).contains(&x)`
|
||||
|
||||
error: manual `RangeInclusive::contains` implementation
|
||||
--> $DIR/range_contains.rs:51:5
|
||||
--> $DIR/range_contains.rs:53:5
|
||||
|
|
||||
LL | y >= -3. && y <= 3.;
|
||||
| ^^^^^^^^^^^^^^^^^^^ help: use: `(-3. ..=3.).contains(&y)`
|
||||
|
||||
error: manual `RangeInclusive::contains` implementation
|
||||
--> $DIR/range_contains.rs:56:30
|
||||
--> $DIR/range_contains.rs:58:30
|
||||
|
|
||||
LL | (x >= 0) && (x <= 10) && (z >= 0) && (z <= 10);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ help: use: `(0..=10).contains(&z)`
|
||||
|
||||
error: manual `RangeInclusive::contains` implementation
|
||||
--> $DIR/range_contains.rs:56:5
|
||||
--> $DIR/range_contains.rs:58:5
|
||||
|
|
||||
LL | (x >= 0) && (x <= 10) && (z >= 0) && (z <= 10);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ help: use: `(0..=10).contains(&x)`
|
||||
|
||||
error: manual `!Range::contains` implementation
|
||||
--> $DIR/range_contains.rs:57:29
|
||||
--> $DIR/range_contains.rs:59:29
|
||||
|
|
||||
LL | (x < 0) || (x >= 10) || (z < 0) || (z >= 10);
|
||||
| ^^^^^^^^^^^^^^^^^^^^ help: use: `!(0..10).contains(&z)`
|
||||
|
||||
error: manual `!Range::contains` implementation
|
||||
--> $DIR/range_contains.rs:57:5
|
||||
--> $DIR/range_contains.rs:59:5
|
||||
|
|
||||
LL | (x < 0) || (x >= 10) || (z < 0) || (z >= 10);
|
||||
| ^^^^^^^^^^^^^^^^^^^^ help: use: `!(0..10).contains(&x)`
|
||||
|
||||
error: manual `Range::contains` implementation
|
||||
--> $DIR/range_contains.rs:76:5
|
||||
--> $DIR/range_contains.rs:78:5
|
||||
|
|
||||
LL | x >= 8 && x < 35;
|
||||
| ^^^^^^^^^^^^^^^^ help: use: `(8..35).contains(&x)`
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue