@@ -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 } ;
18+ use rustc_span:: { symbol:: sym, Span , Symbol } ;
1919
2020declare_clippy_lint ! {
2121 /// ### What it does
@@ -181,6 +181,9 @@ enum State {
181181 deref_span : Span ,
182182 deref_hir_id : HirId ,
183183 } ,
184+ ExplicitDerefField {
185+ name : Symbol ,
186+ } ,
184187 Reborrow {
185188 deref_span : Span ,
186189 deref_hir_id : HirId ,
@@ -243,8 +246,18 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing {
243246 ( None , kind) => {
244247 let parent = get_parent_node ( cx. tcx , expr. hir_id ) ;
245248 let expr_ty = typeck. expr_ty ( expr) ;
246-
247249 match kind {
250+ 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 )
254+ {
255+ self . state = Some ( (
256+ State :: ExplicitDerefField { name : name. name } ,
257+ StateData { span : expr. span , hir_id : expr. hir_id } ,
258+ ) ) ;
259+ }
260+ }
248261 RefOp :: Method ( target_mut)
249262 if !is_lint_allowed ( cx, EXPLICIT_DEREF_METHODS , expr. hir_id )
250263 && is_linted_explicit_deref_position ( parent, expr. hir_id , expr. span ) =>
@@ -349,7 +362,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing {
349362 ) ) ;
350363 }
351364 } ,
352- _ => ( ) ,
365+ RefOp :: Method ( .. ) => ( ) ,
353366 }
354367 } ,
355368 (
@@ -436,6 +449,11 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing {
436449 ( state @ Some ( ( State :: ExplicitDeref { .. } , _) ) , RefOp :: Deref ) => {
437450 self . state = state;
438451 } ,
452+ ( Some ( ( State :: ExplicitDerefField { name } , data) ) , RefOp :: Deref )
453+ if !ty_contains_field ( typeck. expr_ty ( sub_expr) , name) =>
454+ {
455+ self . state = Some ( ( State :: ExplicitDerefField { name } , data) ) ;
456+ } ,
439457
440458 ( Some ( ( state, data) ) , _) => report ( cx, expr, state, data) ,
441459 }
@@ -879,6 +897,14 @@ fn param_auto_deref_stability(ty: Ty<'_>) -> AutoDerefStability {
879897 }
880898}
881899
900+ fn ty_contains_field ( ty : Ty < ' _ > , name : Symbol ) -> bool {
901+ if let ty:: Adt ( adt, _) = * ty. kind ( ) {
902+ adt. is_struct ( ) && adt. non_enum_variant ( ) . fields . iter ( ) . any ( |f| f. name == name)
903+ } else {
904+ false
905+ }
906+ }
907+
882908#[ expect( clippy:: needless_pass_by_value) ]
883909fn report < ' tcx > ( cx : & LateContext < ' tcx > , expr : & ' tcx Expr < ' _ > , state : State , data : StateData ) {
884910 match state {
@@ -968,6 +994,20 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data
968994 } ,
969995 ) ;
970996 } ,
997+ State :: ExplicitDerefField { .. } => {
998+ span_lint_hir_and_then (
999+ cx,
1000+ EXPLICIT_AUTO_DEREF ,
1001+ data. hir_id ,
1002+ data. span ,
1003+ "deref which would be done by auto-deref" ,
1004+ |diag| {
1005+ let mut app = Applicability :: MachineApplicable ;
1006+ let snip = snippet_with_context ( cx, expr. span , data. span . ctxt ( ) , ".." , & mut app) . 0 ;
1007+ diag. span_suggestion ( data. span , "try this" , snip. into_owned ( ) , app) ;
1008+ } ,
1009+ ) ;
1010+ } ,
9711011 State :: Borrow | State :: Reborrow { .. } => ( ) ,
9721012 }
9731013}
0 commit comments