@@ -220,7 +220,7 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> {
220220 let ident_str = map. name ( id) . to_string ( ) ;
221221 let span = map. span ( cmt. hir_id ) ;
222222 let start_span = Span :: new ( self . next_pos , span. lo ( ) , span. ctxt ( ) ) ;
223- let start_snip = snippet_with_applicability ( self . cx , start_span, ".." , & mut self . applicability ) ;
223+ let mut start_snip = snippet_with_applicability ( self . cx , start_span, ".." , & mut self . applicability ) ;
224224
225225 if cmt. place . projections . is_empty ( ) {
226226 // handle item without any projection, that needs an explicit borrowing
@@ -255,19 +255,75 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> {
255255 // handle item projections by removing one explicit deref
256256 // i.e.: suggest `*x` instead of `**x`
257257 let mut replacement_str = ident_str;
258- let last_deref = cmt
259- . place
260- . projections
261- . iter ( )
262- . rposition ( |proj| proj. kind == ProjectionKind :: Deref ) ;
263258
264- if let Some ( pos) = last_deref {
265- let mut projections = cmt. place . projections . clone ( ) ;
266- projections. truncate ( pos) ;
259+ // handle index projection first
260+ let index_handled = cmt. place . projections . iter ( ) . any ( |proj| match proj. kind {
261+ // Index projection like `|x| foo[x]`
262+ // the index is dropped so we can't get it to build the suggestion,
263+ // so the span is set-up again to get more code, using `span.hi()` (i.e.: `foo[x]`)
264+ // instead of `span.lo()` (i.e.: `foo`)
265+ ProjectionKind :: Index => {
266+ let start_span = Span :: new ( self . next_pos , span. hi ( ) , span. ctxt ( ) ) ;
267+ start_snip = snippet_with_applicability ( self . cx , start_span, ".." , & mut self . applicability ) ;
268+ replacement_str. clear ( ) ;
269+ true
270+ } ,
271+ _ => false ,
272+ } ) ;
273+
274+ // looking for projections other that need to be handled differently
275+ let other_projections_handled = cmt. place . projections . iter ( ) . enumerate ( ) . any ( |( i, proj) | {
276+ match proj. kind {
277+ // Field projection like `|v| v.foo`
278+ ProjectionKind :: Field ( idx, variant) => match cmt. place . ty_before_projection ( i) . kind ( ) {
279+ ty:: Adt ( def, ..) => {
280+ replacement_str = format ! (
281+ "{}.{}" ,
282+ replacement_str,
283+ def. variants[ variant] . fields[ idx as usize ] . ident. name. as_str( )
284+ ) ;
285+ true
286+ } ,
287+ ty:: Tuple ( _) => {
288+ replacement_str = format ! ( "{}.{}" , replacement_str, idx) ;
289+ true
290+ } ,
291+ _ => false ,
292+ } ,
293+ ProjectionKind :: Index => false , /* handled previously */
294+ // note: unable to capture `Subslice` kind in tests
295+ ProjectionKind :: Subslice => false ,
296+ ProjectionKind :: Deref => {
297+ // explicit deref for arrays should be avoided in the suggestion
298+ // i.e.: `|sub| *sub[1..4].len() == 3` is not expected
299+ match cmt. place . ty_before_projection ( i) . kind ( ) {
300+ // dereferencing an array (i.e.: `|sub| sub[1..4].len() == 3`)
301+ ty:: Ref ( _, inner, _) => match inner. kind ( ) {
302+ ty:: Ref ( _, innermost, _) if innermost. is_array ( ) => true ,
303+ _ => false ,
304+ } ,
305+ _ => false ,
306+ }
307+ } ,
308+ }
309+ } ) ;
267310
268- for item in projections {
269- if item. kind == ProjectionKind :: Deref {
270- replacement_str = format ! ( "*{}" , replacement_str) ;
311+ // handle `ProjectionKind::Deref` if no special case detected
312+ if !index_handled && !other_projections_handled {
313+ let last_deref = cmt
314+ . place
315+ . projections
316+ . iter ( )
317+ . rposition ( |proj| proj. kind == ProjectionKind :: Deref ) ;
318+
319+ if let Some ( pos) = last_deref {
320+ let mut projections = cmt. place . projections . clone ( ) ;
321+ projections. truncate ( pos) ;
322+
323+ for item in projections {
324+ if item. kind == ProjectionKind :: Deref {
325+ replacement_str = format ! ( "*{}" , replacement_str) ;
326+ }
271327 }
272328 }
273329 }
0 commit comments