]> git.lizzy.rs Git - rust.git/blob - clippy_lints/src/large_include_file.rs
Merge remote-tracking branch 'upstream/master' into rustup
[rust.git] / clippy_lints / src / large_include_file.rs
1 use clippy_utils::diagnostics::span_lint_and_note;
2 use clippy_utils::is_lint_allowed;
3 use clippy_utils::macros::root_macro_call_first_node;
4 use rustc_ast::LitKind;
5 use rustc_hir::Expr;
6 use rustc_hir::ExprKind;
7 use rustc_lint::{LateContext, LateLintPass};
8 use rustc_session::{declare_tool_lint, impl_lint_pass};
9 use rustc_span::sym;
10
11 declare_clippy_lint! {
12     /// ### What it does
13     /// Checks for the inclusion of large files via `include_bytes!()`
14     /// and `include_str!()`
15     ///
16     /// ### Why is this bad?
17     /// Including large files can increase the size of the binary
18     ///
19     /// ### Example
20     /// ```rust,ignore
21     /// let included_str = include_str!("very_large_file.txt");
22     /// let included_bytes = include_bytes!("very_large_file.txt");
23     /// ```
24     ///
25     /// Instead, you can load the file at runtime:
26     /// ```rust,ignore
27     /// use std::fs;
28     ///
29     /// let string = fs::read_to_string("very_large_file.txt")?;
30     /// let bytes = fs::read("very_large_file.txt")?;
31     /// ```
32     #[clippy::version = "1.62.0"]
33     pub LARGE_INCLUDE_FILE,
34     restriction,
35     "including a large file"
36 }
37
38 pub struct LargeIncludeFile {
39     max_file_size: u64,
40 }
41
42 impl LargeIncludeFile {
43     #[must_use]
44     pub fn new(max_file_size: u64) -> Self {
45         Self { max_file_size }
46     }
47 }
48
49 impl_lint_pass!(LargeIncludeFile => [LARGE_INCLUDE_FILE]);
50
51 impl LateLintPass<'_> for LargeIncludeFile {
52     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) {
53         if_chain! {
54             if let Some(macro_call) = root_macro_call_first_node(cx, expr);
55             if !is_lint_allowed(cx, LARGE_INCLUDE_FILE, expr.hir_id);
56             if cx.tcx.is_diagnostic_item(sym::include_bytes_macro, macro_call.def_id)
57             || cx.tcx.is_diagnostic_item(sym::include_str_macro, macro_call.def_id);
58             if let ExprKind::Lit(lit) = &expr.kind;
59             then {
60                 let len = match &lit.node {
61                     // include_bytes
62                     LitKind::ByteStr(bstr) => bstr.len(),
63                     // include_str
64                     LitKind::Str(sym, _) => sym.as_str().len(),
65                     _ => return,
66                 };
67
68                 if len as u64 <= self.max_file_size {
69                     return;
70                 }
71
72                 span_lint_and_note(
73                     cx,
74                     LARGE_INCLUDE_FILE,
75                     expr.span,
76                     "attempted to include a large file",
77                     None,
78                     &format!(
79                         "the configuration allows a maximum size of {} bytes",
80                         self.max_file_size
81                     ),
82                 );
83             }
84         }
85     }
86 }