about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJesse Bakker <github@jessebakker.com>2021-05-06 15:56:48 +0200
committerJesse Bakker <github@jessebakker.com>2021-05-06 16:16:38 +0200
commit10254b5d953c2031edeb6a5fd78dbaed867c2268 (patch)
treee38abb2e9c7399a258896c39395cd6fbef08fac2
parentc3596371d841ebb949dc8b99acc3bc902e4d808a (diff)
downloadrust-10254b5d953c2031edeb6a5fd78dbaed867c2268.tar.gz
rust-10254b5d953c2031edeb6a5fd78dbaed867c2268.zip
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 a26fe7c6cb9..78fbfcd97f7 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};
 use syntax::{
     ast::{self, edit, Impl},
     display::function_declaration,
-    AstNode, SyntaxKind, SyntaxNode, TextRange, T,
+    AstNode, SyntaxElement, SyntaxKind, SyntaxNode, TextRange, T,
 };
 use text_edit::TextEdit;
 
@@ -154,8 +154,7 @@ fn add_function_impl(
     } else {
         CompletionItemKind::SymbolKind(SymbolKind::Function)
     };
-    let range = TextRange::new(fn_def_node.text_range().start(), ctx.source_range().end());
-
+    let range = replacement_range(ctx, fn_def_node);
     if let Some(src) = func.source(ctx.db) {
         let function_decl = function_declaration(&src.value);
         match ctx.config.snippet_cap {
@@ -183,8 +182,7 @@ fn add_type_alias_impl(
 
     let snippet = format!("type {} = ", alias_name);
 
-    let range = TextRange::new(type_def_node.text_range().start(), ctx.source_range().end());
-
+    let range = replacement_range(ctx, type_def_node);
     let mut item = CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone());
     item.text_edit(TextEdit::replace(range, snippet))
         .lookup_by(alias_name)
@@ -205,9 +203,7 @@ fn add_const_impl(
         if let Some(source) = const_.source(ctx.db) {
             let snippet = make_const_compl_syntax(&source.value);
 
-            let range =
-                TextRange::new(const_def_node.text_range().start(), ctx.source_range().end());
-
+            let range = replacement_range(ctx, const_def_node);
             let mut item =
                 CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone());
             item.text_edit(TextEdit::replace(range, snippet))
@@ -242,6 +238,21 @@ fn make_const_compl_syntax(const_: &ast::Const) -> String {
     format!("{} = ", syntax.trim_end())
 }
 
+fn replacement_range(ctx: &CompletionContext, item: &SyntaxNode) -> TextRange {
+    let first_child = item
+        .children_with_tokens()
+        .find(|child| {
+            let kind = child.kind();
+            match kind {
+                SyntaxKind::COMMENT | SyntaxKind::WHITESPACE | SyntaxKind::ATTR => false,
+                _ => true,
+            }
+        })
+        .unwrap_or(SyntaxElement::Node(item.clone()));
+
+    TextRange::new(first_child.text_range().start(), ctx.source_range().end())
+}
+
 #[cfg(test)]
 mod tests {
     use expect_test::{expect, Expect};
@@ -734,4 +745,50 @@ impl Test for T {{
             test("CONST", "const $0", "const CONST: u16 = ", next_sibling);
         }
     }
+
+    #[test]
+    fn snippet_does_not_overwrite_comment_or_attr() {
+        let test = |completion: &str, hint: &str, completed: &str| {
+            check_edit(
+                completion,
+                &format!(
+                    r#"
+trait Foo {{
+    type Type;
+    fn function();
+    const CONST: i32 = 0;
+}}
+struct T;
+
+impl Foo for T {{
+    // Comment
+    #[bar]
+    {}
+}}
+"#,
+                    hint
+                ),
+                &format!(
+                    r#"
+trait Foo {{
+    type Type;
+    fn function();
+    const CONST: i32 = 0;
+}}
+struct T;
+
+impl Foo for T {{
+    // Comment
+    #[bar]
+    {}
+}}
+"#,
+                    completed
+                ),
+            )
+        };
+        test("function", "fn f$0", "fn function() {\n    $0\n}");
+        test("Type", "type T$0", "type Type = ");
+        test("CONST", "const C$0", "const CONST: i32 = ");
+    }
 }