Move IntegerDivision into Operators lint pass

This commit is contained in:
Jason Newcomb 2022-06-01 01:33:06 -04:00
parent 83de67cfec
commit a8df16ae1d
6 changed files with 58 additions and 65 deletions

View File

@ -1,61 +0,0 @@
use clippy_utils::diagnostics::span_lint_and_help;
use if_chain::if_chain;
use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
declare_clippy_lint! {
/// ### What it does
/// Checks for division of integers
///
/// ### Why is this bad?
/// When outside of some very specific algorithms,
/// integer division is very often a mistake because it discards the
/// remainder.
///
/// ### Example
/// ```rust
/// let x = 3 / 2;
/// println!("{}", x);
/// ```
///
/// Use instead:
/// ```rust
/// let x = 3f32 / 2f32;
/// println!("{}", x);
/// ```
#[clippy::version = "1.37.0"]
pub INTEGER_DIVISION,
restriction,
"integer division may cause loss of precision"
}
declare_lint_pass!(IntegerDivision => [INTEGER_DIVISION]);
impl<'tcx> LateLintPass<'tcx> for IntegerDivision {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
if is_integer_division(cx, expr) {
span_lint_and_help(
cx,
INTEGER_DIVISION,
expr.span,
"integer division",
None,
"division of integers may cause loss of precision. consider using floats",
);
}
}
}
fn is_integer_division<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) -> bool {
if_chain! {
if let hir::ExprKind::Binary(binop, left, right) = &expr.kind;
if binop.node == hir::BinOpKind::Div;
then {
let (left_ty, right_ty) = (cx.typeck_results().expr_ty(left), cx.typeck_results().expr_ty(right));
return left_ty.is_integral() && right_ty.is_integral();
}
}
false
}

View File

@ -194,7 +194,6 @@ store.register_lints(&[
init_numbered_fields::INIT_NUMBERED_FIELDS,
inline_fn_without_body::INLINE_FN_WITHOUT_BODY,
int_plus_one::INT_PLUS_ONE,
integer_division::INTEGER_DIVISION,
invalid_upcast_comparisons::INVALID_UPCAST_COMPARISONS,
items_after_statements::ITEMS_AFTER_STATEMENTS,
iter_not_returning_iterator::ITER_NOT_RETURNING_ITERATOR,
@ -434,6 +433,7 @@ store.register_lints(&[
operators::IDENTITY_OP,
operators::INEFFECTIVE_BIT_MASK,
operators::INTEGER_ARITHMETIC,
operators::INTEGER_DIVISION,
operators::MISREFACTORED_ASSIGN_OP,
operators::OP_REF,
operators::VERBOSE_BIT_MASK,

View File

@ -25,7 +25,6 @@ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), ve
LintId::of(implicit_return::IMPLICIT_RETURN),
LintId::of(indexing_slicing::INDEXING_SLICING),
LintId::of(inherent_impl::MULTIPLE_INHERENT_IMPL),
LintId::of(integer_division::INTEGER_DIVISION),
LintId::of(large_include_file::LARGE_INCLUDE_FILE),
LintId::of(let_underscore::LET_UNDERSCORE_MUST_USE),
LintId::of(literal_representation::DECIMAL_LITERAL_REPRESENTATION),
@ -52,6 +51,7 @@ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), ve
LintId::of(modulo_arithmetic::MODULO_ARITHMETIC),
LintId::of(operators::FLOAT_ARITHMETIC),
LintId::of(operators::INTEGER_ARITHMETIC),
LintId::of(operators::INTEGER_DIVISION),
LintId::of(panic_in_result_fn::PANIC_IN_RESULT_FN),
LintId::of(panic_unimplemented::PANIC),
LintId::of(panic_unimplemented::TODO),

View File

@ -254,7 +254,6 @@ mod inherent_to_string;
mod init_numbered_fields;
mod inline_fn_without_body;
mod int_plus_one;
mod integer_division;
mod invalid_upcast_comparisons;
mod items_after_statements;
mod iter_not_returning_iterator;
@ -734,7 +733,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|| Box::new(assertions_on_constants::AssertionsOnConstants));
store.register_late_pass(|| Box::new(transmuting_null::TransmutingNull));
store.register_late_pass(|| Box::new(path_buf_push_overwrite::PathBufPushOverwrite));
store.register_late_pass(|| Box::new(integer_division::IntegerDivision));
store.register_late_pass(|| Box::new(inherent_to_string::InherentToString));
let max_trait_bounds = conf.max_trait_bounds;
store.register_late_pass(move || Box::new(trait_bounds::TraitBounds::new(max_trait_bounds)));

View File

@ -0,0 +1,27 @@
use clippy_utils::diagnostics::span_lint_and_help;
use rustc_hir as hir;
use rustc_lint::LateContext;
use super::INTEGER_DIVISION;
pub(crate) fn check<'tcx>(
cx: &LateContext<'tcx>,
expr: &'tcx hir::Expr<'_>,
op: hir::BinOpKind,
left: &'tcx hir::Expr<'_>,
right: &'tcx hir::Expr<'_>,
) {
if op == hir::BinOpKind::Div
&& cx.typeck_results().expr_ty(left).is_integral()
&& cx.typeck_results().expr_ty(right).is_integral()
{
span_lint_and_help(
cx,
INTEGER_DIVISION,
expr.span,
"integer division",
None,
"division of integers may cause loss of precision. consider using floats",
);
}
}

View File

@ -11,6 +11,7 @@ mod eq_op;
mod erasing_op;
mod float_equality_without_abs;
mod identity_op;
mod integer_division;
mod misrefactored_assign_op;
mod numeric_arithmetic;
mod op_ref;
@ -437,6 +438,32 @@ declare_clippy_lint! {
"using identity operations, e.g., `x + 0` or `y / 1`"
}
declare_clippy_lint! {
/// ### What it does
/// Checks for division of integers
///
/// ### Why is this bad?
/// When outside of some very specific algorithms,
/// integer division is very often a mistake because it discards the
/// remainder.
///
/// ### Example
/// ```rust
/// let x = 3 / 2;
/// println!("{}", x);
/// ```
///
/// Use instead:
/// ```rust
/// let x = 3f32 / 2f32;
/// println!("{}", x);
/// ```
#[clippy::version = "1.37.0"]
pub INTEGER_DIVISION,
restriction,
"integer division may cause loss of precision"
}
pub struct Operators {
arithmetic_context: numeric_arithmetic::Context,
verbose_bit_mask_threshold: u64,
@ -457,6 +484,7 @@ impl_lint_pass!(Operators => [
ERASING_OP,
FLOAT_EQUALITY_WITHOUT_ABS,
IDENTITY_OP,
INTEGER_DIVISION,
]);
impl Operators {
pub fn new(verbose_bit_mask_threshold: u64) -> Self {
@ -486,6 +514,7 @@ impl<'tcx> LateLintPass<'tcx> for Operators {
double_comparison::check(cx, op.node, 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);
},
ExprKind::AssignOp(op, lhs, rhs) => {
self.arithmetic_context.check_binary(cx, e, op.node, lhs, rhs);