aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJesse Bakker <[email protected]>2021-05-06 14:56:48 +0100
committerJesse Bakker <[email protected]>2021-05-06 15:16:38 +0100
commit10254b5d953c2031edeb6a5fd78dbaed867c2268 (patch)
treee38abb2e9c7399a258896c39395cd6fbef08fac2
parentc3596371d841ebb949dc8b99acc3bc902e4d808a (diff)
Fix: Do not overwrite comments and attrs in trait impl completion
-rw-r--r--crates/ide_completion/src/completions/trait_impl.rs73
1 files changed, 65 insertions, 8 deletions
diff --git a/crates/ide_completion/src/completions/trait_impl.rs b/crates/ide_completion/src/completions/trait_impl.rs
index a26fe7c6c..78fbfcd97 100644
--- a/crates/ide_completion/src/completions/trait_impl.rs
+++ b/crates/ide_completion/src/completions/trait_impl.rs
@@ -36,7 +36,7 @@ use ide_db::{traits::get_missing_assoc_items, SymbolKind};
36use syntax::{ 36use syntax::{
37 ast::{self, edit, Impl}, 37 ast::{self, edit, Impl},
38 display::function_declaration, 38 display::function_declaration,
39 AstNode, SyntaxKind, SyntaxNode, TextRange, T, 39 AstNode, SyntaxElement, SyntaxKind, SyntaxNode, TextRange, T,
40}; 40};
41use text_edit::TextEdit; 41use text_edit::TextEdit;
42 42
@@ -154,8 +154,7 @@ fn add_function_impl(
154 } else { 154 } else {
155 CompletionItemKind::SymbolKind(SymbolKind::Function) 155 CompletionItemKind::SymbolKind(SymbolKind::Function)
156 }; 156 };
157 let range = TextRange::new(fn_def_node.text_range().start(), ctx.source_range().end()); 157 let range = replacement_range(ctx, fn_def_node);
158
159 if let Some(src) = func.source(ctx.db) { 158 if let Some(src) = func.source(ctx.db) {
160 let function_decl = function_declaration(&src.value); 159 let function_decl = function_declaration(&src.value);
161 match ctx.config.snippet_cap { 160 match ctx.config.snippet_cap {
@@ -183,8 +182,7 @@ fn add_type_alias_impl(
183 182
184 let snippet = format!("type {} = ", alias_name); 183 let snippet = format!("type {} = ", alias_name);
185 184
186 let range = TextRange::new(type_def_node.text_range().start(), ctx.source_range().end()); 185 let range = replacement_range(ctx, type_def_node);
187
188 let mut item = CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone()); 186 let mut item = CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone());
189 item.text_edit(TextEdit::replace(range, snippet)) 187 item.text_edit(TextEdit::replace(range, snippet))
190 .lookup_by(alias_name) 188 .lookup_by(alias_name)
@@ -205,9 +203,7 @@ fn add_const_impl(
205 if let Some(source) = const_.source(ctx.db) { 203 if let Some(source) = const_.source(ctx.db) {
206 let snippet = make_const_compl_syntax(&source.value); 204 let snippet = make_const_compl_syntax(&source.value);
207 205
208 let range = 206 let range = replacement_range(ctx, const_def_node);
209 TextRange::new(const_def_node.text_range().start(), ctx.source_range().end());
210
211 let mut item = 207 let mut item =
212 CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone()); 208 CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone());
213 item.text_edit(TextEdit::replace(range, snippet)) 209 item.text_edit(TextEdit::replace(range, snippet))
@@ -242,6 +238,21 @@ fn make_const_compl_syntax(const_: &ast::Const) -> String {
242 format!("{} = ", syntax.trim_end()) 238 format!("{} = ", syntax.trim_end())
243} 239}
244 240
241fn replacement_range(ctx: &CompletionContext, item: &SyntaxNode) -> TextRange {
242 let first_child = item
243 .children_with_tokens()
244 .find(|child| {
245 let kind = child.kind();
246 match kind {
247 SyntaxKind::COMMENT | SyntaxKind::WHITESPACE | SyntaxKind::ATTR => false,
248 _ => true,
249 }
250 })
251 .unwrap_or(SyntaxElement::Node(item.clone()));
252
253 TextRange::new(first_child.text_range().start(), ctx.source_range().end())
254}
255
245#[cfg(test)] 256#[cfg(test)]
246mod tests { 257mod tests {
247 use expect_test::{expect, Expect}; 258 use expect_test::{expect, Expect};
@@ -734,4 +745,50 @@ impl Test for T {{
734 test("CONST", "const $0", "const CONST: u16 = ", next_sibling); 745 test("CONST", "const $0", "const CONST: u16 = ", next_sibling);
735 } 746 }
736 } 747 }
748
749 #[test]
750 fn snippet_does_not_overwrite_comment_or_attr() {
751 let test = |completion: &str, hint: &str, completed: &str| {
752 check_edit(
753 completion,
754 &format!(
755 r#"
756trait Foo {{
757 type Type;
758 fn function();
759 const CONST: i32 = 0;
760}}
761struct T;
762
763impl Foo for T {{
764 // Comment
765 #[bar]
766 {}
767}}
768"#,
769 hint
770 ),
771 &format!(
772 r#"
773trait Foo {{
774 type Type;
775 fn function();
776 const CONST: i32 = 0;
777}}
778struct T;
779
780impl Foo for T {{
781 // Comment
782 #[bar]
783 {}
784}}
785"#,
786 completed
787 ),
788 )
789 };
790 test("function", "fn f$0", "fn function() {\n $0\n}");
791 test("Type", "type T$0", "type Type = ");
792 test("CONST", "const C$0", "const CONST: i32 = ");
793 }
737} 794}