@@ -61,56 +61,72 @@ fn gen_fn(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
6161 }
6262
6363 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+ }
6688
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 ( ) {
68108 Some ( qualifier) => match ctx. sema . resolve_path ( & qualifier) {
69109 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 ( ) )
72111 }
73112 Some ( hir:: PathResolution :: Def ( hir:: ModuleDef :: Adt ( adt) ) ) => {
74113 if let hir:: Adt :: Enum ( _) = adt {
75114 // 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) {
77116 return None ;
78117 }
79118 }
80119
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)
91121 }
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)
94125 }
126+ _ => None ,
95127 } ,
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+ }
114130}
115131
116132fn gen_method ( acc : & mut Assists , ctx : & AssistContext < ' _ > ) -> Option < ( ) > {
@@ -366,6 +382,15 @@ fn make_return_type(
366382 ( ret_type, should_focus_return_type)
367383}
368384
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+
369394fn get_fn_target (
370395 ctx : & AssistContext < ' _ > ,
371396 target_module : & Option < Module > ,
@@ -399,6 +424,24 @@ fn get_method_target(
399424 Some ( ( target. clone ( ) , get_insert_offset ( & target) ) )
400425}
401426
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+
402445fn get_insert_offset ( target : & GeneratedFunctionTarget ) -> TextSize {
403446 match & target {
404447 GeneratedFunctionTarget :: BehindItem ( it) => it. text_range ( ) . end ( ) ,
@@ -1633,6 +1676,33 @@ fn bar() ${0:-> _} {
16331676 )
16341677 }
16351678
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+
16361706 #[ test]
16371707 fn no_panic_on_invalid_global_path ( ) {
16381708 check_assist (
0 commit comments