@@ -4,14 +4,14 @@ use hir::{db::HirDatabase, HasSource, PathResolution, Semantics, TypeInfo};
4
4
use ide_db:: {
5
5
base_db:: { FileId , FileRange } ,
6
6
defs:: Definition ,
7
- helpers:: insert_use:: remove_path_if_in_use_stmt,
7
+ helpers:: { insert_use:: remove_path_if_in_use_stmt, node_ext :: expr_as_name_ref } ,
8
8
path_transform:: PathTransform ,
9
9
search:: { FileReference , SearchScope } ,
10
10
RootDatabase ,
11
11
} ;
12
12
use itertools:: { izip, Itertools } ;
13
13
use syntax:: {
14
- ast:: { self , edit_in_place:: Indent , HasArgList } ,
14
+ ast:: { self , edit_in_place:: Indent , HasArgList , PathExpr } ,
15
15
ted, AstNode , SyntaxNode ,
16
16
} ;
17
17
@@ -359,33 +359,37 @@ fn inline(
359
359
}
360
360
// Inline parameter expressions or generate `let` statements depending on whether inlining works or not.
361
361
for ( ( pat, param_ty, _) , usages, expr) in izip ! ( params, param_use_nodes, arguments) . rev ( ) {
362
- let expr_is_name_ref = matches ! ( & expr,
363
- ast:: Expr :: PathExpr ( expr)
364
- if expr. path( ) . and_then( |path| path. as_single_name_ref( ) ) . is_some( )
365
- ) ;
366
- match & * usages {
362
+ let inline_direct = |usage, replacement : & ast:: Expr | {
363
+ if let Some ( field) = path_expr_as_record_field ( usage) {
364
+ cov_mark:: hit!( inline_call_inline_direct_field) ;
365
+ field. replace_expr ( replacement. clone_for_update ( ) ) ;
366
+ } else {
367
+ ted:: replace ( usage. syntax ( ) , & replacement. syntax ( ) . clone_for_update ( ) ) ;
368
+ }
369
+ } ;
370
+ // izip confuses RA due to our lack of hygiene info currently losing us typeinfo
371
+ let usages: & [ ast:: PathExpr ] = & * usages;
372
+ match usages {
367
373
// inline single use closure arguments
368
374
[ usage]
369
375
if matches ! ( expr, ast:: Expr :: ClosureExpr ( _) )
370
376
&& usage. syntax ( ) . parent ( ) . and_then ( ast:: Expr :: cast) . is_some ( ) =>
371
377
{
372
378
cov_mark:: hit!( inline_call_inline_closure) ;
373
379
let expr = make:: expr_paren ( expr. clone ( ) ) ;
374
- ted :: replace ( usage. syntax ( ) , expr. syntax ( ) . clone_for_update ( ) ) ;
380
+ inline_direct ( usage, & expr) ;
375
381
}
376
382
// inline single use literals
377
383
[ usage] if matches ! ( expr, ast:: Expr :: Literal ( _) ) => {
378
384
cov_mark:: hit!( inline_call_inline_literal) ;
379
- ted :: replace ( usage. syntax ( ) , expr. syntax ( ) . clone_for_update ( ) ) ;
385
+ inline_direct ( usage, & expr) ;
380
386
}
381
387
// inline direct local arguments
382
- [ _, ..] if expr_is_name_ref => {
388
+ [ _, ..] if expr_as_name_ref ( & expr ) . is_some ( ) => {
383
389
cov_mark:: hit!( inline_call_inline_locals) ;
384
- usages. into_iter ( ) . for_each ( |usage| {
385
- ted:: replace ( usage. syntax ( ) , & expr. syntax ( ) . clone_for_update ( ) ) ;
386
- } ) ;
390
+ usages. into_iter ( ) . for_each ( |usage| inline_direct ( usage, & expr) ) ;
387
391
}
388
- // cant inline, emit a let statement
392
+ // can't inline, emit a let statement
389
393
_ => {
390
394
let ty =
391
395
sema. type_of_expr ( expr) . filter ( TypeInfo :: has_adjustment) . and ( param_ty. clone ( ) ) ;
@@ -421,6 +425,12 @@ fn inline(
421
425
}
422
426
}
423
427
428
+ fn path_expr_as_record_field ( usage : & PathExpr ) -> Option < ast:: RecordExprField > {
429
+ let path = usage. path ( ) ?;
430
+ let name_ref = path. as_single_name_ref ( ) ?;
431
+ ast:: RecordExprField :: for_name_ref ( & name_ref)
432
+ }
433
+
424
434
#[ cfg( test) ]
425
435
mod tests {
426
436
use crate :: tests:: { check_assist, check_assist_not_applicable} ;
@@ -1022,6 +1032,61 @@ fn foo$0() {
1022
1032
fn foo() {
1023
1033
foo$0();
1024
1034
}
1035
+ "# ,
1036
+ ) ;
1037
+ }
1038
+
1039
+ #[ test]
1040
+ fn inline_call_field_shorthand ( ) {
1041
+ cov_mark:: check!( inline_call_inline_direct_field) ;
1042
+ check_assist (
1043
+ inline_call,
1044
+ r#"
1045
+ struct Foo {
1046
+ field: u32,
1047
+ field1: u32,
1048
+ field2: u32,
1049
+ field3: u32,
1050
+ }
1051
+ fn foo(field: u32, field1: u32, val2: u32, val3: u32) -> Foo {
1052
+ Foo {
1053
+ field,
1054
+ field1,
1055
+ field2: val2,
1056
+ field3: val3,
1057
+ }
1058
+ }
1059
+ fn main() {
1060
+ let bar = 0;
1061
+ let baz = 0;
1062
+ foo$0(bar, 0, baz, 0);
1063
+ }
1064
+ "# ,
1065
+ r#"
1066
+ struct Foo {
1067
+ field: u32,
1068
+ field1: u32,
1069
+ field2: u32,
1070
+ field3: u32,
1071
+ }
1072
+ fn foo(field: u32, field1: u32, val2: u32, val3: u32) -> Foo {
1073
+ Foo {
1074
+ field,
1075
+ field1,
1076
+ field2: val2,
1077
+ field3: val3,
1078
+ }
1079
+ }
1080
+ fn main() {
1081
+ let bar = 0;
1082
+ let baz = 0;
1083
+ Foo {
1084
+ field: bar,
1085
+ field1: 0,
1086
+ field2: baz,
1087
+ field3: 0,
1088
+ };
1089
+ }
1025
1090
"# ,
1026
1091
) ;
1027
1092
}
0 commit comments