From a1c187eef3ba08076aedb5154929f7eda8d1b424 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 12 Aug 2020 18:26:51 +0200 Subject: Rename ra_syntax -> syntax --- crates/ra_assists/src/handlers/generate_new.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'crates/ra_assists/src/handlers/generate_new.rs') diff --git a/crates/ra_assists/src/handlers/generate_new.rs b/crates/ra_assists/src/handlers/generate_new.rs index 32dfed274..7db10f276 100644 --- a/crates/ra_assists/src/handlers/generate_new.rs +++ b/crates/ra_assists/src/handlers/generate_new.rs @@ -1,10 +1,10 @@ use hir::Adt; use itertools::Itertools; -use ra_syntax::{ +use stdx::format_to; +use syntax::{ ast::{self, AstNode, GenericParamsOwner, NameOwner, StructKind, VisibilityOwner}, T, }; -use stdx::format_to; use crate::{AssistContext, AssistId, AssistKind, Assists}; -- cgit v1.2.3 From fc34403018079ea053f26d0a31b7517053c7dd8c Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 13 Aug 2020 17:33:38 +0200 Subject: Rename ra_assists -> assists --- crates/ra_assists/src/handlers/generate_new.rs | 421 ------------------------- 1 file changed, 421 deletions(-) delete mode 100644 crates/ra_assists/src/handlers/generate_new.rs (limited to 'crates/ra_assists/src/handlers/generate_new.rs') diff --git a/crates/ra_assists/src/handlers/generate_new.rs b/crates/ra_assists/src/handlers/generate_new.rs deleted file mode 100644 index 7db10f276..000000000 --- a/crates/ra_assists/src/handlers/generate_new.rs +++ /dev/null @@ -1,421 +0,0 @@ -use hir::Adt; -use itertools::Itertools; -use stdx::format_to; -use syntax::{ - ast::{self, AstNode, GenericParamsOwner, NameOwner, StructKind, VisibilityOwner}, - T, -}; - -use crate::{AssistContext, AssistId, AssistKind, Assists}; - -// Assist: generate_new -// -// Adds a new inherent impl for a type. -// -// ``` -// struct Ctx { -// data: T,<|> -// } -// ``` -// -> -// ``` -// struct Ctx { -// data: T, -// } -// -// impl Ctx { -// fn $0new(data: T) -> Self { Self { data } } -// } -// -// ``` -pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { - let strukt = ctx.find_node_at_offset::()?; - - // We want to only apply this to non-union structs with named fields - let field_list = match strukt.kind() { - StructKind::Record(named) => named, - _ => return None, - }; - - // Return early if we've found an existing new fn - let impl_def = find_struct_impl(&ctx, &strukt)?; - - let target = strukt.syntax().text_range(); - acc.add(AssistId("generate_new", AssistKind::Generate), "Generate `new`", target, |builder| { - let mut buf = String::with_capacity(512); - - if impl_def.is_some() { - buf.push('\n'); - } - - let vis = strukt.visibility().map_or(String::new(), |v| format!("{} ", v)); - - let params = field_list - .fields() - .filter_map(|f| Some(format!("{}: {}", f.name()?.syntax(), f.ty()?.syntax()))) - .format(", "); - let fields = field_list.fields().filter_map(|f| f.name()).format(", "); - - format_to!(buf, " {}fn new({}) -> Self {{ Self {{ {} }} }}", vis, params, fields); - - let start_offset = impl_def - .and_then(|impl_def| { - buf.push('\n'); - let start = impl_def - .syntax() - .descendants_with_tokens() - .find(|t| t.kind() == T!['{'])? - .text_range() - .end(); - - Some(start) - }) - .unwrap_or_else(|| { - buf = generate_impl_text(&strukt, &buf); - strukt.syntax().text_range().end() - }); - - match ctx.config.snippet_cap { - None => builder.insert(start_offset, buf), - Some(cap) => { - buf = buf.replace("fn new", "fn $0new"); - builder.insert_snippet(cap, start_offset, buf); - } - } - }) -} - -// Generates the surrounding `impl Type { }` including type and lifetime -// parameters -fn generate_impl_text(strukt: &ast::Struct, code: &str) -> String { - let type_params = strukt.generic_param_list(); - let mut buf = String::with_capacity(code.len()); - buf.push_str("\n\nimpl"); - if let Some(type_params) = &type_params { - format_to!(buf, "{}", type_params.syntax()); - } - buf.push_str(" "); - buf.push_str(strukt.name().unwrap().text().as_str()); - if let Some(type_params) = type_params { - let lifetime_params = type_params - .lifetime_params() - .filter_map(|it| it.lifetime_token()) - .map(|it| it.text().clone()); - let type_params = - type_params.type_params().filter_map(|it| it.name()).map(|it| it.text().clone()); - format_to!(buf, "<{}>", lifetime_params.chain(type_params).format(", ")) - } - - format_to!(buf, " {{\n{}\n}}\n", code); - - buf -} - -// Uses a syntax-driven approach to find any impl blocks for the struct that -// exist within the module/file -// -// Returns `None` if we've found an existing `new` fn -// -// FIXME: change the new fn checking to a more semantic approach when that's more -// viable (e.g. we process proc macros, etc) -fn find_struct_impl(ctx: &AssistContext, strukt: &ast::Struct) -> Option> { - let db = ctx.db(); - let module = strukt.syntax().ancestors().find(|node| { - ast::Module::can_cast(node.kind()) || ast::SourceFile::can_cast(node.kind()) - })?; - - let struct_def = ctx.sema.to_def(strukt)?; - - let block = module.descendants().filter_map(ast::Impl::cast).find_map(|impl_blk| { - let blk = ctx.sema.to_def(&impl_blk)?; - - // FIXME: handle e.g. `struct S; impl S {}` - // (we currently use the wrong type parameter) - // also we wouldn't want to use e.g. `impl S` - let same_ty = match blk.target_ty(db).as_adt() { - Some(def) => def == Adt::Struct(struct_def), - None => false, - }; - let not_trait_impl = blk.target_trait(db).is_none(); - - if !(same_ty && not_trait_impl) { - None - } else { - Some(impl_blk) - } - }); - - if let Some(ref impl_blk) = block { - if has_new_fn(impl_blk) { - return None; - } - } - - Some(block) -} - -fn has_new_fn(imp: &ast::Impl) -> bool { - if let Some(il) = imp.assoc_item_list() { - for item in il.assoc_items() { - if let ast::AssocItem::Fn(f) = item { - if let Some(name) = f.name() { - if name.text().eq_ignore_ascii_case("new") { - return true; - } - } - } - } - } - - false -} - -#[cfg(test)] -mod tests { - use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target}; - - use super::*; - - #[test] - #[rustfmt::skip] - fn test_generate_new() { - // Check output of generation - check_assist( - generate_new, -"struct Foo {<|>}", -"struct Foo {} - -impl Foo { - fn $0new() -> Self { Self { } } -} -", - ); - check_assist( - generate_new, -"struct Foo {<|>}", -"struct Foo {} - -impl Foo { - fn $0new() -> Self { Self { } } -} -", - ); - check_assist( - generate_new, -"struct Foo<'a, T: Foo<'a>> {<|>}", -"struct Foo<'a, T: Foo<'a>> {} - -impl<'a, T: Foo<'a>> Foo<'a, T> { - fn $0new() -> Self { Self { } } -} -", - ); - check_assist( - generate_new, -"struct Foo { baz: String <|>}", -"struct Foo { baz: String } - -impl Foo { - fn $0new(baz: String) -> Self { Self { baz } } -} -", - ); - check_assist( - generate_new, -"struct Foo { baz: String, qux: Vec <|>}", -"struct Foo { baz: String, qux: Vec } - -impl Foo { - fn $0new(baz: String, qux: Vec) -> Self { Self { baz, qux } } -} -", - ); - - // Check that visibility modifiers don't get brought in for fields - check_assist( - generate_new, -"struct Foo { pub baz: String, pub qux: Vec <|>}", -"struct Foo { pub baz: String, pub qux: Vec } - -impl Foo { - fn $0new(baz: String, qux: Vec) -> Self { Self { baz, qux } } -} -", - ); - - // Check that it reuses existing impls - check_assist( - generate_new, -"struct Foo {<|>} - -impl Foo {} -", -"struct Foo {} - -impl Foo { - fn $0new() -> Self { Self { } } -} -", - ); - check_assist( - generate_new, -"struct Foo {<|>} - -impl Foo { - fn qux(&self) {} -} -", -"struct Foo {} - -impl Foo { - fn $0new() -> Self { Self { } } - - fn qux(&self) {} -} -", - ); - - check_assist( - generate_new, -"struct Foo {<|>} - -impl Foo { - fn qux(&self) {} - fn baz() -> i32 { - 5 - } -} -", -"struct Foo {} - -impl Foo { - fn $0new() -> Self { Self { } } - - fn qux(&self) {} - fn baz() -> i32 { - 5 - } -} -", - ); - - // Check visibility of new fn based on struct - check_assist( - generate_new, -"pub struct Foo {<|>}", -"pub struct Foo {} - -impl Foo { - pub fn $0new() -> Self { Self { } } -} -", - ); - check_assist( - generate_new, -"pub(crate) struct Foo {<|>}", -"pub(crate) struct Foo {} - -impl Foo { - pub(crate) fn $0new() -> Self { Self { } } -} -", - ); - } - - #[test] - fn generate_new_not_applicable_if_fn_exists() { - check_assist_not_applicable( - generate_new, - " -struct Foo {<|>} - -impl Foo { - fn new() -> Self { - Self - } -}", - ); - - check_assist_not_applicable( - generate_new, - " -struct Foo {<|>} - -impl Foo { - fn New() -> Self { - Self - } -}", - ); - } - - #[test] - fn generate_new_target() { - check_assist_target( - generate_new, - " -struct SomeThingIrrelevant; -/// Has a lifetime parameter -struct Foo<'a, T: Foo<'a>> {<|>} -struct EvenMoreIrrelevant; -", - "/// Has a lifetime parameter -struct Foo<'a, T: Foo<'a>> {}", - ); - } - - #[test] - fn test_unrelated_new() { - check_assist( - generate_new, - r##" -pub struct AstId { - file_id: HirFileId, - file_ast_id: FileAstId, -} - -impl AstId { - pub fn new(file_id: HirFileId, file_ast_id: FileAstId) -> AstId { - AstId { file_id, file_ast_id } - } -} - -pub struct Source { - pub file_id: HirFileId,<|> - pub ast: T, -} - -impl Source { - pub fn map U, U>(self, f: F) -> Source { - Source { file_id: self.file_id, ast: f(self.ast) } - } -} -"##, - r##" -pub struct AstId { - file_id: HirFileId, - file_ast_id: FileAstId, -} - -impl AstId { - pub fn new(file_id: HirFileId, file_ast_id: FileAstId) -> AstId { - AstId { file_id, file_ast_id } - } -} - -pub struct Source { - pub file_id: HirFileId, - pub ast: T, -} - -impl Source { - pub fn $0new(file_id: HirFileId, ast: T) -> Self { Self { file_id, ast } } - - pub fn map U, U>(self, f: F) -> Source { - Source { file_id: self.file_id, ast: f(self.ast) } - } -} -"##, - ); - } -} -- cgit v1.2.3