@@ -40,6 +40,28 @@ declare_clippy_lint! {
4040 "consecutive `ifs` with the same condition"
4141}
4242
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+
4365declare_clippy_lint ! {
4466 /// **What it does:** Checks for `if/else` with the same body as the *then* part
4567 /// and the *else* part.
@@ -102,7 +124,7 @@ declare_clippy_lint! {
102124 "`match` with identical arm bodies"
103125}
104126
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 ] ) ;
106128
107129impl < ' a , ' tcx > LateLintPass < ' a , ' tcx > for CopyAndPaste {
108130 fn check_expr ( & mut self , cx : & LateContext < ' a , ' tcx > , expr : & ' tcx Expr ) {
@@ -119,6 +141,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CopyAndPaste {
119141 let ( conds, blocks) = if_sequence ( expr) ;
120142 lint_same_then_else ( cx, & blocks) ;
121143 lint_same_cond ( cx, & conds) ;
144+ lint_same_cond_fn ( cx, & conds) ;
122145 lint_match_arms ( cx, expr) ;
123146 }
124147 }
@@ -163,6 +186,34 @@ fn lint_same_cond(cx: &LateContext<'_, '_>, conds: &[&Expr]) {
163186 }
164187}
165188
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+
166217/// Implementation of `MATCH_SAME_ARMS`.
167218fn lint_match_arms < ' tcx > ( cx : & LateContext < ' _ , ' tcx > , expr : & Expr ) {
168219 fn same_bindings < ' tcx > (
0 commit comments