From dd78ce7bbe70fcb87ecc4f0ce11611be0b3a7e59 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Tue, 31 May 2022 14:07:50 -0400 Subject: [PATCH] Add `Operators` lint pass --- clippy_lints/src/lib.register_all.rs | 2 +- clippy_lints/src/lib.register_correctness.rs | 2 +- clippy_lints/src/lib.register_lints.rs | 2 +- clippy_lints/src/lib.rs | 4 +- .../absurd_extreme_comparisons.rs | 103 ++++++------------ clippy_lints/src/operators/mod.rs | 51 +++++++++ 6 files changed, 91 insertions(+), 73 deletions(-) rename clippy_lints/src/{ => operators}/absurd_extreme_comparisons.rs (53%) create mode 100644 clippy_lints/src/operators/mod.rs diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index b4edb8ea90e..7728157d228 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -3,7 +3,6 @@ // Manual edits will be overwritten. store.register_group(true, "clippy::all", Some("clippy_all"), vec![ - LintId::of(absurd_extreme_comparisons::ABSURD_EXTREME_COMPARISONS), LintId::of(almost_complete_letter_range::ALMOST_COMPLETE_LETTER_RANGE), LintId::of(approx_const::APPROX_CONSTANT), LintId::of(assertions_on_constants::ASSERTIONS_ON_CONSTANTS), @@ -260,6 +259,7 @@ LintId::of(non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS), LintId::of(octal_escapes::OCTAL_ESCAPES), LintId::of(open_options::NONSENSICAL_OPEN_OPTIONS), + LintId::of(operators::ABSURD_EXTREME_COMPARISONS), LintId::of(option_env_unwrap::OPTION_ENV_UNWRAP), LintId::of(overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL), LintId::of(partialeq_ne_impl::PARTIALEQ_NE_IMPL), diff --git a/clippy_lints/src/lib.register_correctness.rs b/clippy_lints/src/lib.register_correctness.rs index 92a3a0aabf1..26852445fdc 100644 --- a/clippy_lints/src/lib.register_correctness.rs +++ b/clippy_lints/src/lib.register_correctness.rs @@ -3,7 +3,6 @@ // Manual edits will be overwritten. store.register_group(true, "clippy::correctness", Some("clippy_correctness"), vec![ - LintId::of(absurd_extreme_comparisons::ABSURD_EXTREME_COMPARISONS), LintId::of(approx_const::APPROX_CONSTANT), LintId::of(async_yields_async::ASYNC_YIELDS_ASYNC), LintId::of(attrs::DEPRECATED_SEMVER), @@ -51,6 +50,7 @@ LintId::of(misc::MODULO_ONE), LintId::of(non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS), LintId::of(open_options::NONSENSICAL_OPEN_OPTIONS), + LintId::of(operators::ABSURD_EXTREME_COMPARISONS), LintId::of(option_env_unwrap::OPTION_ENV_UNWRAP), LintId::of(ptr::INVALID_NULL_PTR_USAGE), LintId::of(ptr::MUT_FROM_REF), diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index 29a5f368f23..f0ce0db65a7 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -35,7 +35,6 @@ utils::internal_lints::PRODUCE_ICE, #[cfg(feature = "internal")] utils::internal_lints::UNNECESSARY_SYMBOL_STR, - absurd_extreme_comparisons::ABSURD_EXTREME_COMPARISONS, almost_complete_letter_range::ALMOST_COMPLETE_LETTER_RANGE, approx_const::APPROX_CONSTANT, as_conversions::AS_CONVERSIONS, @@ -437,6 +436,7 @@ octal_escapes::OCTAL_ESCAPES, only_used_in_recursion::ONLY_USED_IN_RECURSION, open_options::NONSENSICAL_OPEN_OPTIONS, + operators::ABSURD_EXTREME_COMPARISONS, option_env_unwrap::OPTION_ENV_UNWRAP, option_if_let_else::OPTION_IF_LET_ELSE, overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 6c5b5ed98bc..16e72400fbf 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -168,7 +168,6 @@ macro_rules! declare_clippy_lint { mod renamed_lints; // begin lints modules, do not remove this comment, it’s used in `update_lints` -mod absurd_extreme_comparisons; mod almost_complete_letter_range; mod approx_const; mod as_conversions; @@ -336,6 +335,7 @@ macro_rules! declare_clippy_lint { mod octal_escapes; mod only_used_in_recursion; mod open_options; +mod operators; mod option_env_unwrap; mod option_if_let_else; mod overflow_check_conditional; @@ -683,7 +683,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(derivable_impls::DerivableImpls)); store.register_late_pass(|| Box::new(drop_forget_ref::DropForgetRef)); store.register_late_pass(|| Box::new(empty_enum::EmptyEnum)); - store.register_late_pass(|| Box::new(absurd_extreme_comparisons::AbsurdExtremeComparisons)); store.register_late_pass(|| Box::new(invalid_upcast_comparisons::InvalidUpcastComparisons)); store.register_late_pass(|| Box::new(regex::Regex)); store.register_late_pass(|| Box::new(copies::CopyAndPaste)); @@ -941,6 +940,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(default_instead_of_iter_empty::DefaultIterEmpty)); store.register_late_pass(move || Box::new(manual_rem_euclid::ManualRemEuclid::new(msrv))); store.register_late_pass(move || Box::new(manual_retain::ManualRetain::new(msrv))); + store.register_late_pass(|| Box::new(operators::Operators)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/clippy_lints/src/absurd_extreme_comparisons.rs b/clippy_lints/src/operators/absurd_extreme_comparisons.rs similarity index 53% rename from clippy_lints/src/absurd_extreme_comparisons.rs rename to clippy_lints/src/operators/absurd_extreme_comparisons.rs index 7665aa8380b..1ec4240afef 100644 --- a/clippy_lints/src/absurd_extreme_comparisons.rs +++ b/clippy_lints/src/operators/absurd_extreme_comparisons.rs @@ -1,7 +1,6 @@ use rustc_hir::{BinOpKind, Expr, ExprKind}; -use rustc_lint::{LateContext, LateLintPass}; +use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; use clippy_utils::comparisons::{normalize_comparison, Rel}; use clippy_utils::consts::{constant, Constant}; @@ -10,73 +9,41 @@ use clippy_utils::ty::is_isize_or_usize; use clippy_utils::{clip, int_bits, unsext}; -declare_clippy_lint! { - /// ### What it does - /// Checks for comparisons where one side of the relation is - /// either the minimum or maximum value for its type and warns if it involves a - /// case that is always true or always false. Only integer and boolean types are - /// checked. - /// - /// ### Why is this bad? - /// An expression like `min <= x` may misleadingly imply - /// that it is possible for `x` to be less than the minimum. Expressions like - /// `max < x` are probably mistakes. - /// - /// ### Known problems - /// For `usize` the size of the current compile target will - /// be assumed (e.g., 64 bits on 64 bit systems). This means code that uses such - /// a comparison to detect target pointer width will trigger this lint. One can - /// use `mem::sizeof` and compare its value or conditional compilation - /// attributes - /// like `#[cfg(target_pointer_width = "64")] ..` instead. - /// - /// ### Example - /// ```rust - /// let vec: Vec = Vec::new(); - /// if vec.len() <= 0 {} - /// if 100 > i32::MAX {} - /// ``` - #[clippy::version = "pre 1.29.0"] - pub ABSURD_EXTREME_COMPARISONS, - correctness, - "a comparison with a maximum or minimum value that is always true or false" -} +use super::ABSURD_EXTREME_COMPARISONS; -declare_lint_pass!(AbsurdExtremeComparisons => [ABSURD_EXTREME_COMPARISONS]); - -impl<'tcx> LateLintPass<'tcx> for AbsurdExtremeComparisons { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if let ExprKind::Binary(ref cmp, lhs, rhs) = expr.kind { - if let Some((culprit, result)) = detect_absurd_comparison(cx, cmp.node, lhs, rhs) { - if !expr.span.from_expansion() { - let msg = "this comparison involving the minimum or maximum element for this \ - type contains a case that is always true or always false"; - - let conclusion = match result { - AbsurdComparisonResult::AlwaysFalse => "this comparison is always false".to_owned(), - AbsurdComparisonResult::AlwaysTrue => "this comparison is always true".to_owned(), - AbsurdComparisonResult::InequalityImpossible => format!( - "the case where the two sides are not equal never occurs, consider using `{} == {}` \ - instead", - snippet(cx, lhs.span, "lhs"), - snippet(cx, rhs.span, "rhs") - ), - }; - - let help = format!( - "because `{}` is the {} value for this type, {}", - snippet(cx, culprit.expr.span, "x"), - match culprit.which { - ExtremeType::Minimum => "minimum", - ExtremeType::Maximum => "maximum", - }, - conclusion - ); - - span_lint_and_help(cx, ABSURD_EXTREME_COMPARISONS, expr.span, msg, None, &help); - } - } - } +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'_>, + op: BinOpKind, + lhs: &'tcx Expr<'_>, + rhs: &'tcx Expr<'_>, +) { + if let Some((culprit, result)) = detect_absurd_comparison(cx, op, lhs, rhs) { + let msg = "this comparison involving the minimum or maximum element for this \ + type contains a case that is always true or always false"; + + let conclusion = match result { + AbsurdComparisonResult::AlwaysFalse => "this comparison is always false".to_owned(), + AbsurdComparisonResult::AlwaysTrue => "this comparison is always true".to_owned(), + AbsurdComparisonResult::InequalityImpossible => format!( + "the case where the two sides are not equal never occurs, consider using `{} == {}` \ + instead", + snippet(cx, lhs.span, "lhs"), + snippet(cx, rhs.span, "rhs") + ), + }; + + let help = format!( + "because `{}` is the {} value for this type, {}", + snippet(cx, culprit.expr.span, "x"), + match culprit.which { + ExtremeType::Minimum => "minimum", + ExtremeType::Maximum => "maximum", + }, + conclusion + ); + + span_lint_and_help(cx, ABSURD_EXTREME_COMPARISONS, expr.span, msg, None, &help); } } diff --git a/clippy_lints/src/operators/mod.rs b/clippy_lints/src/operators/mod.rs new file mode 100644 index 00000000000..6f5a1647277 --- /dev/null +++ b/clippy_lints/src/operators/mod.rs @@ -0,0 +1,51 @@ +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_tool_lint, impl_lint_pass}; + +mod absurd_extreme_comparisons; + +declare_clippy_lint! { + /// ### What it does + /// Checks for comparisons where one side of the relation is + /// either the minimum or maximum value for its type and warns if it involves a + /// case that is always true or always false. Only integer and boolean types are + /// checked. + /// + /// ### Why is this bad? + /// An expression like `min <= x` may misleadingly imply + /// that it is possible for `x` to be less than the minimum. Expressions like + /// `max < x` are probably mistakes. + /// + /// ### Known problems + /// For `usize` the size of the current compile target will + /// be assumed (e.g., 64 bits on 64 bit systems). This means code that uses such + /// a comparison to detect target pointer width will trigger this lint. One can + /// use `mem::sizeof` and compare its value or conditional compilation + /// attributes + /// like `#[cfg(target_pointer_width = "64")] ..` instead. + /// + /// ### Example + /// ```rust + /// let vec: Vec = Vec::new(); + /// if vec.len() <= 0 {} + /// if 100 > i32::MAX {} + /// ``` + #[clippy::version = "pre 1.29.0"] + pub ABSURD_EXTREME_COMPARISONS, + correctness, + "a comparison with a maximum or minimum value that is always true or false" +} + +pub struct Operators; +impl_lint_pass!(Operators => [ + ABSURD_EXTREME_COMPARISONS, +]); +impl<'tcx> LateLintPass<'tcx> for Operators { + fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { + if let ExprKind::Binary(op, lhs, rhs) = e.kind { + if !e.span.from_expansion() { + absurd_extreme_comparisons::check(cx, e, op.node, lhs, rhs); + } + } + } +} -- 2.44.0