11use either:: Either ;
2- use hir:: HirDisplay ;
32use ide_db:: assists:: { AssistId , AssistKind , GroupLabel } ;
43use syntax:: {
54 ast:: { self , edit:: IndentLevel , make, HasGenericParams , HasName } ,
@@ -39,23 +38,16 @@ use crate::{AssistContext, Assists};
3938pub ( crate ) fn generate_fn_type_alias ( acc : & mut Assists , ctx : & AssistContext < ' _ > ) -> Option < ( ) > {
4039 let name = ctx. find_node_at_offset :: < ast:: Name > ( ) ?;
4140 let func = & name. syntax ( ) . parent ( ) ?;
42- let item = func. ancestors ( ) . find_map ( ast:: Item :: cast) ?;
43- let assoc_owner =
44- item. syntax ( ) . ancestors ( ) . nth ( 2 ) . and_then ( Either :: < ast:: Trait , ast:: Impl > :: cast) ;
45- let node = assoc_owner. as_ref ( ) . map_or_else (
46- || item. syntax ( ) ,
47- |impl_| impl_. as_ref ( ) . either ( AstNode :: syntax, AstNode :: syntax) ,
48- ) ;
4941 let func_node = ast:: Fn :: cast ( func. clone ( ) ) ?;
5042 let param_list = func_node. param_list ( ) ?;
5143
52- for style in ParamStyle :: ALL {
53- let generic_params = func_node. generic_param_list ( ) ;
54- let module = match ctx. sema . scope ( node) {
55- Some ( scope) => scope. module ( ) ,
56- None => continue ,
57- } ;
44+ let assoc_owner = func. ancestors ( ) . nth ( 2 ) . and_then ( Either :: < ast:: Trait , ast:: Impl > :: cast) ;
45+ // This is where we'll insert the type alias, since type aliases in `impl`s or `trait`s are not supported
46+ let insertion_node = assoc_owner
47+ . as_ref ( )
48+ . map_or_else ( || func, |impl_| impl_. as_ref ( ) . either ( AstNode :: syntax, AstNode :: syntax) ) ;
5849
50+ for style in ParamStyle :: ALL {
5951 acc. add_group (
6052 & GroupLabel ( "Generate a type alias for function..." . into ( ) ) ,
6153 style. assist_id ( ) ,
@@ -66,51 +58,53 @@ pub(crate) fn generate_fn_type_alias(acc: &mut Assists, ctx: &AssistContext<'_>)
6658
6759 let alias_name = format ! ( "{}Fn" , stdx:: to_camel_case( & name. to_string( ) ) ) ;
6860
69- let fn_abi = match func_node. abi ( ) {
70- Some ( abi) => format ! ( "{} " , abi) ,
71- None => "" . into ( ) ,
72- } ;
73-
74- let fn_unsafe = if func_node. unsafe_token ( ) . is_some ( ) { "unsafe " } else { "" } ;
61+ let mut fn_params_vec = Vec :: new ( ) ;
7562
76- let fn_qualifiers = format ! ( "{fn_unsafe}{fn_abi}" ) ;
63+ if let Some ( self_ty) =
64+ param_list. self_param ( ) . and_then ( |p| ctx. sema . type_of_self ( & p) )
65+ {
66+ let is_ref = self_ty. is_reference ( ) ;
67+ let is_mut = self_ty. is_mutable_reference ( ) ;
7768
78- let fn_type = return_type ( & func_node) ;
69+ if let Some ( adt) = self_ty. strip_references ( ) . as_adt ( ) {
70+ let inner_type = make:: ty ( adt. name ( ctx. db ( ) ) . as_str ( ) ) ;
7971
80- let mut fn_params_vec = Vec :: new ( ) ;
72+ let ast_self_ty =
73+ if is_ref { make:: ty_ref ( inner_type, is_mut) } else { inner_type } ;
8174
82- if let Some ( self_param) = param_list. self_param ( ) {
83- if let Some ( local) = ctx. sema . to_def ( & self_param) {
84- let ty = local. ty ( ctx. db ( ) ) ;
85- if let Ok ( s) = ty. display_source_code ( ctx. db ( ) , module. into ( ) , false ) {
86- fn_params_vec. push ( s)
87- }
75+ fn_params_vec. push ( make:: unnamed_param ( ast_self_ty) ) ;
8876 }
8977 }
9078
91- match style {
92- ParamStyle :: Named => {
93- fn_params_vec. extend ( param_list. params ( ) . map ( |p| p. to_string ( ) ) )
94- }
95- ParamStyle :: Unnamed => fn_params_vec. extend (
96- param_list. params ( ) . filter_map ( |p| p. ty ( ) ) . map ( |ty| ty. to_string ( ) ) ,
97- ) ,
98- } ;
79+ fn_params_vec. extend ( param_list. params ( ) . filter_map ( |p| match style {
80+ ParamStyle :: Named => Some ( p) ,
81+ ParamStyle :: Unnamed => p. ty ( ) . map ( make:: unnamed_param) ,
82+ } ) ) ;
9983
100- let fn_params = fn_params_vec . join ( ", " ) ;
84+ let generic_params = func_node . generic_param_list ( ) ;
10185
102- // FIXME: sometime in the far future when we have `make::ty_func`, we should use that
103- let ty = make:: ty ( & format ! ( "{fn_qualifiers}fn({fn_params}){fn_type}" ) )
104- . clone_for_update ( ) ;
86+ let is_unsafe = func_node. unsafe_token ( ) . is_some ( ) ;
87+ let ty = make:: ty_fn_ptr (
88+ None ,
89+ is_unsafe,
90+ func_node. abi ( ) ,
91+ fn_params_vec. into_iter ( ) ,
92+ func_node. ret_type ( ) ,
93+ ) ;
10594
10695 // Insert new alias
107- let ty_alias =
108- make:: ty_alias ( & alias_name, generic_params, None , None , Some ( ( ty, None ) ) )
109- . clone_for_update ( ) ;
110-
111- let indent = IndentLevel :: from_node ( node) ;
96+ let ty_alias = make:: ty_alias (
97+ & alias_name,
98+ generic_params,
99+ None ,
100+ None ,
101+ Some ( ( ast:: Type :: FnPtrType ( ty) , None ) ) ,
102+ )
103+ . clone_for_update ( ) ;
104+
105+ let indent = IndentLevel :: from_node ( insertion_node) ;
112106 edit. insert_all (
113- syntax_editor:: Position :: before ( node ) ,
107+ syntax_editor:: Position :: before ( insertion_node ) ,
114108 vec ! [
115109 ty_alias. syntax( ) . clone( ) . into( ) ,
116110 make:: tokens:: whitespace( & format!( "\n \n {indent}" ) ) . into( ) ,
@@ -156,12 +150,6 @@ impl ParamStyle {
156150 }
157151}
158152
159- fn return_type ( func : & ast:: Fn ) -> String {
160- func. ret_type ( )
161- . and_then ( |ret_type| ret_type. ty ( ) )
162- . map_or ( "" . into ( ) , |ty| format ! ( " -> {} " , ty) )
163- }
164-
165153#[ cfg( test) ]
166154mod tests {
167155 use crate :: tests:: check_assist_by_label;
@@ -233,7 +221,7 @@ extern "FooABI" fn foo(param: u32) -> i32 { return 42; }
233221 }
234222
235223 #[ test]
236- fn generate_fn_alias_unnamed_unnamed_unsafe_extern_abi ( ) {
224+ fn generate_fn_alias_unnamed_unsafe_extern_abi ( ) {
237225 check_assist_by_label (
238226 generate_fn_type_alias,
239227 r#"
@@ -369,7 +357,7 @@ extern "FooABI" fn foo(param: u32) -> i32 { return 42; }
369357 }
370358
371359 #[ test]
372- fn generate_fn_alias_named_named_unsafe_extern_abi ( ) {
360+ fn generate_fn_alias_named_unsafe_extern_abi ( ) {
373361 check_assist_by_label (
374362 generate_fn_type_alias,
375363 r#"
0 commit comments