@@ -15,7 +15,7 @@ use rustc_lint::{LateContext, LateLintPass};
1515use rustc_middle:: ty:: adjustment:: { Adjust , Adjustment , AutoBorrow , AutoBorrowMutability } ;
1616use rustc_middle:: ty:: { self , Ty , TyCtxt , TypeFoldable , TypeckResults } ;
1717use rustc_session:: { declare_tool_lint, impl_lint_pass} ;
18- use rustc_span:: { symbol:: sym, Span , Symbol } ;
18+ use rustc_span:: { symbol:: sym, Span , Symbol , SyntaxContext } ;
1919
2020declare_clippy_lint ! {
2121 /// ### What it does
@@ -244,23 +244,22 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing {
244244
245245 match ( self . state . take ( ) , kind) {
246246 ( None , kind) => {
247- let parent = get_parent_node ( cx. tcx , expr. hir_id ) ;
248247 let expr_ty = typeck. expr_ty ( expr) ;
248+ let ( position, parent_ctxt) = get_expr_position ( cx, expr) ;
249249 match kind {
250250 RefOp :: Deref => {
251- if let Some ( Node :: Expr ( e) ) = parent
252- && let ExprKind :: Field ( _, name) = e. kind
253- && !ty_contains_field ( typeck. expr_ty ( sub_expr) , name. name )
251+ if let Position :: FieldAccess ( name) = position
252+ && !ty_contains_field ( typeck. expr_ty ( sub_expr) , name)
254253 {
255254 self . state = Some ( (
256- State :: ExplicitDerefField { name : name . name } ,
255+ State :: ExplicitDerefField { name } ,
257256 StateData { span : expr. span , hir_id : expr. hir_id } ,
258257 ) ) ;
259258 }
260259 }
261260 RefOp :: Method ( target_mut)
262261 if !is_lint_allowed ( cx, EXPLICIT_DEREF_METHODS , expr. hir_id )
263- && is_linted_explicit_deref_position ( parent , expr . hir_id , expr. span ) =>
262+ && ( position . lint_explicit_deref ( ) || parent_ctxt != expr. span . ctxt ( ) ) =>
264263 {
265264 self . state = Some ( (
266265 State :: DerefMethod {
@@ -322,8 +321,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing {
322321 "this expression creates a reference which is immediately dereferenced by the compiler" ;
323322 let borrow_msg = "this expression borrows a value the compiler would automatically borrow" ;
324323
325- let ( required_refs, required_precedence, msg) = if is_auto_borrow_position ( parent, expr. hir_id )
326- {
324+ let ( required_refs, required_precedence, msg) = if position. can_auto_borrow ( ) {
327325 ( 1 , PREC_POSTFIX , if deref_count == 1 { borrow_msg } else { deref_msg } )
328326 } else if let Some ( & Adjust :: Borrow ( AutoBorrow :: Ref ( _, mutability) ) ) =
329327 next_adjust. map ( |a| & a. kind )
@@ -573,60 +571,41 @@ fn deref_method_same_type<'tcx>(result_ty: Ty<'tcx>, arg_ty: Ty<'tcx>) -> bool {
573571 }
574572}
575573
576- // Checks whether the parent node is a suitable context for switching from a deref method to the
577- // deref operator.
578- fn is_linted_explicit_deref_position ( parent : Option < Node < ' _ > > , child_id : HirId , child_span : Span ) -> bool {
579- let parent = match parent {
580- Some ( Node :: Expr ( e) ) if e. span . ctxt ( ) == child_span. ctxt ( ) => e,
581- _ => return true ,
582- } ;
583- match parent. kind {
584- // Leave deref calls in the middle of a method chain.
585- // e.g. x.deref().foo()
586- ExprKind :: MethodCall ( _, [ self_arg, ..] , _) if self_arg. hir_id == child_id => false ,
587-
588- // Leave deref calls resulting in a called function
589- // e.g. (x.deref())()
590- ExprKind :: Call ( func_expr, _) if func_expr. hir_id == child_id => false ,
574+ #[ derive( Clone , Copy ) ]
575+ enum Position {
576+ MethodReceiver ,
577+ FieldAccess ( Symbol ) ,
578+ Callee ,
579+ Postfix ,
580+ Deref ,
581+ Other ,
582+ }
583+ impl Position {
584+ fn can_auto_borrow ( self ) -> bool {
585+ matches ! ( self , Self :: MethodReceiver | Self :: FieldAccess ( _) | Self :: Callee )
586+ }
591587
592- // Makes an ugly suggestion
593- // e.g. *x.deref() => *&*x
594- ExprKind :: Unary ( UnOp :: Deref , _)
595- // Postfix expressions would require parens
596- | ExprKind :: Match ( _, _, MatchSource :: TryDesugar | MatchSource :: AwaitDesugar )
597- | ExprKind :: Field ( ..)
598- | ExprKind :: Index ( ..)
599- | ExprKind :: Err => false ,
588+ fn lint_explicit_deref ( self ) -> bool {
589+ matches ! ( self , Self :: Other )
590+ }
591+ }
600592
601- ExprKind :: Box ( ..)
602- | ExprKind :: ConstBlock ( ..)
603- | ExprKind :: Array ( _)
604- | ExprKind :: Call ( ..)
605- | ExprKind :: MethodCall ( ..)
606- | ExprKind :: Tup ( ..)
607- | ExprKind :: Binary ( ..)
608- | ExprKind :: Unary ( ..)
609- | ExprKind :: Lit ( ..)
610- | ExprKind :: Cast ( ..)
611- | ExprKind :: Type ( ..)
612- | ExprKind :: DropTemps ( ..)
613- | ExprKind :: If ( ..)
614- | ExprKind :: Loop ( ..)
615- | ExprKind :: Match ( ..)
616- | ExprKind :: Let ( ..)
617- | ExprKind :: Closure { ..}
618- | ExprKind :: Block ( ..)
619- | ExprKind :: Assign ( ..)
620- | ExprKind :: AssignOp ( ..)
621- | ExprKind :: Path ( ..)
622- | ExprKind :: AddrOf ( ..)
623- | ExprKind :: Break ( ..)
624- | ExprKind :: Continue ( ..)
625- | ExprKind :: Ret ( ..)
626- | ExprKind :: InlineAsm ( ..)
627- | ExprKind :: Struct ( ..)
628- | ExprKind :: Repeat ( ..)
629- | ExprKind :: Yield ( ..) => true ,
593+ /// Get which position an expression is in relative to it's parent.
594+ fn get_expr_position ( cx : & LateContext < ' _ > , e : & Expr < ' _ > ) -> ( Position , SyntaxContext ) {
595+ if let Some ( Node :: Expr ( parent) ) = get_parent_node ( cx. tcx , e. hir_id ) {
596+ let pos = match parent. kind {
597+ ExprKind :: MethodCall ( _, [ self_arg, ..] , _) if self_arg. hir_id == e. hir_id => Position :: MethodReceiver ,
598+ ExprKind :: Field ( _, name) => Position :: FieldAccess ( name. name ) ,
599+ ExprKind :: Call ( f, _) if f. hir_id == e. hir_id => Position :: Callee ,
600+ ExprKind :: Unary ( UnOp :: Deref , _) => Position :: Deref ,
601+ ExprKind :: Match ( _, _, MatchSource :: TryDesugar | MatchSource :: AwaitDesugar ) | ExprKind :: Index ( ..) => {
602+ Position :: Postfix
603+ } ,
604+ _ => Position :: Other ,
605+ } ;
606+ ( pos, parent. span . ctxt ( ) )
607+ } else {
608+ ( Position :: Other , SyntaxContext :: root ( ) )
630609 }
631610}
632611
@@ -748,20 +727,6 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (AutoDerefSt
748727 ( stability, adjustments)
749728}
750729
751- /// Checks if the given expression is a position which can auto-borrow.
752- fn is_auto_borrow_position ( parent : Option < Node < ' _ > > , child_id : HirId ) -> bool {
753- if let Some ( Node :: Expr ( parent) ) = parent {
754- match parent. kind {
755- // ExprKind::MethodCall(_, [self_arg, ..], _) => self_arg.hir_id == child_id,
756- ExprKind :: Field ( ..) => true ,
757- ExprKind :: Call ( f, _) => f. hir_id == child_id,
758- _ => false ,
759- }
760- } else {
761- false
762- }
763- }
764-
765730// Checks the stability of auto-deref when assigned to a binding with the given explicit type.
766731//
767732// e.g.
0 commit comments