]> git.lizzy.rs Git - rust.git/blob - src/tools/clippy/clippy_lints/src/size_of_ref.rs
Rollup merge of #105903 - joboet:unify_parking, r=m-ou-se
[rust.git] / src / tools / clippy / clippy_lints / src / size_of_ref.rs
1 use clippy_utils::{diagnostics::span_lint_and_help, path_def_id, ty::peel_mid_ty_refs};
2 use rustc_hir::{Expr, ExprKind};
3 use rustc_lint::{LateContext, LateLintPass};
4 use rustc_session::{declare_lint_pass, declare_tool_lint};
5 use rustc_span::sym;
6
7 declare_clippy_lint! {
8     /// ### What it does
9     ///
10     /// Checks for calls to `std::mem::size_of_val()` where the argument is
11     /// a reference to a reference.
12     ///
13     /// ### Why is this bad?
14     ///
15     /// Calling `size_of_val()` with a reference to a reference as the argument
16     /// yields the size of the reference-type, not the size of the value behind
17     /// the reference.
18     ///
19     /// ### Example
20     /// ```rust
21     /// struct Foo {
22     ///     buffer: [u8],
23     /// }
24     ///
25     /// impl Foo {
26     ///     fn size(&self) -> usize {
27     ///         // Note that `&self` as an argument is a `&&Foo`: Because `self`
28     ///         // is already a reference, `&self` is a double-reference.
29     ///         // The return value of `size_of_val()` therefor is the
30     ///         // size of the reference-type, not the size of `self`.
31     ///         std::mem::size_of_val(&self)
32     ///     }
33     /// }
34     /// ```
35     /// Use instead:
36     /// ```rust
37     /// struct Foo {
38     ///     buffer: [u8],
39     /// }
40     ///
41     /// impl Foo {
42     ///     fn size(&self) -> usize {
43     ///         // Correct
44     ///         std::mem::size_of_val(self)
45     ///     }
46     /// }
47     /// ```
48     #[clippy::version = "1.67.0"]
49     pub SIZE_OF_REF,
50     suspicious,
51     "Argument to `std::mem::size_of_val()` is a double-reference, which is almost certainly unintended"
52 }
53 declare_lint_pass!(SizeOfRef => [SIZE_OF_REF]);
54
55 impl LateLintPass<'_> for SizeOfRef {
56     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) {
57         if let ExprKind::Call(path, [arg]) = expr.kind
58             && let Some(def_id) = path_def_id(cx, path)
59             && cx.tcx.is_diagnostic_item(sym::mem_size_of_val, def_id)
60             && let arg_ty = cx.typeck_results().expr_ty(arg)
61             && peel_mid_ty_refs(arg_ty).1 > 1
62         {
63             span_lint_and_help(
64                 cx,
65                 SIZE_OF_REF,
66                 expr.span,
67                 "argument to `std::mem::size_of_val()` is a reference to a reference",
68                 None,
69                 "dereference the argument to `std::mem::size_of_val()` to get the size of the value instead of the size of the reference-type",
70             );
71         }
72     }
73 }