From d4bf59b6ef24042653951b69105a3a68542f3bbd Mon Sep 17 00:00:00 2001 From: Marijn Suijten Date: Tue, 12 Jan 2021 11:35:44 +0100 Subject: [PATCH] size_of_in_element_count: Disable lint on division by byte-size It is fairly common to divide some length in bytes by the byte-size of a single element before creating a `from_raw_parts` slice or similar operation. This lint would erroneously disallow such expressions. Just in case, instead of simply disabling this lint in the RHS of a division, keep track of the inversion and enable it again on recursive division. --- clippy_lints/src/size_of_in_element_count.rs | 14 +++++++++----- tests/ui/size_of_in_element_count/expressions.rs | 9 +++++++++ .../ui/size_of_in_element_count/expressions.stderr | 10 +++++++++- 3 files changed, 27 insertions(+), 6 deletions(-) diff --git a/clippy_lints/src/size_of_in_element_count.rs b/clippy_lints/src/size_of_in_element_count.rs index ea7a76146f5..87e386baadc 100644 --- a/clippy_lints/src/size_of_in_element_count.rs +++ b/clippy_lints/src/size_of_in_element_count.rs @@ -35,10 +35,11 @@ declare_lint_pass!(SizeOfInElementCount => [SIZE_OF_IN_ELEMENT_COUNT]); -fn get_size_of_ty(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option> { +fn get_size_of_ty(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, inverted: bool) -> Option> { match expr.kind { ExprKind::Call(count_func, _func_args) => { if_chain! { + if !inverted; if let ExprKind::Path(ref count_func_qpath) = count_func.kind; if let Some(def_id) = cx.qpath_res(count_func_qpath, count_func.hir_id).opt_def_id(); if match_def_path(cx, def_id, &paths::MEM_SIZE_OF) @@ -50,10 +51,13 @@ fn get_size_of_ty(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option { - get_size_of_ty(cx, left).or_else(|| get_size_of_ty(cx, right)) + ExprKind::Binary(op, left, right) if BinOpKind::Mul == op.node => { + get_size_of_ty(cx, left, inverted).or_else(|| get_size_of_ty(cx, right, inverted)) }, - ExprKind::Cast(expr, _) => get_size_of_ty(cx, expr), + ExprKind::Binary(op, left, right) if BinOpKind::Div == op.node => { + get_size_of_ty(cx, left, inverted).or_else(|| get_size_of_ty(cx, right, !inverted)) + }, + ExprKind::Cast(expr, _) => get_size_of_ty(cx, expr, inverted), _ => None, } } @@ -128,7 +132,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { // Find a size_of call in the count parameter expression and // check that it's the same type - if let Some(ty_used_for_size_of) = get_size_of_ty(cx, count_expr); + if let Some(ty_used_for_size_of) = get_size_of_ty(cx, count_expr, false); if TyS::same_type(pointee_ty, ty_used_for_size_of); then { span_lint_and_help( diff --git a/tests/ui/size_of_in_element_count/expressions.rs b/tests/ui/size_of_in_element_count/expressions.rs index b56910917ba..2594e8fa6ad 100644 --- a/tests/ui/size_of_in_element_count/expressions.rs +++ b/tests/ui/size_of_in_element_count/expressions.rs @@ -20,6 +20,15 @@ fn main() { // Count expression involving divisions of size_of (Should trigger the lint) unsafe { copy(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE * size_of::() / 2) }; + // Count expression involving divisions by size_of (Should not trigger the lint) + unsafe { copy(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE / size_of::()) }; + + // Count expression involving divisions by multiple size_of (Should not trigger the lint) + unsafe { copy(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE / (2 * size_of::())) }; + + // Count expression involving recursive divisions by size_of (Should trigger the lint) + unsafe { copy(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE / (2 / size_of::())) }; + // No size_of calls (Should not trigger the lint) unsafe { copy(x.as_ptr(), y.as_mut_ptr(), SIZE) }; diff --git a/tests/ui/size_of_in_element_count/expressions.stderr b/tests/ui/size_of_in_element_count/expressions.stderr index 47b98e9d947..0f0dff57f51 100644 --- a/tests/ui/size_of_in_element_count/expressions.stderr +++ b/tests/ui/size_of_in_element_count/expressions.stderr @@ -23,5 +23,13 @@ LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE * size_of::() | = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type -error: aborting due to 3 previous errors +error: found a count of bytes instead of a count of elements of `T` + --> $DIR/expressions.rs:30:47 + | +LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE / (2 / size_of::())) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type + +error: aborting due to 4 previous errors -- 2.44.0