11use clippy_utils:: diagnostics:: span_lint_and_help;
22use rustc_ast:: {
33 node_id:: NodeId ,
4+ ptr:: P ,
45 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 ,
68} ;
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;
1011use rustc_session:: { declare_tool_lint, impl_lint_pass} ;
1112use rustc_span:: Span ;
13+ use thin_vec:: ThinVec ;
1214
1315declare_clippy_lint ! {
1416 /// ### What it does
@@ -20,10 +22,44 @@ declare_clippy_lint! {
2022 /// It can severely hinder readability. The default is very generous; if you
2123 /// exceed this, it's a sign you should refactor.
2224 ///
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+ ///
2330 /// ### 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+ /// }
2548 /// 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+ /// }
2763 #[ clippy:: version = "1.70.0" ]
2864 pub EXCESSIVE_NESTING ,
2965 restriction,
@@ -58,14 +94,13 @@ impl<'conf, 'cx> Visitor<'_> for NestingVisitor<'conf, 'cx> {
5894 fn visit_local ( & mut self , local : & Local ) {
5995 self . visit_pat ( & local. pat ) ;
6096
61- #[ expect( clippy:: match_wildcard_for_single_variants, reason = "this is intentional" ) ]
6297 match & local. kind {
6398 LocalKind :: Init ( expr) => self . visit_expr ( expr) ,
6499 LocalKind :: InitElse ( expr, block) => {
65100 self . visit_expr ( expr) ;
66101 self . visit_block ( block) ;
67102 } ,
68- _ => ( ) ,
103+ LocalKind :: Decl => ( ) ,
69104 }
70105 }
71106
@@ -163,10 +198,13 @@ impl<'conf, 'cx> Visitor<'_> for NestingVisitor<'conf, 'cx> {
163198 | ExprKind :: Await ( expr)
164199 | ExprKind :: Field ( expr, ..)
165200 | ExprKind :: AddrOf ( .., expr)
166- | ExprKind :: Repeat ( expr, ..)
167201 | ExprKind :: Try ( expr) => {
168202 self . visit_expr ( expr) ;
169203 } ,
204+ ExprKind :: Repeat ( expr, anon_const) => {
205+ self . visit_expr ( expr) ;
206+ self . visit_expr ( & anon_const. value ) ;
207+ }
170208 ExprKind :: If ( expr, block, else_expr) => {
171209 self . visit_expr ( expr) ;
172210 self . visit_block ( block) ;
@@ -221,11 +259,11 @@ impl<'conf, 'cx> Visitor<'_> for NestingVisitor<'conf, 'cx> {
221259 }
222260
223261 fn visit_fn ( & mut self , fk : FnKind < ' _ > , _: Span , _: NodeId ) {
224- #[ expect( clippy:: match_wildcard_for_single_variants, reason = "this is intentional" ) ]
225262 match fk {
226263 FnKind :: Fn ( .., block) if let Some ( block) = block => self . visit_block ( block) ,
227264 FnKind :: Closure ( .., expr) => self . visit_expr ( expr) ,
228- _ => ( ) ,
265+ // :/
266+ FnKind :: Fn ( ..) => ( ) ,
229267 }
230268 }
231269
@@ -234,55 +272,42 @@ impl<'conf, 'cx> Visitor<'_> for NestingVisitor<'conf, 'cx> {
234272 ItemKind :: Static ( static_item) if let Some ( expr) = static_item. expr . as_ref ( ) => self . visit_expr ( expr) ,
235273 ItemKind :: Const ( const_item) if let Some ( expr) = const_item. expr . as_ref ( ) => self . visit_expr ( expr) ,
236274 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+ {
238278 self . nest_level += 1 ;
239279
240- for item in items {
241- self . visit_item ( item) ;
242- }
280+ check_indent ( self , * inner_span) ;
243281
244282 self . nest_level -= 1 ;
245283 }
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+ }
265290
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 ;
276293
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+ _ => ( ) ,
278302 }
279- _ => ( ) ,
280303 }
281304 }
305+
306+ visitor. nest_level -= 1 ;
282307}
283308
284309fn 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 ) {
286311 span_lint_and_help (
287312 visitor. cx ,
288313 EXCESSIVE_NESTING ,
0 commit comments