@@ -6,9 +6,9 @@ use crate::ty::expr_sig;
6
6
use crate :: { get_parent_expr_for_hir, higher} ;
7
7
use rustc_ast:: ast;
8
8
use rustc_ast:: util:: parser:: AssocOp ;
9
+ use rustc_data_structures:: fx:: FxHashSet ;
9
10
use rustc_errors:: Applicability ;
10
- use rustc_hir as hir;
11
- use rustc_hir:: { Closure , ExprKind , HirId , MutTy , TyKind } ;
11
+ use rustc_hir:: { self as hir, Closure , ExprKind , HirId , MutTy , Node , TyKind } ;
12
12
use rustc_hir_typeck:: expr_use_visitor:: { Delegate , ExprUseVisitor , PlaceBase , PlaceWithHirId } ;
13
13
use rustc_lint:: { EarlyContext , LateContext , LintContext } ;
14
14
use rustc_middle:: hir:: place:: ProjectionKind ;
@@ -753,8 +753,10 @@ pub fn deref_closure_args(cx: &LateContext<'_>, closure: &hir::Expr<'_>) -> Opti
753
753
let mut visitor = DerefDelegate {
754
754
cx,
755
755
closure_span : closure. span ,
756
+ closure_arg_id : closure_body. params [ 0 ] . pat . hir_id ,
756
757
closure_arg_is_type_annotated_double_ref,
757
758
next_pos : closure. span . lo ( ) ,
759
+ checked_borrows : FxHashSet :: default ( ) ,
758
760
suggestion_start : String :: new ( ) ,
759
761
applicability : Applicability :: MachineApplicable ,
760
762
} ;
@@ -780,10 +782,15 @@ struct DerefDelegate<'a, 'tcx> {
780
782
cx : & ' a LateContext < ' tcx > ,
781
783
/// The span of the input closure to adapt
782
784
closure_span : Span ,
785
+ /// The `hir_id` of the closure argument being checked
786
+ closure_arg_id : HirId ,
783
787
/// Indicates if the arg of the closure is a type annotated double reference
784
788
closure_arg_is_type_annotated_double_ref : bool ,
785
789
/// last position of the span to gradually build the suggestion
786
790
next_pos : BytePos ,
791
+ /// `hir_id` that has been checked. This is used to avoid checking the same `hir_id` multiple
792
+ /// times when inside macro expansions.
793
+ checked_borrows : FxHashSet < HirId > ,
787
794
/// starting part of the gradually built suggestion
788
795
suggestion_start : String ,
789
796
/// confidence on the built suggestion
@@ -847,9 +854,15 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> {
847
854
848
855
fn use_cloned ( & mut self , _: & PlaceWithHirId < ' tcx > , _: HirId ) { }
849
856
857
+ #[ expect( clippy:: too_many_lines) ]
850
858
fn borrow ( & mut self , cmt : & PlaceWithHirId < ' tcx > , _: HirId , _: ty:: BorrowKind ) {
851
859
if let PlaceBase :: Local ( id) = cmt. place . base {
852
860
let span = self . cx . tcx . hir_span ( cmt. hir_id ) ;
861
+ if !self . checked_borrows . insert ( cmt. hir_id ) {
862
+ // already checked this span and hir_id, skip
863
+ return ;
864
+ }
865
+
853
866
let start_span = Span :: new ( self . next_pos , span. lo ( ) , span. ctxt ( ) , None ) ;
854
867
let mut start_snip = snippet_with_applicability ( self . cx , start_span, ".." , & mut self . applicability ) ;
855
868
@@ -858,7 +871,11 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> {
858
871
// full identifier that includes projection (i.e.: `fp.field`)
859
872
let ident_str_with_proj = snippet ( self . cx , span, ".." ) . to_string ( ) ;
860
873
861
- if cmt. place . projections . is_empty ( ) {
874
+ if let Node :: Pat ( pat) = self . cx . tcx . hir_node ( id)
875
+ && pat. hir_id != self . closure_arg_id
876
+ {
877
+ let _ = write ! ( self . suggestion_start, "{start_snip}{ident_str_with_proj}" ) ;
878
+ } else if cmt. place . projections . is_empty ( ) {
862
879
// handle item without any projection, that needs an explicit borrowing
863
880
// i.e.: suggest `&x` instead of `x`
864
881
let _: fmt:: Result = write ! ( self . suggestion_start, "{start_snip}&{ident_str}" ) ;
0 commit comments