@@ -668,7 +668,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
668668 err : & ' a mut Diag < ' infcx > ,
669669 ty : Ty < ' tcx > ,
670670 suggested : bool ,
671+ infcx : & ' a rustc_infer:: infer:: InferCtxt < ' tcx > ,
671672 }
673+
672674 impl < ' a , ' infcx , ' tcx > Visitor < ' tcx > for SuggestIndexOperatorAlternativeVisitor < ' a , ' infcx , ' tcx > {
673675 fn visit_stmt ( & mut self , stmt : & ' tcx hir:: Stmt < ' tcx > ) {
674676 hir:: intravisit:: walk_stmt ( self , stmt) ;
@@ -679,81 +681,101 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
679681 return ;
680682 }
681683 } ;
684+
685+ /// Taken straight from https://doc.rust-lang.org/nightly/nightly-rustc/clippy_utils/fn.peel_hir_ty_refs.html
686+ /// Adapted to mid using https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.Ty.html#method.peel_refs
687+ /// Simplified to counting only
688+ /// Peels off all references on the type. Returns the number of references
689+ /// removed.
690+ fn count_ty_refs < ' tcx > ( ty : Ty < ' tcx > ) -> usize {
691+ let mut count = 0 ;
692+ let mut ty = ty;
693+ while let ty:: Ref ( _, inner_ty, _) = ty. kind ( ) {
694+ ty = * inner_ty;
695+ count += 1 ;
696+ }
697+ count
698+ }
682699 if let hir:: ExprKind :: Assign ( place, rv, _sp) = expr. kind
683700 && let hir:: ExprKind :: Index ( val, index, _) = place. kind
684701 && ( expr. span == self . assign_span || place. span == self . assign_span )
685702 {
686- // val[index] = rv;
687- // ---------- place
688- self . err . multipart_suggestions (
703+ let ref_depth_difference: usize ;
704+ let _index_is_copy_clone: bool ;
705+
706+ if let Some ( index_ty) =
707+ self . infcx . tcx . typeck ( val. hir_id . owner . def_id ) . expr_ty_opt ( index)
708+ {
709+ // we know ty is a map, with a key type at walk distance 2.
710+ let key_type = self . ty . walk ( ) . nth ( 1 ) . unwrap ( ) . expect_ty ( ) ;
711+ let key_ref_depth = count_ty_refs ( key_type) ;
712+
713+ let index_ref_depth = count_ty_refs ( index_ty) ;
714+ ref_depth_difference = index_ref_depth - key_ref_depth; //index should
715+ //be deeper than key
716+ } else {
717+ // no type ?
718+ return ;
719+ } ;
720+
721+ // remove the exessive referencing if necessary, but get_mut requires a ref
722+ let ( prefix, gm_prefix) = match ref_depth_difference {
723+ 0 => ( String :: new ( ) , String :: from ( "&" ) ) ,
724+ n => ( "*" . repeat ( n) , "*" . repeat ( n - 1 ) ) ,
725+ } ;
726+
727+ self . err . multipart_suggestion (
728+ format ! ( "use `.insert()` to insert a value into a `{}`" , self . ty) ,
729+ vec ! [
730+ // val.insert(index, rv);
731+ (
732+ val. span. shrink_to_hi( ) . with_hi( index. span. lo( ) ) ,
733+ format!( ".insert({prefix}" ) ,
734+ ) ,
735+ ( index. span. shrink_to_hi( ) . with_hi( rv. span. lo( ) ) , ", " . to_string( ) ) ,
736+ ( rv. span. shrink_to_hi( ) , ")" . to_string( ) ) ,
737+ ] ,
738+ Applicability :: MaybeIncorrect ,
739+ ) ;
740+ self . err . multipart_suggestion (
689741 format ! (
690- "use `.insert()` to insert a value into a `{}`, `.get_mut()` \
691- to modify it, or the entry API for more flexibility",
742+ "use `.get_mut()` to modify an existing key in a `{}`" ,
692743 self . ty,
693744 ) ,
694745 vec ! [
695- vec![
696- // val.insert(index, rv);
697- (
698- val. span. shrink_to_hi( ) . with_hi( index. span. lo( ) ) ,
699- ".insert(" . to_string( ) ,
700- ) ,
701- (
702- index. span. shrink_to_hi( ) . with_hi( rv. span. lo( ) ) ,
703- ", " . to_string( ) ,
704- ) ,
705- ( rv. span. shrink_to_hi( ) , ")" . to_string( ) ) ,
706- ] ,
707- vec![
708- // if let Some(v) = val.get_mut(index) { *v = rv; }
709- ( val. span. shrink_to_lo( ) , "if let Some(val) = " . to_string( ) ) ,
710- (
711- val. span. shrink_to_hi( ) . with_hi( index. span. lo( ) ) ,
712- ".get_mut(" . to_string( ) ,
713- ) ,
714- (
715- index. span. shrink_to_hi( ) . with_hi( place. span. hi( ) ) ,
716- ") { *val" . to_string( ) ,
717- ) ,
718- ( rv. span. shrink_to_hi( ) , "; }" . to_string( ) ) ,
719- ] ,
720- vec![
721- // let x = val.entry(index).or_insert(rv);
722- ( val. span. shrink_to_lo( ) , "let val = " . to_string( ) ) ,
723- (
724- val. span. shrink_to_hi( ) . with_hi( index. span. lo( ) ) ,
725- ".entry(" . to_string( ) ,
726- ) ,
727- (
728- index. span. shrink_to_hi( ) . with_hi( rv. span. lo( ) ) ,
729- ").or_insert(" . to_string( ) ,
730- ) ,
731- ( rv. span. shrink_to_hi( ) , ")" . to_string( ) ) ,
732- ] ,
746+ // if let Some(v) = val.get_mut(index) { *v = rv; }
747+ ( val. span. shrink_to_lo( ) , "if let Some(val) = " . to_string( ) ) ,
748+ (
749+ val. span. shrink_to_hi( ) . with_hi( index. span. lo( ) ) ,
750+ format!( ".get_mut({gm_prefix}" ) ,
751+ ) ,
752+ (
753+ index. span. shrink_to_hi( ) . with_hi( place. span. hi( ) ) ,
754+ ") { *val" . to_string( ) ,
755+ ) ,
756+ ( rv. span. shrink_to_hi( ) , "; }" . to_string( ) ) ,
733757 ] ,
734- Applicability :: MachineApplicable ,
758+ Applicability :: MaybeIncorrect ,
735759 ) ;
736- self . suggested = true ;
737- } else if let hir:: ExprKind :: MethodCall ( _path, receiver, _, sp) = expr. kind
738- && let hir:: ExprKind :: Index ( val, index, _) = receiver. kind
739- && receiver. span == self . assign_span
740- {
741- // val[index].path(args..);
742760 self . err . multipart_suggestion (
743- format ! ( "to modify a `{}` use `.get_mut()`" , self . ty) ,
761+ format ! (
762+ "use the entry API to modify a `{}` for more flexibility" ,
763+ self . ty
764+ ) ,
744765 vec ! [
745- ( val. span. shrink_to_lo( ) , "if let Some(val) = " . to_string( ) ) ,
766+ // let x = val.entry(index).insert_entry(rv);
767+ ( val. span. shrink_to_lo( ) , "let val = " . to_string( ) ) ,
746768 (
747769 val. span. shrink_to_hi( ) . with_hi( index. span. lo( ) ) ,
748- ".get_mut (". to_string ( ) ,
770+ format! ( ".entry({prefix}" ) ,
749771 ) ,
750772 (
751- index. span. shrink_to_hi( ) . with_hi( receiver . span. hi ( ) ) ,
752- ") { val " . to_string( ) ,
773+ index. span. shrink_to_hi( ) . with_hi( rv . span. lo ( ) ) ,
774+ ").insert_entry( " . to_string( ) ,
753775 ) ,
754- ( sp . shrink_to_hi( ) , "; } " . to_string( ) ) ,
776+ ( rv . span . shrink_to_hi( ) , ") " . to_string( ) ) ,
755777 ] ,
756- Applicability :: MachineApplicable ,
778+ Applicability :: MaybeIncorrect ,
757779 ) ;
758780 self . suggested = true ;
759781 }
@@ -768,6 +790,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
768790 err,
769791 ty,
770792 suggested : false ,
793+ infcx : self . infcx ,
771794 } ;
772795 v. visit_body ( & body) ;
773796 if !v. suggested {
0 commit comments