Skip to content

Commit d0de3fa

Browse files
committed
Rework generate_fn_type_alias
1 parent a00b4c2 commit d0de3fa

File tree

1 file changed

+43
-55
lines changed

1 file changed

+43
-55
lines changed

src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_fn_type_alias.rs

Lines changed: 43 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
use either::Either;
2-
use hir::HirDisplay;
32
use ide_db::assists::{AssistId, AssistKind, GroupLabel};
43
use syntax::{
54
ast::{self, edit::IndentLevel, make, HasGenericParams, HasName},
@@ -39,23 +38,16 @@ use crate::{AssistContext, Assists};
3938
pub(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)]
166154
mod 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

Comments
 (0)