1
1
use either:: Either ;
2
- use hir:: HirDisplay ;
3
2
use ide_db:: assists:: { AssistId , AssistKind , GroupLabel } ;
4
3
use syntax:: {
5
4
ast:: { self , edit:: IndentLevel , make, HasGenericParams , HasName } ,
@@ -39,23 +38,16 @@ use crate::{AssistContext, Assists};
39
38
pub ( crate ) fn generate_fn_type_alias ( acc : & mut Assists , ctx : & AssistContext < ' _ > ) -> Option < ( ) > {
40
39
let name = ctx. find_node_at_offset :: < ast:: Name > ( ) ?;
41
40
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
- ) ;
49
41
let func_node = ast:: Fn :: cast ( func. clone ( ) ) ?;
50
42
let param_list = func_node. param_list ( ) ?;
51
43
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) ) ;
58
49
50
+ for style in ParamStyle :: ALL {
59
51
acc. add_group (
60
52
& GroupLabel ( "Generate a type alias for function..." . into ( ) ) ,
61
53
style. assist_id ( ) ,
@@ -66,51 +58,53 @@ pub(crate) fn generate_fn_type_alias(acc: &mut Assists, ctx: &AssistContext<'_>)
66
58
67
59
let alias_name = format ! ( "{}Fn" , stdx:: to_camel_case( & name. to_string( ) ) ) ;
68
60
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 ( ) ;
75
62
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 ( ) ;
77
68
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 ( ) ) ;
79
71
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 } ;
81
74
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) ) ;
88
76
}
89
77
}
90
78
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
+ } ) ) ;
99
83
100
- let fn_params = fn_params_vec . join ( ", " ) ;
84
+ let generic_params = func_node . generic_param_list ( ) ;
101
85
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
+ ) ;
105
94
106
95
// 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) ;
112
106
edit. insert_all (
113
- syntax_editor:: Position :: before ( node ) ,
107
+ syntax_editor:: Position :: before ( insertion_node ) ,
114
108
vec ! [
115
109
ty_alias. syntax( ) . clone( ) . into( ) ,
116
110
make:: tokens:: whitespace( & format!( "\n \n {indent}" ) ) . into( ) ,
@@ -156,12 +150,6 @@ impl ParamStyle {
156
150
}
157
151
}
158
152
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
-
165
153
#[ cfg( test) ]
166
154
mod tests {
167
155
use crate :: tests:: check_assist_by_label;
@@ -233,7 +221,7 @@ extern "FooABI" fn foo(param: u32) -> i32 { return 42; }
233
221
}
234
222
235
223
#[ test]
236
- fn generate_fn_alias_unnamed_unnamed_unsafe_extern_abi ( ) {
224
+ fn generate_fn_alias_unnamed_unsafe_extern_abi ( ) {
237
225
check_assist_by_label (
238
226
generate_fn_type_alias,
239
227
r#"
@@ -369,7 +357,7 @@ extern "FooABI" fn foo(param: u32) -> i32 { return 42; }
369
357
}
370
358
371
359
#[ test]
372
- fn generate_fn_alias_named_named_unsafe_extern_abi ( ) {
360
+ fn generate_fn_alias_named_unsafe_extern_abi ( ) {
373
361
check_assist_by_label (
374
362
generate_fn_type_alias,
375
363
r#"
0 commit comments