11use clippy_utils:: diagnostics:: { multispan_sugg, span_lint, span_lint_and_then} ;
2+ use clippy_utils:: get_enclosing_block;
23use clippy_utils:: macros:: { find_assert_eq_args, first_node_macro_backtrace} ;
34use clippy_utils:: source:: snippet;
45use clippy_utils:: ty:: { implements_trait, is_copy} ;
56use clippy_utils:: { ast_utils:: is_useless_with_eq_exprs, eq_expr_value, is_in_test_function} ;
67use if_chain:: if_chain;
78use 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+ } ;
912use rustc_lint:: { LateContext , LateLintPass } ;
13+ use rustc_middle:: ty:: { self , TyS } ;
1014use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
1115
1216declare_clippy_lint ! {
@@ -146,6 +150,13 @@ impl<'tcx> LateLintPass<'tcx> for EqOp {
146150 let rty = cx. typeck_results ( ) . expr_ty ( r) ;
147151 let lcpy = is_copy ( cx, lty) ;
148152 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+ }
149160 // either operator autorefs or both args are copyable
150161 if ( requires_ref || ( lcpy && rcpy) ) && implements_trait ( cx, lty, trait_id, & [ rty. into ( ) ] ) {
151162 span_lint_and_then (
@@ -206,6 +217,14 @@ impl<'tcx> LateLintPass<'tcx> for EqOp {
206217 // &foo == bar
207218 ( & ExprKind :: AddrOf ( BorrowKind :: Ref , _, l) , _) => {
208219 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+ }
209228 let lcpy = is_copy ( cx, lty) ;
210229 if ( requires_ref || lcpy)
211230 && implements_trait ( cx, lty, trait_id, & [ cx. typeck_results ( ) . expr_ty ( right) . into ( ) ] )
@@ -230,6 +249,14 @@ impl<'tcx> LateLintPass<'tcx> for EqOp {
230249 // foo == &bar
231250 ( _, & ExprKind :: AddrOf ( BorrowKind :: Ref , _, r) ) => {
232251 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+ }
233260 let rcpy = is_copy ( cx, rty) ;
234261 if ( requires_ref || rcpy)
235262 && implements_trait ( cx, cx. typeck_results ( ) . expr_ty ( left) , trait_id, & [ rty. into ( ) ] )
@@ -251,3 +278,43 @@ impl<'tcx> LateLintPass<'tcx> for EqOp {
251278 }
252279 }
253280}
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