1
1
use clippy_utils:: diagnostics:: { multispan_sugg, span_lint, span_lint_and_then} ;
2
+ use clippy_utils:: get_enclosing_block;
2
3
use clippy_utils:: macros:: { find_assert_eq_args, first_node_macro_backtrace} ;
3
4
use clippy_utils:: source:: snippet;
4
5
use clippy_utils:: ty:: { implements_trait, is_copy} ;
5
6
use clippy_utils:: { ast_utils:: is_useless_with_eq_exprs, eq_expr_value, is_in_test_function} ;
6
7
use if_chain:: if_chain;
7
8
use rustc_errors:: Applicability ;
8
- use rustc_hir:: { BinOpKind , BorrowKind , Expr , ExprKind } ;
9
+ use rustc_hir:: {
10
+ def:: Res , def_id:: DefId , BinOpKind , BorrowKind , Expr , ExprKind , GenericArg , ItemKind , QPath , Ty , TyKind ,
11
+ } ;
9
12
use rustc_lint:: { LateContext , LateLintPass } ;
13
+ use rustc_middle:: ty:: { self , TyS } ;
10
14
use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
11
15
12
16
declare_clippy_lint ! {
@@ -146,6 +150,13 @@ impl<'tcx> LateLintPass<'tcx> for EqOp {
146
150
let rty = cx. typeck_results ( ) . expr_ty ( r) ;
147
151
let lcpy = is_copy ( cx, lty) ;
148
152
let rcpy = is_copy ( cx, rty) ;
153
+ if let Some ( ( self_ty, other_ty) ) = in_impl ( cx, e, trait_id) {
154
+ if ( are_equal ( cx, rty, self_ty) && are_equal ( cx, lty, other_ty) )
155
+ || ( are_equal ( cx, rty, other_ty) && are_equal ( cx, lty, self_ty) )
156
+ {
157
+ return ; // Don't lint
158
+ }
159
+ }
149
160
// either operator autorefs or both args are copyable
150
161
if ( requires_ref || ( lcpy && rcpy) ) && implements_trait ( cx, lty, trait_id, & [ rty. into ( ) ] ) {
151
162
span_lint_and_then (
@@ -206,6 +217,14 @@ impl<'tcx> LateLintPass<'tcx> for EqOp {
206
217
// &foo == bar
207
218
( & ExprKind :: AddrOf ( BorrowKind :: Ref , _, l) , _) => {
208
219
let lty = cx. typeck_results ( ) . expr_ty ( l) ;
220
+ if let Some ( ( self_ty, other_ty) ) = in_impl ( cx, e, trait_id) {
221
+ let rty = cx. typeck_results ( ) . expr_ty ( right) ;
222
+ if ( are_equal ( cx, rty, self_ty) && are_equal ( cx, lty, other_ty) )
223
+ || ( are_equal ( cx, rty, other_ty) && are_equal ( cx, lty, self_ty) )
224
+ {
225
+ return ; // Don't lint
226
+ }
227
+ }
209
228
let lcpy = is_copy ( cx, lty) ;
210
229
if ( requires_ref || lcpy)
211
230
&& implements_trait ( cx, lty, trait_id, & [ cx. typeck_results ( ) . expr_ty ( right) . into ( ) ] )
@@ -230,6 +249,14 @@ impl<'tcx> LateLintPass<'tcx> for EqOp {
230
249
// foo == &bar
231
250
( _, & ExprKind :: AddrOf ( BorrowKind :: Ref , _, r) ) => {
232
251
let rty = cx. typeck_results ( ) . expr_ty ( r) ;
252
+ if let Some ( ( self_ty, other_ty) ) = in_impl ( cx, e, trait_id) {
253
+ let lty = cx. typeck_results ( ) . expr_ty ( left) ;
254
+ if ( are_equal ( cx, rty, self_ty) && are_equal ( cx, lty, other_ty) )
255
+ || ( are_equal ( cx, rty, other_ty) && are_equal ( cx, lty, self_ty) )
256
+ {
257
+ return ; // Don't lint
258
+ }
259
+ }
233
260
let rcpy = is_copy ( cx, rty) ;
234
261
if ( requires_ref || rcpy)
235
262
&& implements_trait ( cx, cx. typeck_results ( ) . expr_ty ( left) , trait_id, & [ rty. into ( ) ] )
@@ -251,3 +278,43 @@ impl<'tcx> LateLintPass<'tcx> for EqOp {
251
278
}
252
279
}
253
280
}
281
+
282
+ fn in_impl < ' tcx > ( cx : & LateContext < ' tcx > , e : & ' tcx Expr < ' _ > , bin_op : DefId ) -> Option < ( & ' tcx Ty < ' tcx > , & ' tcx Ty < ' tcx > ) > {
283
+ if_chain ! {
284
+ if let Some ( block) = get_enclosing_block( cx, e. hir_id) ;
285
+ if let Some ( impl_def_id) = cx. tcx. impl_of_method( block. hir_id. owner. to_def_id( ) ) ;
286
+ let item = cx. tcx. hir( ) . expect_item( impl_def_id. expect_local( ) ) ;
287
+ if let ItemKind :: Impl ( item) = & item. kind;
288
+ if let Some ( of_trait) = & item. of_trait;
289
+ if let Some ( seg) = of_trait. path. segments. last( ) ;
290
+ if let Some ( Res :: Def ( _, trait_id) ) = seg. res;
291
+ if trait_id == bin_op;
292
+ if let Some ( generic_args) = seg. args;
293
+ if let Some ( GenericArg :: Type ( other_ty) ) = generic_args. args. last( ) ;
294
+
295
+ then {
296
+ Some ( ( item. self_ty, other_ty) )
297
+ }
298
+ else {
299
+ None
300
+ }
301
+ }
302
+ }
303
+
304
+ fn are_equal < ' tcx > ( cx : & LateContext < ' tcx > , middle_ty : & TyS < ' _ > , hir_ty : & Ty < ' _ > ) -> bool {
305
+ if_chain ! {
306
+ if let ty:: Adt ( adt_def, _) = middle_ty. kind( ) ;
307
+ if let Some ( local_did) = adt_def. did. as_local( ) ;
308
+ let item = cx. tcx. hir( ) . expect_item( local_did) ;
309
+ let middle_ty_id = item. def_id. to_def_id( ) ;
310
+ if let TyKind :: Path ( QPath :: Resolved ( _, path) ) = hir_ty. kind;
311
+ if let Res :: Def ( _, hir_ty_id) = path. res;
312
+
313
+ then {
314
+ hir_ty_id == middle_ty_id
315
+ }
316
+ else {
317
+ false
318
+ }
319
+ }
320
+ }
0 commit comments