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.
This commit is contained in:
Marijn Suijten 2021-01-12 11:35:44 +01:00
parent 391bb218b5
commit d4bf59b6ef
3 changed files with 27 additions and 6 deletions

View File

@ -35,10 +35,11 @@ declare_clippy_lint! {
declare_lint_pass!(SizeOfInElementCount => [SIZE_OF_IN_ELEMENT_COUNT]);
fn get_size_of_ty(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<Ty<'tcx>> {
fn get_size_of_ty(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, inverted: bool) -> Option<Ty<'tcx>> {
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<Ty<'tc
}
}
},
ExprKind::Binary(op, left, right) if BinOpKind::Mul == op.node || BinOpKind::Div == op.node => {
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 @@ impl<'tcx> LateLintPass<'tcx> for SizeOfInElementCount {
// 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(

View File

@ -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::<u8>() / 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::<u8>()) };
// 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::<u8>())) };
// 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::<u8>())) };
// No size_of calls (Should not trigger the lint)
unsafe { copy(x.as_ptr(), y.as_mut_ptr(), SIZE) };

View File

@ -23,5 +23,13 @@ LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE * size_of::<u8>()
|
= 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::<u8>())) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= 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