]> git.lizzy.rs Git - rust.git/blob - src/tools/clippy/clippy_lints/src/large_include_file.rs
Rollup merge of #103443 - mucinoab:recover-colon-as-path-separetor, r=compiler-errors
[rust.git] / src / tools / clippy / 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     /// Use instead:
26     /// ```rust,ignore
27     /// use std::fs;
28     ///
29     /// // You can load the file at runtime
30     /// let string = fs::read_to_string("very_large_file.txt")?;
31     /// let bytes = fs::read("very_large_file.txt")?;
32     /// ```
33     #[clippy::version = "1.62.0"]
34     pub LARGE_INCLUDE_FILE,
35     restriction,
36     "including a large file"
37 }
38
39 pub struct LargeIncludeFile {
40     max_file_size: u64,
41 }
42
43 impl LargeIncludeFile {
44     #[must_use]
45     pub fn new(max_file_size: u64) -> Self {
46         Self { max_file_size }
47     }
48 }
49
50 impl_lint_pass!(LargeIncludeFile => [LARGE_INCLUDE_FILE]);
51
52 impl LateLintPass<'_> for LargeIncludeFile {
53     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) {
54         if_chain! {
55             if let Some(macro_call) = root_macro_call_first_node(cx, expr);
56             if !is_lint_allowed(cx, LARGE_INCLUDE_FILE, expr.hir_id);
57             if cx.tcx.is_diagnostic_item(sym::include_bytes_macro, macro_call.def_id)
58             || cx.tcx.is_diagnostic_item(sym::include_str_macro, macro_call.def_id);
59             if let ExprKind::Lit(lit) = &expr.kind;
60             then {
61                 let len = match &lit.node {
62                     // include_bytes
63                     LitKind::ByteStr(bstr) => bstr.len(),
64                     // include_str
65                     LitKind::Str(sym, _) => sym.as_str().len(),
66                     _ => return,
67                 };
68
69                 if len as u64 <= self.max_file_size {
70                     return;
71                 }
72
73                 span_lint_and_note(
74                     cx,
75                     LARGE_INCLUDE_FILE,
76                     expr.span,
77                     "attempted to include a large file",
78                     None,
79                     &format!(
80                         "the configuration allows a maximum size of {} bytes",
81                         self.max_file_size
82                     ),
83                 );
84             }
85         }
86     }
87 }