@@ -61,56 +61,72 @@ fn gen_fn(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
61
61
}
62
62
63
63
let fn_name = & * name_ref. text ( ) ;
64
- let target_module;
65
- let mut adt_name = None ;
64
+ let TargetInfo { target_module, adt_name, target, file, insert_offset } =
65
+ fn_target_info ( ctx, path, & call, fn_name) ?;
66
+ let function_builder = FunctionBuilder :: from_call ( ctx, & call, fn_name, target_module, target) ?;
67
+ let text_range = call. syntax ( ) . text_range ( ) ;
68
+ let label = format ! ( "Generate {} function" , function_builder. fn_name) ;
69
+ add_func_to_accumulator (
70
+ acc,
71
+ ctx,
72
+ text_range,
73
+ function_builder,
74
+ insert_offset,
75
+ file,
76
+ adt_name,
77
+ label,
78
+ )
79
+ }
80
+
81
+ struct TargetInfo {
82
+ target_module : Option < Module > ,
83
+ adt_name : Option < hir:: Name > ,
84
+ target : GeneratedFunctionTarget ,
85
+ file : FileId ,
86
+ insert_offset : TextSize ,
87
+ }
66
88
67
- let ( target, file, insert_offset) = match path. qualifier ( ) {
89
+ impl TargetInfo {
90
+ fn new (
91
+ target_module : Option < Module > ,
92
+ adt_name : Option < hir:: Name > ,
93
+ target : GeneratedFunctionTarget ,
94
+ file : FileId ,
95
+ insert_offset : TextSize ,
96
+ ) -> Self {
97
+ Self { target_module, adt_name, target, file, insert_offset }
98
+ }
99
+ }
100
+
101
+ fn fn_target_info (
102
+ ctx : & AssistContext < ' _ > ,
103
+ path : ast:: Path ,
104
+ call : & CallExpr ,
105
+ fn_name : & str ,
106
+ ) -> Option < TargetInfo > {
107
+ match path. qualifier ( ) {
68
108
Some ( qualifier) => match ctx. sema . resolve_path ( & qualifier) {
69
109
Some ( hir:: PathResolution :: Def ( hir:: ModuleDef :: Module ( module) ) ) => {
70
- target_module = Some ( module) ;
71
- get_fn_target ( ctx, & target_module, call. clone ( ) ) ?
110
+ get_fn_target_info ( ctx, & Some ( module) , call. clone ( ) )
72
111
}
73
112
Some ( hir:: PathResolution :: Def ( hir:: ModuleDef :: Adt ( adt) ) ) => {
74
113
if let hir:: Adt :: Enum ( _) = adt {
75
114
// Don't suggest generating function if the name starts with an uppercase letter
76
- if name_ref . text ( ) . starts_with ( char:: is_uppercase) {
115
+ if fn_name . starts_with ( char:: is_uppercase) {
77
116
return None ;
78
117
}
79
118
}
80
119
81
- let current_module = ctx. sema . scope ( call. syntax ( ) ) ?. module ( ) ;
82
- let module = adt. module ( ctx. sema . db ) ;
83
- target_module = if current_module == module { None } else { Some ( module) } ;
84
- if current_module. krate ( ) != module. krate ( ) {
85
- return None ;
86
- }
87
- let ( impl_, file) = get_adt_source ( ctx, & adt, fn_name) ?;
88
- let ( target, insert_offset) = get_method_target ( ctx, & module, & impl_) ?;
89
- adt_name = if impl_. is_none ( ) { Some ( adt. name ( ctx. sema . db ) ) } else { None } ;
90
- ( target, file, insert_offset)
120
+ assoc_fn_target_info ( ctx, call, adt, fn_name)
91
121
}
92
- _ => {
93
- return None ;
122
+ Some ( hir:: PathResolution :: SelfType ( impl_) ) => {
123
+ let adt = impl_. self_ty ( ctx. db ( ) ) . as_adt ( ) ?;
124
+ assoc_fn_target_info ( ctx, call, adt, fn_name)
94
125
}
126
+ _ => None ,
95
127
} ,
96
- _ => {
97
- target_module = None ;
98
- get_fn_target ( ctx, & target_module, call. clone ( ) ) ?
99
- }
100
- } ;
101
- let function_builder = FunctionBuilder :: from_call ( ctx, & call, fn_name, target_module, target) ?;
102
- let text_range = call. syntax ( ) . text_range ( ) ;
103
- let label = format ! ( "Generate {} function" , function_builder. fn_name) ;
104
- add_func_to_accumulator (
105
- acc,
106
- ctx,
107
- text_range,
108
- function_builder,
109
- insert_offset,
110
- file,
111
- adt_name,
112
- label,
113
- )
128
+ _ => get_fn_target_info ( ctx, & None , call. clone ( ) ) ,
129
+ }
114
130
}
115
131
116
132
fn gen_method ( acc : & mut Assists , ctx : & AssistContext < ' _ > ) -> Option < ( ) > {
@@ -366,6 +382,15 @@ fn make_return_type(
366
382
( ret_type, should_focus_return_type)
367
383
}
368
384
385
+ fn get_fn_target_info (
386
+ ctx : & AssistContext < ' _ > ,
387
+ target_module : & Option < Module > ,
388
+ call : CallExpr ,
389
+ ) -> Option < TargetInfo > {
390
+ let ( target, file, insert_offset) = get_fn_target ( ctx, target_module, call) ?;
391
+ Some ( TargetInfo :: new ( * target_module, None , target, file, insert_offset) )
392
+ }
393
+
369
394
fn get_fn_target (
370
395
ctx : & AssistContext < ' _ > ,
371
396
target_module : & Option < Module > ,
@@ -399,6 +424,24 @@ fn get_method_target(
399
424
Some ( ( target. clone ( ) , get_insert_offset ( & target) ) )
400
425
}
401
426
427
+ fn assoc_fn_target_info (
428
+ ctx : & AssistContext < ' _ > ,
429
+ call : & CallExpr ,
430
+ adt : hir:: Adt ,
431
+ fn_name : & str ,
432
+ ) -> Option < TargetInfo > {
433
+ let current_module = ctx. sema . scope ( call. syntax ( ) ) ?. module ( ) ;
434
+ let module = adt. module ( ctx. sema . db ) ;
435
+ let target_module = if current_module == module { None } else { Some ( module) } ;
436
+ if current_module. krate ( ) != module. krate ( ) {
437
+ return None ;
438
+ }
439
+ let ( impl_, file) = get_adt_source ( ctx, & adt, fn_name) ?;
440
+ let ( target, insert_offset) = get_method_target ( ctx, & module, & impl_) ?;
441
+ let adt_name = if impl_. is_none ( ) { Some ( adt. name ( ctx. sema . db ) ) } else { None } ;
442
+ Some ( TargetInfo :: new ( target_module, adt_name, target, file, insert_offset) )
443
+ }
444
+
402
445
fn get_insert_offset ( target : & GeneratedFunctionTarget ) -> TextSize {
403
446
match & target {
404
447
GeneratedFunctionTarget :: BehindItem ( it) => it. text_range ( ) . end ( ) ,
@@ -1633,6 +1676,33 @@ fn bar() ${0:-> _} {
1633
1676
)
1634
1677
}
1635
1678
1679
+ #[ test]
1680
+ fn create_static_method_within_an_impl_with_self_syntax ( ) {
1681
+ check_assist (
1682
+ generate_function,
1683
+ r"
1684
+ struct S;
1685
+ impl S {
1686
+ fn foo(&self) {
1687
+ Self::bar$0();
1688
+ }
1689
+ }
1690
+ " ,
1691
+ r"
1692
+ struct S;
1693
+ impl S {
1694
+ fn foo(&self) {
1695
+ Self::bar();
1696
+ }
1697
+
1698
+ fn bar() ${0:-> _} {
1699
+ todo!()
1700
+ }
1701
+ }
1702
+ " ,
1703
+ )
1704
+ }
1705
+
1636
1706
#[ test]
1637
1707
fn no_panic_on_invalid_global_path ( ) {
1638
1708
check_assist (
0 commit comments