1
1
use clippy_config:: Conf ;
2
2
use clippy_utils:: diagnostics:: span_lint_and_then;
3
3
use 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 } ;
5
6
use rustc_hir:: { Expr , ExprKind } ;
6
7
use rustc_lint:: { LateContext , LateLintPass } ;
7
8
use rustc_session:: impl_lint_pass;
8
- use rustc_span:: sym;
9
+ use rustc_span:: { Span , sym} ;
9
10
10
11
declare_clippy_lint ! {
11
12
/// ### What it does
@@ -51,6 +52,24 @@ impl LargeIncludeFile {
51
52
52
53
impl_lint_pass ! ( LargeIncludeFile => [ LARGE_INCLUDE_FILE ] ) ;
53
54
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
+
54
73
impl LateLintPass < ' _ > for LargeIncludeFile {
55
74
fn check_expr ( & mut self , cx : & LateContext < ' _ > , expr : & ' _ Expr < ' _ > ) {
56
75
if let ExprKind :: Lit ( lit) = & expr. kind
@@ -66,19 +85,33 @@ impl LateLintPass<'_> for LargeIncludeFile {
66
85
&& ( cx. tcx . is_diagnostic_item ( sym:: include_bytes_macro, macro_call. def_id )
67
86
|| cx. tcx . is_diagnostic_item ( sym:: include_str_macro, macro_call. def_id ) )
68
87
{
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 ) ;
82
115
}
83
116
}
84
117
}
0 commit comments