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