From 4362297a0b25ba4b3993324755c2f57cd846bc8e Mon Sep 17 00:00:00 2001 From: Matt Hooper Date: Mon, 21 Sep 2020 00:38:18 +0100 Subject: Add edit utility for adding an associated item list to a impl def --- crates/syntax/src/ast/edit.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'crates') diff --git a/crates/syntax/src/ast/edit.rs b/crates/syntax/src/ast/edit.rs index 45cf31f13..ceeb0fb4b 100644 --- a/crates/syntax/src/ast/edit.rs +++ b/crates/syntax/src/ast/edit.rs @@ -93,6 +93,22 @@ where } } +impl ast::Impl { + #[must_use] + pub fn with_items(&self, items: ast::AssocItemList) -> ast::Impl { + let mut to_insert: ArrayVec<[SyntaxElement; 2]> = ArrayVec::new(); + if let Some(old_items) = self.assoc_item_list() { + let to_replace: SyntaxElement = old_items.syntax().clone().into(); + to_insert.push(items.syntax().clone().into()); + self.replace_children(single_node(to_replace), to_insert) + } else { + to_insert.push(make::tokens::single_space().into()); + to_insert.push(items.syntax().clone().into()); + self.insert_children(InsertPosition::Last, to_insert) + } + } +} + impl ast::AssocItemList { #[must_use] pub fn append_items( -- cgit v1.2.3 From ae7c9824215dbaa53786cba2fcc1d9537cb06276 Mon Sep 17 00:00:00 2001 From: Matt Hooper Date: Mon, 21 Sep 2020 00:39:17 +0100 Subject: Add make utility for empty associated item lists --- crates/syntax/src/ast/make.rs | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'crates') diff --git a/crates/syntax/src/ast/make.rs b/crates/syntax/src/ast/make.rs index 6868feed9..4a0ffcbb0 100644 --- a/crates/syntax/src/ast/make.rs +++ b/crates/syntax/src/ast/make.rs @@ -21,6 +21,10 @@ pub fn ty(text: &str) -> ast::Type { ast_from_text(&format!("impl {} for D {{}};", text)) } +pub fn assoc_item_list() -> ast::AssocItemList { + ast_from_text("impl C for D {};") +} + pub fn path_segment(name_ref: ast::NameRef) -> ast::PathSegment { ast_from_text(&format!("use {};", name_ref)) } -- cgit v1.2.3 From 9724af038b60331fc0205e14707700c4e93d7c35 Mon Sep 17 00:00:00 2001 From: Matt Hooper Date: Mon, 21 Sep 2020 00:42:27 +0100 Subject: Replace entire impl def instead of only associated items for missing impl member assist (if braces are missing from an impl def then there is no associated item list in the AST) --- .../src/handlers/add_missing_impl_members.rs | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) (limited to 'crates') diff --git a/crates/assists/src/handlers/add_missing_impl_members.rs b/crates/assists/src/handlers/add_missing_impl_members.rs index 83a2ada9a..e6f72f4bd 100644 --- a/crates/assists/src/handlers/add_missing_impl_members.rs +++ b/crates/assists/src/handlers/add_missing_impl_members.rs @@ -111,8 +111,6 @@ fn add_missing_impl_members_inner( ) -> Option<()> { let _p = profile::span("add_missing_impl_members_inner"); let impl_def = ctx.find_node_at_offset::()?; - let impl_item_list = impl_def.assoc_item_list()?; - let trait_ = resolve_target_trait(&ctx.sema, &impl_def)?; let def_name = |item: &ast::AssocItem| -> Option { @@ -148,11 +146,14 @@ fn add_missing_impl_members_inner( let target = impl_def.syntax().text_range(); acc.add(AssistId(assist_id, AssistKind::QuickFix), label, target, |builder| { + let impl_item_list = impl_def.assoc_item_list().unwrap_or(make::assoc_item_list()); + let n_existing_items = impl_item_list.assoc_items().count(); let source_scope = ctx.sema.scope_for_def(trait_); - let target_scope = ctx.sema.scope(impl_item_list.syntax()); + let target_scope = ctx.sema.scope(impl_def.syntax()); let ast_transform = QualifyPaths::new(&target_scope, &source_scope) - .or(SubstituteTypeParams::for_trait_impl(&source_scope, trait_, impl_def)); + .or(SubstituteTypeParams::for_trait_impl(&source_scope, trait_, impl_def.clone())); + let items = missing_items .into_iter() .map(|it| ast_transform::apply(&*ast_transform, it)) @@ -162,12 +163,14 @@ fn add_missing_impl_members_inner( _ => it, }) .map(|it| edit::remove_attrs_and_docs(&it)); + let new_impl_item_list = impl_item_list.append_items(items); - let first_new_item = new_impl_item_list.assoc_items().nth(n_existing_items).unwrap(); + let new_impl_def = impl_def.with_items(new_impl_item_list); + let first_new_item = + new_impl_def.assoc_item_list().unwrap().assoc_items().nth(n_existing_items).unwrap(); - let original_range = impl_item_list.syntax().text_range(); match ctx.config.snippet_cap { - None => builder.replace(original_range, new_impl_item_list.to_string()), + None => builder.replace(target, new_impl_def.to_string()), Some(cap) => { let mut cursor = Cursor::Before(first_new_item.syntax()); let placeholder; @@ -181,8 +184,8 @@ fn add_missing_impl_members_inner( } builder.replace_snippet( cap, - original_range, - render_snippet(cap, new_impl_item_list.syntax(), cursor), + target, + render_snippet(cap, new_impl_def.syntax(), cursor), ) } }; -- cgit v1.2.3 From 532be0e780e1f27e4669c8c032d364504c89b02e Mon Sep 17 00:00:00 2001 From: Matt Hooper Date: Mon, 21 Sep 2020 00:43:03 +0100 Subject: Added test for impl member assist when impl def is missing braces --- .../assists/src/handlers/add_missing_impl_members.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'crates') diff --git a/crates/assists/src/handlers/add_missing_impl_members.rs b/crates/assists/src/handlers/add_missing_impl_members.rs index e6f72f4bd..01cf95222 100644 --- a/crates/assists/src/handlers/add_missing_impl_members.rs +++ b/crates/assists/src/handlers/add_missing_impl_members.rs @@ -313,6 +313,25 @@ impl Foo for S { ); } + #[test] + fn test_impl_def_without_braces() { + check_assist( + add_missing_impl_members, + r#" +trait Foo { fn foo(&self); } +struct S; +impl Foo for S<|>"#, + r#" +trait Foo { fn foo(&self); } +struct S; +impl Foo for S { + fn foo(&self) { + ${0:todo!()} + } +}"#, + ); + } + #[test] fn fill_in_type_params_1() { check_assist( -- cgit v1.2.3 From 7d90bb1f47e1ab6f0ac1d7a042d7161295cf9320 Mon Sep 17 00:00:00 2001 From: Matt Hooper Date: Mon, 21 Sep 2020 10:01:50 +0100 Subject: Rename impl edit method to be more explicit --- crates/assists/src/handlers/add_missing_impl_members.rs | 2 +- crates/syntax/src/ast/edit.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'crates') diff --git a/crates/assists/src/handlers/add_missing_impl_members.rs b/crates/assists/src/handlers/add_missing_impl_members.rs index 01cf95222..8df1d786b 100644 --- a/crates/assists/src/handlers/add_missing_impl_members.rs +++ b/crates/assists/src/handlers/add_missing_impl_members.rs @@ -165,7 +165,7 @@ fn add_missing_impl_members_inner( .map(|it| edit::remove_attrs_and_docs(&it)); let new_impl_item_list = impl_item_list.append_items(items); - let new_impl_def = impl_def.with_items(new_impl_item_list); + let new_impl_def = impl_def.with_assoc_item_list(new_impl_item_list); let first_new_item = new_impl_def.assoc_item_list().unwrap().assoc_items().nth(n_existing_items).unwrap(); diff --git a/crates/syntax/src/ast/edit.rs b/crates/syntax/src/ast/edit.rs index ceeb0fb4b..dda0a0319 100644 --- a/crates/syntax/src/ast/edit.rs +++ b/crates/syntax/src/ast/edit.rs @@ -95,7 +95,7 @@ where impl ast::Impl { #[must_use] - pub fn with_items(&self, items: ast::AssocItemList) -> ast::Impl { + pub fn with_assoc_item_list(&self, items: ast::AssocItemList) -> ast::Impl { let mut to_insert: ArrayVec<[SyntaxElement; 2]> = ArrayVec::new(); if let Some(old_items) = self.assoc_item_list() { let to_replace: SyntaxElement = old_items.syntax().clone().into(); -- cgit v1.2.3