From cb3f4d43d9646deadf27da54e0d2a204685ed665 Mon Sep 17 00:00:00 2001 From: Chetan Khilosiya Date: Sun, 28 Feb 2021 01:48:51 +0530 Subject: 7708: Initial implementation of generate Default assist. The Generate Default impl from new function. --- .../src/handlers/generate_default_from_new.rs | 221 +++++++++++++++++++++ crates/ide_assists/src/lib.rs | 2 + 2 files changed, 223 insertions(+) create mode 100644 crates/ide_assists/src/handlers/generate_default_from_new.rs (limited to 'crates/ide_assists') diff --git a/crates/ide_assists/src/handlers/generate_default_from_new.rs b/crates/ide_assists/src/handlers/generate_default_from_new.rs new file mode 100644 index 000000000..a1174d315 --- /dev/null +++ b/crates/ide_assists/src/handlers/generate_default_from_new.rs @@ -0,0 +1,221 @@ +use crate::{AssistId, assist_context::{AssistContext, Assists}}; +use syntax::{AstNode, SyntaxKind, SyntaxNode, SyntaxText, ast::{self, NameOwner}}; +use test_utils::mark; + +// Assist: generate_default_from_new +// +// Generates default implementation from new method +// +// ``` +// struct Example { _inner: () } +// +// impl Example { +// pu|b fn new() -> Self { +// Self { _inner: () } +// } +// } +// ``` +// -> +// ``` +// struct Example { _inner: () } + +// impl Example { +// pub fn new() -> Self { +// Self { _inner: () } +// } +// } + +// impl Default for Example { +// fn default() -> Self { +// Self::new() +// } +// } +// ``` +pub(crate) fn generate_default_from_new(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { + let fn_node: ast::Fn = ctx.find_node_at_offset()?; + let fn_name = fn_node.name()?.to_string(); + + if !fn_name.eq("new") { + mark::hit!(other_function_than_new); + return None; + } + + if fn_node.param_list()?.params().count() != 0 { + mark::hit!(new_function_with_parameters); + return None; + } + + let insert_after = scope_for_fn_insertion_node(&fn_node.syntax())?; + let impl_obj = ast::Impl::cast(insert_after)?; + let struct_name = impl_obj.self_ty()?.syntax().text(); + + let default_fn_syntax = default_fn_node_for_new(struct_name); + + + acc.add( + AssistId("generate_default_from_new", crate::AssistKind::Generate), + "Generate a Default impl from a new fn", + impl_obj.syntax().text_range(), + move |builder| { + // TODO: indentation logic can also go here. + // let new_indent = IndentLevel::from_node(&insert_after); + let insert_location = impl_obj.syntax().text_range().end(); + builder.insert(insert_location, default_fn_syntax); + }, + ) +} + +fn scope_for_fn_insertion_node(node: &SyntaxNode) -> Option { + node.ancestors().into_iter().find(|node| node.kind() == SyntaxKind::IMPL) +} + +fn default_fn_node_for_new(struct_name: SyntaxText) -> String { + // TODO: Update the implementation to consider the code indentation. + format!( + r#" + +impl Default for {} {{ + fn default() -> Self {{ + Self::new() + }} +}}"# + ,struct_name) +} + +#[cfg(test)] +mod tests { + use crate::tests::{check_assist, check_assist_not_applicable}; + + use super::*; + + #[test] + fn generate_default() { + check_assist( + generate_default_from_new, + r#" +struct Example { _inner: () } + +impl Example { + pub fn ne$0w() -> Self { + Self { _inner: () } + } +} + +fn main() {} +"#, + r#" +struct Example { _inner: () } + +impl Example { + pub fn new() -> Self { + Self { _inner: () } + } +} + +impl Default for Example { + fn default() -> Self { + Self::new() + } +} + +fn main() {} +"#, + ); + } + + #[test] + fn generate_default2() { + check_assist( + generate_default_from_new, + r#" +struct Test { value: u32 } + +impl Test { + pub fn ne$0w() -> Self { + Self { value: 0 } + } +} +"#, + r#" +struct Test { value: u32 } + +impl Test { + pub fn new() -> Self { + Self { value: 0 } + } +} + +impl Default for Test { + fn default() -> Self { + Self::new() + } +} +"#, + ); + } + + #[test] + fn new_function_with_parameters() { + mark::check!(new_function_with_parameters); + check_assist_not_applicable(generate_default_from_new, + r#" +struct Example { _inner: () } + +impl Example { + pub fn $0new(value: ()) -> Self { + Self { _inner: value } + } +} +"# + ); + } + + #[test] + fn other_function_than_new() { + mark::check!(other_function_than_new); + check_assist_not_applicable(generate_default_from_new, + r#" +struct Example { _inner: () } + +impl Exmaple { + pub fn a$0dd() -> Self { + Self { _inner: () } + } +} + +"# + ); + } + +// #[test] +// fn default_block_is_already_present() { +// check_assist_not_applicable(generate_default_from_new, +// r#" +// struct Example { _inner: () } + +// impl Exmaple { +// pub fn n$0ew() -> Self { +// Self { _inner: () } +// } +// } + +// impl Default for Example { +// fn default() -> Self { +// Self::new() +// } +// } +// "#, +// ); +// } + + #[test] + fn standalone_new_function() { + check_assist_not_applicable(generate_default_from_new, + r#" +fn n$0ew() -> u32 { + 0 +} +"# + ); + } +} diff --git a/crates/ide_assists/src/lib.rs b/crates/ide_assists/src/lib.rs index 9c8148462..ea62d5f5d 100644 --- a/crates/ide_assists/src/lib.rs +++ b/crates/ide_assists/src/lib.rs @@ -127,6 +127,7 @@ mod handlers { mod flip_comma; mod flip_trait_bound; mod generate_default_from_enum_variant; + mod generate_default_from_new; mod generate_derive; mod generate_enum_is_method; mod generate_enum_projection_method; @@ -189,6 +190,7 @@ mod handlers { flip_comma::flip_comma, flip_trait_bound::flip_trait_bound, generate_default_from_enum_variant::generate_default_from_enum_variant, + generate_default_from_new::generate_default_from_new, generate_derive::generate_derive, generate_enum_is_method::generate_enum_is_method, generate_enum_projection_method::generate_enum_as_method, -- cgit v1.2.3 From 69a6e4c80c9efa5c611e357f56a4d8cbd9d81e6b Mon Sep 17 00:00:00 2001 From: Chetan Khilosiya Date: Sun, 28 Feb 2021 01:59:19 +0530 Subject: 7708: Format code through rust-analyzer formatter. --- .../src/handlers/generate_default_from_new.rs | 79 ++++++++++++---------- 1 file changed, 44 insertions(+), 35 deletions(-) (limited to 'crates/ide_assists') diff --git a/crates/ide_assists/src/handlers/generate_default_from_new.rs b/crates/ide_assists/src/handlers/generate_default_from_new.rs index a1174d315..e7f4591ac 100644 --- a/crates/ide_assists/src/handlers/generate_default_from_new.rs +++ b/crates/ide_assists/src/handlers/generate_default_from_new.rs @@ -1,5 +1,11 @@ -use crate::{AssistId, assist_context::{AssistContext, Assists}}; -use syntax::{AstNode, SyntaxKind, SyntaxNode, SyntaxText, ast::{self, NameOwner}}; +use crate::{ + assist_context::{AssistContext, Assists}, + AssistId, +}; +use syntax::{ + ast::{self, NameOwner}, + AstNode, SyntaxKind, SyntaxNode, SyntaxText, +}; use test_utils::mark; // Assist: generate_default_from_new @@ -51,7 +57,6 @@ pub(crate) fn generate_default_from_new(acc: &mut Assists, ctx: &AssistContext) let default_fn_syntax = default_fn_node_for_new(struct_name); - acc.add( AssistId("generate_default_from_new", crate::AssistKind::Generate), "Generate a Default impl from a new fn", @@ -72,14 +77,15 @@ fn scope_for_fn_insertion_node(node: &SyntaxNode) -> Option { fn default_fn_node_for_new(struct_name: SyntaxText) -> String { // TODO: Update the implementation to consider the code indentation. format!( - r#" + r#" impl Default for {} {{ fn default() -> Self {{ Self::new() }} -}}"# - ,struct_name) +}}"#, + struct_name + ) } #[cfg(test)] @@ -157,8 +163,9 @@ impl Default for Test { #[test] fn new_function_with_parameters() { mark::check!(new_function_with_parameters); - check_assist_not_applicable(generate_default_from_new, - r#" + check_assist_not_applicable( + generate_default_from_new, + r#" struct Example { _inner: () } impl Example { @@ -166,15 +173,16 @@ impl Example { Self { _inner: value } } } -"# +"#, ); } #[test] fn other_function_than_new() { mark::check!(other_function_than_new); - check_assist_not_applicable(generate_default_from_new, - r#" + check_assist_not_applicable( + generate_default_from_new, + r#" struct Example { _inner: () } impl Exmaple { @@ -183,39 +191,40 @@ impl Exmaple { } } -"# +"#, ); } -// #[test] -// fn default_block_is_already_present() { -// check_assist_not_applicable(generate_default_from_new, -// r#" -// struct Example { _inner: () } - -// impl Exmaple { -// pub fn n$0ew() -> Self { -// Self { _inner: () } -// } -// } - -// impl Default for Example { -// fn default() -> Self { -// Self::new() -// } -// } -// "#, -// ); -// } + // #[test] + // fn default_block_is_already_present() { + // check_assist_not_applicable(generate_default_from_new, + // r#" + // struct Example { _inner: () } + + // impl Exmaple { + // pub fn n$0ew() -> Self { + // Self { _inner: () } + // } + // } + + // impl Default for Example { + // fn default() -> Self { + // Self::new() + // } + // } + // "#, + // ); + // } #[test] fn standalone_new_function() { - check_assist_not_applicable(generate_default_from_new, - r#" + check_assist_not_applicable( + generate_default_from_new, + r#" fn n$0ew() -> u32 { 0 } -"# +"#, ); } } -- cgit v1.2.3 From 135c9e2027583181e89c696385c24af89127c7a4 Mon Sep 17 00:00:00 2001 From: Chetan Khilosiya Date: Sun, 28 Feb 2021 02:30:19 +0530 Subject: 7708: Fixed many documentaion example issues. --- .../src/handlers/generate_default_from_new.rs | 12 ++++----- crates/ide_assists/src/tests/generated.rs | 31 ++++++++++++++++++++++ 2 files changed, 37 insertions(+), 6 deletions(-) (limited to 'crates/ide_assists') diff --git a/crates/ide_assists/src/handlers/generate_default_from_new.rs b/crates/ide_assists/src/handlers/generate_default_from_new.rs index e7f4591ac..c7b049a46 100644 --- a/crates/ide_assists/src/handlers/generate_default_from_new.rs +++ b/crates/ide_assists/src/handlers/generate_default_from_new.rs @@ -10,13 +10,13 @@ use test_utils::mark; // Assist: generate_default_from_new // -// Generates default implementation from new method +// Generates default implementation from new method. // // ``` // struct Example { _inner: () } // // impl Example { -// pu|b fn new() -> Self { +// pub fn n$0ew() -> Self { // Self { _inner: () } // } // } @@ -24,13 +24,13 @@ use test_utils::mark; // -> // ``` // struct Example { _inner: () } - +// // impl Example { // pub fn new() -> Self { // Self { _inner: () } // } // } - +// // impl Default for Example { // fn default() -> Self { // Self::new() @@ -62,7 +62,7 @@ pub(crate) fn generate_default_from_new(acc: &mut Assists, ctx: &AssistContext) "Generate a Default impl from a new fn", impl_obj.syntax().text_range(), move |builder| { - // TODO: indentation logic can also go here. + // FIXME: indentation logic can also go here. // let new_indent = IndentLevel::from_node(&insert_after); let insert_location = impl_obj.syntax().text_range().end(); builder.insert(insert_location, default_fn_syntax); @@ -75,7 +75,7 @@ fn scope_for_fn_insertion_node(node: &SyntaxNode) -> Option { } fn default_fn_node_for_new(struct_name: SyntaxText) -> String { - // TODO: Update the implementation to consider the code indentation. + // FIXME: Update the implementation to consider the code indentation. format!( r#" diff --git a/crates/ide_assists/src/tests/generated.rs b/crates/ide_assists/src/tests/generated.rs index 4f007aa48..304b5798f 100644 --- a/crates/ide_assists/src/tests/generated.rs +++ b/crates/ide_assists/src/tests/generated.rs @@ -439,6 +439,37 @@ impl Default for Version { ) } +#[test] +fn doctest_generate_default_from_new() { + check_doc_test( + "generate_default_from_new", + r#####" +struct Example { _inner: () } + +impl Example { + pub fn n$0ew() -> Self { + Self { _inner: () } + } +} +"#####, + r#####" +struct Example { _inner: () } + +impl Example { + pub fn new() -> Self { + Self { _inner: () } + } +} + +impl Default for Example { + fn default() -> Self { + Self::new() + } +} +"#####, + ) +} + #[test] fn doctest_generate_derive() { check_doc_test( -- cgit v1.2.3 From 54b4727fa3a4628bac6a29fc0b3034da8c5824c0 Mon Sep 17 00:00:00 2001 From: Chetan Khilosiya Date: Tue, 2 Mar 2021 00:49:19 +0530 Subject: 7708: Added the work for review comments. Also added 1 test case to test multiple struct blocks are present. --- .../src/handlers/generate_default_from_new.rs | 91 ++++++++++++++-------- 1 file changed, 60 insertions(+), 31 deletions(-) (limited to 'crates/ide_assists') diff --git a/crates/ide_assists/src/handlers/generate_default_from_new.rs b/crates/ide_assists/src/handlers/generate_default_from_new.rs index c7b049a46..b4f80fec9 100644 --- a/crates/ide_assists/src/handlers/generate_default_from_new.rs +++ b/crates/ide_assists/src/handlers/generate_default_from_new.rs @@ -1,10 +1,10 @@ use crate::{ assist_context::{AssistContext, Assists}, - AssistId, + utils, AssistId, }; use syntax::{ - ast::{self, NameOwner}, - AstNode, SyntaxKind, SyntaxNode, SyntaxText, + ast::{self, Adt, Impl, NameOwner}, + AstNode, Direction, }; use test_utils::mark; @@ -38,54 +38,50 @@ use test_utils::mark; // } // ``` pub(crate) fn generate_default_from_new(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { - let fn_node: ast::Fn = ctx.find_node_at_offset()?; - let fn_name = fn_node.name()?.to_string(); + let fn_node = ctx.find_node_at_offset::()?; + let fn_name = fn_node.name()?; - if !fn_name.eq("new") { + if fn_name.text() != "new" { mark::hit!(other_function_than_new); return None; } - if fn_node.param_list()?.params().count() != 0 { + if fn_node.param_list()?.params().next().is_some() { mark::hit!(new_function_with_parameters); return None; } - let insert_after = scope_for_fn_insertion_node(&fn_node.syntax())?; - let impl_obj = ast::Impl::cast(insert_after)?; - let struct_name = impl_obj.self_ty()?.syntax().text(); + let impl_ = fn_node.syntax().ancestors().into_iter().find_map(ast::Impl::cast)?; - let default_fn_syntax = default_fn_node_for_new(struct_name); + let insert_location = impl_.syntax().text_range(); acc.add( AssistId("generate_default_from_new", crate::AssistKind::Generate), "Generate a Default impl from a new fn", - impl_obj.syntax().text_range(), + insert_location, move |builder| { - // FIXME: indentation logic can also go here. - // let new_indent = IndentLevel::from_node(&insert_after); - let insert_location = impl_obj.syntax().text_range().end(); - builder.insert(insert_location, default_fn_syntax); + let default_fn_syntax = default_fn_node_for_new(impl_); + if let Some(code) = default_fn_syntax { + builder.insert(insert_location.end(), code) + } }, ) } -fn scope_for_fn_insertion_node(node: &SyntaxNode) -> Option { - node.ancestors().into_iter().find(|node| node.kind() == SyntaxKind::IMPL) -} - -fn default_fn_node_for_new(struct_name: SyntaxText) -> String { - // FIXME: Update the implementation to consider the code indentation. - format!( - r#" - -impl Default for {} {{ - fn default() -> Self {{ +fn default_fn_node_for_new(impl_: Impl) -> Option { + // the code string is this way due to formatting reason + let code = r#" fn default() -> Self { Self::new() - }} -}}"#, - struct_name - ) + }"#; + let struct_name = impl_.self_ty()?.syntax().to_string(); + let struct_ = impl_ + .syntax() + .siblings(Direction::Prev) + .filter_map(ast::Struct::cast) + .find(|struct_| struct_.name().unwrap().text() == struct_name)?; + + let adt = Adt::cast(struct_.syntax().clone())?; + Some(utils::generate_trait_impl_text(&adt, "Default", code)) } #[cfg(test)] @@ -224,6 +220,39 @@ impl Exmaple { fn n$0ew() -> u32 { 0 } +"#, + ); + } + + #[test] + fn multiple_struct_blocks() { + check_assist( + generate_default_from_new, + r#" +struct Example { _inner: () } +struct Test { value: u32 } + +impl Example { + pub fn new$0 () -> Self { + Self { _inner: () } + } +} +"#, + r#" +struct Example { _inner: () } +struct Test { value: u32 } + +impl Example { + pub fn new () -> Self { + Self { _inner: () } + } +} + +impl Default for Example { + fn default() -> Self { + Self::new() + } +} "#, ); } -- cgit v1.2.3 From a59a97ae04224b1de719d0f4d505f46e5e4ecb96 Mon Sep 17 00:00:00 2001 From: Chetan Khilosiya Date: Tue, 2 Mar 2021 01:34:18 +0530 Subject: 7708: Updated generate default fn logic. --- .../src/handlers/generate_default_from_new.rs | 70 +++++++++++++++------- 1 file changed, 48 insertions(+), 22 deletions(-) (limited to 'crates/ide_assists') diff --git a/crates/ide_assists/src/handlers/generate_default_from_new.rs b/crates/ide_assists/src/handlers/generate_default_from_new.rs index b4f80fec9..9592876b4 100644 --- a/crates/ide_assists/src/handlers/generate_default_from_new.rs +++ b/crates/ide_assists/src/handlers/generate_default_from_new.rs @@ -1,10 +1,10 @@ use crate::{ assist_context::{AssistContext, Assists}, - utils, AssistId, + AssistId, }; use syntax::{ - ast::{self, Adt, Impl, NameOwner}, - AstNode, Direction, + ast::{self, Impl, NameOwner}, + AstNode, }; use test_utils::mark; @@ -60,28 +60,23 @@ pub(crate) fn generate_default_from_new(acc: &mut Assists, ctx: &AssistContext) "Generate a Default impl from a new fn", insert_location, move |builder| { - let default_fn_syntax = default_fn_node_for_new(impl_); - if let Some(code) = default_fn_syntax { - builder.insert(insert_location.end(), code) - } + let code = default_fn_node_for_new(impl_); + builder.insert(insert_location.end(), code); }, ) } -fn default_fn_node_for_new(impl_: Impl) -> Option { - // the code string is this way due to formatting reason - let code = r#" fn default() -> Self { +fn default_fn_node_for_new(impl_: Impl) -> String { + format!( + " + +impl Default for {} {{ + fn default() -> Self {{ Self::new() - }"#; - let struct_name = impl_.self_ty()?.syntax().to_string(); - let struct_ = impl_ - .syntax() - .siblings(Direction::Prev) - .filter_map(ast::Struct::cast) - .find(|struct_| struct_.name().unwrap().text() == struct_name)?; - - let adt = Adt::cast(struct_.syntax().clone())?; - Some(utils::generate_trait_impl_text(&adt, "Default", code)) + }} +}}", + impl_.self_ty().unwrap().syntax().text() + ) } #[cfg(test)] @@ -233,7 +228,7 @@ struct Example { _inner: () } struct Test { value: u32 } impl Example { - pub fn new$0 () -> Self { + pub fn new$0() -> Self { Self { _inner: () } } } @@ -243,7 +238,36 @@ struct Example { _inner: () } struct Test { value: u32 } impl Example { - pub fn new () -> Self { + pub fn new() -> Self { + Self { _inner: () } + } +} + +impl Default for Example { + fn default() -> Self { + Self::new() + } +} +"#, + ); + } + + #[test] + fn when_struct_is_after_impl() { + check_assist( + generate_default_from_new, + r#" +impl Example { + pub fn $0new() -> Self { + Self { _inner: () } + } +} + +struct Example { _inner: () } +"#, + r#" +impl Example { + pub fn new() -> Self { Self { _inner: () } } } @@ -253,6 +277,8 @@ impl Default for Example { Self::new() } } + +struct Example { _inner: () } "#, ); } -- cgit v1.2.3 From b8e6d6a60674c84b1507383407cf6a88cd4200d6 Mon Sep 17 00:00:00 2001 From: Chetan Khilosiya Date: Thu, 4 Mar 2021 23:56:18 +0530 Subject: 7708: Added the logic to check is default impl is already present. Also added test cases for code present within module. --- .../src/handlers/generate_default_from_new.rs | 115 +++++++++++++++++---- 1 file changed, 97 insertions(+), 18 deletions(-) (limited to 'crates/ide_assists') diff --git a/crates/ide_assists/src/handlers/generate_default_from_new.rs b/crates/ide_assists/src/handlers/generate_default_from_new.rs index 9592876b4..2df5adc85 100644 --- a/crates/ide_assists/src/handlers/generate_default_from_new.rs +++ b/crates/ide_assists/src/handlers/generate_default_from_new.rs @@ -2,6 +2,7 @@ use crate::{ assist_context::{AssistContext, Assists}, AssistId, }; +use hir::TypeRef; use syntax::{ ast::{self, Impl, NameOwner}, AstNode, @@ -52,6 +53,9 @@ pub(crate) fn generate_default_from_new(acc: &mut Assists, ctx: &AssistContext) } let impl_ = fn_node.syntax().ancestors().into_iter().find_map(ast::Impl::cast)?; + if is_default_implemented(ctx, &impl_).is_some() { + return None; + } let insert_location = impl_.syntax().text_range(); @@ -79,6 +83,21 @@ impl Default for {} {{ ) } +fn is_default_implemented(ctx: &AssistContext, impl_: &Impl) -> Option { + let db = ctx.sema.db; + let module = impl_.syntax().parent()?; + let sema_scope = ctx.sema.scope(&module); + let impls = sema_scope.module()?.impl_defs(db); + let mut name = None; + for i in impls { + if let Some(TypeRef::Path(p)) = i.target_trait(db) { + name = p.segments().iter().map(|s| s.name.to_string()).find(|n| n == "Default"); + } + } + + name.map(|n| !n.is_empty()) +} + #[cfg(test)] mod tests { use crate::tests::{check_assist, check_assist_not_applicable}; @@ -186,26 +205,27 @@ impl Exmaple { ); } - // #[test] - // fn default_block_is_already_present() { - // check_assist_not_applicable(generate_default_from_new, - // r#" - // struct Example { _inner: () } + #[test] + fn default_block_is_already_present() { + check_assist_not_applicable( + generate_default_from_new, + r#" +struct Example { _inner: () } - // impl Exmaple { - // pub fn n$0ew() -> Self { - // Self { _inner: () } - // } - // } +impl Exmaple { + pub fn n$0ew() -> Self { + Self { _inner: () } + } +} - // impl Default for Example { - // fn default() -> Self { - // Self::new() - // } - // } - // "#, - // ); - // } +impl Default for Example { + fn default() -> Self { + Self::new() + } +} +"#, + ); + } #[test] fn standalone_new_function() { @@ -279,6 +299,65 @@ impl Default for Example { } struct Example { _inner: () } +"#, + ); + } + + #[test] + fn struct_in_module() { + check_assist( + generate_default_from_new, + r#" +mod test { + struct Example { _inner: () } + + impl Example { + pub fn n$0ew() -> Self { + Self { _inner: () } + } + } +} +"#, + r#" +mod test { + struct Example { _inner: () } + + impl Example { + pub fn new() -> Self { + Self { _inner: () } + } + } + +impl Default for Example { + fn default() -> Self { + Self::new() + } +} +} +"#, + ); + } + + #[test] + fn struct_in_module_with_default() { + check_assist_not_applicable( + generate_default_from_new, + r#" +mod test { + struct Example { _inner: () } + + impl Example { + pub fn n$0ew() -> Self { + Self { _inner: () } + } + } + + impl Default for Example { + fn default() -> Self { + Self::new() + } + } +} "#, ); } -- cgit v1.2.3 From 9a84daf47d259380ae0fba21a54853a0fa384cb1 Mon Sep 17 00:00:00 2001 From: Chetan Khilosiya Date: Sat, 6 Mar 2021 23:15:00 +0530 Subject: 7708: Added the updated implementation of is_default_implemented. The implementation uses hir create to find the implemented trait. --- .../src/handlers/generate_default_from_new.rs | 64 +++++++++++----------- 1 file changed, 31 insertions(+), 33 deletions(-) (limited to 'crates/ide_assists') diff --git a/crates/ide_assists/src/handlers/generate_default_from_new.rs b/crates/ide_assists/src/handlers/generate_default_from_new.rs index 2df5adc85..2eb0d6aad 100644 --- a/crates/ide_assists/src/handlers/generate_default_from_new.rs +++ b/crates/ide_assists/src/handlers/generate_default_from_new.rs @@ -2,7 +2,7 @@ use crate::{ assist_context::{AssistContext, Assists}, AssistId, }; -use hir::TypeRef; +use ide_db::helpers::FamousDefs; use syntax::{ ast::{self, Impl, NameOwner}, AstNode, @@ -53,7 +53,8 @@ pub(crate) fn generate_default_from_new(acc: &mut Assists, ctx: &AssistContext) } let impl_ = fn_node.syntax().ancestors().into_iter().find_map(ast::Impl::cast)?; - if is_default_implemented(ctx, &impl_).is_some() { + let implements_default = is_default_implemented(ctx, &impl_)?; + if implements_default { return None; } @@ -85,29 +86,25 @@ impl Default for {} {{ fn is_default_implemented(ctx: &AssistContext, impl_: &Impl) -> Option { let db = ctx.sema.db; - let module = impl_.syntax().parent()?; - let sema_scope = ctx.sema.scope(&module); - let impls = sema_scope.module()?.impl_defs(db); - let mut name = None; - for i in impls { - if let Some(TypeRef::Path(p)) = i.target_trait(db) { - name = p.segments().iter().map(|s| s.name.to_string()).find(|n| n == "Default"); - } - } - - name.map(|n| !n.is_empty()) + let impl_def = ctx.sema.to_def(impl_)?; + let ty = impl_def.target_ty(db); + let krate = impl_def.module(db).krate(); + let default_trait = FamousDefs(&ctx.sema, Some(krate)).core_default_Default()?; + let implements_default = ty.impls_trait(db, default_trait, &[]); + Some(implements_default) } #[cfg(test)] mod tests { + use ide_db::helpers::FamousDefs; + use crate::tests::{check_assist, check_assist_not_applicable}; use super::*; #[test] fn generate_default() { - check_assist( - generate_default_from_new, + check_pass( r#" struct Example { _inner: () } @@ -141,8 +138,7 @@ fn main() {} #[test] fn generate_default2() { - check_assist( - generate_default_from_new, + check_pass( r#" struct Test { value: u32 } @@ -173,8 +169,7 @@ impl Default for Test { #[test] fn new_function_with_parameters() { mark::check!(new_function_with_parameters); - check_assist_not_applicable( - generate_default_from_new, + check_not_applicable( r#" struct Example { _inner: () } @@ -190,8 +185,7 @@ impl Example { #[test] fn other_function_than_new() { mark::check!(other_function_than_new); - check_assist_not_applicable( - generate_default_from_new, + check_not_applicable( r#" struct Example { _inner: () } @@ -207,8 +201,7 @@ impl Exmaple { #[test] fn default_block_is_already_present() { - check_assist_not_applicable( - generate_default_from_new, + check_not_applicable( r#" struct Example { _inner: () } @@ -229,8 +222,7 @@ impl Default for Example { #[test] fn standalone_new_function() { - check_assist_not_applicable( - generate_default_from_new, + check_not_applicable( r#" fn n$0ew() -> u32 { 0 @@ -241,8 +233,7 @@ fn n$0ew() -> u32 { #[test] fn multiple_struct_blocks() { - check_assist( - generate_default_from_new, + check_pass( r#" struct Example { _inner: () } struct Test { value: u32 } @@ -274,8 +265,7 @@ impl Default for Example { #[test] fn when_struct_is_after_impl() { - check_assist( - generate_default_from_new, + check_pass( r#" impl Example { pub fn $0new() -> Self { @@ -305,8 +295,7 @@ struct Example { _inner: () } #[test] fn struct_in_module() { - check_assist( - generate_default_from_new, + check_pass( r#" mod test { struct Example { _inner: () } @@ -340,8 +329,7 @@ impl Default for Example { #[test] fn struct_in_module_with_default() { - check_assist_not_applicable( - generate_default_from_new, + check_not_applicable( r#" mod test { struct Example { _inner: () } @@ -361,4 +349,14 @@ mod test { "#, ); } + + fn check_pass(before: &str, after: &str) { + let before = &format!("//- /main.rs crate:main deps:core{}{}", before, FamousDefs::FIXTURE); + check_assist(generate_default_from_new, before, after); + } + + fn check_not_applicable(before: &str) { + let before = &format!("//- /main.rs crate:main deps:core{}{}", before, FamousDefs::FIXTURE); + check_assist_not_applicable(generate_default_from_new, before); + } } -- cgit v1.2.3 From e4b6541c7a86f387c1b60f36df2177047907048e Mon Sep 17 00:00:00 2001 From: Chetan Khilosiya Date: Sun, 7 Mar 2021 00:51:48 +0530 Subject: 7708: handle both FamousDefs fixture and plain code. Also fix typo in example. --- .../src/handlers/generate_default_from_new.rs | 26 +++++++++++++++------- 1 file changed, 18 insertions(+), 8 deletions(-) (limited to 'crates/ide_assists') diff --git a/crates/ide_assists/src/handlers/generate_default_from_new.rs b/crates/ide_assists/src/handlers/generate_default_from_new.rs index 2eb0d6aad..82f05c65d 100644 --- a/crates/ide_assists/src/handlers/generate_default_from_new.rs +++ b/crates/ide_assists/src/handlers/generate_default_from_new.rs @@ -53,8 +53,7 @@ pub(crate) fn generate_default_from_new(acc: &mut Assists, ctx: &AssistContext) } let impl_ = fn_node.syntax().ancestors().into_iter().find_map(ast::Impl::cast)?; - let implements_default = is_default_implemented(ctx, &impl_)?; - if implements_default { + if is_default_implemented(ctx, &impl_) { return None; } @@ -84,14 +83,25 @@ impl Default for {} {{ ) } -fn is_default_implemented(ctx: &AssistContext, impl_: &Impl) -> Option { +fn is_default_implemented(ctx: &AssistContext, impl_: &Impl) -> bool { let db = ctx.sema.db; - let impl_def = ctx.sema.to_def(impl_)?; + let impl_ = ctx.sema.to_def(impl_); + let impl_def; + match impl_ { + Some(value) => impl_def = value, + None => return false, + } + let ty = impl_def.target_ty(db); let krate = impl_def.module(db).krate(); - let default_trait = FamousDefs(&ctx.sema, Some(krate)).core_default_Default()?; - let implements_default = ty.impls_trait(db, default_trait, &[]); - Some(implements_default) + let default = FamousDefs(&ctx.sema, Some(krate)).core_default_Default(); + let default_trait; + match default { + Some(value) => default_trait = value, + None => return false, + } + + ty.impls_trait(db, default_trait, &[]) } #[cfg(test)] @@ -205,7 +215,7 @@ impl Exmaple { r#" struct Example { _inner: () } -impl Exmaple { +impl Example { pub fn n$0ew() -> Self { Self { _inner: () } } -- cgit v1.2.3 From d40a4fc92c42271b085683c3b7de2d9815bdb410 Mon Sep 17 00:00:00 2001 From: Chetan Khilosiya Date: Sun, 7 Mar 2021 01:26:05 +0530 Subject: 7708: rust ideomatic code fixes. --- .../src/handlers/generate_default_from_new.rs | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) (limited to 'crates/ide_assists') diff --git a/crates/ide_assists/src/handlers/generate_default_from_new.rs b/crates/ide_assists/src/handlers/generate_default_from_new.rs index 82f05c65d..fa1254579 100644 --- a/crates/ide_assists/src/handlers/generate_default_from_new.rs +++ b/crates/ide_assists/src/handlers/generate_default_from_new.rs @@ -54,6 +54,8 @@ pub(crate) fn generate_default_from_new(acc: &mut Assists, ctx: &AssistContext) let impl_ = fn_node.syntax().ancestors().into_iter().find_map(ast::Impl::cast)?; if is_default_implemented(ctx, &impl_) { + mark::hit!(default_block_is_already_present); + mark::hit!(struct_in_module_with_default); return None; } @@ -86,20 +88,18 @@ impl Default for {} {{ fn is_default_implemented(ctx: &AssistContext, impl_: &Impl) -> bool { let db = ctx.sema.db; let impl_ = ctx.sema.to_def(impl_); - let impl_def; - match impl_ { - Some(value) => impl_def = value, + let impl_def = match impl_ { + Some(value) => value, None => return false, - } + }; let ty = impl_def.target_ty(db); let krate = impl_def.module(db).krate(); let default = FamousDefs(&ctx.sema, Some(krate)).core_default_Default(); - let default_trait; - match default { - Some(value) => default_trait = value, + let default_trait = match default { + Some(value) => value, None => return false, - } + }; ty.impls_trait(db, default_trait, &[]) } @@ -199,7 +199,7 @@ impl Example { r#" struct Example { _inner: () } -impl Exmaple { +impl Example { pub fn a$0dd() -> Self { Self { _inner: () } } @@ -211,6 +211,7 @@ impl Exmaple { #[test] fn default_block_is_already_present() { + mark::check!(default_block_is_already_present); check_not_applicable( r#" struct Example { _inner: () } @@ -339,6 +340,7 @@ impl Default for Example { #[test] fn struct_in_module_with_default() { + mark::check!(struct_in_module_with_default); check_not_applicable( r#" mod test { -- cgit v1.2.3