From af3f9900cce22bfa0080fbc7780ca3830ea14e19 Mon Sep 17 00:00:00 2001 From: Giga Bowser <45986823+Giga-Bowser@users.noreply.github.com> Date: Wed, 23 Oct 2024 10:35:48 -0400 Subject: [PATCH 1/4] Add assist to generate a type alias for a function --- .../src/handlers/generate_fn_type_alias.rs | 442 ++++++++++++++++++ .../crates/ide-assists/src/lib.rs | 2 + .../crates/ide-assists/src/tests/generated.rs | 30 ++ 3 files changed, 474 insertions(+) create mode 100644 src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_fn_type_alias.rs diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_fn_type_alias.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_fn_type_alias.rs new file mode 100644 index 00000000000..597d94d3fc6 --- /dev/null +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_fn_type_alias.rs @@ -0,0 +1,442 @@ +use either::Either; +use hir::HirDisplay; +use ide_db::assists::{AssistId, AssistKind, GroupLabel}; +use syntax::{ + ast::{self, edit::IndentLevel, make, HasGenericParams, HasName}, + syntax_editor, AstNode, +}; + +use crate::{AssistContext, Assists}; + +// Assist: generate_fn_type_alias_named +// +// Generate a type alias for the function with named parameters. +// +// ``` +// unsafe fn fo$0o(n: i32) -> i32 { 42i32 } +// ``` +// -> +// ``` +// type ${0:FooFn} = unsafe fn(n: i32) -> i32; +// +// unsafe fn foo(n: i32) -> i32 { 42i32 } +// ``` + +// Assist: generate_fn_type_alias_unnamed +// +// Generate a type alias for the function with unnamed parameters. +// +// ``` +// unsafe fn fo$0o(n: i32) -> i32 { 42i32 } +// ``` +// -> +// ``` +// type ${0:FooFn} = unsafe fn(i32) -> i32; +// +// unsafe fn foo(n: i32) -> i32 { 42i32 } +// ``` + +pub(crate) fn generate_fn_type_alias(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { + let name = ctx.find_node_at_offset::()?; + let func = &name.syntax().parent()?; + let item = func.ancestors().find_map(ast::Item::cast)?; + let assoc_owner = + item.syntax().ancestors().nth(2).and_then(Either::::cast); + let node = assoc_owner.as_ref().map_or_else( + || item.syntax(), + |impl_| impl_.as_ref().either(AstNode::syntax, AstNode::syntax), + ); + let func_node = ast::Fn::cast(func.clone())?; + let param_list = func_node.param_list()?; + + for style in ParamStyle::ALL { + let generic_params = func_node.generic_param_list(); + let module = match ctx.sema.scope(node) { + Some(scope) => scope.module(), + None => continue, + }; + + acc.add_group( + &GroupLabel("Generate a type alias for function...".into()), + style.assist_id(), + style.label(), + func_node.syntax().text_range(), + |builder| { + let mut edit = builder.make_editor(func); + + let alias_name = format!("{}Fn", stdx::to_camel_case(&name.to_string())); + + let fn_abi = match func_node.abi() { + Some(abi) => format!("{} ", abi), + None => "".into(), + }; + + let fn_unsafe = if func_node.unsafe_token().is_some() { "unsafe " } else { "" }; + + let fn_qualifiers = format!("{fn_unsafe}{fn_abi}"); + + let fn_type = return_type(&func_node); + + let mut fn_params_vec = Vec::new(); + + if let Some(self_param) = param_list.self_param() { + if let Some(local) = ctx.sema.to_def(&self_param) { + let ty = local.ty(ctx.db()); + if let Ok(s) = ty.display_source_code(ctx.db(), module.into(), false) { + fn_params_vec.push(s) + } + } + } + + match style { + ParamStyle::Named => { + fn_params_vec.extend(param_list.params().map(|p| p.to_string())) + } + ParamStyle::Unnamed => fn_params_vec.extend( + param_list.params().filter_map(|p| p.ty()).map(|ty| ty.to_string()), + ), + }; + + let fn_params = fn_params_vec.join(", "); + + // FIXME: sometime in the far future when we have `make::ty_func`, we should use that + let ty = make::ty(&format!("{fn_qualifiers}fn({fn_params}){fn_type}")) + .clone_for_update(); + + // Insert new alias + let ty_alias = + make::ty_alias(&alias_name, generic_params, None, None, Some((ty, None))) + .clone_for_update(); + + let indent = IndentLevel::from_node(node); + edit.insert_all( + syntax_editor::Position::before(node), + vec![ + ty_alias.syntax().clone().into(), + make::tokens::whitespace(&format!("\n\n{indent}")).into(), + ], + ); + + if let Some(cap) = ctx.config.snippet_cap { + if let Some(name) = ty_alias.name() { + edit.add_annotation(name.syntax(), builder.make_placeholder_snippet(cap)); + } + } + + builder.add_file_edits(ctx.file_id(), edit); + }, + ); + } + + Some(()) +} + +enum ParamStyle { + Named, + Unnamed, +} + +impl ParamStyle { + const ALL: &'static [ParamStyle] = &[ParamStyle::Named, ParamStyle::Unnamed]; + + fn assist_id(&self) -> AssistId { + let s = match self { + ParamStyle::Named => "generate_fn_type_alias_named", + ParamStyle::Unnamed => "generate_fn_type_alias_unnamed", + }; + + AssistId(s, AssistKind::Generate) + } + + fn label(&self) -> &'static str { + match self { + ParamStyle::Named => "Generate a type alias for function with named params", + ParamStyle::Unnamed => "Generate a type alias for function with unnamed params", + } + } +} + +fn return_type(func: &ast::Fn) -> String { + func.ret_type() + .and_then(|ret_type| ret_type.ty()) + .map_or("".into(), |ty| format!(" -> {} ", ty)) +} + +#[cfg(test)] +mod tests { + use crate::tests::check_assist_by_label; + + use super::*; + + #[test] + fn generate_fn_alias_unnamed_simple() { + check_assist_by_label( + generate_fn_type_alias, + r#" +fn fo$0o(param: u32) -> i32 { return 42; } +"#, + r#" +type ${0:FooFn} = fn(u32) -> i32; + +fn foo(param: u32) -> i32 { return 42; } +"#, + ParamStyle::Unnamed.label(), + ); + } + + #[test] + fn generate_fn_alias_unnamed_unsafe() { + check_assist_by_label( + generate_fn_type_alias, + r#" +unsafe fn fo$0o(param: u32) -> i32 { return 42; } +"#, + r#" +type ${0:FooFn} = unsafe fn(u32) -> i32; + +unsafe fn foo(param: u32) -> i32 { return 42; } +"#, + ParamStyle::Unnamed.label(), + ); + } + + #[test] + fn generate_fn_alias_unnamed_extern() { + check_assist_by_label( + generate_fn_type_alias, + r#" +extern fn fo$0o(param: u32) -> i32 { return 42; } +"#, + r#" +type ${0:FooFn} = extern fn(u32) -> i32; + +extern fn foo(param: u32) -> i32 { return 42; } +"#, + ParamStyle::Unnamed.label(), + ); + } + + #[test] + fn generate_fn_type_unnamed_extern_abi() { + check_assist_by_label( + generate_fn_type_alias, + r#" +extern "FooABI" fn fo$0o(param: u32) -> i32 { return 42; } +"#, + r#" +type ${0:FooFn} = extern "FooABI" fn(u32) -> i32; + +extern "FooABI" fn foo(param: u32) -> i32 { return 42; } +"#, + ParamStyle::Unnamed.label(), + ); + } + + #[test] + fn generate_fn_alias_unnamed_unnamed_unsafe_extern_abi() { + check_assist_by_label( + generate_fn_type_alias, + r#" +unsafe extern "FooABI" fn fo$0o(param: u32) -> i32 { return 42; } +"#, + r#" +type ${0:FooFn} = unsafe extern "FooABI" fn(u32) -> i32; + +unsafe extern "FooABI" fn foo(param: u32) -> i32 { return 42; } +"#, + ParamStyle::Unnamed.label(), + ); + } + + #[test] + fn generate_fn_alias_unnamed_generics() { + check_assist_by_label( + generate_fn_type_alias, + r#" +fn fo$0o(a: A, b: B) -> i32 { return 42; } +"#, + r#" +type ${0:FooFn} = fn(A, B) -> i32; + +fn foo(a: A, b: B) -> i32 { return 42; } +"#, + ParamStyle::Unnamed.label(), + ); + } + + #[test] + fn generate_fn_alias_unnamed_generics_bounds() { + check_assist_by_label( + generate_fn_type_alias, + r#" +fn fo$0o(a: A, b: B) -> i32 { return 42; } +"#, + r#" +type ${0:FooFn} = fn(A, B) -> i32; + +fn foo(a: A, b: B) -> i32 { return 42; } +"#, + ParamStyle::Unnamed.label(), + ); + } + + #[test] + fn generate_fn_alias_unnamed_self() { + check_assist_by_label( + generate_fn_type_alias, + r#" +struct S; + +impl S { + fn fo$0o(&mut self, param: u32) -> i32 { return 42; } +} +"#, + r#" +struct S; + +type ${0:FooFn} = fn(&mut S, u32) -> i32; + +impl S { + fn foo(&mut self, param: u32) -> i32 { return 42; } +} +"#, + ParamStyle::Unnamed.label(), + ); + } + + #[test] + fn generate_fn_alias_named_simple() { + check_assist_by_label( + generate_fn_type_alias, + r#" +fn fo$0o(param: u32) -> i32 { return 42; } +"#, + r#" +type ${0:FooFn} = fn(param: u32) -> i32; + +fn foo(param: u32) -> i32 { return 42; } +"#, + ParamStyle::Named.label(), + ); + } + + #[test] + fn generate_fn_alias_named_unsafe() { + check_assist_by_label( + generate_fn_type_alias, + r#" +unsafe fn fo$0o(param: u32) -> i32 { return 42; } +"#, + r#" +type ${0:FooFn} = unsafe fn(param: u32) -> i32; + +unsafe fn foo(param: u32) -> i32 { return 42; } +"#, + ParamStyle::Named.label(), + ); + } + + #[test] + fn generate_fn_alias_named_extern() { + check_assist_by_label( + generate_fn_type_alias, + r#" +extern fn fo$0o(param: u32) -> i32 { return 42; } +"#, + r#" +type ${0:FooFn} = extern fn(param: u32) -> i32; + +extern fn foo(param: u32) -> i32 { return 42; } +"#, + ParamStyle::Named.label(), + ); + } + + #[test] + fn generate_fn_type_named_extern_abi() { + check_assist_by_label( + generate_fn_type_alias, + r#" +extern "FooABI" fn fo$0o(param: u32) -> i32 { return 42; } +"#, + r#" +type ${0:FooFn} = extern "FooABI" fn(param: u32) -> i32; + +extern "FooABI" fn foo(param: u32) -> i32 { return 42; } +"#, + ParamStyle::Named.label(), + ); + } + + #[test] + fn generate_fn_alias_named_named_unsafe_extern_abi() { + check_assist_by_label( + generate_fn_type_alias, + r#" +unsafe extern "FooABI" fn fo$0o(param: u32) -> i32 { return 42; } +"#, + r#" +type ${0:FooFn} = unsafe extern "FooABI" fn(param: u32) -> i32; + +unsafe extern "FooABI" fn foo(param: u32) -> i32 { return 42; } +"#, + ParamStyle::Named.label(), + ); + } + + #[test] + fn generate_fn_alias_named_generics() { + check_assist_by_label( + generate_fn_type_alias, + r#" +fn fo$0o(a: A, b: B) -> i32 { return 42; } +"#, + r#" +type ${0:FooFn} = fn(a: A, b: B) -> i32; + +fn foo(a: A, b: B) -> i32 { return 42; } +"#, + ParamStyle::Named.label(), + ); + } + + #[test] + fn generate_fn_alias_named_generics_bounds() { + check_assist_by_label( + generate_fn_type_alias, + r#" +fn fo$0o(a: A, b: B) -> i32 { return 42; } +"#, + r#" +type ${0:FooFn} = fn(a: A, b: B) -> i32; + +fn foo(a: A, b: B) -> i32 { return 42; } +"#, + ParamStyle::Named.label(), + ); + } + + #[test] + fn generate_fn_alias_named_self() { + check_assist_by_label( + generate_fn_type_alias, + r#" +struct S; + +impl S { + fn fo$0o(&mut self, param: u32) -> i32 { return 42; } +} +"#, + r#" +struct S; + +type ${0:FooFn} = fn(&mut S, param: u32) -> i32; + +impl S { + fn foo(&mut self, param: u32) -> i32 { return 42; } +} +"#, + ParamStyle::Named.label(), + ); + } +} diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs b/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs index 22620816d50..5944c0a2bbe 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs @@ -162,6 +162,7 @@ mod handlers { mod generate_enum_projection_method; mod generate_enum_variant; mod generate_from_impl_for_enum; + mod generate_fn_type_alias; mod generate_function; mod generate_getter_or_setter; mod generate_impl; @@ -290,6 +291,7 @@ pub(crate) fn all() -> &'static [Handler] { generate_enum_projection_method::generate_enum_try_into_method, generate_enum_variant::generate_enum_variant, generate_from_impl_for_enum::generate_from_impl_for_enum, + generate_fn_type_alias::generate_fn_type_alias, generate_function::generate_function, generate_impl::generate_impl, generate_impl::generate_trait_impl, diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs index 933d45d7508..64b7ab1a123 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs @@ -1548,6 +1548,36 @@ fn main() { ) } +#[test] +fn doctest_generate_fn_type_alias_named() { + check_doc_test( + "generate_fn_type_alias_named", + r#####" +unsafe fn fo$0o(n: i32) -> i32 { 42i32 } +"#####, + r#####" +type ${0:FooFn} = unsafe fn(n: i32) -> i32; + +unsafe fn foo(n: i32) -> i32 { 42i32 } +"#####, + ) +} + +#[test] +fn doctest_generate_fn_type_alias_unnamed() { + check_doc_test( + "generate_fn_type_alias_unnamed", + r#####" +unsafe fn fo$0o(n: i32) -> i32 { 42i32 } +"#####, + r#####" +type ${0:FooFn} = unsafe fn(i32) -> i32; + +unsafe fn foo(n: i32) -> i32 { 42i32 } +"#####, + ) +} + #[test] fn doctest_generate_from_impl_for_enum() { check_doc_test( From 0ac5c8a8425c151bd1f68764bd728cf6b83b1b89 Mon Sep 17 00:00:00 2001 From: Giga Bowser <45986823+Giga-Bowser@users.noreply.github.com> Date: Wed, 23 Oct 2024 11:54:48 -0400 Subject: [PATCH 2/4] Fix alphabetical order of handlers No idea how this slipped past me --- src/tools/rust-analyzer/crates/ide-assists/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs b/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs index 5944c0a2bbe..217234bd0ad 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs @@ -161,8 +161,8 @@ mod handlers { mod generate_enum_is_method; mod generate_enum_projection_method; mod generate_enum_variant; - mod generate_from_impl_for_enum; mod generate_fn_type_alias; + mod generate_from_impl_for_enum; mod generate_function; mod generate_getter_or_setter; mod generate_impl; @@ -290,8 +290,8 @@ pub(crate) fn all() -> &'static [Handler] { generate_enum_projection_method::generate_enum_as_method, generate_enum_projection_method::generate_enum_try_into_method, generate_enum_variant::generate_enum_variant, - generate_from_impl_for_enum::generate_from_impl_for_enum, generate_fn_type_alias::generate_fn_type_alias, + generate_from_impl_for_enum::generate_from_impl_for_enum, generate_function::generate_function, generate_impl::generate_impl, generate_impl::generate_trait_impl, From a00b4c2a529089b9eeeba140c9a82b872025d801 Mon Sep 17 00:00:00 2001 From: Giga Bowser <45986823+Giga-Bowser@users.noreply.github.com> Date: Thu, 24 Oct 2024 17:46:14 -0400 Subject: [PATCH 3/4] Add `ty_fn_ptr` function to create function pointer type --- .../crates/syntax/src/ast/make.rs | 42 ++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs index fcdc97ce327..2ec83d23b27 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs @@ -15,7 +15,11 @@ use rowan::NodeOrToken; use stdx::{format_to, format_to_acc, never}; -use crate::{ast, utils::is_raw_identifier, AstNode, SourceFile, SyntaxKind, SyntaxToken}; +use crate::{ + ast::{self, Param}, + utils::is_raw_identifier, + AstNode, SourceFile, SyntaxKind, SyntaxToken, +}; /// While the parent module defines basic atomic "constructors", the `ext` /// module defines shortcuts for common things. @@ -198,6 +202,38 @@ pub fn ty_alias( ast_from_text(&s) } +pub fn ty_fn_ptr>( + for_lifetime_list: Option, + is_unsafe: bool, + abi: Option, + params: I, + ret_type: Option, +) -> ast::FnPtrType { + let mut s = String::from("type __ = "); + + if let Some(list) = for_lifetime_list { + format_to!(s, "for{} ", list); + } + + if is_unsafe { + s.push_str("unsafe "); + } + + if let Some(abi) = abi { + format_to!(s, "{} ", abi) + } + + s.push_str("fn"); + + format_to!(s, "({})", params.map(|p| p.to_string()).join(", ")); + + if let Some(ret_type) = ret_type { + format_to!(s, " {}", ret_type); + } + + ast_from_text(&s) +} + pub fn assoc_item_list() -> ast::AssocItemList { ast_from_text("impl C for D {}") } @@ -862,6 +898,10 @@ pub fn item_const( ast_from_text(&format!("{visibility} const {name}: {ty} = {expr};")) } +pub fn unnamed_param(ty: ast::Type) -> ast::Param { + ast_from_text(&format!("fn f({ty}) {{ }}")) +} + pub fn param(pat: ast::Pat, ty: ast::Type) -> ast::Param { ast_from_text(&format!("fn f({pat}: {ty}) {{ }}")) } From d0de3fa7ca728b41db8aaf3735561895aaeeae5c Mon Sep 17 00:00:00 2001 From: Giga Bowser <45986823+Giga-Bowser@users.noreply.github.com> Date: Thu, 24 Oct 2024 17:54:58 -0400 Subject: [PATCH 4/4] Rework `generate_fn_type_alias` --- .../src/handlers/generate_fn_type_alias.rs | 100 ++++++++---------- 1 file changed, 44 insertions(+), 56 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_fn_type_alias.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_fn_type_alias.rs index 597d94d3fc6..f4b4c22d98d 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_fn_type_alias.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_fn_type_alias.rs @@ -1,5 +1,4 @@ use either::Either; -use hir::HirDisplay; use ide_db::assists::{AssistId, AssistKind, GroupLabel}; use syntax::{ ast::{self, edit::IndentLevel, make, HasGenericParams, HasName}, @@ -39,23 +38,16 @@ pub(crate) fn generate_fn_type_alias(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { let name = ctx.find_node_at_offset::()?; let func = &name.syntax().parent()?; - let item = func.ancestors().find_map(ast::Item::cast)?; - let assoc_owner = - item.syntax().ancestors().nth(2).and_then(Either::::cast); - let node = assoc_owner.as_ref().map_or_else( - || item.syntax(), - |impl_| impl_.as_ref().either(AstNode::syntax, AstNode::syntax), - ); let func_node = ast::Fn::cast(func.clone())?; let param_list = func_node.param_list()?; - for style in ParamStyle::ALL { - let generic_params = func_node.generic_param_list(); - let module = match ctx.sema.scope(node) { - Some(scope) => scope.module(), - None => continue, - }; + let assoc_owner = func.ancestors().nth(2).and_then(Either::::cast); + // This is where we'll insert the type alias, since type aliases in `impl`s or `trait`s are not supported + let insertion_node = assoc_owner + .as_ref() + .map_or_else(|| func, |impl_| impl_.as_ref().either(AstNode::syntax, AstNode::syntax)); + for style in ParamStyle::ALL { acc.add_group( &GroupLabel("Generate a type alias for function...".into()), style.assist_id(), @@ -66,51 +58,53 @@ pub(crate) fn generate_fn_type_alias(acc: &mut Assists, ctx: &AssistContext<'_>) let alias_name = format!("{}Fn", stdx::to_camel_case(&name.to_string())); - let fn_abi = match func_node.abi() { - Some(abi) => format!("{} ", abi), - None => "".into(), - }; - - let fn_unsafe = if func_node.unsafe_token().is_some() { "unsafe " } else { "" }; - - let fn_qualifiers = format!("{fn_unsafe}{fn_abi}"); - - let fn_type = return_type(&func_node); - let mut fn_params_vec = Vec::new(); - if let Some(self_param) = param_list.self_param() { - if let Some(local) = ctx.sema.to_def(&self_param) { - let ty = local.ty(ctx.db()); - if let Ok(s) = ty.display_source_code(ctx.db(), module.into(), false) { - fn_params_vec.push(s) - } + if let Some(self_ty) = + param_list.self_param().and_then(|p| ctx.sema.type_of_self(&p)) + { + let is_ref = self_ty.is_reference(); + let is_mut = self_ty.is_mutable_reference(); + + if let Some(adt) = self_ty.strip_references().as_adt() { + let inner_type = make::ty(adt.name(ctx.db()).as_str()); + + let ast_self_ty = + if is_ref { make::ty_ref(inner_type, is_mut) } else { inner_type }; + + fn_params_vec.push(make::unnamed_param(ast_self_ty)); } } - match style { - ParamStyle::Named => { - fn_params_vec.extend(param_list.params().map(|p| p.to_string())) - } - ParamStyle::Unnamed => fn_params_vec.extend( - param_list.params().filter_map(|p| p.ty()).map(|ty| ty.to_string()), - ), - }; + fn_params_vec.extend(param_list.params().filter_map(|p| match style { + ParamStyle::Named => Some(p), + ParamStyle::Unnamed => p.ty().map(make::unnamed_param), + })); - let fn_params = fn_params_vec.join(", "); + let generic_params = func_node.generic_param_list(); - // FIXME: sometime in the far future when we have `make::ty_func`, we should use that - let ty = make::ty(&format!("{fn_qualifiers}fn({fn_params}){fn_type}")) - .clone_for_update(); + let is_unsafe = func_node.unsafe_token().is_some(); + let ty = make::ty_fn_ptr( + None, + is_unsafe, + func_node.abi(), + fn_params_vec.into_iter(), + func_node.ret_type(), + ); // Insert new alias - let ty_alias = - make::ty_alias(&alias_name, generic_params, None, None, Some((ty, None))) - .clone_for_update(); + let ty_alias = make::ty_alias( + &alias_name, + generic_params, + None, + None, + Some((ast::Type::FnPtrType(ty), None)), + ) + .clone_for_update(); - let indent = IndentLevel::from_node(node); + let indent = IndentLevel::from_node(insertion_node); edit.insert_all( - syntax_editor::Position::before(node), + syntax_editor::Position::before(insertion_node), vec![ ty_alias.syntax().clone().into(), make::tokens::whitespace(&format!("\n\n{indent}")).into(), @@ -156,12 +150,6 @@ fn label(&self) -> &'static str { } } -fn return_type(func: &ast::Fn) -> String { - func.ret_type() - .and_then(|ret_type| ret_type.ty()) - .map_or("".into(), |ty| format!(" -> {} ", ty)) -} - #[cfg(test)] mod tests { use crate::tests::check_assist_by_label; @@ -233,7 +221,7 @@ fn generate_fn_type_unnamed_extern_abi() { } #[test] - fn generate_fn_alias_unnamed_unnamed_unsafe_extern_abi() { + fn generate_fn_alias_unnamed_unsafe_extern_abi() { check_assist_by_label( generate_fn_type_alias, r#" @@ -369,7 +357,7 @@ fn generate_fn_type_named_extern_abi() { } #[test] - fn generate_fn_alias_named_named_unsafe_extern_abi() { + fn generate_fn_alias_named_unsafe_extern_abi() { check_assist_by_label( generate_fn_type_alias, r#"