diff options
Diffstat (limited to 'crates/ide_completion/src/completions')
5 files changed, 78 insertions, 21 deletions
diff --git a/crates/ide_completion/src/completions/pattern.rs b/crates/ide_completion/src/completions/pattern.rs index 808d7ff7e..8dc9ab73c 100644 --- a/crates/ide_completion/src/completions/pattern.rs +++ b/crates/ide_completion/src/completions/pattern.rs | |||
@@ -12,8 +12,10 @@ pub(crate) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) { | |||
12 | } | 12 | } |
13 | 13 | ||
14 | if !ctx.is_irrefutable_pat_binding { | 14 | if !ctx.is_irrefutable_pat_binding { |
15 | if let Some(ty) = ctx.expected_type.as_ref() { | 15 | if let Some(hir::Adt::Enum(e)) = |
16 | super::complete_enum_variants(acc, ctx, ty, |acc, ctx, variant, path| { | 16 | ctx.expected_type.as_ref().and_then(|ty| ty.strip_references().as_adt()) |
17 | { | ||
18 | super::complete_enum_variants(acc, ctx, e, |acc, ctx, variant, path| { | ||
17 | acc.add_qualified_variant_pat(ctx, variant, path.clone()); | 19 | acc.add_qualified_variant_pat(ctx, variant, path.clone()); |
18 | acc.add_qualified_enum_variant(ctx, variant, path); | 20 | acc.add_qualified_enum_variant(ctx, variant, path); |
19 | }); | 21 | }); |
diff --git a/crates/ide_completion/src/completions/postfix.rs b/crates/ide_completion/src/completions/postfix.rs index ac69b720a..962aaf0df 100644 --- a/crates/ide_completion/src/completions/postfix.rs +++ b/crates/ide_completion/src/completions/postfix.rs | |||
@@ -35,14 +35,11 @@ pub(crate) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { | |||
35 | None => return, | 35 | None => return, |
36 | }; | 36 | }; |
37 | 37 | ||
38 | let ref_removed_ty = | ||
39 | std::iter::successors(Some(receiver_ty.clone()), |ty| ty.remove_ref()).last().unwrap(); | ||
40 | |||
41 | let cap = match ctx.config.snippet_cap { | 38 | let cap = match ctx.config.snippet_cap { |
42 | Some(it) => it, | 39 | Some(it) => it, |
43 | None => return, | 40 | None => return, |
44 | }; | 41 | }; |
45 | let try_enum = TryEnum::from_ty(&ctx.sema, &ref_removed_ty); | 42 | let try_enum = TryEnum::from_ty(&ctx.sema, &receiver_ty.strip_references()); |
46 | if let Some(try_enum) = &try_enum { | 43 | if let Some(try_enum) = &try_enum { |
47 | match try_enum { | 44 | match try_enum { |
48 | TryEnum::Result => { | 45 | TryEnum::Result => { |
diff --git a/crates/ide_completion/src/completions/qualified_path.rs b/crates/ide_completion/src/completions/qualified_path.rs index d2ebba65f..eedb44873 100644 --- a/crates/ide_completion/src/completions/qualified_path.rs +++ b/crates/ide_completion/src/completions/qualified_path.rs | |||
@@ -59,6 +59,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon | |||
59 | hir::ModuleDef::TypeAlias(a) => { | 59 | hir::ModuleDef::TypeAlias(a) => { |
60 | let ty = a.ty(ctx.db); | 60 | let ty = a.ty(ctx.db); |
61 | if let Some(Adt::Enum(e)) = ty.as_adt() { | 61 | if let Some(Adt::Enum(e)) = ty.as_adt() { |
62 | cov_mark::hit!(completes_variant_through_alias); | ||
62 | add_enum_variants(ctx, acc, e); | 63 | add_enum_variants(ctx, acc, e); |
63 | } | 64 | } |
64 | ty | 65 | ty |
@@ -68,6 +69,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon | |||
68 | Some(it) => it, | 69 | Some(it) => it, |
69 | None => return, | 70 | None => return, |
70 | }; | 71 | }; |
72 | cov_mark::hit!(completes_primitive_assoc_const); | ||
71 | builtin.ty(ctx.db, module) | 73 | builtin.ty(ctx.db, module) |
72 | } | 74 | } |
73 | _ => unreachable!(), | 75 | _ => unreachable!(), |
@@ -96,9 +98,8 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon | |||
96 | if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) { | 98 | if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) { |
97 | return None; | 99 | return None; |
98 | } | 100 | } |
99 | match item { | 101 | if let hir::AssocItem::TypeAlias(ty) = item { |
100 | hir::AssocItem::Function(_) | hir::AssocItem::Const(_) => {} | 102 | acc.add_type_alias(ctx, ty) |
101 | hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty), | ||
102 | } | 103 | } |
103 | None::<()> | 104 | None::<()> |
104 | }); | 105 | }); |
@@ -745,7 +746,7 @@ fn f() {} | |||
745 | } | 746 | } |
746 | 747 | ||
747 | #[test] | 748 | #[test] |
748 | fn completes_self_enum() { | 749 | fn completes_variant_through_self() { |
749 | check( | 750 | check( |
750 | r#" | 751 | r#" |
751 | enum Foo { | 752 | enum Foo { |
@@ -769,6 +770,7 @@ impl Foo { | |||
769 | 770 | ||
770 | #[test] | 771 | #[test] |
771 | fn completes_primitive_assoc_const() { | 772 | fn completes_primitive_assoc_const() { |
773 | cov_mark::check!(completes_primitive_assoc_const); | ||
772 | check( | 774 | check( |
773 | r#" | 775 | r#" |
774 | //- /lib.rs crate:lib deps:core | 776 | //- /lib.rs crate:lib deps:core |
@@ -792,7 +794,8 @@ impl u8 { | |||
792 | } | 794 | } |
793 | 795 | ||
794 | #[test] | 796 | #[test] |
795 | fn completes_through_alias() { | 797 | fn completes_variant_through_alias() { |
798 | cov_mark::check!(completes_variant_through_alias); | ||
796 | check( | 799 | check( |
797 | r#" | 800 | r#" |
798 | enum Foo { | 801 | enum Foo { |
diff --git a/crates/ide_completion/src/completions/trait_impl.rs b/crates/ide_completion/src/completions/trait_impl.rs index a26fe7c6c..968c0254d 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}; | |||
36 | use syntax::{ | 36 | use 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 | }; |
41 | use text_edit::TextEdit; | 41 | use 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,17 @@ fn make_const_compl_syntax(const_: &ast::Const) -> String { | |||
242 | format!("{} = ", syntax.trim_end()) | 238 | format!("{} = ", syntax.trim_end()) |
243 | } | 239 | } |
244 | 240 | ||
241 | fn replacement_range(ctx: &CompletionContext, item: &SyntaxNode) -> TextRange { | ||
242 | let first_child = item | ||
243 | .children_with_tokens() | ||
244 | .find(|child| { | ||
245 | !matches!(child.kind(), SyntaxKind::COMMENT | SyntaxKind::WHITESPACE | SyntaxKind::ATTR) | ||
246 | }) | ||
247 | .unwrap_or_else(|| SyntaxElement::Node(item.clone())); | ||
248 | |||
249 | TextRange::new(first_child.text_range().start(), ctx.source_range().end()) | ||
250 | } | ||
251 | |||
245 | #[cfg(test)] | 252 | #[cfg(test)] |
246 | mod tests { | 253 | mod tests { |
247 | use expect_test::{expect, Expect}; | 254 | use expect_test::{expect, Expect}; |
@@ -734,4 +741,50 @@ impl Test for T {{ | |||
734 | test("CONST", "const $0", "const CONST: u16 = ", next_sibling); | 741 | test("CONST", "const $0", "const CONST: u16 = ", next_sibling); |
735 | } | 742 | } |
736 | } | 743 | } |
744 | |||
745 | #[test] | ||
746 | fn snippet_does_not_overwrite_comment_or_attr() { | ||
747 | let test = |completion: &str, hint: &str, completed: &str| { | ||
748 | check_edit( | ||
749 | completion, | ||
750 | &format!( | ||
751 | r#" | ||
752 | trait Foo {{ | ||
753 | type Type; | ||
754 | fn function(); | ||
755 | const CONST: i32 = 0; | ||
756 | }} | ||
757 | struct T; | ||
758 | |||
759 | impl Foo for T {{ | ||
760 | // Comment | ||
761 | #[bar] | ||
762 | {} | ||
763 | }} | ||
764 | "#, | ||
765 | hint | ||
766 | ), | ||
767 | &format!( | ||
768 | r#" | ||
769 | trait Foo {{ | ||
770 | type Type; | ||
771 | fn function(); | ||
772 | const CONST: i32 = 0; | ||
773 | }} | ||
774 | struct T; | ||
775 | |||
776 | impl Foo for T {{ | ||
777 | // Comment | ||
778 | #[bar] | ||
779 | {} | ||
780 | }} | ||
781 | "#, | ||
782 | completed | ||
783 | ), | ||
784 | ) | ||
785 | }; | ||
786 | test("function", "fn f$0", "fn function() {\n $0\n}"); | ||
787 | test("Type", "type T$0", "type Type = "); | ||
788 | test("CONST", "const C$0", "const CONST: i32 = "); | ||
789 | } | ||
737 | } | 790 | } |
diff --git a/crates/ide_completion/src/completions/unqualified_path.rs b/crates/ide_completion/src/completions/unqualified_path.rs index 1b8b063e7..7875500c1 100644 --- a/crates/ide_completion/src/completions/unqualified_path.rs +++ b/crates/ide_completion/src/completions/unqualified_path.rs | |||
@@ -17,8 +17,10 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC | |||
17 | return; | 17 | return; |
18 | } | 18 | } |
19 | 19 | ||
20 | if let Some(ty) = &ctx.expected_type { | 20 | if let Some(hir::Adt::Enum(e)) = |
21 | super::complete_enum_variants(acc, ctx, ty, |acc, ctx, variant, path| { | 21 | ctx.expected_type.as_ref().and_then(|ty| ty.strip_references().as_adt()) |
22 | { | ||
23 | super::complete_enum_variants(acc, ctx, e, |acc, ctx, variant, path| { | ||
22 | acc.add_qualified_enum_variant(ctx, variant, path) | 24 | acc.add_qualified_enum_variant(ctx, variant, path) |
23 | }); | 25 | }); |
24 | } | 26 | } |