]>
Commit | Line | Data |
---|---|---|
1 | use crate::rustc_target::abi::LayoutOf; | |
2 | use clippy_utils::diagnostics::span_lint_and_then; | |
3 | use if_chain::if_chain; | |
4 | use rustc_errors::Applicability; | |
5 | use rustc_hir::{Item, ItemKind}; | |
6 | use rustc_lint::{LateContext, LateLintPass}; | |
7 | use rustc_middle::mir::interpret::ConstValue; | |
8 | use rustc_middle::ty::{self, ConstKind}; | |
9 | use rustc_session::{declare_tool_lint, impl_lint_pass}; | |
10 | use rustc_span::{BytePos, Pos, Span}; | |
11 | use rustc_typeck::hir_ty_to_ty; | |
12 | ||
13 | declare_clippy_lint! { | |
14 | /// ### What it does | |
15 | /// Checks for large `const` arrays that should | |
16 | /// be defined as `static` instead. | |
17 | /// | |
18 | /// ### Why is this bad? | |
19 | /// Performance: const variables are inlined upon use. | |
20 | /// Static items result in only one instance and has a fixed location in memory. | |
21 | /// | |
22 | /// ### Example | |
23 | /// ```rust,ignore | |
24 | /// // Bad | |
25 | /// pub const a = [0u32; 1_000_000]; | |
26 | /// | |
27 | /// // Good | |
28 | /// pub static a = [0u32; 1_000_000]; | |
29 | /// ``` | |
30 | pub LARGE_CONST_ARRAYS, | |
31 | perf, | |
32 | "large non-scalar const array may cause performance overhead" | |
33 | } | |
34 | ||
35 | pub struct LargeConstArrays { | |
36 | maximum_allowed_size: u64, | |
37 | } | |
38 | ||
39 | impl LargeConstArrays { | |
40 | #[must_use] | |
41 | pub fn new(maximum_allowed_size: u64) -> Self { | |
42 | Self { maximum_allowed_size } | |
43 | } | |
44 | } | |
45 | ||
46 | impl_lint_pass!(LargeConstArrays => [LARGE_CONST_ARRAYS]); | |
47 | ||
48 | impl<'tcx> LateLintPass<'tcx> for LargeConstArrays { | |
49 | fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { | |
50 | if_chain! { | |
51 | if !item.span.from_expansion(); | |
52 | if let ItemKind::Const(hir_ty, _) = &item.kind; | |
53 | let ty = hir_ty_to_ty(cx.tcx, hir_ty); | |
54 | if let ty::Array(element_type, cst) = ty.kind(); | |
55 | if let ConstKind::Value(ConstValue::Scalar(element_count)) = cst.val; | |
56 | if let Ok(element_count) = element_count.to_machine_usize(&cx.tcx); | |
57 | if let Ok(element_size) = cx.layout_of(element_type).map(|l| l.size.bytes()); | |
58 | if self.maximum_allowed_size < element_count * element_size; | |
59 | ||
60 | then { | |
61 | let hi_pos = item.ident.span.lo() - BytePos::from_usize(1); | |
62 | let sugg_span = Span::new( | |
63 | hi_pos - BytePos::from_usize("const".len()), | |
64 | hi_pos, | |
65 | item.span.ctxt(), | |
66 | ); | |
67 | span_lint_and_then( | |
68 | cx, | |
69 | LARGE_CONST_ARRAYS, | |
70 | item.span, | |
71 | "large array defined as const", | |
72 | |diag| { | |
73 | diag.span_suggestion( | |
74 | sugg_span, | |
75 | "make this a static item", | |
76 | "static".to_string(), | |
77 | Applicability::MachineApplicable, | |
78 | ); | |
79 | } | |
80 | ); | |
81 | } | |
82 | } | |
83 | } | |
84 | } |