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