@@ -227,6 +227,11 @@ fn edit_tuple_usage(
227227
228228 // no index access -> make invalid -> requires handling by user
229229 // -> put usage in block comment
230+ //
231+ // Note: For macro invocations this might result in still valid code:
232+ // When a macro accepts the tuple as argument, as well as no arguments at all,
233+ // uncommenting the tuple still leaves the macro call working (see `tests::in_macro_call::empty_macro`).
234+ // But this is an unlikely case. Usually the resulting macro call will become erroneous.
230235 builder. insert ( usage. range . start ( ) , "/*" ) ;
231236 builder. insert ( usage. range . end ( ) , "*/" ) ;
232237 }
@@ -322,89 +327,91 @@ fn handle_ref_field_usage(ctx: &AssistContext, field_expr: &FieldExpr) -> RefDat
322327 let mut ref_data =
323328 RefData { range : s. text_range ( ) , needs_deref : true , needs_parentheses : true } ;
324329
325- let parent = match s. parent ( ) {
326- Some ( parent) => parent,
330+ let parent = match s. parent ( ) . map ( ast:: Expr :: cast) {
331+ Some ( Some ( parent) ) => parent,
332+ Some ( None ) => {
333+ ref_data. needs_parentheses = false ;
334+ return ref_data;
335+ }
327336 None => return ref_data,
328337 } ;
329338
330- match_ast ! {
331- match parent {
332- ast:: ParenExpr ( it) => {
333- // already parens in place -> don't replace
334- ref_data. needs_parentheses = false ;
335- // there might be a ref outside: `&(t.0)` -> can be removed
336- if let Some ( it) = it. syntax( ) . parent( ) . and_then( ast:: RefExpr :: cast) {
337- ref_data. needs_deref = false ;
338- ref_data. range = it. syntax( ) . text_range( ) ;
339- }
340- } ,
341- ast:: RefExpr ( it) => {
342- // `&*` -> cancel each other out
339+ match parent {
340+ ast:: Expr :: ParenExpr ( it) => {
341+ // already parens in place -> don't replace
342+ ref_data. needs_parentheses = false ;
343+ // there might be a ref outside: `&(t.0)` -> can be removed
344+ if let Some ( it) = it. syntax ( ) . parent ( ) . and_then ( ast:: RefExpr :: cast) {
343345 ref_data. needs_deref = false ;
344- ref_data. needs_parentheses = false ;
345- // might be surrounded by parens -> can be removed too
346- match it. syntax( ) . parent( ) . and_then( ast:: ParenExpr :: cast) {
347- Some ( parent) => ref_data. range = parent. syntax( ) . text_range( ) ,
348- None => ref_data. range = it. syntax( ) . text_range( ) ,
349- } ;
350- } ,
351- // higher precedence than deref `*`
352- // https://doc.rust-lang.org/reference/expressions.html#expression-precedence
353- // -> requires parentheses
354- ast:: PathExpr ( _it) => { } ,
355- ast:: MethodCallExpr ( it) => {
356- // `field_expr` is `self_param` (otherwise it would be in `ArgList`)
346+ ref_data. range = it. syntax ( ) . text_range ( ) ;
347+ }
348+ }
349+ ast:: Expr :: RefExpr ( it) => {
350+ // `&*` -> cancel each other out
351+ ref_data. needs_deref = false ;
352+ ref_data. needs_parentheses = false ;
353+ // might be surrounded by parens -> can be removed too
354+ match it. syntax ( ) . parent ( ) . and_then ( ast:: ParenExpr :: cast) {
355+ Some ( parent) => ref_data. range = parent. syntax ( ) . text_range ( ) ,
356+ None => ref_data. range = it. syntax ( ) . text_range ( ) ,
357+ } ;
358+ }
359+ // higher precedence than deref `*`
360+ // https://doc.rust-lang.org/reference/expressions.html#expression-precedence
361+ // -> requires parentheses
362+ ast:: Expr :: PathExpr ( _it) => { }
363+ ast:: Expr :: MethodCallExpr ( it) => {
364+ // `field_expr` is `self_param` (otherwise it would be in `ArgList`)
365+
366+ // test if there's already auto-ref in place (`value` -> `&value`)
367+ // -> no method accepting `self`, but `&self` -> no need for deref
368+ //
369+ // other combinations (`&value` -> `value`, `&&value` -> `&value`, `&value` -> `&&value`) might or might not be able to auto-ref/deref,
370+ // but there might be trait implementations an added `&` might resolve to
371+ // -> ONLY handle auto-ref from `value` to `&value`
372+ fn is_auto_ref ( ctx : & AssistContext , call_expr : & MethodCallExpr ) -> bool {
373+ fn impl_ ( ctx : & AssistContext , call_expr : & MethodCallExpr ) -> Option < bool > {
374+ let rec = call_expr. receiver ( ) ?;
375+ let rec_ty = ctx. sema . type_of_expr ( & rec) ?. adjusted ( ) ;
376+ // input must be actual value
377+ if rec_ty. is_reference ( ) {
378+ return Some ( false ) ;
379+ }
357380
358- // test if there's already auto-ref in place (`value` -> `&value`)
359- // -> no method accepting `self`, but `&self` -> no need for deref
360- //
361- // other combinations (`&value` -> `value`, `&&value` -> `&value`, `&value` -> `&&value`) might or might not be able to auto-ref/deref,
362- // but there might be trait implementations an added `&` might resolve to
363- // -> ONLY handle auto-ref from `value` to `&value`
364- fn is_auto_ref( ctx: & AssistContext , call_expr: & MethodCallExpr ) -> bool {
365- fn impl_( ctx: & AssistContext , call_expr: & MethodCallExpr ) -> Option <bool > {
366- let rec = call_expr. receiver( ) ?;
367- let rec_ty = ctx. sema. type_of_expr( & rec) ?. adjusted( ) ;
368- // input must be actual value
369- if rec_ty. is_reference( ) {
370- return Some ( false ) ;
371- }
372-
373- // doesn't resolve trait impl
374- let f = ctx. sema. resolve_method_call( call_expr) ?;
375- let self_param = f. self_param( ctx. db( ) ) ?;
376- // self must be ref
377- match self_param. access( ctx. db( ) ) {
378- hir:: Access :: Shared | hir:: Access :: Exclusive => Some ( true ) ,
379- hir:: Access :: Owned => Some ( false ) ,
380- }
381+ // doesn't resolve trait impl
382+ let f = ctx. sema . resolve_method_call ( call_expr) ?;
383+ let self_param = f. self_param ( ctx. db ( ) ) ?;
384+ // self must be ref
385+ match self_param. access ( ctx. db ( ) ) {
386+ hir:: Access :: Shared | hir:: Access :: Exclusive => Some ( true ) ,
387+ hir:: Access :: Owned => Some ( false ) ,
381388 }
382- impl_( ctx, call_expr) . unwrap_or( false )
383389 }
390+ impl_ ( ctx, call_expr) . unwrap_or ( false )
391+ }
384392
385- if is_auto_ref( ctx, & it) {
386- ref_data. needs_deref = false ;
387- ref_data. needs_parentheses = false ;
388- }
389- } ,
390- ast:: FieldExpr ( _it) => {
391- // `t.0.my_field`
392- ref_data. needs_deref = false ;
393- ref_data. needs_parentheses = false ;
394- } ,
395- ast:: IndexExpr ( _it) => {
396- // `t.0[1]`
393+ if is_auto_ref ( ctx, & it) {
397394 ref_data. needs_deref = false ;
398395 ref_data. needs_parentheses = false ;
399- } ,
400- ast:: TryExpr ( _it) => {
401- // `t.0?`
402- // requires deref and parens: `(*_0)`
403- } ,
404- // lower precedence than deref `*` -> no parens
405- _ => {
406- ref_data. needs_parentheses = false ;
407- } ,
396+ }
397+ }
398+ ast:: Expr :: FieldExpr ( _it) => {
399+ // `t.0.my_field`
400+ ref_data. needs_deref = false ;
401+ ref_data. needs_parentheses = false ;
402+ }
403+ ast:: Expr :: IndexExpr ( _it) => {
404+ // `t.0[1]`
405+ ref_data. needs_deref = false ;
406+ ref_data. needs_parentheses = false ;
407+ }
408+ ast:: Expr :: TryExpr ( _it) => {
409+ // `t.0?`
410+ // requires deref and parens: `(*_0)`
411+ }
412+ // lower precedence than deref `*` -> no parens
413+ _ => {
414+ ref_data. needs_parentheses = false ;
408415 }
409416 } ;
410417
0 commit comments