]>
Commit | Line | Data |
---|---|---|
9c376795 FG |
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 | /// ``` | |
353b0b11 | 48 | #[clippy::version = "1.68.0"] |
9c376795 FG |
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 | } |