aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2020-09-21 10:06:24 +0100
committerGitHub <[email protected]>2020-09-21 10:06:24 +0100
commit3b52d3181a44a0ccedd30c52e70ce84231918e72 (patch)
tree0cf70a2a1d5db2b7afa39dafcb0fcd72ba05dc4d
parente70cf706bb7c6c07e8c33b537ad24e5333aa5e75 (diff)
parent7d90bb1f47e1ab6f0ac1d7a042d7161295cf9320 (diff)
Merge #6043
6043: Allow missing trait members assist without needing braces r=matklad a=M-J-Hooper Assist to complete missing items when implementing a trait does not appear without impl def braces (see #5144 ). The reason behind this was that this assist is based on `ast::AssocItemList` which only appears in the AST after the braces are added to the impl def. Instead of relying on and replacing the item list, we now instead replace the entire `ast::Impl` and add the item list if its missing. Co-authored-by: Matt Hooper <[email protected]>
-rw-r--r--crates/assists/src/handlers/add_missing_impl_members.rs40
-rw-r--r--crates/syntax/src/ast/edit.rs16
-rw-r--r--crates/syntax/src/ast/make.rs4
3 files changed, 51 insertions, 9 deletions
diff --git a/crates/assists/src/handlers/add_missing_impl_members.rs b/crates/assists/src/handlers/add_missing_impl_members.rs
index 83a2ada9a..8df1d786b 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(
111) -> Option<()> { 111) -> Option<()> {
112 let _p = profile::span("add_missing_impl_members_inner"); 112 let _p = profile::span("add_missing_impl_members_inner");
113 let impl_def = ctx.find_node_at_offset::<ast::Impl>()?; 113 let impl_def = ctx.find_node_at_offset::<ast::Impl>()?;
114 let impl_item_list = impl_def.assoc_item_list()?;
115
116 let trait_ = resolve_target_trait(&ctx.sema, &impl_def)?; 114 let trait_ = resolve_target_trait(&ctx.sema, &impl_def)?;
117 115
118 let def_name = |item: &ast::AssocItem| -> Option<SmolStr> { 116 let def_name = |item: &ast::AssocItem| -> Option<SmolStr> {
@@ -148,11 +146,14 @@ fn add_missing_impl_members_inner(
148 146
149 let target = impl_def.syntax().text_range(); 147 let target = impl_def.syntax().text_range();
150 acc.add(AssistId(assist_id, AssistKind::QuickFix), label, target, |builder| { 148 acc.add(AssistId(assist_id, AssistKind::QuickFix), label, target, |builder| {
149 let impl_item_list = impl_def.assoc_item_list().unwrap_or(make::assoc_item_list());
150
151 let n_existing_items = impl_item_list.assoc_items().count(); 151 let n_existing_items = impl_item_list.assoc_items().count();
152 let source_scope = ctx.sema.scope_for_def(trait_); 152 let source_scope = ctx.sema.scope_for_def(trait_);
153 let target_scope = ctx.sema.scope(impl_item_list.syntax()); 153 let target_scope = ctx.sema.scope(impl_def.syntax());
154 let ast_transform = QualifyPaths::new(&target_scope, &source_scope) 154 let ast_transform = QualifyPaths::new(&target_scope, &source_scope)
155 .or(SubstituteTypeParams::for_trait_impl(&source_scope, trait_, impl_def)); 155 .or(SubstituteTypeParams::for_trait_impl(&source_scope, trait_, impl_def.clone()));
156
156 let items = missing_items 157 let items = missing_items
157 .into_iter() 158 .into_iter()
158 .map(|it| ast_transform::apply(&*ast_transform, it)) 159 .map(|it| ast_transform::apply(&*ast_transform, it))
@@ -162,12 +163,14 @@ fn add_missing_impl_members_inner(
162 _ => it, 163 _ => it,
163 }) 164 })
164 .map(|it| edit::remove_attrs_and_docs(&it)); 165 .map(|it| edit::remove_attrs_and_docs(&it));
166
165 let new_impl_item_list = impl_item_list.append_items(items); 167 let new_impl_item_list = impl_item_list.append_items(items);
166 let first_new_item = new_impl_item_list.assoc_items().nth(n_existing_items).unwrap(); 168 let new_impl_def = impl_def.with_assoc_item_list(new_impl_item_list);
169 let first_new_item =
170 new_impl_def.assoc_item_list().unwrap().assoc_items().nth(n_existing_items).unwrap();
167 171
168 let original_range = impl_item_list.syntax().text_range();
169 match ctx.config.snippet_cap { 172 match ctx.config.snippet_cap {
170 None => builder.replace(original_range, new_impl_item_list.to_string()), 173 None => builder.replace(target, new_impl_def.to_string()),
171 Some(cap) => { 174 Some(cap) => {
172 let mut cursor = Cursor::Before(first_new_item.syntax()); 175 let mut cursor = Cursor::Before(first_new_item.syntax());
173 let placeholder; 176 let placeholder;
@@ -181,8 +184,8 @@ fn add_missing_impl_members_inner(
181 } 184 }
182 builder.replace_snippet( 185 builder.replace_snippet(
183 cap, 186 cap,
184 original_range, 187 target,
185 render_snippet(cap, new_impl_item_list.syntax(), cursor), 188 render_snippet(cap, new_impl_def.syntax(), cursor),
186 ) 189 )
187 } 190 }
188 }; 191 };
@@ -311,6 +314,25 @@ impl Foo for S {
311 } 314 }
312 315
313 #[test] 316 #[test]
317 fn test_impl_def_without_braces() {
318 check_assist(
319 add_missing_impl_members,
320 r#"
321trait Foo { fn foo(&self); }
322struct S;
323impl Foo for S<|>"#,
324 r#"
325trait Foo { fn foo(&self); }
326struct S;
327impl Foo for S {
328 fn foo(&self) {
329 ${0:todo!()}
330 }
331}"#,
332 );
333 }
334
335 #[test]
314 fn fill_in_type_params_1() { 336 fn fill_in_type_params_1() {
315 check_assist( 337 check_assist(
316 add_missing_impl_members, 338 add_missing_impl_members,
diff --git a/crates/syntax/src/ast/edit.rs b/crates/syntax/src/ast/edit.rs
index 45cf31f13..dda0a0319 100644
--- a/crates/syntax/src/ast/edit.rs
+++ b/crates/syntax/src/ast/edit.rs
@@ -93,6 +93,22 @@ where
93 } 93 }
94} 94}
95 95
96impl ast::Impl {
97 #[must_use]
98 pub fn with_assoc_item_list(&self, items: ast::AssocItemList) -> ast::Impl {
99 let mut to_insert: ArrayVec<[SyntaxElement; 2]> = ArrayVec::new();
100 if let Some(old_items) = self.assoc_item_list() {
101 let to_replace: SyntaxElement = old_items.syntax().clone().into();
102 to_insert.push(items.syntax().clone().into());
103 self.replace_children(single_node(to_replace), to_insert)
104 } else {
105 to_insert.push(make::tokens::single_space().into());
106 to_insert.push(items.syntax().clone().into());
107 self.insert_children(InsertPosition::Last, to_insert)
108 }
109 }
110}
111
96impl ast::AssocItemList { 112impl ast::AssocItemList {
97 #[must_use] 113 #[must_use]
98 pub fn append_items( 114 pub fn append_items(
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 {
21 ast_from_text(&format!("impl {} for D {{}};", text)) 21 ast_from_text(&format!("impl {} for D {{}};", text))
22} 22}
23 23
24pub fn assoc_item_list() -> ast::AssocItemList {
25 ast_from_text("impl C for D {};")
26}
27
24pub fn path_segment(name_ref: ast::NameRef) -> ast::PathSegment { 28pub fn path_segment(name_ref: ast::NameRef) -> ast::PathSegment {
25 ast_from_text(&format!("use {};", name_ref)) 29 ast_from_text(&format!("use {};", name_ref))
26} 30}