@@ -21,7 +21,7 @@ use rustc_span::Span;
2121
2222declare_clippy_lint ! {
2323 /// ### What it does
24- /// Checks for arguments that is only used in recursion with no side-effects.
24+ /// Checks for arguments that are only used in recursion with no side-effects.
2525 /// The arguments can be involved in calculations and assignments but as long as
2626 /// the calculations have no side-effects (function calls or mutating dereference)
2727 /// and the assigned variables are also only in recursion, it is useless.
@@ -30,7 +30,21 @@ declare_clippy_lint! {
3030 /// The could contain a useless calculation and can make function simpler.
3131 ///
3232 /// ### Known problems
33- /// It could not catch the variable that has no side effects but only used in recursion.
33+ /// In some cases, this would not catch all useless arguments.
34+ ///
35+ /// ```rust
36+ /// fn foo(a: usize, b: usize) -> usize {
37+ /// let f = |x| x + 1;
38+ ///
39+ /// if a == 0 {
40+ /// 1
41+ /// } else {
42+ /// foo(a - 1, f(b))
43+ /// }
44+ /// }
45+ /// ```
46+ ///
47+ /// For example, the argument `b` is only used in recursion, but the lint would not catch it.
3448 ///
3549 /// ### Example
3650 /// ```rust
@@ -111,10 +125,12 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion {
111125
112126 visitor. visit_expr ( & body. value ) ;
113127 let vars = std:: mem:: take ( & mut visitor. ret_vars ) ;
128+ // this would set the return variables to side effect
114129 visitor. add_side_effect ( vars) ;
115130
116131 let mut queue = visitor. has_side_effect . iter ( ) . copied ( ) . collect :: < VecDeque < _ > > ( ) ;
117132
133+ // a simple BFS to check all the variables that have side effect
118134 while let Some ( id) = queue. pop_front ( ) {
119135 if let Some ( next) = visitor. graph . get ( & id) {
120136 for i in next {
@@ -134,6 +150,8 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion {
134150
135151 queue. push_back ( id) ;
136152
153+ // a simple BFS to check the graph can reach to itself
154+ // if it can't, it means the variable is never used in recursion
137155 while let Some ( id) = queue. pop_front ( ) {
138156 if let Some ( next) = visitor. graph . get ( & id) {
139157 for i in next {
@@ -150,7 +168,7 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion {
150168 cx,
151169 ONLY_USED_IN_RECURSION ,
152170 span,
153- "parameter is only used in recursion with no side-effects " ,
171+ "parameter is only used in recursion" ,
154172 "if this is intentional, prefix with an underscore" ,
155173 format ! ( "_{}" , ident. name. as_str( ) ) ,
156174 Applicability :: MaybeIncorrect ,
@@ -178,6 +196,21 @@ pub fn is_array(ty: Ty<'_>) -> bool {
178196 }
179197}
180198
199+ /// This builds the graph of side effect.
200+ /// The edge `a -> b` means if `a` has side effect, `b` will have side effect.
201+ ///
202+ /// There are some exmaple in following code:
203+ /// ```rust, ignore
204+ /// let b = 1;
205+ /// let a = b; // a -> b
206+ /// let (c, d) = (a, b); // c -> b, d -> b
207+ ///
208+ /// let e = if a == 0 { // e -> a
209+ /// c // e -> c
210+ /// } else {
211+ /// d // e -> d
212+ /// };
213+ /// ```
181214pub struct SideEffectVisit < ' tcx > {
182215 graph : FxHashMap < HirId , FxHashSet < HirId > > ,
183216 has_side_effect : FxHashSet < HirId > ,
@@ -241,6 +274,7 @@ impl<'tcx> Visitor<'tcx> for SideEffectVisit<'tcx> {
241274 self . visit_if ( bind, then_expr, else_expr) ;
242275 } ,
243276 ExprKind :: Match ( expr, arms, _) => self . visit_match ( expr, arms) ,
277+ // since analysing the closure is not easy, just set all variables in it to side-effect
244278 ExprKind :: Closure ( _, _, body_id, _, _) => {
245279 let body = self . ty_ctx . hir ( ) . body ( body_id) ;
246280 self . visit_body ( body) ;
@@ -359,6 +393,9 @@ impl<'tcx> SideEffectVisit<'tcx> {
359393 let mut ret_vars = std:: mem:: take ( & mut self . ret_vars ) ;
360394 self . visit_expr ( rhs) ;
361395 self . ret_vars . append ( & mut ret_vars) ;
396+
397+ // the binary operation between non primitive values are overloaded operators
398+ // so they can have side-effects
362399 if !is_primitive ( self . ty_res . expr_ty ( lhs) ) || !is_primitive ( self . ty_res . expr_ty ( rhs) ) {
363400 self . ret_vars . iter ( ) . for_each ( |id| {
364401 self . has_side_effect . insert ( id. 0 ) ;
0 commit comments