@@ -12,8 +12,8 @@ use rustc_errors::Applicability;
1212use rustc_hir:: def_id:: DefId ;
1313use rustc_hir:: intravisit:: { InferKind , Visitor , VisitorExt , walk_ty} ;
1414use rustc_hir:: {
15- self as hir, AmbigArg , BindingMode , Body , BodyId , BorrowKind , Expr , ExprKind , HirId , MatchSource , Mutability , Node ,
16- Pat , PatKind , Path , QPath , TyKind , UnOp ,
15+ self as hir, AmbigArg , BindingMode , Body , BodyId , BorrowKind , Expr , ExprKind , HirId , Impl , Item , ItemKind ,
16+ MatchSource , Mutability , Node , Pat , PatKind , Path , QPath , TyKind , UnOp ,
1717} ;
1818use rustc_lint:: { LateContext , LateLintPass } ;
1919use rustc_middle:: ty:: adjustment:: { Adjust , Adjustment , AutoBorrow , AutoBorrowMutability } ;
@@ -50,6 +50,8 @@ declare_clippy_lint! {
5050 /// let _ = Foo::deref(&foo);
5151 /// let _ = <Foo as Deref>::deref(&foo);
5252 /// ```
53+ ///
54+ /// This lint also excludes explicit `deref` or `deref_mut` method calls inside implementations of the `Deref` or `DerefMut` traits.
5355 #[ clippy:: version = "1.44.0" ]
5456 pub EXPLICIT_DEREF_METHODS ,
5557 pedantic,
@@ -169,6 +171,9 @@ pub struct Dereferencing<'tcx> {
169171 ///
170172 /// e.g. `m!(x) | Foo::Bar(ref x)`
171173 ref_locals : FxIndexMap < HirId , Option < RefPat > > ,
174+
175+ /// Whether the current context is within a `Deref` or `DerefMut` impl.
176+ in_deref_or_deref_mut_impl : bool ,
172177}
173178
174179#[ derive( Debug ) ]
@@ -246,7 +251,14 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
246251 // Stop processing sub expressions when a macro call is seen
247252 if expr. span . from_expansion ( ) {
248253 if let Some ( ( state, data) ) = self . state . take ( ) {
249- report ( cx, expr, state, data, cx. typeck_results ( ) ) ;
254+ report (
255+ cx,
256+ expr,
257+ state,
258+ data,
259+ cx. typeck_results ( ) ,
260+ self . in_deref_or_deref_mut_impl ,
261+ ) ;
250262 }
251263 return ;
252264 }
@@ -255,15 +267,22 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
255267 let Some ( ( kind, sub_expr, skip_expr) ) = try_parse_ref_op ( cx. tcx , typeck, expr) else {
256268 // The whole chain of reference operations has been seen
257269 if let Some ( ( state, data) ) = self . state . take ( ) {
258- report ( cx, expr, state, data, typeck) ;
270+ report ( cx, expr, state, data, typeck, self . in_deref_or_deref_mut_impl ) ;
259271 }
260272 return ;
261273 } ;
262274 self . skip_expr = skip_expr;
263275
264276 if is_from_proc_macro ( cx, expr) {
265277 if let Some ( ( state, data) ) = self . state . take ( ) {
266- report ( cx, expr, state, data, cx. typeck_results ( ) ) ;
278+ report (
279+ cx,
280+ expr,
281+ state,
282+ data,
283+ cx. typeck_results ( ) ,
284+ self . in_deref_or_deref_mut_impl ,
285+ ) ;
267286 }
268287 return ;
269288 }
@@ -515,7 +534,14 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
515534 ( Some ( ( State :: DerefedBorrow ( state) , data) ) , RefOp :: AddrOf ( mutability) ) => {
516535 let adjusted_ty = data. adjusted_ty ;
517536 let stability = state. stability ;
518- report ( cx, expr, State :: DerefedBorrow ( state) , data, typeck) ;
537+ report (
538+ cx,
539+ expr,
540+ State :: DerefedBorrow ( state) ,
541+ data,
542+ typeck,
543+ self . in_deref_or_deref_mut_impl ,
544+ ) ;
519545 if stability. is_deref_stable ( ) {
520546 self . state = Some ( (
521547 State :: Borrow { mutability } ,
@@ -530,7 +556,14 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
530556 let adjusted_ty = data. adjusted_ty ;
531557 let stability = state. stability ;
532558 let for_field_access = state. for_field_access ;
533- report ( cx, expr, State :: DerefedBorrow ( state) , data, typeck) ;
559+ report (
560+ cx,
561+ expr,
562+ State :: DerefedBorrow ( state) ,
563+ data,
564+ typeck,
565+ self . in_deref_or_deref_mut_impl ,
566+ ) ;
534567 if let Some ( name) = for_field_access
535568 && let sub_expr_ty = typeck. expr_ty ( sub_expr)
536569 && !ty_contains_field ( sub_expr_ty, name)
@@ -602,7 +635,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
602635 ) ) ;
603636 } ,
604637
605- ( Some ( ( state, data) ) , _) => report ( cx, expr, state, data, typeck) ,
638+ ( Some ( ( state, data) ) , _) => report ( cx, expr, state, data, typeck, self . in_deref_or_deref_mut_impl ) ,
606639 }
607640 }
608641
@@ -673,6 +706,31 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
673706 self . current_body = None ;
674707 }
675708 }
709+
710+ fn check_item ( & mut self , cx : & LateContext < ' _ > , item : & Item < ' _ > ) {
711+ if is_deref_or_deref_mut_impl ( cx, item) {
712+ self . in_deref_or_deref_mut_impl = true ;
713+ }
714+ }
715+
716+ fn check_item_post ( & mut self , cx : & LateContext < ' _ > , item : & Item < ' _ > ) {
717+ if is_deref_or_deref_mut_impl ( cx, item) {
718+ self . in_deref_or_deref_mut_impl = false ;
719+ }
720+ }
721+ }
722+
723+ fn is_deref_or_deref_mut_impl ( cx : & LateContext < ' _ > , item : & Item < ' _ > ) -> bool {
724+ if let ItemKind :: Impl ( Impl {
725+ of_trait : Some ( of_trait) ,
726+ ..
727+ } ) = & item. kind
728+ && let Some ( trait_id) = of_trait. trait_ref . trait_def_id ( )
729+ {
730+ cx. tcx . lang_items ( ) . deref_trait ( ) == Some ( trait_id) || cx. tcx . lang_items ( ) . deref_mut_trait ( ) == Some ( trait_id)
731+ } else {
732+ false
733+ }
676734}
677735
678736fn try_parse_ref_op < ' tcx > (
@@ -938,13 +996,19 @@ fn report<'tcx>(
938996 state : State ,
939997 data : StateData < ' tcx > ,
940998 typeck : & ' tcx TypeckResults < ' tcx > ,
999+ in_deref_or_deref_mut_impl : bool ,
9411000) {
9421001 match state {
9431002 State :: DerefMethod {
9441003 ty_changed_count,
9451004 is_ufcs,
9461005 mutbl,
9471006 } => {
1007+ // Skip when inside implementation of the `Deref` or `DerefMut` trait.
1008+ if in_deref_or_deref_mut_impl {
1009+ return ;
1010+ }
1011+
9481012 let mut app = Applicability :: MachineApplicable ;
9491013 let ( expr_str, expr_is_macro_call) =
9501014 snippet_with_context ( cx, expr. span , data. first_expr . span . ctxt ( ) , ".." , & mut app) ;
0 commit comments