1
1
use clippy_utils:: diagnostics:: span_lint_and_help;
2
2
use rustc_ast:: {
3
3
node_id:: NodeId ,
4
+ ptr:: P ,
4
5
visit:: { FnKind , Visitor } ,
5
- Arm , AssocItemKind , Block , Expr , ExprKind , Item , ItemKind , Local , LocalKind , ModKind , Pat , PatKind , Stmt , StmtKind ,
6
+ Arm , AssocItemKind , Block , Expr , ExprKind , Inline , Item , ItemKind , Local , LocalKind , ModKind , ModSpans , Pat ,
7
+ PatKind , Stmt , StmtKind ,
6
8
} ;
7
- use rustc_lint:: { EarlyContext , EarlyLintPass } ;
8
- // TODO: Use this? Not sure if this is necessary here. After all, this is pre macro expansion...
9
- // use rustc_middle::lint::in_external_macro;
9
+ use rustc_lint:: { EarlyContext , EarlyLintPass , LintContext } ;
10
+ use rustc_middle:: lint:: in_external_macro;
10
11
use rustc_session:: { declare_tool_lint, impl_lint_pass} ;
11
12
use rustc_span:: Span ;
13
+ use thin_vec:: ThinVec ;
12
14
13
15
declare_clippy_lint ! {
14
16
/// ### What it does
@@ -20,10 +22,44 @@ declare_clippy_lint! {
20
22
/// It can severely hinder readability. The default is very generous; if you
21
23
/// exceed this, it's a sign you should refactor.
22
24
///
25
+ /// ### Known issues
26
+ ///
27
+ /// Nested inline modules will all be linted, rather than just the outermost one
28
+ /// that applies. This makes the output a bit verbose.
29
+ ///
23
30
/// ### Example
24
- /// TODO
31
+ /// An example clippy.toml configuration:
32
+ /// ```toml
33
+ /// # clippy.toml
34
+ /// excessive-nesting-threshold = 3
35
+ /// ```
36
+ /// lib.rs:
37
+ /// ```rust,ignore
38
+ /// pub mod a {
39
+ /// pub struct X;
40
+ /// impl X {
41
+ /// pub fn run(&self) {
42
+ /// if true {
43
+ /// // etc...
44
+ /// }
45
+ /// }
46
+ /// }
47
+ /// }
25
48
/// Use instead:
26
- /// TODO
49
+ /// a.rs:
50
+ /// ```rust,ignore
51
+ /// fn private_run(x: &X) {
52
+ /// if true {
53
+ /// // etc...
54
+ /// }
55
+ /// }
56
+ ///
57
+ /// pub struct X;
58
+ /// impl X {
59
+ /// pub fn run(&self) {
60
+ /// private_run(self);
61
+ /// }
62
+ /// }
27
63
#[ clippy:: version = "1.70.0" ]
28
64
pub EXCESSIVE_NESTING ,
29
65
restriction,
@@ -58,14 +94,13 @@ impl<'conf, 'cx> Visitor<'_> for NestingVisitor<'conf, 'cx> {
58
94
fn visit_local ( & mut self , local : & Local ) {
59
95
self . visit_pat ( & local. pat ) ;
60
96
61
- #[ expect( clippy:: match_wildcard_for_single_variants, reason = "this is intentional" ) ]
62
97
match & local. kind {
63
98
LocalKind :: Init ( expr) => self . visit_expr ( expr) ,
64
99
LocalKind :: InitElse ( expr, block) => {
65
100
self . visit_expr ( expr) ;
66
101
self . visit_block ( block) ;
67
102
} ,
68
- _ => ( ) ,
103
+ LocalKind :: Decl => ( ) ,
69
104
}
70
105
}
71
106
@@ -163,10 +198,13 @@ impl<'conf, 'cx> Visitor<'_> for NestingVisitor<'conf, 'cx> {
163
198
| ExprKind :: Await ( expr)
164
199
| ExprKind :: Field ( expr, ..)
165
200
| ExprKind :: AddrOf ( .., expr)
166
- | ExprKind :: Repeat ( expr, ..)
167
201
| ExprKind :: Try ( expr) => {
168
202
self . visit_expr ( expr) ;
169
203
} ,
204
+ ExprKind :: Repeat ( expr, anon_const) => {
205
+ self . visit_expr ( expr) ;
206
+ self . visit_expr ( & anon_const. value ) ;
207
+ }
170
208
ExprKind :: If ( expr, block, else_expr) => {
171
209
self . visit_expr ( expr) ;
172
210
self . visit_block ( block) ;
@@ -221,11 +259,11 @@ impl<'conf, 'cx> Visitor<'_> for NestingVisitor<'conf, 'cx> {
221
259
}
222
260
223
261
fn visit_fn ( & mut self , fk : FnKind < ' _ > , _: Span , _: NodeId ) {
224
- #[ expect( clippy:: match_wildcard_for_single_variants, reason = "this is intentional" ) ]
225
262
match fk {
226
263
FnKind :: Fn ( .., block) if let Some ( block) = block => self . visit_block ( block) ,
227
264
FnKind :: Closure ( .., expr) => self . visit_expr ( expr) ,
228
- _ => ( ) ,
265
+ // :/
266
+ FnKind :: Fn ( ..) => ( ) ,
229
267
}
230
268
}
231
269
@@ -234,55 +272,42 @@ impl<'conf, 'cx> Visitor<'_> for NestingVisitor<'conf, 'cx> {
234
272
ItemKind :: Static ( static_item) if let Some ( expr) = static_item. expr . as_ref ( ) => self . visit_expr ( expr) ,
235
273
ItemKind :: Const ( const_item) if let Some ( expr) = const_item. expr . as_ref ( ) => self . visit_expr ( expr) ,
236
274
ItemKind :: Fn ( fk) if let Some ( block) = fk. body . as_ref ( ) => self . visit_block ( block) ,
237
- ItemKind :: Mod ( .., mod_kind) if let ModKind :: Loaded ( items, inline, ..) = mod_kind => {
275
+ ItemKind :: Mod ( .., mod_kind)
276
+ if let ModKind :: Loaded ( items, Inline :: Yes , ModSpans { inner_span, ..} ) = mod_kind =>
277
+ {
238
278
self . nest_level += 1 ;
239
279
240
- for item in items {
241
- self . visit_item ( item) ;
242
- }
280
+ check_indent ( self , * inner_span) ;
243
281
244
282
self . nest_level -= 1 ;
245
283
}
246
- // TODO: These 2 are duplicated
247
- ItemKind :: Trait ( trit) => {
248
- self . nest_level += 1 ;
249
-
250
- for item in & trit. items {
251
- match & item. kind {
252
- // TODO: This is copied from above, is this necessary?
253
- AssocItemKind :: Const ( const_item) if let Some ( expr) = const_item. expr . as_ref ( ) => {
254
- self . visit_expr ( expr) ;
255
- } ,
256
- AssocItemKind :: Fn ( fk) if let Some ( block) = fk. body . as_ref ( ) => self . visit_block ( block) ,
257
- _ => ( ) ,
258
- }
259
- }
260
-
261
- self . nest_level -= 1 ;
262
- }
263
- ItemKind :: Impl ( imp) => {
264
- self . nest_level += 1 ;
284
+ ItemKind :: Trait ( trit) => check_trait_and_impl ( self , item, & trit. items ) ,
285
+ ItemKind :: Impl ( imp) => check_trait_and_impl ( self , item, & imp. items ) ,
286
+ _ => ( ) ,
287
+ }
288
+ }
289
+ }
265
290
266
- for item in & imp. items {
267
- match & item. kind {
268
- // TODO: This is copied from above, is this necessary?
269
- AssocItemKind :: Const ( const_item) if let Some ( expr) = const_item. expr . as_ref ( ) => {
270
- self . visit_expr ( expr) ;
271
- } ,
272
- AssocItemKind :: Fn ( fk) if let Some ( block) = fk. body . as_ref ( ) => self . visit_block ( block) ,
273
- _ => ( ) ,
274
- }
275
- }
291
+ fn check_trait_and_impl ( visitor : & mut NestingVisitor < ' _ , ' _ > , item : & Item , items : & ThinVec < P < Item < AssocItemKind > > > ) {
292
+ visitor. nest_level += 1 ;
276
293
277
- self . nest_level -= 1 ;
294
+ if !check_indent ( visitor, item. span ) {
295
+ for item in items {
296
+ match & item. kind {
297
+ AssocItemKind :: Const ( const_item) if let Some ( expr) = const_item. expr . as_ref ( ) => {
298
+ visitor. visit_expr ( expr) ;
299
+ } ,
300
+ AssocItemKind :: Fn ( fk) if let Some ( block) = fk. body . as_ref ( ) => visitor. visit_block ( block) ,
301
+ _ => ( ) ,
278
302
}
279
- _ => ( ) ,
280
303
}
281
304
}
305
+
306
+ visitor. nest_level -= 1 ;
282
307
}
283
308
284
309
fn check_indent ( visitor : & NestingVisitor < ' _ , ' _ > , span : Span ) -> bool {
285
- if visitor. nest_level > visitor. conf . excessive_nesting_threshold {
310
+ if visitor. nest_level > visitor. conf . excessive_nesting_threshold && ! in_external_macro ( visitor . cx . sess ( ) , span ) {
286
311
span_lint_and_help (
287
312
visitor. cx ,
288
313
EXCESSIVE_NESTING ,
0 commit comments