@@ -83,7 +83,85 @@ declare_clippy_lint! {
8383    complexity, 
8484    "arguments that is only used in recursion can be removed" 
8585} 
86- impl_lint_pass ! ( OnlyUsedInRecursion  => [ ONLY_USED_IN_RECURSION ] ) ; 
86+ 
87+ declare_clippy_lint !  { 
88+     /// ### What it does 
89+ /// Checks for `self` receiver that is only used in recursion with no side-effects. 
90+ /// 
91+ /// ### Why is this bad? 
92+ /// 
93+ /// It may be possible to remove the `self` argument, allowing the function to be 
94+ /// used without an object of type `Self`. 
95+ /// 
96+ /// ### Known problems 
97+ /// Too many code paths in the linting code are currently untested and prone to produce false 
98+ /// positives or are prone to have performance implications. 
99+ /// 
100+ /// In some cases, this would not catch all useless arguments. 
101+ /// 
102+ /// ```no_run 
103+ /// struct Foo; 
104+ /// impl Foo { 
105+ ///     fn foo(&self, a: usize) -> usize { 
106+ ///         let f = |x| x; 
107+ /// 
108+ ///         if a == 0 { 
109+ ///             1 
110+ ///         } else { 
111+ ///             f(self).foo(a) 
112+ ///         } 
113+ ///     } 
114+ /// } 
115+ /// ``` 
116+ /// 
117+ /// For example, here `self` is only used in recursion, but the lint would not catch it. 
118+ /// 
119+ /// List of some examples that can not be caught: 
120+ /// - binary operation of non-primitive types 
121+ /// - closure usage 
122+ /// - some `break` relative operations 
123+ /// - struct pattern binding 
124+ /// 
125+ /// Also, when you recurse the function name with path segments, it is not possible to detect. 
126+ /// 
127+ /// ### Example 
128+ /// ```no_run 
129+ /// struct Foo; 
130+ /// impl Foo { 
131+ ///     fn f(&self, n: u32) -> u32 { 
132+ ///         if n == 0 { 
133+ ///             1 
134+ ///         } else { 
135+ ///             n * self.f(n - 1) 
136+ ///         } 
137+ ///     } 
138+ /// } 
139+ /// # fn main() { 
140+ /// #     print!("{}", Foo.f(10)); 
141+ /// # } 
142+ /// ``` 
143+ /// Use instead: 
144+ /// ```no_run 
145+ /// struct Foo; 
146+ /// impl Foo { 
147+ ///     fn f(n: u32) -> u32 { 
148+ ///         if n == 0 { 
149+ ///             1 
150+ ///         } else { 
151+ ///             n * Self::f(n - 1) 
152+ ///         } 
153+ ///     } 
154+ /// } 
155+ /// # fn main() { 
156+ /// #     print!("{}", Foo::f(10)); 
157+ /// # } 
158+ /// ``` 
159+ [ clippy:: version = "1.92.0" ] 
160+     pub  SELF_ONLY_USED_IN_RECURSION , 
161+     pedantic, 
162+     "self receiver only used to recursively call method can be removed" 
163+ } 
164+ impl_lint_pass ! ( OnlyUsedInRecursion  => [ ONLY_USED_IN_RECURSION ,  SELF_ONLY_USED_IN_RECURSION ] ) ; 
87165
88166#[ derive( Clone ,  Copy ) ]  
89167enum  FnKind  { 
@@ -355,26 +433,39 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion {
355433            self . params . flag_for_linting ( ) ; 
356434            for  param in  & self . params . params  { 
357435                if  param. apply_lint . get ( )  { 
358-                     span_lint_and_then ( 
359-                         cx, 
360-                         ONLY_USED_IN_RECURSION , 
361-                         param. ident . span , 
362-                         "parameter is only used in recursion" , 
363-                         |diag| { 
364-                             if  param. ident . name  != kw:: SelfLower  { 
436+                     if  param. ident . name  == kw:: SelfLower  { 
437+                         span_lint_and_then ( 
438+                             cx, 
439+                             SELF_ONLY_USED_IN_RECURSION , 
440+                             param. ident . span , 
441+                             "`self` is only used in recursion" , 
442+                             |diag| { 
443+                                 diag. span_note ( 
444+                                     param. uses . iter ( ) . map ( |x| x. span ) . collect :: < Vec < _ > > ( ) , 
445+                                     "`self` used here" , 
446+                                 ) ; 
447+                             } , 
448+                         ) ; 
449+                     }  else  { 
450+                         span_lint_and_then ( 
451+                             cx, 
452+                             ONLY_USED_IN_RECURSION , 
453+                             param. ident . span , 
454+                             "parameter is only used in recursion" , 
455+                             |diag| { 
365456                                diag. span_suggestion ( 
366457                                    param. ident . span , 
367458                                    "if this is intentional, prefix it with an underscore" , 
368459                                    format ! ( "_{}" ,  param. ident. name) , 
369460                                    Applicability :: MaybeIncorrect , 
370461                                ) ; 
371-                             } 
372-                             diag . span_note ( 
373-                                 param . uses . iter ( ) . map ( |x| x . span ) . collect :: < Vec < _ > > ( ) , 
374-                                 "parameter used here" , 
375-                             ) ; 
376-                         } , 
377-                     ) ; 
462+                                 diag . span_note ( 
463+                                     param . uses . iter ( ) . map ( |x| x . span ) . collect :: < Vec < _ > > ( ) , 
464+                                      "parameter used here" , 
465+                                 ) ; 
466+                             } , 
467+                         ) ; 
468+                     } 
378469                } 
379470            } 
380471            self . params . clear ( ) ; 
0 commit comments