11use clippy_config:: Conf ;
22use clippy_utils:: diagnostics:: span_lint_and_then;
33use clippy_utils:: macros:: root_macro_call_first_node;
4- use rustc_ast:: LitKind ;
4+ use clippy_utils:: source:: snippet_opt;
5+ use rustc_ast:: { AttrArgs , AttrArgsEq , AttrKind , Attribute , LitKind } ;
56use rustc_hir:: { Expr , ExprKind } ;
67use rustc_lint:: { LateContext , LateLintPass } ;
78use rustc_session:: impl_lint_pass;
8- use rustc_span:: sym;
9+ use rustc_span:: { Span , sym} ;
910
1011declare_clippy_lint ! {
1112 /// ### What it does
@@ -51,6 +52,24 @@ impl LargeIncludeFile {
5152
5253impl_lint_pass ! ( LargeIncludeFile => [ LARGE_INCLUDE_FILE ] ) ;
5354
55+ impl LargeIncludeFile {
56+ fn emit_lint ( & self , cx : & LateContext < ' _ > , span : Span ) {
57+ #[ expect( clippy:: collapsible_span_lint_calls, reason = "rust-clippy#7797" ) ]
58+ span_lint_and_then (
59+ cx,
60+ LARGE_INCLUDE_FILE ,
61+ span,
62+ "attempted to include a large file" ,
63+ |diag| {
64+ diag. note ( format ! (
65+ "the configuration allows a maximum size of {} bytes" ,
66+ self . max_file_size
67+ ) ) ;
68+ } ,
69+ ) ;
70+ }
71+ }
72+
5473impl LateLintPass < ' _ > for LargeIncludeFile {
5574 fn check_expr ( & mut self , cx : & LateContext < ' _ > , expr : & ' _ Expr < ' _ > ) {
5675 if let ExprKind :: Lit ( lit) = & expr. kind
@@ -66,19 +85,33 @@ impl LateLintPass<'_> for LargeIncludeFile {
6685 && ( cx. tcx . is_diagnostic_item ( sym:: include_bytes_macro, macro_call. def_id )
6786 || cx. tcx . is_diagnostic_item ( sym:: include_str_macro, macro_call. def_id ) )
6887 {
69- #[ expect( clippy:: collapsible_span_lint_calls, reason = "rust-clippy#7797" ) ]
70- span_lint_and_then (
71- cx,
72- LARGE_INCLUDE_FILE ,
73- expr. span . source_callsite ( ) ,
74- "attempted to include a large file" ,
75- |diag| {
76- diag. note ( format ! (
77- "the configuration allows a maximum size of {} bytes" ,
78- self . max_file_size
79- ) ) ;
80- } ,
81- ) ;
88+ self . emit_lint ( cx, expr. span . source_callsite ( ) ) ;
89+ }
90+ }
91+
92+ fn check_attribute ( & mut self , cx : & LateContext < ' _ > , attr : & Attribute ) {
93+ if !attr. span . from_expansion ( )
94+ // Currently, rustc limits the usage of macro at the top-level of attributes,
95+ // so we don't need to recurse into each level.
96+ && let AttrKind :: Normal ( ref normal) = attr. kind
97+ && let AttrArgs :: Eq ( _, AttrArgsEq :: Hir ( ref meta) ) = normal. item . args
98+ && !attr. span . contains ( meta. span )
99+ // Since the `include_str` is already expanded at this point, we can only take the
100+ // whole attribute snippet and then modify for our suggestion.
101+ && let Some ( snippet) = snippet_opt ( cx, attr. span )
102+ // We cannot remove this because a `#[doc = include_str!("...")]` attribute can
103+ // occupy several lines.
104+ && let Some ( start) = snippet. find ( '[' )
105+ && let Some ( end) = snippet. rfind ( ']' )
106+ && let snippet = & snippet[ start + 1 ..end]
107+ // We check that the expansion actually comes from `include_str!` and not just from
108+ // another macro.
109+ && let Some ( sub_snippet) = snippet. trim ( ) . strip_prefix ( "doc" )
110+ && let Some ( sub_snippet) = sub_snippet. trim ( ) . strip_prefix ( "=" )
111+ && let sub_snippet = sub_snippet. trim ( )
112+ && ( sub_snippet. starts_with ( "include_str!" ) || sub_snippet. starts_with ( "include_bytes!" ) )
113+ {
114+ self . emit_lint ( cx, attr. span ) ;
82115 }
83116 }
84117}
0 commit comments