Skip to content

Commit 2ebe751

Browse files
committed
add documentation
1 parent 2b3e7fa commit 2ebe751

File tree

2 files changed

+51
-14
lines changed

2 files changed

+51
-14
lines changed

clippy_lints/src/only_used_in_recursion.rs

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use rustc_span::Span;
2121

2222
declare_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+
/// ```
181214
pub 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);

tests/ui/only_used_in_recursion.stderr

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,66 +1,66 @@
1-
error: parameter is only used in recursion with no side-effects
1+
error: parameter is only used in recursion
22
--> $DIR/only_used_in_recursion.rs:3:21
33
|
44
LL | fn simple(a: usize, b: usize) -> usize {
55
| ^ help: if this is intentional, prefix with an underscore: `_b`
66
|
77
= note: `-D clippy::only-used-in-recursion` implied by `-D warnings`
88

9-
error: parameter is only used in recursion with no side-effects
9+
error: parameter is only used in recursion
1010
--> $DIR/only_used_in_recursion.rs:7:24
1111
|
1212
LL | fn with_calc(a: usize, b: isize) -> usize {
1313
| ^ help: if this is intentional, prefix with an underscore: `_b`
1414

15-
error: parameter is only used in recursion with no side-effects
15+
error: parameter is only used in recursion
1616
--> $DIR/only_used_in_recursion.rs:11:14
1717
|
1818
LL | fn tuple((a, b): (usize, usize)) -> usize {
1919
| ^ help: if this is intentional, prefix with an underscore: `_b`
2020

21-
error: parameter is only used in recursion with no side-effects
21+
error: parameter is only used in recursion
2222
--> $DIR/only_used_in_recursion.rs:15:24
2323
|
2424
LL | fn let_tuple(a: usize, b: usize) -> usize {
2525
| ^ help: if this is intentional, prefix with an underscore: `_b`
2626

27-
error: parameter is only used in recursion with no side-effects
27+
error: parameter is only used in recursion
2828
--> $DIR/only_used_in_recursion.rs:20:14
2929
|
3030
LL | fn array([a, b]: [usize; 2]) -> usize {
3131
| ^ help: if this is intentional, prefix with an underscore: `_b`
3232

33-
error: parameter is only used in recursion with no side-effects
33+
error: parameter is only used in recursion
3434
--> $DIR/only_used_in_recursion.rs:24:20
3535
|
3636
LL | fn index(a: usize, mut b: &[usize], c: usize) -> usize {
3737
| ^^^^^ help: if this is intentional, prefix with an underscore: `_b`
3838

39-
error: parameter is only used in recursion with no side-effects
39+
error: parameter is only used in recursion
4040
--> $DIR/only_used_in_recursion.rs:24:37
4141
|
4242
LL | fn index(a: usize, mut b: &[usize], c: usize) -> usize {
4343
| ^ help: if this is intentional, prefix with an underscore: `_c`
4444

45-
error: parameter is only used in recursion with no side-effects
45+
error: parameter is only used in recursion
4646
--> $DIR/only_used_in_recursion.rs:28:21
4747
|
4848
LL | fn break_(a: usize, mut b: usize, mut c: usize) -> usize {
4949
| ^^^^^ help: if this is intentional, prefix with an underscore: `_b`
5050

51-
error: parameter is only used in recursion with no side-effects
51+
error: parameter is only used in recursion
5252
--> $DIR/only_used_in_recursion.rs:46:23
5353
|
5454
LL | fn mut_ref2(a: usize, b: &mut usize) -> usize {
5555
| ^ help: if this is intentional, prefix with an underscore: `_b`
5656

57-
error: parameter is only used in recursion with no side-effects
57+
error: parameter is only used in recursion
5858
--> $DIR/only_used_in_recursion.rs:51:28
5959
|
6060
LL | fn not_primitive(a: usize, b: String) -> usize {
6161
| ^ help: if this is intentional, prefix with an underscore: `_b`
6262

63-
error: parameter is only used in recursion with no side-effects
63+
error: parameter is only used in recursion
6464
--> $DIR/only_used_in_recursion.rs:64:32
6565
|
6666
LL | fn method(&self, a: usize, b: usize) -> usize {

0 commit comments

Comments
 (0)