@@ -40,6 +40,28 @@ declare_clippy_lint! {
40
40
"consecutive `ifs` with the same condition"
41
41
}
42
42
43
+ declare_clippy_lint ! {
44
+ /// **What it does:** Checks for consecutive `if`s with the same function call.
45
+ ///
46
+ /// **Why is this bad?** This is probably a copy & paste error.
47
+ /// Despite the fact that function can have side effects and `if` works as
48
+ /// intended, such an approach is implicit and can be considered a "code smell".
49
+ ///
50
+ /// **Known problems:** Hopefully none.
51
+ ///
52
+ /// **Example:**
53
+ /// ```ignore
54
+ /// if foo() {
55
+ /// …
56
+ /// } else if foo() {
57
+ /// …
58
+ /// }
59
+ /// ```
60
+ pub IFS_SAME_COND_FN ,
61
+ pedantic,
62
+ "consecutive `ifs` with the same function call"
63
+ }
64
+
43
65
declare_clippy_lint ! {
44
66
/// **What it does:** Checks for `if/else` with the same body as the *then* part
45
67
/// and the *else* part.
@@ -102,7 +124,7 @@ declare_clippy_lint! {
102
124
"`match` with identical arm bodies"
103
125
}
104
126
105
- declare_lint_pass ! ( CopyAndPaste => [ IFS_SAME_COND , IF_SAME_THEN_ELSE , MATCH_SAME_ARMS ] ) ;
127
+ declare_lint_pass ! ( CopyAndPaste => [ IFS_SAME_COND , IFS_SAME_COND_FN , IF_SAME_THEN_ELSE , MATCH_SAME_ARMS ] ) ;
106
128
107
129
impl < ' a , ' tcx > LateLintPass < ' a , ' tcx > for CopyAndPaste {
108
130
fn check_expr ( & mut self , cx : & LateContext < ' a , ' tcx > , expr : & ' tcx Expr ) {
@@ -119,6 +141,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CopyAndPaste {
119
141
let ( conds, blocks) = if_sequence ( expr) ;
120
142
lint_same_then_else ( cx, & blocks) ;
121
143
lint_same_cond ( cx, & conds) ;
144
+ lint_same_cond_fn ( cx, & conds) ;
122
145
lint_match_arms ( cx, expr) ;
123
146
}
124
147
}
@@ -163,6 +186,34 @@ fn lint_same_cond(cx: &LateContext<'_, '_>, conds: &[&Expr]) {
163
186
}
164
187
}
165
188
189
+ /// Implementation of `IFS_SAME_COND_FN`.
190
+ fn lint_same_cond_fn ( cx : & LateContext < ' _ , ' _ > , conds : & [ & Expr ] ) {
191
+ let hash: & dyn Fn ( & & Expr ) -> u64 = & |expr| -> u64 {
192
+ let mut h = SpanlessHash :: new ( cx, cx. tables ) ;
193
+ h. hash_expr ( expr) ;
194
+ h. finish ( )
195
+ } ;
196
+
197
+ let eq: & dyn Fn ( & & Expr , & & Expr ) -> bool = & |& lhs, & rhs| -> bool {
198
+ // Do not spawn warning if `IFS_SAME_COND` already produced it.
199
+ if SpanlessEq :: new ( cx) . ignore_fn ( ) . eq_expr ( lhs, rhs) {
200
+ return false ;
201
+ }
202
+ SpanlessEq :: new ( cx) . eq_expr ( lhs, rhs)
203
+ } ;
204
+
205
+ for ( i, j) in search_same ( conds, hash, eq) {
206
+ span_note_and_lint (
207
+ cx,
208
+ IFS_SAME_COND_FN ,
209
+ j. span ,
210
+ "this `if` has the same function call as a previous if" ,
211
+ i. span ,
212
+ "same as this" ,
213
+ ) ;
214
+ }
215
+ }
216
+
166
217
/// Implementation of `MATCH_SAME_ARMS`.
167
218
fn lint_match_arms < ' tcx > ( cx : & LateContext < ' _ , ' tcx > , expr : & Expr ) {
168
219
fn same_bindings < ' tcx > (
0 commit comments