Skip to content

Commit 10254b5

Browse files
committed
Fix: Do not overwrite comments and attrs in trait impl completion
1 parent c359637 commit 10254b5

File tree

1 file changed

+65
-8
lines changed

1 file changed

+65
-8
lines changed

crates/ide_completion/src/completions/trait_impl.rs

Lines changed: 65 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ use ide_db::{traits::get_missing_assoc_items, SymbolKind};
3636
use syntax::{
3737
ast::{self, edit, Impl},
3838
display::function_declaration,
39-
AstNode, SyntaxKind, SyntaxNode, TextRange, T,
39+
AstNode, SyntaxElement, SyntaxKind, SyntaxNode, TextRange, T,
4040
};
4141
use text_edit::TextEdit;
4242

@@ -154,8 +154,7 @@ fn add_function_impl(
154154
} else {
155155
CompletionItemKind::SymbolKind(SymbolKind::Function)
156156
};
157-
let range = TextRange::new(fn_def_node.text_range().start(), ctx.source_range().end());
158-
157+
let range = replacement_range(ctx, fn_def_node);
159158
if let Some(src) = func.source(ctx.db) {
160159
let function_decl = function_declaration(&src.value);
161160
match ctx.config.snippet_cap {
@@ -183,8 +182,7 @@ fn add_type_alias_impl(
183182

184183
let snippet = format!("type {} = ", alias_name);
185184

186-
let range = TextRange::new(type_def_node.text_range().start(), ctx.source_range().end());
187-
185+
let range = replacement_range(ctx, type_def_node);
188186
let mut item = CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone());
189187
item.text_edit(TextEdit::replace(range, snippet))
190188
.lookup_by(alias_name)
@@ -205,9 +203,7 @@ fn add_const_impl(
205203
if let Some(source) = const_.source(ctx.db) {
206204
let snippet = make_const_compl_syntax(&source.value);
207205

208-
let range =
209-
TextRange::new(const_def_node.text_range().start(), ctx.source_range().end());
210-
206+
let range = replacement_range(ctx, const_def_node);
211207
let mut item =
212208
CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone());
213209
item.text_edit(TextEdit::replace(range, snippet))
@@ -242,6 +238,21 @@ fn make_const_compl_syntax(const_: &ast::Const) -> String {
242238
format!("{} = ", syntax.trim_end())
243239
}
244240

241+
fn 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+
245256
#[cfg(test)]
246257
mod tests {
247258
use expect_test::{expect, Expect};
@@ -734,4 +745,50 @@ impl Test for T {{
734745
test("CONST", "const $0", "const CONST: u16 = ", next_sibling);
735746
}
736747
}
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#"
756+
trait Foo {{
757+
type Type;
758+
fn function();
759+
const CONST: i32 = 0;
760+
}}
761+
struct T;
762+
763+
impl Foo for T {{
764+
// Comment
765+
#[bar]
766+
{}
767+
}}
768+
"#,
769+
hint
770+
),
771+
&format!(
772+
r#"
773+
trait Foo {{
774+
type Type;
775+
fn function();
776+
const CONST: i32 = 0;
777+
}}
778+
struct T;
779+
780+
impl 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+
}
737794
}

0 commit comments

Comments
 (0)