diff options
Diffstat (limited to 'crates/ide_completion')
17 files changed, 359 insertions, 294 deletions
diff --git a/crates/ide_completion/src/completions.rs b/crates/ide_completion/src/completions.rs index 78154bf3e..151bf3783 100644 --- a/crates/ide_completion/src/completions.rs +++ b/crates/ide_completion/src/completions.rs | |||
@@ -18,7 +18,7 @@ pub(crate) mod unqualified_path; | |||
18 | 18 | ||
19 | use std::iter; | 19 | use std::iter; |
20 | 20 | ||
21 | use hir::{known, ModPath, ScopeDef, Type}; | 21 | use hir::known; |
22 | use ide_db::SymbolKind; | 22 | use ide_db::SymbolKind; |
23 | 23 | ||
24 | use crate::{ | 24 | use crate::{ |
@@ -69,12 +69,17 @@ impl Completions { | |||
69 | items.into_iter().for_each(|item| self.add(item.into())) | 69 | items.into_iter().for_each(|item| self.add(item.into())) |
70 | } | 70 | } |
71 | 71 | ||
72 | pub(crate) fn add_field(&mut self, ctx: &CompletionContext, field: hir::Field, ty: &Type) { | 72 | pub(crate) fn add_field(&mut self, ctx: &CompletionContext, field: hir::Field, ty: &hir::Type) { |
73 | let item = render_field(RenderContext::new(ctx), field, ty); | 73 | let item = render_field(RenderContext::new(ctx), field, ty); |
74 | self.add(item); | 74 | self.add(item); |
75 | } | 75 | } |
76 | 76 | ||
77 | pub(crate) fn add_tuple_field(&mut self, ctx: &CompletionContext, field: usize, ty: &Type) { | 77 | pub(crate) fn add_tuple_field( |
78 | &mut self, | ||
79 | ctx: &CompletionContext, | ||
80 | field: usize, | ||
81 | ty: &hir::Type, | ||
82 | ) { | ||
78 | let item = render_tuple_field(RenderContext::new(ctx), field, ty); | 83 | let item = render_tuple_field(RenderContext::new(ctx), field, ty); |
79 | self.add(item); | 84 | self.add(item); |
80 | } | 85 | } |
@@ -89,8 +94,8 @@ impl Completions { | |||
89 | pub(crate) fn add_resolution( | 94 | pub(crate) fn add_resolution( |
90 | &mut self, | 95 | &mut self, |
91 | ctx: &CompletionContext, | 96 | ctx: &CompletionContext, |
92 | local_name: String, | 97 | local_name: hir::Name, |
93 | resolution: &ScopeDef, | 98 | resolution: &hir::ScopeDef, |
94 | ) { | 99 | ) { |
95 | if let Some(item) = render_resolution(RenderContext::new(ctx), local_name, resolution) { | 100 | if let Some(item) = render_resolution(RenderContext::new(ctx), local_name, resolution) { |
96 | self.add(item); | 101 | self.add(item); |
@@ -100,7 +105,7 @@ impl Completions { | |||
100 | pub(crate) fn add_macro( | 105 | pub(crate) fn add_macro( |
101 | &mut self, | 106 | &mut self, |
102 | ctx: &CompletionContext, | 107 | ctx: &CompletionContext, |
103 | name: Option<String>, | 108 | name: Option<hir::Name>, |
104 | macro_: hir::MacroDef, | 109 | macro_: hir::MacroDef, |
105 | ) { | 110 | ) { |
106 | let name = match name { | 111 | let name = match name { |
@@ -116,7 +121,7 @@ impl Completions { | |||
116 | &mut self, | 121 | &mut self, |
117 | ctx: &CompletionContext, | 122 | ctx: &CompletionContext, |
118 | func: hir::Function, | 123 | func: hir::Function, |
119 | local_name: Option<String>, | 124 | local_name: Option<hir::Name>, |
120 | ) { | 125 | ) { |
121 | if let Some(item) = render_fn(RenderContext::new(ctx), None, local_name, func) { | 126 | if let Some(item) = render_fn(RenderContext::new(ctx), None, local_name, func) { |
122 | self.add(item) | 127 | self.add(item) |
@@ -127,7 +132,7 @@ impl Completions { | |||
127 | &mut self, | 132 | &mut self, |
128 | ctx: &CompletionContext, | 133 | ctx: &CompletionContext, |
129 | func: hir::Function, | 134 | func: hir::Function, |
130 | local_name: Option<String>, | 135 | local_name: Option<hir::Name>, |
131 | ) { | 136 | ) { |
132 | if let Some(item) = render_method(RenderContext::new(ctx), None, local_name, func) { | 137 | if let Some(item) = render_method(RenderContext::new(ctx), None, local_name, func) { |
133 | self.add(item) | 138 | self.add(item) |
@@ -149,7 +154,7 @@ impl Completions { | |||
149 | &mut self, | 154 | &mut self, |
150 | ctx: &CompletionContext, | 155 | ctx: &CompletionContext, |
151 | variant: hir::Variant, | 156 | variant: hir::Variant, |
152 | path: ModPath, | 157 | path: hir::ModPath, |
153 | ) { | 158 | ) { |
154 | if let Some(item) = render_variant_pat(RenderContext::new(ctx), variant, None, Some(path)) { | 159 | if let Some(item) = render_variant_pat(RenderContext::new(ctx), variant, None, Some(path)) { |
155 | self.add(item); | 160 | self.add(item); |
@@ -183,7 +188,7 @@ impl Completions { | |||
183 | &mut self, | 188 | &mut self, |
184 | ctx: &CompletionContext, | 189 | ctx: &CompletionContext, |
185 | variant: hir::Variant, | 190 | variant: hir::Variant, |
186 | path: ModPath, | 191 | path: hir::ModPath, |
187 | ) { | 192 | ) { |
188 | let item = render_variant(RenderContext::new(ctx), None, None, variant, Some(path)); | 193 | let item = render_variant(RenderContext::new(ctx), None, None, variant, Some(path)); |
189 | self.add(item); | 194 | self.add(item); |
@@ -193,7 +198,7 @@ impl Completions { | |||
193 | &mut self, | 198 | &mut self, |
194 | ctx: &CompletionContext, | 199 | ctx: &CompletionContext, |
195 | variant: hir::Variant, | 200 | variant: hir::Variant, |
196 | local_name: Option<String>, | 201 | local_name: Option<hir::Name>, |
197 | ) { | 202 | ) { |
198 | let item = render_variant(RenderContext::new(ctx), None, local_name, variant, None); | 203 | let item = render_variant(RenderContext::new(ctx), None, local_name, variant, None); |
199 | self.add(item); | 204 | self.add(item); |
diff --git a/crates/ide_completion/src/completions/attribute.rs b/crates/ide_completion/src/completions/attribute.rs index 13d5b90c9..76d926157 100644 --- a/crates/ide_completion/src/completions/attribute.rs +++ b/crates/ide_completion/src/completions/attribute.rs | |||
@@ -219,8 +219,7 @@ const ATTRIBUTES: &[AttrCompletion] = &[ | |||
219 | ), | 219 | ), |
220 | attr("feature(…)", Some("feature"), Some("feature(${0:flag})")).prefer_inner(), | 220 | attr("feature(…)", Some("feature"), Some("feature(${0:flag})")).prefer_inner(), |
221 | attr("forbid(…)", Some("forbid"), Some("forbid(${0:lint})")), | 221 | attr("forbid(…)", Some("forbid"), Some("forbid(${0:lint})")), |
222 | // FIXME: resolve through macro resolution? | 222 | attr("global_allocator", None, None), |
223 | attr("global_allocator", None, None).prefer_inner(), | ||
224 | attr(r#"ignore = "…""#, Some("ignore"), Some(r#"ignore = "${0:reason}""#)), | 223 | attr(r#"ignore = "…""#, Some("ignore"), Some(r#"ignore = "${0:reason}""#)), |
225 | attr("inline", Some("inline"), Some("inline")), | 224 | attr("inline", Some("inline"), Some("inline")), |
226 | attr("link", None, None), | 225 | attr("link", None, None), |
@@ -239,7 +238,7 @@ const ATTRIBUTES: &[AttrCompletion] = &[ | |||
239 | attr("no_mangle", None, None), | 238 | attr("no_mangle", None, None), |
240 | attr("no_std", None, None).prefer_inner(), | 239 | attr("no_std", None, None).prefer_inner(), |
241 | attr("non_exhaustive", None, None), | 240 | attr("non_exhaustive", None, None), |
242 | attr("panic_handler", None, None).prefer_inner(), | 241 | attr("panic_handler", None, None), |
243 | attr(r#"path = "…""#, Some("path"), Some(r#"path ="${0:path}""#)), | 242 | attr(r#"path = "…""#, Some("path"), Some(r#"path ="${0:path}""#)), |
244 | attr("proc_macro", None, None), | 243 | attr("proc_macro", None, None), |
245 | attr("proc_macro_attribute", None, None), | 244 | attr("proc_macro_attribute", None, None), |
@@ -609,6 +608,7 @@ mod tests { | |||
609 | at export_name = "…" | 608 | at export_name = "…" |
610 | at link_name = "…" | 609 | at link_name = "…" |
611 | at link_section = "…" | 610 | at link_section = "…" |
611 | at global_allocator | ||
612 | at used | 612 | at used |
613 | "#]], | 613 | "#]], |
614 | ); | 614 | ); |
@@ -732,9 +732,9 @@ mod tests { | |||
732 | } | 732 | } |
733 | 733 | ||
734 | #[test] | 734 | #[test] |
735 | fn complete_attribute_on_expr() { | 735 | fn complete_attribute_on_fn() { |
736 | check( | 736 | check( |
737 | r#"fn main() { #[$0] foo() }"#, | 737 | r#"#[$0] fn main() {}"#, |
738 | expect![[r#" | 738 | expect![[r#" |
739 | at allow(…) | 739 | at allow(…) |
740 | at cfg(…) | 740 | at cfg(…) |
@@ -742,10 +742,35 @@ mod tests { | |||
742 | at deny(…) | 742 | at deny(…) |
743 | at forbid(…) | 743 | at forbid(…) |
744 | at warn(…) | 744 | at warn(…) |
745 | at deprecated | ||
746 | at doc = "…" | ||
747 | at doc(hidden) | ||
748 | at doc(alias = "…") | ||
749 | at must_use | ||
750 | at no_mangle | ||
751 | at export_name = "…" | ||
752 | at link_name = "…" | ||
753 | at link_section = "…" | ||
754 | at cold | ||
755 | at ignore = "…" | ||
756 | at inline | ||
757 | at must_use | ||
758 | at panic_handler | ||
759 | at proc_macro | ||
760 | at proc_macro_derive(…) | ||
761 | at proc_macro_attribute | ||
762 | at should_panic | ||
763 | at target_feature = "…" | ||
764 | at test | ||
765 | at track_caller | ||
745 | "#]], | 766 | "#]], |
746 | ); | 767 | ); |
768 | } | ||
769 | |||
770 | #[test] | ||
771 | fn complete_attribute_on_expr() { | ||
747 | check( | 772 | check( |
748 | r#"fn main() { #[$0] foo(); }"#, | 773 | r#"fn main() { #[$0] foo() }"#, |
749 | expect![[r#" | 774 | expect![[r#" |
750 | at allow(…) | 775 | at allow(…) |
751 | at cfg(…) | 776 | at cfg(…) |
diff --git a/crates/ide_completion/src/completions/fn_param.rs b/crates/ide_completion/src/completions/fn_param.rs index 0ea558489..cb90e8a3e 100644 --- a/crates/ide_completion/src/completions/fn_param.rs +++ b/crates/ide_completion/src/completions/fn_param.rs | |||
@@ -128,4 +128,19 @@ fn outer(text: String) { | |||
128 | "#]], | 128 | "#]], |
129 | ) | 129 | ) |
130 | } | 130 | } |
131 | |||
132 | #[test] | ||
133 | fn completes_non_ident_pat_param() { | ||
134 | check( | ||
135 | r#" | ||
136 | struct Bar { bar: u32 } | ||
137 | |||
138 | fn foo(Bar { bar }: Bar) {} | ||
139 | fn foo2($0) {} | ||
140 | "#, | ||
141 | expect![[r#" | ||
142 | bn Bar { bar }: Bar | ||
143 | "#]], | ||
144 | ) | ||
145 | } | ||
131 | } | 146 | } |
diff --git a/crates/ide_completion/src/completions/keyword.rs b/crates/ide_completion/src/completions/keyword.rs index e71a04b6e..0d035c611 100644 --- a/crates/ide_completion/src/completions/keyword.rs +++ b/crates/ide_completion/src/completions/keyword.rs | |||
@@ -4,7 +4,10 @@ use std::iter; | |||
4 | 4 | ||
5 | use syntax::{SyntaxKind, T}; | 5 | use syntax::{SyntaxKind, T}; |
6 | 6 | ||
7 | use crate::{CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions}; | 7 | use crate::{ |
8 | patterns::ImmediateLocation, CompletionContext, CompletionItem, CompletionItemKind, | ||
9 | CompletionKind, Completions, | ||
10 | }; | ||
8 | 11 | ||
9 | pub(crate) fn complete_use_tree_keyword(acc: &mut Completions, ctx: &CompletionContext) { | 12 | pub(crate) fn complete_use_tree_keyword(acc: &mut Completions, ctx: &CompletionContext) { |
10 | // complete keyword "crate" in use stmt | 13 | // complete keyword "crate" in use stmt |
@@ -44,7 +47,7 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte | |||
44 | cov_mark::hit!(no_keyword_completion_in_comments); | 47 | cov_mark::hit!(no_keyword_completion_in_comments); |
45 | return; | 48 | return; |
46 | } | 49 | } |
47 | if ctx.record_lit_syntax.is_some() { | 50 | if matches!(ctx.completion_location, Some(ImmediateLocation::RecordExpr(_))) { |
48 | cov_mark::hit!(no_keyword_completion_in_record_lit); | 51 | cov_mark::hit!(no_keyword_completion_in_record_lit); |
49 | return; | 52 | return; |
50 | } | 53 | } |
@@ -55,7 +58,6 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte | |||
55 | let expects_item = ctx.expects_item(); | 58 | let expects_item = ctx.expects_item(); |
56 | 59 | ||
57 | if ctx.has_impl_or_trait_prev_sibling() { | 60 | if ctx.has_impl_or_trait_prev_sibling() { |
58 | // FIXME this also incorrectly shows up after a complete trait/impl | ||
59 | add_keyword("where", "where "); | 61 | add_keyword("where", "where "); |
60 | return; | 62 | return; |
61 | } | 63 | } |
@@ -77,11 +79,8 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte | |||
77 | add_keyword("pub", "pub "); | 79 | add_keyword("pub", "pub "); |
78 | } | 80 | } |
79 | 81 | ||
80 | if expects_item || expects_assoc_item || has_block_expr_parent || ctx.is_match_arm { | ||
81 | add_keyword("unsafe", "unsafe "); | ||
82 | } | ||
83 | |||
84 | if expects_item || expects_assoc_item || has_block_expr_parent { | 82 | if expects_item || expects_assoc_item || has_block_expr_parent { |
83 | add_keyword("unsafe", "unsafe "); | ||
85 | add_keyword("fn", "fn $1($2) {\n $0\n}"); | 84 | add_keyword("fn", "fn $1($2) {\n $0\n}"); |
86 | add_keyword("const", "const $0"); | 85 | add_keyword("const", "const $0"); |
87 | add_keyword("type", "type $0"); | 86 | add_keyword("type", "type $0"); |
@@ -103,6 +102,9 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte | |||
103 | } | 102 | } |
104 | 103 | ||
105 | if ctx.expects_expression() { | 104 | if ctx.expects_expression() { |
105 | if !has_block_expr_parent { | ||
106 | add_keyword("unsafe", "unsafe {\n $0\n}"); | ||
107 | } | ||
106 | add_keyword("match", "match $1 {\n $0\n}"); | 108 | add_keyword("match", "match $1 {\n $0\n}"); |
107 | add_keyword("while", "while $1 {\n $0\n}"); | 109 | add_keyword("while", "while $1 {\n $0\n}"); |
108 | add_keyword("while let", "while let $1 = $2 {\n $0\n}"); | 110 | add_keyword("while let", "while let $1 = $2 {\n $0\n}"); |
@@ -574,6 +576,7 @@ pub mod future { | |||
574 | check( | 576 | check( |
575 | r#"fn main() { let _ = $0 }"#, | 577 | r#"fn main() { let _ = $0 }"#, |
576 | expect![[r#" | 578 | expect![[r#" |
579 | kw unsafe | ||
577 | kw match | 580 | kw match |
578 | kw while | 581 | kw while |
579 | kw while let | 582 | kw while let |
@@ -634,6 +637,7 @@ fn foo() { | |||
634 | } | 637 | } |
635 | "#, | 638 | "#, |
636 | expect![[r#" | 639 | expect![[r#" |
640 | kw unsafe | ||
637 | kw match | 641 | kw match |
638 | kw while | 642 | kw while |
639 | kw while let | 643 | kw while let |
diff --git a/crates/ide_completion/src/completions/lifetime.rs b/crates/ide_completion/src/completions/lifetime.rs index 5f6285b84..8ccccb646 100644 --- a/crates/ide_completion/src/completions/lifetime.rs +++ b/crates/ide_completion/src/completions/lifetime.rs | |||
@@ -16,15 +16,14 @@ pub(crate) fn complete_lifetime(acc: &mut Completions, ctx: &CompletionContext) | |||
16 | (Some(lt), Some(lp)) if lp == lt.clone() => return, | 16 | (Some(lt), Some(lp)) if lp == lt.clone() => return, |
17 | (Some(_), Some(lp)) => { | 17 | (Some(_), Some(lp)) => { |
18 | lp_string = lp.to_string(); | 18 | lp_string = lp.to_string(); |
19 | Some(&lp_string) | 19 | Some(&*lp_string) |
20 | } | 20 | } |
21 | _ => None, | 21 | _ => None, |
22 | }; | 22 | }; |
23 | 23 | ||
24 | ctx.scope.process_all_names(&mut |name, res| { | 24 | ctx.scope.process_all_names(&mut |name, res| { |
25 | if let ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_)) = res { | 25 | if let ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_)) = res { |
26 | let name = name.to_string(); | 26 | if param_lifetime != Some(&*name.to_string()) { |
27 | if param_lifetime != Some(&name) { | ||
28 | acc.add_resolution(ctx, name, &res); | 27 | acc.add_resolution(ctx, name, &res); |
29 | } | 28 | } |
30 | } | 29 | } |
@@ -41,7 +40,7 @@ pub(crate) fn complete_label(acc: &mut Completions, ctx: &CompletionContext) { | |||
41 | } | 40 | } |
42 | ctx.scope.process_all_names(&mut |name, res| { | 41 | ctx.scope.process_all_names(&mut |name, res| { |
43 | if let ScopeDef::Label(_) = res { | 42 | if let ScopeDef::Label(_) = res { |
44 | acc.add_resolution(ctx, name.to_string(), &res); | 43 | acc.add_resolution(ctx, name, &res); |
45 | } | 44 | } |
46 | }); | 45 | }); |
47 | } | 46 | } |
diff --git a/crates/ide_completion/src/completions/macro_in_item_position.rs b/crates/ide_completion/src/completions/macro_in_item_position.rs index ec57aee30..202e71215 100644 --- a/crates/ide_completion/src/completions/macro_in_item_position.rs +++ b/crates/ide_completion/src/completions/macro_in_item_position.rs | |||
@@ -11,11 +11,11 @@ pub(crate) fn complete_macro_in_item_position(acc: &mut Completions, ctx: &Compl | |||
11 | 11 | ||
12 | ctx.scope.process_all_names(&mut |name, res| { | 12 | ctx.scope.process_all_names(&mut |name, res| { |
13 | if let hir::ScopeDef::MacroDef(mac) = res { | 13 | if let hir::ScopeDef::MacroDef(mac) = res { |
14 | acc.add_macro(ctx, Some(name.to_string()), mac); | 14 | acc.add_macro(ctx, Some(name.clone()), mac); |
15 | } | 15 | } |
16 | // FIXME: This should be done in qualified_path/unqualified_path instead? | 16 | // FIXME: This should be done in qualified_path/unqualified_path instead? |
17 | if let hir::ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = res { | 17 | if let hir::ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = res { |
18 | acc.add_resolution(ctx, name.to_string(), &res); | 18 | acc.add_resolution(ctx, name, &res); |
19 | } | 19 | } |
20 | }) | 20 | }) |
21 | } | 21 | } |
diff --git a/crates/ide_completion/src/completions/mod_.rs b/crates/ide_completion/src/completions/mod_.rs index 4f9415736..6a5746fb9 100644 --- a/crates/ide_completion/src/completions/mod_.rs +++ b/crates/ide_completion/src/completions/mod_.rs | |||
@@ -9,14 +9,14 @@ use ide_db::{ | |||
9 | }; | 9 | }; |
10 | use rustc_hash::FxHashSet; | 10 | use rustc_hash::FxHashSet; |
11 | 11 | ||
12 | use crate::CompletionItem; | 12 | use crate::{patterns::ImmediateLocation, CompletionItem}; |
13 | 13 | ||
14 | use crate::{context::CompletionContext, item::CompletionKind, Completions}; | 14 | use crate::{context::CompletionContext, item::CompletionKind, Completions}; |
15 | 15 | ||
16 | /// Complete mod declaration, i.e. `mod $0 ;` | 16 | /// Complete mod declaration, i.e. `mod $0 ;` |
17 | pub(crate) fn complete_mod(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> { | 17 | pub(crate) fn complete_mod(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> { |
18 | let mod_under_caret = match &ctx.mod_declaration_under_caret { | 18 | let mod_under_caret = match &ctx.completion_location { |
19 | Some(mod_under_caret) if mod_under_caret.item_list().is_none() => mod_under_caret, | 19 | Some(ImmediateLocation::ModDeclaration(mod_under_caret)) => mod_under_caret, |
20 | _ => return None, | 20 | _ => return None, |
21 | }; | 21 | }; |
22 | 22 | ||
diff --git a/crates/ide_completion/src/completions/pattern.rs b/crates/ide_completion/src/completions/pattern.rs index b84e9a967..8a728c67e 100644 --- a/crates/ide_completion/src/completions/pattern.rs +++ b/crates/ide_completion/src/completions/pattern.rs | |||
@@ -51,7 +51,7 @@ pub(crate) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) { | |||
51 | _ => false, | 51 | _ => false, |
52 | }; | 52 | }; |
53 | if add_resolution { | 53 | if add_resolution { |
54 | acc.add_resolution(ctx, name.to_string(), &res); | 54 | acc.add_resolution(ctx, name, &res); |
55 | } | 55 | } |
56 | }); | 56 | }); |
57 | } | 57 | } |
diff --git a/crates/ide_completion/src/completions/qualified_path.rs b/crates/ide_completion/src/completions/qualified_path.rs index 7a0e1ead3..de58ce1cd 100644 --- a/crates/ide_completion/src/completions/qualified_path.rs +++ b/crates/ide_completion/src/completions/qualified_path.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | //! Completion of paths, i.e. `some::prefix::$0`. | 1 | //! Completion of paths, i.e. `some::prefix::$0`. |
2 | 2 | ||
3 | use hir::{Adt, HasVisibility, PathResolution, ScopeDef}; | 3 | use hir::HasVisibility; |
4 | use rustc_hash::FxHashSet; | 4 | use rustc_hash::FxHashSet; |
5 | use syntax::AstNode; | 5 | use syntax::AstNode; |
6 | 6 | ||
@@ -21,14 +21,14 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon | |||
21 | }; | 21 | }; |
22 | let context_module = ctx.scope.module(); | 22 | let context_module = ctx.scope.module(); |
23 | if ctx.expects_assoc_item() { | 23 | if ctx.expects_assoc_item() { |
24 | if let PathResolution::Def(hir::ModuleDef::Module(module)) = resolution { | 24 | if let hir::PathResolution::Def(hir::ModuleDef::Module(module)) = resolution { |
25 | let module_scope = module.scope(ctx.db, context_module); | 25 | let module_scope = module.scope(ctx.db, context_module); |
26 | for (name, def) in module_scope { | 26 | for (name, def) in module_scope { |
27 | if let ScopeDef::MacroDef(macro_def) = def { | 27 | if let hir::ScopeDef::MacroDef(macro_def) = def { |
28 | acc.add_macro(ctx, Some(name.to_string()), macro_def); | 28 | acc.add_macro(ctx, Some(name.clone()), macro_def); |
29 | } | 29 | } |
30 | if let ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = def { | 30 | if let hir::ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = def { |
31 | acc.add_resolution(ctx, name.to_string(), &def); | 31 | acc.add_resolution(ctx, name, &def); |
32 | } | 32 | } |
33 | } | 33 | } |
34 | } | 34 | } |
@@ -42,11 +42,11 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon | |||
42 | }); | 42 | }); |
43 | 43 | ||
44 | match resolution { | 44 | match resolution { |
45 | PathResolution::Def(hir::ModuleDef::Module(module)) => { | 45 | hir::PathResolution::Def(hir::ModuleDef::Module(module)) => { |
46 | let module_scope = module.scope(ctx.db, context_module); | 46 | let module_scope = module.scope(ctx.db, context_module); |
47 | for (name, def) in module_scope { | 47 | for (name, def) in module_scope { |
48 | if ctx.use_item_syntax.is_some() { | 48 | if ctx.use_item_syntax.is_some() { |
49 | if let ScopeDef::Unknown = def { | 49 | if let hir::ScopeDef::Unknown = def { |
50 | if let Some(name_ref) = ctx.name_ref_syntax.as_ref() { | 50 | if let Some(name_ref) = ctx.name_ref_syntax.as_ref() { |
51 | if name_ref.syntax().text() == name.to_string().as_str() { | 51 | if name_ref.syntax().text() == name.to_string().as_str() { |
52 | // for `use self::foo$0`, don't suggest `foo` as a completion | 52 | // for `use self::foo$0`, don't suggest `foo` as a completion |
@@ -57,20 +57,20 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon | |||
57 | } | 57 | } |
58 | } | 58 | } |
59 | 59 | ||
60 | acc.add_resolution(ctx, name.to_string(), &def); | 60 | acc.add_resolution(ctx, name, &def); |
61 | } | 61 | } |
62 | } | 62 | } |
63 | PathResolution::Def(def @ hir::ModuleDef::Adt(_)) | 63 | hir::PathResolution::Def(def @ hir::ModuleDef::Adt(_)) |
64 | | PathResolution::Def(def @ hir::ModuleDef::TypeAlias(_)) | 64 | | hir::PathResolution::Def(def @ hir::ModuleDef::TypeAlias(_)) |
65 | | PathResolution::Def(def @ hir::ModuleDef::BuiltinType(_)) => { | 65 | | hir::PathResolution::Def(def @ hir::ModuleDef::BuiltinType(_)) => { |
66 | if let hir::ModuleDef::Adt(Adt::Enum(e)) = def { | 66 | if let hir::ModuleDef::Adt(hir::Adt::Enum(e)) = def { |
67 | add_enum_variants(ctx, acc, e); | 67 | add_enum_variants(ctx, acc, e); |
68 | } | 68 | } |
69 | let ty = match def { | 69 | let ty = match def { |
70 | hir::ModuleDef::Adt(adt) => adt.ty(ctx.db), | 70 | hir::ModuleDef::Adt(adt) => adt.ty(ctx.db), |
71 | hir::ModuleDef::TypeAlias(a) => { | 71 | hir::ModuleDef::TypeAlias(a) => { |
72 | let ty = a.ty(ctx.db); | 72 | let ty = a.ty(ctx.db); |
73 | if let Some(Adt::Enum(e)) = ty.as_adt() { | 73 | if let Some(hir::Adt::Enum(e)) = ty.as_adt() { |
74 | cov_mark::hit!(completes_variant_through_alias); | 74 | cov_mark::hit!(completes_variant_through_alias); |
75 | add_enum_variants(ctx, acc, e); | 75 | add_enum_variants(ctx, acc, e); |
76 | } | 76 | } |
@@ -117,7 +117,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon | |||
117 | }); | 117 | }); |
118 | } | 118 | } |
119 | } | 119 | } |
120 | PathResolution::Def(hir::ModuleDef::Trait(t)) => { | 120 | hir::PathResolution::Def(hir::ModuleDef::Trait(t)) => { |
121 | // Handles `Trait::assoc` as well as `<Ty as Trait>::assoc`. | 121 | // Handles `Trait::assoc` as well as `<Ty as Trait>::assoc`. |
122 | for item in t.items(ctx.db) { | 122 | for item in t.items(ctx.db) { |
123 | if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) { | 123 | if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) { |
@@ -130,15 +130,15 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon | |||
130 | } | 130 | } |
131 | } | 131 | } |
132 | } | 132 | } |
133 | PathResolution::TypeParam(_) | PathResolution::SelfType(_) => { | 133 | hir::PathResolution::TypeParam(_) | hir::PathResolution::SelfType(_) => { |
134 | if let Some(krate) = ctx.krate { | 134 | if let Some(krate) = ctx.krate { |
135 | let ty = match resolution { | 135 | let ty = match resolution { |
136 | PathResolution::TypeParam(param) => param.ty(ctx.db), | 136 | hir::PathResolution::TypeParam(param) => param.ty(ctx.db), |
137 | PathResolution::SelfType(impl_def) => impl_def.self_ty(ctx.db), | 137 | hir::PathResolution::SelfType(impl_def) => impl_def.self_ty(ctx.db), |
138 | _ => return, | 138 | _ => return, |
139 | }; | 139 | }; |
140 | 140 | ||
141 | if let Some(Adt::Enum(e)) = ty.as_adt() { | 141 | if let Some(hir::Adt::Enum(e)) = ty.as_adt() { |
142 | add_enum_variants(ctx, acc, e); | 142 | add_enum_variants(ctx, acc, e); |
143 | } | 143 | } |
144 | 144 | ||
diff --git a/crates/ide_completion/src/completions/record.rs b/crates/ide_completion/src/completions/record.rs index e1526b70b..227c08d01 100644 --- a/crates/ide_completion/src/completions/record.rs +++ b/crates/ide_completion/src/completions/record.rs | |||
@@ -2,21 +2,21 @@ | |||
2 | use ide_db::{helpers::FamousDefs, SymbolKind}; | 2 | use ide_db::{helpers::FamousDefs, SymbolKind}; |
3 | use syntax::ast::Expr; | 3 | use syntax::ast::Expr; |
4 | 4 | ||
5 | use crate::{item::CompletionKind, CompletionContext, CompletionItem, Completions}; | 5 | use crate::{ |
6 | item::CompletionKind, patterns::ImmediateLocation, CompletionContext, CompletionItem, | ||
7 | Completions, | ||
8 | }; | ||
6 | 9 | ||
7 | pub(crate) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> { | 10 | pub(crate) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> { |
8 | let missing_fields = match (ctx.record_pat_syntax.as_ref(), ctx.record_lit_syntax.as_ref()) { | 11 | let missing_fields = match &ctx.completion_location { |
9 | (None, None) => return None, | 12 | Some(ImmediateLocation::RecordExpr(record_expr)) => { |
10 | (Some(_), Some(_)) => unreachable!("A record cannot be both a literal and a pattern"), | 13 | let ty = ctx.sema.type_of_expr(&Expr::RecordExpr(record_expr.clone())); |
11 | (Some(record_pat), _) => ctx.sema.record_pattern_missing_fields(record_pat), | ||
12 | (_, Some(record_lit)) => { | ||
13 | let ty = ctx.sema.type_of_expr(&Expr::RecordExpr(record_lit.clone())); | ||
14 | let default_trait = FamousDefs(&ctx.sema, ctx.krate).core_default_Default(); | 14 | let default_trait = FamousDefs(&ctx.sema, ctx.krate).core_default_Default(); |
15 | let impl_default_trait = default_trait | 15 | let impl_default_trait = default_trait |
16 | .zip(ty) | 16 | .zip(ty) |
17 | .map_or(false, |(default_trait, ty)| ty.impls_trait(ctx.db, default_trait, &[])); | 17 | .map_or(false, |(default_trait, ty)| ty.impls_trait(ctx.db, default_trait, &[])); |
18 | 18 | ||
19 | let missing_fields = ctx.sema.record_literal_missing_fields(record_lit); | 19 | let missing_fields = ctx.sema.record_literal_missing_fields(record_expr); |
20 | if impl_default_trait && !missing_fields.is_empty() { | 20 | if impl_default_trait && !missing_fields.is_empty() { |
21 | let completion_text = "..Default::default()"; | 21 | let completion_text = "..Default::default()"; |
22 | let mut item = CompletionItem::new( | 22 | let mut item = CompletionItem::new( |
@@ -32,6 +32,10 @@ pub(crate) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) -> | |||
32 | 32 | ||
33 | missing_fields | 33 | missing_fields |
34 | } | 34 | } |
35 | Some(ImmediateLocation::RecordPat(record_pat)) => { | ||
36 | ctx.sema.record_pattern_missing_fields(record_pat) | ||
37 | } | ||
38 | _ => return None, | ||
35 | }; | 39 | }; |
36 | 40 | ||
37 | for (field, ty) in missing_fields { | 41 | for (field, ty) in missing_fields { |
diff --git a/crates/ide_completion/src/completions/unqualified_path.rs b/crates/ide_completion/src/completions/unqualified_path.rs index ede07f605..9db8516d0 100644 --- a/crates/ide_completion/src/completions/unqualified_path.rs +++ b/crates/ide_completion/src/completions/unqualified_path.rs | |||
@@ -14,10 +14,10 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC | |||
14 | if ctx.expects_assoc_item() { | 14 | if ctx.expects_assoc_item() { |
15 | ctx.scope.process_all_names(&mut |name, def| { | 15 | ctx.scope.process_all_names(&mut |name, def| { |
16 | if let ScopeDef::MacroDef(macro_def) = def { | 16 | if let ScopeDef::MacroDef(macro_def) = def { |
17 | acc.add_macro(ctx, Some(name.to_string()), macro_def); | 17 | acc.add_macro(ctx, Some(name.clone()), macro_def); |
18 | } | 18 | } |
19 | if let ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = def { | 19 | if let ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = def { |
20 | acc.add_resolution(ctx, name.to_string(), &def); | 20 | acc.add_resolution(ctx, name, &def); |
21 | } | 21 | } |
22 | }); | 22 | }); |
23 | return; | 23 | return; |
@@ -27,7 +27,7 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC | |||
27 | cov_mark::hit!(only_completes_modules_in_import); | 27 | cov_mark::hit!(only_completes_modules_in_import); |
28 | ctx.scope.process_all_names(&mut |name, res| { | 28 | ctx.scope.process_all_names(&mut |name, res| { |
29 | if let ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = res { | 29 | if let ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = res { |
30 | acc.add_resolution(ctx, name.to_string(), &res); | 30 | acc.add_resolution(ctx, name, &res); |
31 | } | 31 | } |
32 | }); | 32 | }); |
33 | return; | 33 | return; |
@@ -45,7 +45,7 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC | |||
45 | cov_mark::hit!(skip_lifetime_completion); | 45 | cov_mark::hit!(skip_lifetime_completion); |
46 | return; | 46 | return; |
47 | } | 47 | } |
48 | acc.add_resolution(ctx, name.to_string(), &res); | 48 | acc.add_resolution(ctx, name, &res); |
49 | }); | 49 | }); |
50 | } | 50 | } |
51 | 51 | ||
diff --git a/crates/ide_completion/src/context.rs b/crates/ide_completion/src/context.rs index 8d6440cb2..7c46c815d 100644 --- a/crates/ide_completion/src/context.rs +++ b/crates/ide_completion/src/context.rs | |||
@@ -18,7 +18,7 @@ use text_edit::Indel; | |||
18 | use crate::{ | 18 | use crate::{ |
19 | patterns::{ | 19 | patterns::{ |
20 | determine_location, determine_prev_sibling, for_is_prev2, inside_impl_trait_block, | 20 | determine_location, determine_prev_sibling, for_is_prev2, inside_impl_trait_block, |
21 | is_in_loop_body, is_match_arm, previous_token, ImmediateLocation, ImmediatePrevSibling, | 21 | is_in_loop_body, previous_token, ImmediateLocation, ImmediatePrevSibling, |
22 | }, | 22 | }, |
23 | CompletionConfig, | 23 | CompletionConfig, |
24 | }; | 24 | }; |
@@ -54,11 +54,6 @@ pub(crate) struct CompletionContext<'a> { | |||
54 | /// The parent impl of the cursor position if it exists. | 54 | /// The parent impl of the cursor position if it exists. |
55 | pub(super) impl_def: Option<ast::Impl>, | 55 | pub(super) impl_def: Option<ast::Impl>, |
56 | 56 | ||
57 | /// RecordExpr the token is a field of | ||
58 | pub(super) record_lit_syntax: Option<ast::RecordExpr>, | ||
59 | /// RecordPat the token is a field of | ||
60 | pub(super) record_pat_syntax: Option<ast::RecordPat>, | ||
61 | |||
62 | // potentially set if we are completing a lifetime | 57 | // potentially set if we are completing a lifetime |
63 | pub(super) lifetime_syntax: Option<ast::Lifetime>, | 58 | pub(super) lifetime_syntax: Option<ast::Lifetime>, |
64 | pub(super) lifetime_param_syntax: Option<ast::LifetimeParam>, | 59 | pub(super) lifetime_param_syntax: Option<ast::LifetimeParam>, |
@@ -71,6 +66,7 @@ pub(crate) struct CompletionContext<'a> { | |||
71 | 66 | ||
72 | pub(super) completion_location: Option<ImmediateLocation>, | 67 | pub(super) completion_location: Option<ImmediateLocation>, |
73 | pub(super) prev_sibling: Option<ImmediatePrevSibling>, | 68 | pub(super) prev_sibling: Option<ImmediatePrevSibling>, |
69 | pub(super) attribute_under_caret: Option<ast::Attr>, | ||
74 | 70 | ||
75 | /// FIXME: `ActiveParameter` is string-based, which is very very wrong | 71 | /// FIXME: `ActiveParameter` is string-based, which is very very wrong |
76 | pub(super) active_parameter: Option<ActiveParameter>, | 72 | pub(super) active_parameter: Option<ActiveParameter>, |
@@ -95,14 +91,10 @@ pub(crate) struct CompletionContext<'a> { | |||
95 | pub(super) is_macro_call: bool, | 91 | pub(super) is_macro_call: bool, |
96 | pub(super) is_path_type: bool, | 92 | pub(super) is_path_type: bool, |
97 | pub(super) has_type_args: bool, | 93 | pub(super) has_type_args: bool, |
98 | pub(super) attribute_under_caret: Option<ast::Attr>, | ||
99 | pub(super) mod_declaration_under_caret: Option<ast::Module>, | ||
100 | pub(super) locals: Vec<(String, Local)>, | 94 | pub(super) locals: Vec<(String, Local)>, |
101 | 95 | ||
102 | // keyword patterns | ||
103 | pub(super) previous_token: Option<SyntaxToken>, | 96 | pub(super) previous_token: Option<SyntaxToken>, |
104 | pub(super) in_loop_body: bool, | 97 | pub(super) in_loop_body: bool, |
105 | pub(super) is_match_arm: bool, | ||
106 | pub(super) incomplete_let: bool, | 98 | pub(super) incomplete_let: bool, |
107 | 99 | ||
108 | no_completion_required: bool, | 100 | no_completion_required: bool, |
@@ -157,8 +149,6 @@ impl<'a> CompletionContext<'a> { | |||
157 | lifetime_param_syntax: None, | 149 | lifetime_param_syntax: None, |
158 | function_def: None, | 150 | function_def: None, |
159 | use_item_syntax: None, | 151 | use_item_syntax: None, |
160 | record_lit_syntax: None, | ||
161 | record_pat_syntax: None, | ||
162 | impl_def: None, | 152 | impl_def: None, |
163 | active_parameter: ActiveParameter::at(db, position), | 153 | active_parameter: ActiveParameter::at(db, position), |
164 | is_label_ref: false, | 154 | is_label_ref: false, |
@@ -176,15 +166,13 @@ impl<'a> CompletionContext<'a> { | |||
176 | is_macro_call: false, | 166 | is_macro_call: false, |
177 | is_path_type: false, | 167 | is_path_type: false, |
178 | has_type_args: false, | 168 | has_type_args: false, |
179 | attribute_under_caret: None, | ||
180 | mod_declaration_under_caret: None, | ||
181 | previous_token: None, | 169 | previous_token: None, |
182 | in_loop_body: false, | 170 | in_loop_body: false, |
183 | completion_location: None, | 171 | completion_location: None, |
184 | prev_sibling: None, | 172 | prev_sibling: None, |
185 | is_match_arm: false, | ||
186 | no_completion_required: false, | 173 | no_completion_required: false, |
187 | incomplete_let: false, | 174 | incomplete_let: false, |
175 | attribute_under_caret: None, | ||
188 | locals, | 176 | locals, |
189 | }; | 177 | }; |
190 | 178 | ||
@@ -227,7 +215,6 @@ impl<'a> CompletionContext<'a> { | |||
227 | break; | 215 | break; |
228 | } | 216 | } |
229 | } | 217 | } |
230 | ctx.fill_keyword_patterns(&speculative_file, offset); | ||
231 | ctx.fill(&original_file, speculative_file, offset); | 218 | ctx.fill(&original_file, speculative_file, offset); |
232 | Some(ctx) | 219 | Some(ctx) |
233 | } | 220 | } |
@@ -311,31 +298,13 @@ impl<'a> CompletionContext<'a> { | |||
311 | } | 298 | } |
312 | 299 | ||
313 | pub(crate) fn is_path_disallowed(&self) -> bool { | 300 | pub(crate) fn is_path_disallowed(&self) -> bool { |
314 | self.record_lit_syntax.is_some() | 301 | matches!( |
315 | || self.record_pat_syntax.is_some() | 302 | self.completion_location, |
316 | || self.attribute_under_caret.is_some() | 303 | Some(ImmediateLocation::Attribute(_)) |
317 | || self.mod_declaration_under_caret.is_some() | 304 | | Some(ImmediateLocation::ModDeclaration(_)) |
318 | } | 305 | | Some(ImmediateLocation::RecordPat(_)) |
319 | 306 | | Some(ImmediateLocation::RecordExpr(_)) | |
320 | fn fill_keyword_patterns(&mut self, file_with_fake_ident: &SyntaxNode, offset: TextSize) { | 307 | ) || self.attribute_under_caret.is_some() |
321 | let fake_ident_token = file_with_fake_ident.token_at_offset(offset).right_biased().unwrap(); | ||
322 | let syntax_element = NodeOrToken::Token(fake_ident_token); | ||
323 | self.previous_token = previous_token(syntax_element.clone()); | ||
324 | self.in_loop_body = is_in_loop_body(syntax_element.clone()); | ||
325 | self.is_match_arm = is_match_arm(syntax_element.clone()); | ||
326 | |||
327 | self.mod_declaration_under_caret = | ||
328 | find_node_at_offset::<ast::Module>(&file_with_fake_ident, offset) | ||
329 | .filter(|module| module.item_list().is_none()); | ||
330 | self.incomplete_let = | ||
331 | syntax_element.ancestors().take(6).find_map(ast::LetStmt::cast).map_or(false, |it| { | ||
332 | it.syntax().text_range().end() == syntax_element.text_range().end() | ||
333 | }); | ||
334 | |||
335 | let inside_impl_trait_block = inside_impl_trait_block(syntax_element.clone()); | ||
336 | let fn_is_prev = self.previous_token_is(T![fn]); | ||
337 | let for_is_prev2 = for_is_prev2(syntax_element.clone()); | ||
338 | self.no_completion_required = (fn_is_prev && !inside_impl_trait_block) || for_is_prev2; | ||
339 | } | 308 | } |
340 | 309 | ||
341 | fn fill_impl_def(&mut self) { | 310 | fn fill_impl_def(&mut self) { |
@@ -453,25 +422,43 @@ impl<'a> CompletionContext<'a> { | |||
453 | file_with_fake_ident: SyntaxNode, | 422 | file_with_fake_ident: SyntaxNode, |
454 | offset: TextSize, | 423 | offset: TextSize, |
455 | ) { | 424 | ) { |
425 | let fake_ident_token = file_with_fake_ident.token_at_offset(offset).right_biased().unwrap(); | ||
426 | let syntax_element = NodeOrToken::Token(fake_ident_token); | ||
427 | self.previous_token = previous_token(syntax_element.clone()); | ||
428 | self.attribute_under_caret = syntax_element.ancestors().find_map(ast::Attr::cast); | ||
429 | self.no_completion_required = { | ||
430 | let inside_impl_trait_block = inside_impl_trait_block(syntax_element.clone()); | ||
431 | let fn_is_prev = self.previous_token_is(T![fn]); | ||
432 | let for_is_prev2 = for_is_prev2(syntax_element.clone()); | ||
433 | (fn_is_prev && !inside_impl_trait_block) || for_is_prev2 | ||
434 | }; | ||
435 | self.in_loop_body = is_in_loop_body(syntax_element.clone()); | ||
436 | |||
437 | self.incomplete_let = | ||
438 | syntax_element.ancestors().take(6).find_map(ast::LetStmt::cast).map_or(false, |it| { | ||
439 | it.syntax().text_range().end() == syntax_element.text_range().end() | ||
440 | }); | ||
441 | |||
456 | let (expected_type, expected_name) = self.expected_type_and_name(); | 442 | let (expected_type, expected_name) = self.expected_type_and_name(); |
457 | self.expected_type = expected_type; | 443 | self.expected_type = expected_type; |
458 | self.expected_name = expected_name; | 444 | self.expected_name = expected_name; |
459 | self.attribute_under_caret = find_node_at_offset(&file_with_fake_ident, offset); | 445 | |
460 | let name_like = match find_node_at_offset(&&file_with_fake_ident, offset) { | 446 | let name_like = match find_node_at_offset(&&file_with_fake_ident, offset) { |
461 | Some(it) => it, | 447 | Some(it) => it, |
462 | None => return, | 448 | None => return, |
463 | }; | 449 | }; |
464 | self.completion_location = determine_location(&name_like); | 450 | self.completion_location = |
451 | determine_location(&self.sema, original_file, offset, &name_like); | ||
465 | self.prev_sibling = determine_prev_sibling(&name_like); | 452 | self.prev_sibling = determine_prev_sibling(&name_like); |
466 | match name_like { | 453 | match name_like { |
467 | ast::NameLike::Lifetime(lifetime) => { | 454 | ast::NameLike::Lifetime(lifetime) => { |
468 | self.classify_lifetime(original_file, lifetime, offset); | 455 | self.classify_lifetime(original_file, lifetime, offset); |
469 | } | 456 | } |
470 | ast::NameLike::NameRef(name_ref) => { | 457 | ast::NameLike::NameRef(name_ref) => { |
471 | self.classify_name_ref(original_file, name_ref, offset); | 458 | self.classify_name_ref(original_file, name_ref); |
472 | } | 459 | } |
473 | ast::NameLike::Name(name) => { | 460 | ast::NameLike::Name(name) => { |
474 | self.classify_name(original_file, name, offset); | 461 | self.classify_name(name); |
475 | } | 462 | } |
476 | } | 463 | } |
477 | } | 464 | } |
@@ -505,7 +492,7 @@ impl<'a> CompletionContext<'a> { | |||
505 | } | 492 | } |
506 | } | 493 | } |
507 | 494 | ||
508 | fn classify_name(&mut self, original_file: &SyntaxNode, name: ast::Name, offset: TextSize) { | 495 | fn classify_name(&mut self, name: ast::Name) { |
509 | if let Some(bind_pat) = name.syntax().parent().and_then(ast::IdentPat::cast) { | 496 | if let Some(bind_pat) = name.syntax().parent().and_then(ast::IdentPat::cast) { |
510 | self.is_pat_or_const = Some(PatternRefutability::Refutable); | 497 | self.is_pat_or_const = Some(PatternRefutability::Refutable); |
511 | // if any of these is here our bind pat can't be a const pat anymore | 498 | // if any of these is here our bind pat can't be a const pat anymore |
@@ -543,28 +530,12 @@ impl<'a> CompletionContext<'a> { | |||
543 | 530 | ||
544 | self.fill_impl_def(); | 531 | self.fill_impl_def(); |
545 | } | 532 | } |
533 | |||
546 | self.is_param |= is_node::<ast::Param>(name.syntax()); | 534 | self.is_param |= is_node::<ast::Param>(name.syntax()); |
547 | if ast::RecordPatField::for_field_name(&name).is_some() { | ||
548 | self.record_pat_syntax = | ||
549 | self.sema.find_node_at_offset_with_macros(&original_file, offset); | ||
550 | } | ||
551 | } | 535 | } |
552 | 536 | ||
553 | fn classify_name_ref( | 537 | fn classify_name_ref(&mut self, original_file: &SyntaxNode, name_ref: ast::NameRef) { |
554 | &mut self, | ||
555 | original_file: &SyntaxNode, | ||
556 | name_ref: ast::NameRef, | ||
557 | offset: TextSize, | ||
558 | ) { | ||
559 | self.fill_impl_def(); | 538 | self.fill_impl_def(); |
560 | if ast::RecordExprField::for_field_name(&name_ref).is_some() { | ||
561 | self.record_lit_syntax = | ||
562 | self.sema.find_node_at_offset_with_macros(original_file, offset); | ||
563 | } | ||
564 | if ast::RecordPatField::for_field_name_ref(&name_ref).is_some() { | ||
565 | self.record_pat_syntax = | ||
566 | self.sema.find_node_at_offset_with_macros(&original_file, offset); | ||
567 | } | ||
568 | 539 | ||
569 | self.name_ref_syntax = | 540 | self.name_ref_syntax = |
570 | find_node_at_offset(original_file, name_ref.syntax().text_range().start()); | 541 | find_node_at_offset(original_file, name_ref.syntax().text_range().start()); |
diff --git a/crates/ide_completion/src/patterns.rs b/crates/ide_completion/src/patterns.rs index caf0ef39f..26516046b 100644 --- a/crates/ide_completion/src/patterns.rs +++ b/crates/ide_completion/src/patterns.rs | |||
@@ -1,15 +1,18 @@ | |||
1 | //! Patterns telling us certain facts about current syntax element, they are used in completion context | 1 | //! Patterns telling us certain facts about current syntax element, they are used in completion context |
2 | 2 | ||
3 | use hir::Semantics; | ||
4 | use ide_db::RootDatabase; | ||
3 | use syntax::{ | 5 | use syntax::{ |
4 | algo::non_trivia_sibling, | 6 | algo::non_trivia_sibling, |
5 | ast::{self, LoopBodyOwner}, | 7 | ast::{self, LoopBodyOwner}, |
6 | match_ast, AstNode, Direction, NodeOrToken, SyntaxElement, | 8 | match_ast, AstNode, Direction, SyntaxElement, |
7 | SyntaxKind::*, | 9 | SyntaxKind::*, |
8 | SyntaxNode, SyntaxToken, T, | 10 | SyntaxNode, SyntaxToken, TextSize, T, |
9 | }; | 11 | }; |
10 | 12 | ||
11 | #[cfg(test)] | 13 | #[cfg(test)] |
12 | use crate::test_utils::{check_pattern_is_applicable, check_pattern_is_not_applicable}; | 14 | use crate::test_utils::{check_pattern_is_applicable, check_pattern_is_not_applicable}; |
15 | |||
13 | /// Direct parent container of the cursor position | 16 | /// Direct parent container of the cursor position |
14 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] | 17 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] |
15 | pub(crate) enum ImmediatePrevSibling { | 18 | pub(crate) enum ImmediatePrevSibling { |
@@ -19,7 +22,7 @@ pub(crate) enum ImmediatePrevSibling { | |||
19 | } | 22 | } |
20 | 23 | ||
21 | /// Direct parent container of the cursor position | 24 | /// Direct parent container of the cursor position |
22 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] | 25 | #[derive(Clone, Debug, PartialEq, Eq)] |
23 | pub(crate) enum ImmediateLocation { | 26 | pub(crate) enum ImmediateLocation { |
24 | Use, | 27 | Use, |
25 | Impl, | 28 | Impl, |
@@ -29,10 +32,24 @@ pub(crate) enum ImmediateLocation { | |||
29 | IdentPat, | 32 | IdentPat, |
30 | BlockExpr, | 33 | BlockExpr, |
31 | ItemList, | 34 | ItemList, |
35 | // Fake file ast node | ||
36 | Attribute(ast::Attr), | ||
37 | // Fake file ast node | ||
38 | ModDeclaration(ast::Module), | ||
39 | // Original file ast node | ||
40 | /// The record expr of the field name we are completing | ||
41 | RecordExpr(ast::RecordExpr), | ||
42 | // Original file ast node | ||
43 | /// The record pat of the field name we are completing | ||
44 | RecordPat(ast::RecordPat), | ||
32 | } | 45 | } |
33 | 46 | ||
34 | pub(crate) fn determine_prev_sibling(name_like: &ast::NameLike) -> Option<ImmediatePrevSibling> { | 47 | pub(crate) fn determine_prev_sibling(name_like: &ast::NameLike) -> Option<ImmediatePrevSibling> { |
35 | let node = maximize_name_ref(name_like)?; | 48 | let node = match name_like { |
49 | ast::NameLike::NameRef(name_ref) => maximize_name_ref(name_ref), | ||
50 | ast::NameLike::Name(n) => n.syntax().clone(), | ||
51 | ast::NameLike::Lifetime(lt) => lt.syntax().clone(), | ||
52 | }; | ||
36 | let node = match node.parent().and_then(ast::MacroCall::cast) { | 53 | let node = match node.parent().and_then(ast::MacroCall::cast) { |
37 | // When a path is being typed after the name of a trait/type of an impl it is being | 54 | // When a path is being typed after the name of a trait/type of an impl it is being |
38 | // parsed as a macro, so when the trait/impl has a block following it an we are between the | 55 | // parsed as a macro, so when the trait/impl has a block following it an we are between the |
@@ -77,8 +94,37 @@ pub(crate) fn determine_prev_sibling(name_like: &ast::NameLike) -> Option<Immedi | |||
77 | Some(res) | 94 | Some(res) |
78 | } | 95 | } |
79 | 96 | ||
80 | pub(crate) fn determine_location(name_like: &ast::NameLike) -> Option<ImmediateLocation> { | 97 | pub(crate) fn determine_location( |
81 | let node = maximize_name_ref(name_like)?; | 98 | sema: &Semantics<RootDatabase>, |
99 | original_file: &SyntaxNode, | ||
100 | offset: TextSize, | ||
101 | name_like: &ast::NameLike, | ||
102 | ) -> Option<ImmediateLocation> { | ||
103 | let node = match name_like { | ||
104 | ast::NameLike::NameRef(name_ref) => { | ||
105 | if ast::RecordExprField::for_field_name(&name_ref).is_some() { | ||
106 | return sema | ||
107 | .find_node_at_offset_with_macros(original_file, offset) | ||
108 | .map(ImmediateLocation::RecordExpr); | ||
109 | } | ||
110 | if ast::RecordPatField::for_field_name_ref(&name_ref).is_some() { | ||
111 | return sema | ||
112 | .find_node_at_offset_with_macros(original_file, offset) | ||
113 | .map(ImmediateLocation::RecordPat); | ||
114 | } | ||
115 | maximize_name_ref(name_ref) | ||
116 | } | ||
117 | ast::NameLike::Name(name) => { | ||
118 | if ast::RecordPatField::for_field_name(&name).is_some() { | ||
119 | return sema | ||
120 | .find_node_at_offset_with_macros(original_file, offset) | ||
121 | .map(ImmediateLocation::RecordPat); | ||
122 | } | ||
123 | name.syntax().clone() | ||
124 | } | ||
125 | ast::NameLike::Lifetime(lt) => lt.syntax().clone(), | ||
126 | }; | ||
127 | |||
82 | let parent = match node.parent() { | 128 | let parent = match node.parent() { |
83 | Some(parent) => match ast::MacroCall::cast(parent.clone()) { | 129 | Some(parent) => match ast::MacroCall::cast(parent.clone()) { |
84 | // When a path is being typed in an (Assoc)ItemList the parser will always emit a macro_call. | 130 | // When a path is being typed in an (Assoc)ItemList the parser will always emit a macro_call. |
@@ -103,6 +149,7 @@ pub(crate) fn determine_location(name_like: &ast::NameLike) -> Option<ImmediateL | |||
103 | } | 149 | } |
104 | } | 150 | } |
105 | }; | 151 | }; |
152 | |||
106 | let res = match_ast! { | 153 | let res = match_ast! { |
107 | match parent { | 154 | match parent { |
108 | ast::IdentPat(_it) => ImmediateLocation::IdentPat, | 155 | ast::IdentPat(_it) => ImmediateLocation::IdentPat, |
@@ -117,36 +164,34 @@ pub(crate) fn determine_location(name_like: &ast::NameLike) -> Option<ImmediateL | |||
117 | Some(TRAIT) => ImmediateLocation::Trait, | 164 | Some(TRAIT) => ImmediateLocation::Trait, |
118 | _ => return None, | 165 | _ => return None, |
119 | }, | 166 | }, |
167 | ast::Module(it) => if it.item_list().is_none() { | ||
168 | ImmediateLocation::ModDeclaration(it) | ||
169 | } else { | ||
170 | return None | ||
171 | }, | ||
172 | ast::Attr(it) => ImmediateLocation::Attribute(it), | ||
120 | _ => return None, | 173 | _ => return None, |
121 | } | 174 | } |
122 | }; | 175 | }; |
123 | Some(res) | 176 | Some(res) |
124 | } | 177 | } |
125 | 178 | ||
126 | fn maximize_name_ref(name_like: &ast::NameLike) -> Option<SyntaxNode> { | 179 | fn maximize_name_ref(name_ref: &ast::NameRef) -> SyntaxNode { |
127 | // First walk the element we are completing up to its highest node that has the same text range | 180 | // Maximize a nameref to its enclosing path if its the last segment of said path |
128 | // as the element so that we can check in what context it immediately lies. We only do this for | 181 | if let Some(segment) = name_ref.syntax().parent().and_then(ast::PathSegment::cast) { |
129 | // NameRef -> Path as that's the only thing that makes sense to being "expanded" semantically. | 182 | let p = segment.parent_path(); |
130 | // We only wanna do this if the NameRef is the last segment of the path. | 183 | if p.parent_path().is_none() { |
131 | let node = match name_like { | 184 | if let Some(it) = p |
132 | ast::NameLike::NameRef(name_ref) => { | 185 | .syntax() |
133 | if let Some(segment) = name_ref.syntax().parent().and_then(ast::PathSegment::cast) { | 186 | .ancestors() |
134 | let p = segment.parent_path(); | 187 | .take_while(|it| it.text_range() == p.syntax().text_range()) |
135 | if p.parent_path().is_none() { | 188 | .last() |
136 | p.syntax() | 189 | { |
137 | .ancestors() | 190 | return it; |
138 | .take_while(|it| it.text_range() == p.syntax().text_range()) | ||
139 | .last()? | ||
140 | } else { | ||
141 | return None; | ||
142 | } | ||
143 | } else { | ||
144 | return None; | ||
145 | } | 191 | } |
146 | } | 192 | } |
147 | it @ ast::NameLike::Name(_) | it @ ast::NameLike::Lifetime(_) => it.syntax().clone(), | 193 | } |
148 | }; | 194 | name_ref.syntax().clone() |
149 | Some(node) | ||
150 | } | 195 | } |
151 | 196 | ||
152 | pub(crate) fn inside_impl_trait_block(element: SyntaxElement) -> bool { | 197 | pub(crate) fn inside_impl_trait_block(element: SyntaxElement) -> bool { |
@@ -167,18 +212,6 @@ fn test_inside_impl_trait_block() { | |||
167 | check_pattern_is_not_applicable(r"impl A { fn f$0 }", inside_impl_trait_block); | 212 | check_pattern_is_not_applicable(r"impl A { fn f$0 }", inside_impl_trait_block); |
168 | } | 213 | } |
169 | 214 | ||
170 | pub(crate) fn is_match_arm(element: SyntaxElement) -> bool { | ||
171 | not_same_range_ancestor(element.clone()).filter(|it| it.kind() == MATCH_ARM).is_some() | ||
172 | && previous_sibling_or_ancestor_sibling(element) | ||
173 | .and_then(|it| it.into_token()) | ||
174 | .filter(|it| it.kind() == FAT_ARROW) | ||
175 | .is_some() | ||
176 | } | ||
177 | #[test] | ||
178 | fn test_is_match_arm() { | ||
179 | check_pattern_is_applicable(r"fn my_fn() { match () { () => m$0 } }", is_match_arm); | ||
180 | } | ||
181 | |||
182 | pub(crate) fn previous_token(element: SyntaxElement) -> Option<SyntaxToken> { | 215 | pub(crate) fn previous_token(element: SyntaxElement) -> Option<SyntaxToken> { |
183 | element.into_token().and_then(|it| previous_non_trivia_token(it)) | 216 | element.into_token().and_then(|it| previous_non_trivia_token(it)) |
184 | } | 217 | } |
@@ -216,10 +249,6 @@ pub(crate) fn is_in_loop_body(element: SyntaxElement) -> bool { | |||
216 | .is_some() | 249 | .is_some() |
217 | } | 250 | } |
218 | 251 | ||
219 | pub(crate) fn not_same_range_ancestor(element: SyntaxElement) -> Option<SyntaxNode> { | ||
220 | element.ancestors().skip_while(|it| it.text_range() == element.text_range()).next() | ||
221 | } | ||
222 | |||
223 | fn previous_non_trivia_token(token: SyntaxToken) -> Option<SyntaxToken> { | 252 | fn previous_non_trivia_token(token: SyntaxToken) -> Option<SyntaxToken> { |
224 | let mut token = token.prev_token(); | 253 | let mut token = token.prev_token(); |
225 | while let Some(inner) = token.clone() { | 254 | while let Some(inner) = token.clone() { |
@@ -232,31 +261,25 @@ fn previous_non_trivia_token(token: SyntaxToken) -> Option<SyntaxToken> { | |||
232 | None | 261 | None |
233 | } | 262 | } |
234 | 263 | ||
235 | fn previous_sibling_or_ancestor_sibling(element: SyntaxElement) -> Option<SyntaxElement> { | ||
236 | let token_sibling = non_trivia_sibling(element.clone(), Direction::Prev); | ||
237 | if let Some(sibling) = token_sibling { | ||
238 | Some(sibling) | ||
239 | } else { | ||
240 | // if not trying to find first ancestor which has such a sibling | ||
241 | let range = element.text_range(); | ||
242 | let top_node = element.ancestors().take_while(|it| it.text_range() == range).last()?; | ||
243 | let prev_sibling_node = top_node.ancestors().find(|it| { | ||
244 | non_trivia_sibling(NodeOrToken::Node(it.to_owned()), Direction::Prev).is_some() | ||
245 | })?; | ||
246 | non_trivia_sibling(NodeOrToken::Node(prev_sibling_node), Direction::Prev) | ||
247 | } | ||
248 | } | ||
249 | |||
250 | #[cfg(test)] | 264 | #[cfg(test)] |
251 | mod tests { | 265 | mod tests { |
266 | use syntax::algo::find_node_at_offset; | ||
267 | |||
268 | use crate::test_utils::position; | ||
269 | |||
252 | use super::*; | 270 | use super::*; |
253 | 271 | ||
254 | fn check_location(code: &str, loc: impl Into<Option<ImmediateLocation>>) { | 272 | fn check_location(code: &str, loc: impl Into<Option<ImmediateLocation>>) { |
255 | check_pattern_is_applicable(code, |e| { | 273 | let (db, pos) = position(code); |
256 | let name = &e.parent().and_then(ast::NameLike::cast).expect("Expected a namelike"); | 274 | |
257 | assert_eq!(determine_location(name), loc.into()); | 275 | let sema = Semantics::new(&db); |
258 | true | 276 | let original_file = sema.parse(pos.file_id); |
259 | }); | 277 | |
278 | let name_like = find_node_at_offset(original_file.syntax(), pos.offset).unwrap(); | ||
279 | assert_eq!( | ||
280 | determine_location(&sema, original_file.syntax(), pos.offset, &name_like), | ||
281 | loc.into() | ||
282 | ); | ||
260 | } | 283 | } |
261 | 284 | ||
262 | fn check_prev_sibling(code: &str, sibling: impl Into<Option<ImmediatePrevSibling>>) { | 285 | fn check_prev_sibling(code: &str, sibling: impl Into<Option<ImmediatePrevSibling>>) { |
diff --git a/crates/ide_completion/src/render.rs b/crates/ide_completion/src/render.rs index 91300c56e..425dd0247 100644 --- a/crates/ide_completion/src/render.rs +++ b/crates/ide_completion/src/render.rs | |||
@@ -10,9 +10,7 @@ pub(crate) mod type_alias; | |||
10 | 10 | ||
11 | mod builder_ext; | 11 | mod builder_ext; |
12 | 12 | ||
13 | use hir::{ | 13 | use hir::{AsAssocItem, HasAttrs, HirDisplay}; |
14 | AsAssocItem, Documentation, HasAttrs, HirDisplay, ModuleDef, Mutability, ScopeDef, Type, | ||
15 | }; | ||
16 | use ide_db::{ | 14 | use ide_db::{ |
17 | helpers::{item_name, SnippetCap}, | 15 | helpers::{item_name, SnippetCap}, |
18 | RootDatabase, SymbolKind, | 16 | RootDatabase, SymbolKind, |
@@ -21,31 +19,30 @@ use syntax::TextRange; | |||
21 | 19 | ||
22 | use crate::{ | 20 | use crate::{ |
23 | item::{CompletionRelevanceTypeMatch, ImportEdit}, | 21 | item::{CompletionRelevanceTypeMatch, ImportEdit}, |
22 | render::{enum_variant::render_variant, function::render_fn, macro_::render_macro}, | ||
24 | CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, CompletionRelevance, | 23 | CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, CompletionRelevance, |
25 | }; | 24 | }; |
26 | 25 | ||
27 | use crate::render::{enum_variant::render_variant, function::render_fn, macro_::render_macro}; | ||
28 | |||
29 | pub(crate) fn render_field<'a>( | 26 | pub(crate) fn render_field<'a>( |
30 | ctx: RenderContext<'a>, | 27 | ctx: RenderContext<'a>, |
31 | field: hir::Field, | 28 | field: hir::Field, |
32 | ty: &Type, | 29 | ty: &hir::Type, |
33 | ) -> CompletionItem { | 30 | ) -> CompletionItem { |
34 | Render::new(ctx).add_field(field, ty) | 31 | Render::new(ctx).render_field(field, ty) |
35 | } | 32 | } |
36 | 33 | ||
37 | pub(crate) fn render_tuple_field<'a>( | 34 | pub(crate) fn render_tuple_field<'a>( |
38 | ctx: RenderContext<'a>, | 35 | ctx: RenderContext<'a>, |
39 | field: usize, | 36 | field: usize, |
40 | ty: &Type, | 37 | ty: &hir::Type, |
41 | ) -> CompletionItem { | 38 | ) -> CompletionItem { |
42 | Render::new(ctx).add_tuple_field(field, ty) | 39 | Render::new(ctx).render_tuple_field(field, ty) |
43 | } | 40 | } |
44 | 41 | ||
45 | pub(crate) fn render_resolution<'a>( | 42 | pub(crate) fn render_resolution<'a>( |
46 | ctx: RenderContext<'a>, | 43 | ctx: RenderContext<'a>, |
47 | local_name: String, | 44 | local_name: hir::Name, |
48 | resolution: &ScopeDef, | 45 | resolution: &hir::ScopeDef, |
49 | ) -> Option<CompletionItem> { | 46 | ) -> Option<CompletionItem> { |
50 | Render::new(ctx).render_resolution(local_name, None, resolution) | 47 | Render::new(ctx).render_resolution(local_name, None, resolution) |
51 | } | 48 | } |
@@ -54,12 +51,12 @@ pub(crate) fn render_resolution_with_import<'a>( | |||
54 | ctx: RenderContext<'a>, | 51 | ctx: RenderContext<'a>, |
55 | import_edit: ImportEdit, | 52 | import_edit: ImportEdit, |
56 | ) -> Option<CompletionItem> { | 53 | ) -> Option<CompletionItem> { |
57 | let resolution = ScopeDef::from(import_edit.import.original_item); | 54 | let resolution = hir::ScopeDef::from(import_edit.import.original_item); |
58 | let local_name = match resolution { | 55 | let local_name = match resolution { |
59 | ScopeDef::ModuleDef(ModuleDef::Function(f)) => f.name(ctx.completion.db).to_string(), | 56 | hir::ScopeDef::ModuleDef(hir::ModuleDef::Function(f)) => f.name(ctx.completion.db), |
60 | ScopeDef::ModuleDef(ModuleDef::Const(c)) => c.name(ctx.completion.db)?.to_string(), | 57 | hir::ScopeDef::ModuleDef(hir::ModuleDef::Const(c)) => c.name(ctx.completion.db)?, |
61 | ScopeDef::ModuleDef(ModuleDef::TypeAlias(t)) => t.name(ctx.completion.db).to_string(), | 58 | hir::ScopeDef::ModuleDef(hir::ModuleDef::TypeAlias(t)) => t.name(ctx.completion.db), |
62 | _ => item_name(ctx.db(), import_edit.import.original_item)?.to_string(), | 59 | _ => item_name(ctx.db(), import_edit.import.original_item)?, |
63 | }; | 60 | }; |
64 | Render::new(ctx).render_resolution(local_name, Some(import_edit), &resolution).map( | 61 | Render::new(ctx).render_resolution(local_name, Some(import_edit), &resolution).map( |
65 | |mut item| { | 62 | |mut item| { |
@@ -113,7 +110,7 @@ impl<'a> RenderContext<'a> { | |||
113 | || assoc.containing_trait(db).map(|trait_| self.is_deprecated(trait_)).unwrap_or(false) | 110 | || assoc.containing_trait(db).map(|trait_| self.is_deprecated(trait_)).unwrap_or(false) |
114 | } | 111 | } |
115 | 112 | ||
116 | fn docs(&self, node: impl HasAttrs) -> Option<Documentation> { | 113 | fn docs(&self, node: impl HasAttrs) -> Option<hir::Documentation> { |
117 | node.docs(self.db()) | 114 | node.docs(self.db()) |
118 | } | 115 | } |
119 | } | 116 | } |
@@ -129,14 +126,11 @@ impl<'a> Render<'a> { | |||
129 | Render { ctx } | 126 | Render { ctx } |
130 | } | 127 | } |
131 | 128 | ||
132 | fn add_field(&mut self, field: hir::Field, ty: &Type) -> CompletionItem { | 129 | fn render_field(&self, field: hir::Field, ty: &hir::Type) -> CompletionItem { |
133 | let is_deprecated = self.ctx.is_deprecated(field); | 130 | let is_deprecated = self.ctx.is_deprecated(field); |
134 | let name = field.name(self.ctx.db()); | 131 | let name = field.name(self.ctx.db()).to_string(); |
135 | let mut item = CompletionItem::new( | 132 | let mut item = |
136 | CompletionKind::Reference, | 133 | CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), name.clone()); |
137 | self.ctx.source_range(), | ||
138 | name.to_string(), | ||
139 | ); | ||
140 | item.kind(SymbolKind::Field) | 134 | item.kind(SymbolKind::Field) |
141 | .detail(ty.display(self.ctx.db()).to_string()) | 135 | .detail(ty.display(self.ctx.db()).to_string()) |
142 | .set_documentation(field.docs(self.ctx.db())) | 136 | .set_documentation(field.docs(self.ctx.db())) |
@@ -144,7 +138,7 @@ impl<'a> Render<'a> { | |||
144 | 138 | ||
145 | item.set_relevance(CompletionRelevance { | 139 | item.set_relevance(CompletionRelevance { |
146 | type_match: compute_type_match(self.ctx.completion, ty), | 140 | type_match: compute_type_match(self.ctx.completion, ty), |
147 | exact_name_match: compute_exact_name_match(self.ctx.completion, name.to_string()), | 141 | exact_name_match: compute_exact_name_match(self.ctx.completion, &name), |
148 | ..CompletionRelevance::default() | 142 | ..CompletionRelevance::default() |
149 | }); | 143 | }); |
150 | 144 | ||
@@ -157,7 +151,7 @@ impl<'a> Render<'a> { | |||
157 | item.build() | 151 | item.build() |
158 | } | 152 | } |
159 | 153 | ||
160 | fn add_tuple_field(&mut self, field: usize, ty: &Type) -> CompletionItem { | 154 | fn render_tuple_field(&self, field: usize, ty: &hir::Type) -> CompletionItem { |
161 | let mut item = CompletionItem::new( | 155 | let mut item = CompletionItem::new( |
162 | CompletionKind::Reference, | 156 | CompletionKind::Reference, |
163 | self.ctx.source_range(), | 157 | self.ctx.source_range(), |
@@ -171,71 +165,82 @@ impl<'a> Render<'a> { | |||
171 | 165 | ||
172 | fn render_resolution( | 166 | fn render_resolution( |
173 | self, | 167 | self, |
174 | local_name: String, | 168 | local_name: hir::Name, |
175 | import_to_add: Option<ImportEdit>, | 169 | import_to_add: Option<ImportEdit>, |
176 | resolution: &ScopeDef, | 170 | resolution: &hir::ScopeDef, |
177 | ) -> Option<CompletionItem> { | 171 | ) -> Option<CompletionItem> { |
178 | let _p = profile::span("render_resolution"); | 172 | let _p = profile::span("render_resolution"); |
179 | use hir::ModuleDef::*; | 173 | use hir::ModuleDef::*; |
180 | 174 | ||
181 | let completion_kind = match resolution { | 175 | let completion_kind = match resolution { |
182 | ScopeDef::ModuleDef(BuiltinType(..)) => CompletionKind::BuiltinType, | 176 | hir::ScopeDef::ModuleDef(BuiltinType(..)) => CompletionKind::BuiltinType, |
183 | _ => CompletionKind::Reference, | 177 | _ => CompletionKind::Reference, |
184 | }; | 178 | }; |
185 | 179 | ||
186 | let kind = match resolution { | 180 | let kind = match resolution { |
187 | ScopeDef::ModuleDef(Function(func)) => { | 181 | hir::ScopeDef::ModuleDef(Function(func)) => { |
188 | return render_fn(self.ctx, import_to_add, Some(local_name), *func); | 182 | return render_fn(self.ctx, import_to_add, Some(local_name), *func); |
189 | } | 183 | } |
190 | ScopeDef::ModuleDef(Variant(_)) if self.ctx.completion.is_pat_or_const.is_some() => { | 184 | hir::ScopeDef::ModuleDef(Variant(_)) |
185 | if self.ctx.completion.is_pat_or_const.is_some() => | ||
186 | { | ||
191 | CompletionItemKind::SymbolKind(SymbolKind::Variant) | 187 | CompletionItemKind::SymbolKind(SymbolKind::Variant) |
192 | } | 188 | } |
193 | ScopeDef::ModuleDef(Variant(var)) => { | 189 | hir::ScopeDef::ModuleDef(Variant(var)) => { |
194 | let item = render_variant(self.ctx, import_to_add, Some(local_name), *var, None); | 190 | let item = render_variant(self.ctx, import_to_add, Some(local_name), *var, None); |
195 | return Some(item); | 191 | return Some(item); |
196 | } | 192 | } |
197 | ScopeDef::MacroDef(mac) => { | 193 | hir::ScopeDef::MacroDef(mac) => { |
198 | let item = render_macro(self.ctx, import_to_add, local_name, *mac); | 194 | let item = render_macro(self.ctx, import_to_add, local_name, *mac); |
199 | return item; | 195 | return item; |
200 | } | 196 | } |
201 | 197 | ||
202 | ScopeDef::ModuleDef(Module(..)) => CompletionItemKind::SymbolKind(SymbolKind::Module), | 198 | hir::ScopeDef::ModuleDef(Module(..)) => { |
203 | ScopeDef::ModuleDef(Adt(adt)) => CompletionItemKind::SymbolKind(match adt { | 199 | CompletionItemKind::SymbolKind(SymbolKind::Module) |
200 | } | ||
201 | hir::ScopeDef::ModuleDef(Adt(adt)) => CompletionItemKind::SymbolKind(match adt { | ||
204 | hir::Adt::Struct(_) => SymbolKind::Struct, | 202 | hir::Adt::Struct(_) => SymbolKind::Struct, |
205 | hir::Adt::Union(_) => SymbolKind::Union, | 203 | hir::Adt::Union(_) => SymbolKind::Union, |
206 | hir::Adt::Enum(_) => SymbolKind::Enum, | 204 | hir::Adt::Enum(_) => SymbolKind::Enum, |
207 | }), | 205 | }), |
208 | ScopeDef::ModuleDef(Const(..)) => CompletionItemKind::SymbolKind(SymbolKind::Const), | 206 | hir::ScopeDef::ModuleDef(Const(..)) => { |
209 | ScopeDef::ModuleDef(Static(..)) => CompletionItemKind::SymbolKind(SymbolKind::Static), | 207 | CompletionItemKind::SymbolKind(SymbolKind::Const) |
210 | ScopeDef::ModuleDef(Trait(..)) => CompletionItemKind::SymbolKind(SymbolKind::Trait), | 208 | } |
211 | ScopeDef::ModuleDef(TypeAlias(..)) => { | 209 | hir::ScopeDef::ModuleDef(Static(..)) => { |
210 | CompletionItemKind::SymbolKind(SymbolKind::Static) | ||
211 | } | ||
212 | hir::ScopeDef::ModuleDef(Trait(..)) => { | ||
213 | CompletionItemKind::SymbolKind(SymbolKind::Trait) | ||
214 | } | ||
215 | hir::ScopeDef::ModuleDef(TypeAlias(..)) => { | ||
212 | CompletionItemKind::SymbolKind(SymbolKind::TypeAlias) | 216 | CompletionItemKind::SymbolKind(SymbolKind::TypeAlias) |
213 | } | 217 | } |
214 | ScopeDef::ModuleDef(BuiltinType(..)) => CompletionItemKind::BuiltinType, | 218 | hir::ScopeDef::ModuleDef(BuiltinType(..)) => CompletionItemKind::BuiltinType, |
215 | ScopeDef::GenericParam(param) => CompletionItemKind::SymbolKind(match param { | 219 | hir::ScopeDef::GenericParam(param) => CompletionItemKind::SymbolKind(match param { |
216 | hir::GenericParam::TypeParam(_) => SymbolKind::TypeParam, | 220 | hir::GenericParam::TypeParam(_) => SymbolKind::TypeParam, |
217 | hir::GenericParam::LifetimeParam(_) => SymbolKind::LifetimeParam, | 221 | hir::GenericParam::LifetimeParam(_) => SymbolKind::LifetimeParam, |
218 | hir::GenericParam::ConstParam(_) => SymbolKind::ConstParam, | 222 | hir::GenericParam::ConstParam(_) => SymbolKind::ConstParam, |
219 | }), | 223 | }), |
220 | ScopeDef::Local(..) => CompletionItemKind::SymbolKind(SymbolKind::Local), | 224 | hir::ScopeDef::Local(..) => CompletionItemKind::SymbolKind(SymbolKind::Local), |
221 | ScopeDef::Label(..) => CompletionItemKind::SymbolKind(SymbolKind::Label), | 225 | hir::ScopeDef::Label(..) => CompletionItemKind::SymbolKind(SymbolKind::Label), |
222 | ScopeDef::AdtSelfType(..) | ScopeDef::ImplSelfType(..) => { | 226 | hir::ScopeDef::AdtSelfType(..) | hir::ScopeDef::ImplSelfType(..) => { |
223 | CompletionItemKind::SymbolKind(SymbolKind::SelfParam) | 227 | CompletionItemKind::SymbolKind(SymbolKind::SelfParam) |
224 | } | 228 | } |
225 | ScopeDef::Unknown => { | 229 | hir::ScopeDef::Unknown => { |
226 | let mut item = CompletionItem::new( | 230 | let mut item = CompletionItem::new( |
227 | CompletionKind::Reference, | 231 | CompletionKind::Reference, |
228 | self.ctx.source_range(), | 232 | self.ctx.source_range(), |
229 | local_name, | 233 | local_name.to_string(), |
230 | ); | 234 | ); |
231 | item.kind(CompletionItemKind::UnresolvedReference).add_import(import_to_add); | 235 | item.kind(CompletionItemKind::UnresolvedReference).add_import(import_to_add); |
232 | return Some(item.build()); | 236 | return Some(item.build()); |
233 | } | 237 | } |
234 | }; | 238 | }; |
235 | 239 | ||
240 | let local_name = local_name.to_string(); | ||
236 | let mut item = | 241 | let mut item = |
237 | CompletionItem::new(completion_kind, self.ctx.source_range(), local_name.clone()); | 242 | CompletionItem::new(completion_kind, self.ctx.source_range(), local_name.clone()); |
238 | if let ScopeDef::Local(local) = resolution { | 243 | if let hir::ScopeDef::Local(local) = resolution { |
239 | let ty = local.ty(self.ctx.db()); | 244 | let ty = local.ty(self.ctx.db()); |
240 | if !ty.is_unknown() { | 245 | if !ty.is_unknown() { |
241 | item.detail(ty.display(self.ctx.db()).to_string()); | 246 | item.detail(ty.display(self.ctx.db()).to_string()); |
@@ -260,8 +265,10 @@ impl<'a> Render<'a> { | |||
260 | { | 265 | { |
261 | if let Some(cap) = self.ctx.snippet_cap() { | 266 | if let Some(cap) = self.ctx.snippet_cap() { |
262 | let has_non_default_type_params = match resolution { | 267 | let has_non_default_type_params = match resolution { |
263 | ScopeDef::ModuleDef(Adt(it)) => it.has_non_default_type_params(self.ctx.db()), | 268 | hir::ScopeDef::ModuleDef(Adt(it)) => { |
264 | ScopeDef::ModuleDef(TypeAlias(it)) => { | 269 | it.has_non_default_type_params(self.ctx.db()) |
270 | } | ||
271 | hir::ScopeDef::ModuleDef(TypeAlias(it)) => { | ||
265 | it.has_non_default_type_params(self.ctx.db()) | 272 | it.has_non_default_type_params(self.ctx.db()) |
266 | } | 273 | } |
267 | _ => false, | 274 | _ => false, |
@@ -281,26 +288,26 @@ impl<'a> Render<'a> { | |||
281 | Some(item.build()) | 288 | Some(item.build()) |
282 | } | 289 | } |
283 | 290 | ||
284 | fn docs(&self, resolution: &ScopeDef) -> Option<Documentation> { | 291 | fn docs(&self, resolution: &hir::ScopeDef) -> Option<hir::Documentation> { |
285 | use hir::ModuleDef::*; | 292 | use hir::ModuleDef::*; |
286 | match resolution { | 293 | match resolution { |
287 | ScopeDef::ModuleDef(Module(it)) => it.docs(self.ctx.db()), | 294 | hir::ScopeDef::ModuleDef(Module(it)) => it.docs(self.ctx.db()), |
288 | ScopeDef::ModuleDef(Adt(it)) => it.docs(self.ctx.db()), | 295 | hir::ScopeDef::ModuleDef(Adt(it)) => it.docs(self.ctx.db()), |
289 | ScopeDef::ModuleDef(Variant(it)) => it.docs(self.ctx.db()), | 296 | hir::ScopeDef::ModuleDef(Variant(it)) => it.docs(self.ctx.db()), |
290 | ScopeDef::ModuleDef(Const(it)) => it.docs(self.ctx.db()), | 297 | hir::ScopeDef::ModuleDef(Const(it)) => it.docs(self.ctx.db()), |
291 | ScopeDef::ModuleDef(Static(it)) => it.docs(self.ctx.db()), | 298 | hir::ScopeDef::ModuleDef(Static(it)) => it.docs(self.ctx.db()), |
292 | ScopeDef::ModuleDef(Trait(it)) => it.docs(self.ctx.db()), | 299 | hir::ScopeDef::ModuleDef(Trait(it)) => it.docs(self.ctx.db()), |
293 | ScopeDef::ModuleDef(TypeAlias(it)) => it.docs(self.ctx.db()), | 300 | hir::ScopeDef::ModuleDef(TypeAlias(it)) => it.docs(self.ctx.db()), |
294 | _ => None, | 301 | _ => None, |
295 | } | 302 | } |
296 | } | 303 | } |
297 | 304 | ||
298 | fn is_deprecated(&self, resolution: &ScopeDef) -> bool { | 305 | fn is_deprecated(&self, resolution: &hir::ScopeDef) -> bool { |
299 | match resolution { | 306 | match resolution { |
300 | ScopeDef::ModuleDef(it) => self.ctx.is_deprecated_assoc_item(*it), | 307 | hir::ScopeDef::ModuleDef(it) => self.ctx.is_deprecated_assoc_item(*it), |
301 | ScopeDef::MacroDef(it) => self.ctx.is_deprecated(*it), | 308 | hir::ScopeDef::MacroDef(it) => self.ctx.is_deprecated(*it), |
302 | ScopeDef::GenericParam(it) => self.ctx.is_deprecated(*it), | 309 | hir::ScopeDef::GenericParam(it) => self.ctx.is_deprecated(*it), |
303 | ScopeDef::AdtSelfType(it) => self.ctx.is_deprecated(*it), | 310 | hir::ScopeDef::AdtSelfType(it) => self.ctx.is_deprecated(*it), |
304 | _ => false, | 311 | _ => false, |
305 | } | 312 | } |
306 | } | 313 | } |
@@ -327,21 +334,23 @@ fn compute_type_match( | |||
327 | } | 334 | } |
328 | } | 335 | } |
329 | 336 | ||
330 | fn compute_exact_name_match(ctx: &CompletionContext, completion_name: impl Into<String>) -> bool { | 337 | fn compute_exact_name_match(ctx: &CompletionContext, completion_name: &str) -> bool { |
331 | let completion_name = completion_name.into(); | ||
332 | ctx.expected_name.as_ref().map_or(false, |name| name.text() == completion_name) | 338 | ctx.expected_name.as_ref().map_or(false, |name| name.text() == completion_name) |
333 | } | 339 | } |
334 | 340 | ||
335 | fn compute_ref_match(ctx: &CompletionContext, completion_ty: &hir::Type) -> Option<Mutability> { | 341 | fn compute_ref_match( |
342 | ctx: &CompletionContext, | ||
343 | completion_ty: &hir::Type, | ||
344 | ) -> Option<hir::Mutability> { | ||
336 | let expected_type = ctx.expected_type.as_ref()?; | 345 | let expected_type = ctx.expected_type.as_ref()?; |
337 | if completion_ty != expected_type { | 346 | if completion_ty != expected_type { |
338 | let expected_type_without_ref = expected_type.remove_ref()?; | 347 | let expected_type_without_ref = expected_type.remove_ref()?; |
339 | if completion_ty.autoderef(ctx.db).any(|deref_ty| deref_ty == expected_type_without_ref) { | 348 | if completion_ty.autoderef(ctx.db).any(|deref_ty| deref_ty == expected_type_without_ref) { |
340 | cov_mark::hit!(suggest_ref); | 349 | cov_mark::hit!(suggest_ref); |
341 | let mutability = if expected_type.is_mutable_reference() { | 350 | let mutability = if expected_type.is_mutable_reference() { |
342 | Mutability::Mut | 351 | hir::Mutability::Mut |
343 | } else { | 352 | } else { |
344 | Mutability::Shared | 353 | hir::Mutability::Shared |
345 | }; | 354 | }; |
346 | return Some(mutability); | 355 | return Some(mutability); |
347 | }; | 356 | }; |
diff --git a/crates/ide_completion/src/render/enum_variant.rs b/crates/ide_completion/src/render/enum_variant.rs index 0c0c71134..28f056e77 100644 --- a/crates/ide_completion/src/render/enum_variant.rs +++ b/crates/ide_completion/src/render/enum_variant.rs | |||
@@ -1,6 +1,8 @@ | |||
1 | //! Renderer for `enum` variants. | 1 | //! Renderer for `enum` variants. |
2 | 2 | ||
3 | use hir::{HasAttrs, HirDisplay, ModPath, StructKind}; | 3 | use std::iter; |
4 | |||
5 | use hir::{HasAttrs, HirDisplay}; | ||
4 | use ide_db::SymbolKind; | 6 | use ide_db::SymbolKind; |
5 | use itertools::Itertools; | 7 | use itertools::Itertools; |
6 | 8 | ||
@@ -13,9 +15,9 @@ use crate::{ | |||
13 | pub(crate) fn render_variant<'a>( | 15 | pub(crate) fn render_variant<'a>( |
14 | ctx: RenderContext<'a>, | 16 | ctx: RenderContext<'a>, |
15 | import_to_add: Option<ImportEdit>, | 17 | import_to_add: Option<ImportEdit>, |
16 | local_name: Option<String>, | 18 | local_name: Option<hir::Name>, |
17 | variant: hir::Variant, | 19 | variant: hir::Variant, |
18 | path: Option<ModPath>, | 20 | path: Option<hir::ModPath>, |
19 | ) -> CompletionItem { | 21 | ) -> CompletionItem { |
20 | let _p = profile::span("render_enum_variant"); | 22 | let _p = profile::span("render_enum_variant"); |
21 | EnumRender::new(ctx, local_name, variant, path).render(import_to_add) | 23 | EnumRender::new(ctx, local_name, variant, path).render(import_to_add) |
@@ -24,42 +26,45 @@ pub(crate) fn render_variant<'a>( | |||
24 | #[derive(Debug)] | 26 | #[derive(Debug)] |
25 | struct EnumRender<'a> { | 27 | struct EnumRender<'a> { |
26 | ctx: RenderContext<'a>, | 28 | ctx: RenderContext<'a>, |
27 | name: String, | 29 | name: hir::Name, |
28 | variant: hir::Variant, | 30 | variant: hir::Variant, |
29 | path: Option<ModPath>, | 31 | path: Option<hir::ModPath>, |
30 | qualified_name: String, | 32 | qualified_name: hir::ModPath, |
31 | short_qualified_name: String, | 33 | short_qualified_name: hir::ModPath, |
32 | variant_kind: StructKind, | 34 | variant_kind: hir::StructKind, |
33 | } | 35 | } |
34 | 36 | ||
35 | impl<'a> EnumRender<'a> { | 37 | impl<'a> EnumRender<'a> { |
36 | fn new( | 38 | fn new( |
37 | ctx: RenderContext<'a>, | 39 | ctx: RenderContext<'a>, |
38 | local_name: Option<String>, | 40 | local_name: Option<hir::Name>, |
39 | variant: hir::Variant, | 41 | variant: hir::Variant, |
40 | path: Option<ModPath>, | 42 | path: Option<hir::ModPath>, |
41 | ) -> EnumRender<'a> { | 43 | ) -> EnumRender<'a> { |
42 | let name = local_name.unwrap_or_else(|| variant.name(ctx.db()).to_string()); | 44 | let name = local_name.unwrap_or_else(|| variant.name(ctx.db())); |
43 | let variant_kind = variant.kind(ctx.db()); | 45 | let variant_kind = variant.kind(ctx.db()); |
44 | 46 | ||
45 | let (qualified_name, short_qualified_name) = match &path { | 47 | let (qualified_name, short_qualified_name) = match &path { |
46 | Some(path) => { | 48 | Some(path) => { |
47 | let full = path.to_string(); | 49 | let short = hir::ModPath::from_segments( |
48 | let segments = path.segments(); | 50 | hir::PathKind::Plain, |
49 | let short = segments[segments.len().saturating_sub(2)..].iter().join("::"); | 51 | path.segments().iter().skip(path.segments().len().saturating_sub(2)).cloned(), |
50 | (full, short) | 52 | ); |
53 | (path.clone(), short) | ||
51 | } | 54 | } |
52 | None => (name.to_string(), name.to_string()), | 55 | None => ( |
56 | hir::ModPath::from_segments(hir::PathKind::Plain, iter::once(name.clone())), | ||
57 | hir::ModPath::from_segments(hir::PathKind::Plain, iter::once(name.clone())), | ||
58 | ), | ||
53 | }; | 59 | }; |
54 | 60 | ||
55 | EnumRender { ctx, name, variant, path, qualified_name, short_qualified_name, variant_kind } | 61 | EnumRender { ctx, name, variant, path, qualified_name, short_qualified_name, variant_kind } |
56 | } | 62 | } |
57 | |||
58 | fn render(self, import_to_add: Option<ImportEdit>) -> CompletionItem { | 63 | fn render(self, import_to_add: Option<ImportEdit>) -> CompletionItem { |
59 | let mut item = CompletionItem::new( | 64 | let mut item = CompletionItem::new( |
60 | CompletionKind::Reference, | 65 | CompletionKind::Reference, |
61 | self.ctx.source_range(), | 66 | self.ctx.source_range(), |
62 | self.qualified_name.clone(), | 67 | self.qualified_name.to_string(), |
63 | ); | 68 | ); |
64 | item.kind(SymbolKind::Variant) | 69 | item.kind(SymbolKind::Variant) |
65 | .set_documentation(self.variant.docs(self.ctx.db())) | 70 | .set_documentation(self.variant.docs(self.ctx.db())) |
@@ -67,12 +72,16 @@ impl<'a> EnumRender<'a> { | |||
67 | .add_import(import_to_add) | 72 | .add_import(import_to_add) |
68 | .detail(self.detail()); | 73 | .detail(self.detail()); |
69 | 74 | ||
70 | if self.variant_kind == StructKind::Tuple { | 75 | if self.variant_kind == hir::StructKind::Tuple { |
71 | cov_mark::hit!(inserts_parens_for_tuple_enums); | 76 | cov_mark::hit!(inserts_parens_for_tuple_enums); |
72 | let params = Params::Anonymous(self.variant.fields(self.ctx.db()).len()); | 77 | let params = Params::Anonymous(self.variant.fields(self.ctx.db()).len()); |
73 | item.add_call_parens(self.ctx.completion, self.short_qualified_name, params); | 78 | item.add_call_parens( |
79 | self.ctx.completion, | ||
80 | self.short_qualified_name.to_string(), | ||
81 | params, | ||
82 | ); | ||
74 | } else if self.path.is_some() { | 83 | } else if self.path.is_some() { |
75 | item.lookup_by(self.short_qualified_name); | 84 | item.lookup_by(self.short_qualified_name.to_string()); |
76 | } | 85 | } |
77 | 86 | ||
78 | let ty = self.variant.parent_enum(self.ctx.completion.db).ty(self.ctx.completion.db); | 87 | let ty = self.variant.parent_enum(self.ctx.completion.db).ty(self.ctx.completion.db); |
@@ -96,11 +105,11 @@ impl<'a> EnumRender<'a> { | |||
96 | .map(|field| (field.name(self.ctx.db()), field.ty(self.ctx.db()))); | 105 | .map(|field| (field.name(self.ctx.db()), field.ty(self.ctx.db()))); |
97 | 106 | ||
98 | match self.variant_kind { | 107 | match self.variant_kind { |
99 | StructKind::Tuple | StructKind::Unit => format!( | 108 | hir::StructKind::Tuple | hir::StructKind::Unit => format!( |
100 | "({})", | 109 | "({})", |
101 | detail_types.map(|(_, t)| t.display(self.ctx.db()).to_string()).format(", ") | 110 | detail_types.map(|(_, t)| t.display(self.ctx.db()).to_string()).format(", ") |
102 | ), | 111 | ), |
103 | StructKind::Record => format!( | 112 | hir::StructKind::Record => format!( |
104 | "{{ {} }}", | 113 | "{{ {} }}", |
105 | detail_types | 114 | detail_types |
106 | .map(|(n, t)| format!("{}: {}", n, t.display(self.ctx.db()).to_string())) | 115 | .map(|(n, t)| format!("{}: {}", n, t.display(self.ctx.db()).to_string())) |
diff --git a/crates/ide_completion/src/render/function.rs b/crates/ide_completion/src/render/function.rs index d681e2c91..63bd66926 100644 --- a/crates/ide_completion/src/render/function.rs +++ b/crates/ide_completion/src/render/function.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | //! Renderer for function calls. | 1 | //! Renderer for function calls. |
2 | 2 | ||
3 | use hir::{HasSource, HirDisplay, Type}; | 3 | use hir::{HasSource, HirDisplay}; |
4 | use ide_db::SymbolKind; | 4 | use ide_db::SymbolKind; |
5 | use itertools::Itertools; | 5 | use itertools::Itertools; |
6 | use syntax::ast::Fn; | 6 | use syntax::ast::Fn; |
@@ -16,7 +16,7 @@ use crate::{ | |||
16 | pub(crate) fn render_fn<'a>( | 16 | pub(crate) fn render_fn<'a>( |
17 | ctx: RenderContext<'a>, | 17 | ctx: RenderContext<'a>, |
18 | import_to_add: Option<ImportEdit>, | 18 | import_to_add: Option<ImportEdit>, |
19 | local_name: Option<String>, | 19 | local_name: Option<hir::Name>, |
20 | fn_: hir::Function, | 20 | fn_: hir::Function, |
21 | ) -> Option<CompletionItem> { | 21 | ) -> Option<CompletionItem> { |
22 | let _p = profile::span("render_fn"); | 22 | let _p = profile::span("render_fn"); |
@@ -26,7 +26,7 @@ pub(crate) fn render_fn<'a>( | |||
26 | pub(crate) fn render_method<'a>( | 26 | pub(crate) fn render_method<'a>( |
27 | ctx: RenderContext<'a>, | 27 | ctx: RenderContext<'a>, |
28 | import_to_add: Option<ImportEdit>, | 28 | import_to_add: Option<ImportEdit>, |
29 | local_name: Option<String>, | 29 | local_name: Option<hir::Name>, |
30 | fn_: hir::Function, | 30 | fn_: hir::Function, |
31 | ) -> Option<CompletionItem> { | 31 | ) -> Option<CompletionItem> { |
32 | let _p = profile::span("render_method"); | 32 | let _p = profile::span("render_method"); |
@@ -45,11 +45,11 @@ struct FunctionRender<'a> { | |||
45 | impl<'a> FunctionRender<'a> { | 45 | impl<'a> FunctionRender<'a> { |
46 | fn new( | 46 | fn new( |
47 | ctx: RenderContext<'a>, | 47 | ctx: RenderContext<'a>, |
48 | local_name: Option<String>, | 48 | local_name: Option<hir::Name>, |
49 | fn_: hir::Function, | 49 | fn_: hir::Function, |
50 | is_method: bool, | 50 | is_method: bool, |
51 | ) -> Option<FunctionRender<'a>> { | 51 | ) -> Option<FunctionRender<'a>> { |
52 | let name = local_name.unwrap_or_else(|| fn_.name(ctx.db()).to_string()); | 52 | let name = local_name.unwrap_or_else(|| fn_.name(ctx.db())).to_string(); |
53 | let ast_node = fn_.source(ctx.db())?.value; | 53 | let ast_node = fn_.source(ctx.db())?.value; |
54 | 54 | ||
55 | Some(FunctionRender { ctx, name, func: fn_, ast_node, is_method }) | 55 | Some(FunctionRender { ctx, name, func: fn_, ast_node, is_method }) |
@@ -74,7 +74,7 @@ impl<'a> FunctionRender<'a> { | |||
74 | let ret_type = self.func.ret_type(self.ctx.db()); | 74 | let ret_type = self.func.ret_type(self.ctx.db()); |
75 | item.set_relevance(CompletionRelevance { | 75 | item.set_relevance(CompletionRelevance { |
76 | type_match: compute_type_match(self.ctx.completion, &ret_type), | 76 | type_match: compute_type_match(self.ctx.completion, &ret_type), |
77 | exact_name_match: compute_exact_name_match(self.ctx.completion, self.name.clone()), | 77 | exact_name_match: compute_exact_name_match(self.ctx.completion, &self.name), |
78 | ..CompletionRelevance::default() | 78 | ..CompletionRelevance::default() |
79 | }); | 79 | }); |
80 | 80 | ||
@@ -129,7 +129,7 @@ impl<'a> FunctionRender<'a> { | |||
129 | format!("-> {}", ret_ty.display(self.ctx.db())) | 129 | format!("-> {}", ret_ty.display(self.ctx.db())) |
130 | } | 130 | } |
131 | 131 | ||
132 | fn add_arg(&self, arg: &str, ty: &Type) -> String { | 132 | fn add_arg(&self, arg: &str, ty: &hir::Type) -> String { |
133 | if let Some(derefed_ty) = ty.remove_ref() { | 133 | if let Some(derefed_ty) = ty.remove_ref() { |
134 | for (name, local) in self.ctx.completion.locals.iter() { | 134 | for (name, local) in self.ctx.completion.locals.iter() { |
135 | if name == arg && local.ty(self.ctx.db()) == derefed_ty { | 135 | if name == arg && local.ty(self.ctx.db()) == derefed_ty { |
diff --git a/crates/ide_completion/src/render/macro_.rs b/crates/ide_completion/src/render/macro_.rs index b90fd3890..0dfba8acc 100644 --- a/crates/ide_completion/src/render/macro_.rs +++ b/crates/ide_completion/src/render/macro_.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | //! Renderer for macro invocations. | 1 | //! Renderer for macro invocations. |
2 | 2 | ||
3 | use hir::{Documentation, HasSource}; | 3 | use hir::HasSource; |
4 | use ide_db::SymbolKind; | 4 | use ide_db::SymbolKind; |
5 | use syntax::display::macro_label; | 5 | use syntax::display::macro_label; |
6 | 6 | ||
@@ -12,7 +12,7 @@ use crate::{ | |||
12 | pub(crate) fn render_macro<'a>( | 12 | pub(crate) fn render_macro<'a>( |
13 | ctx: RenderContext<'a>, | 13 | ctx: RenderContext<'a>, |
14 | import_to_add: Option<ImportEdit>, | 14 | import_to_add: Option<ImportEdit>, |
15 | name: String, | 15 | name: hir::Name, |
16 | macro_: hir::MacroDef, | 16 | macro_: hir::MacroDef, |
17 | ) -> Option<CompletionItem> { | 17 | ) -> Option<CompletionItem> { |
18 | let _p = profile::span("render_macro"); | 18 | let _p = profile::span("render_macro"); |
@@ -24,13 +24,14 @@ struct MacroRender<'a> { | |||
24 | ctx: RenderContext<'a>, | 24 | ctx: RenderContext<'a>, |
25 | name: String, | 25 | name: String, |
26 | macro_: hir::MacroDef, | 26 | macro_: hir::MacroDef, |
27 | docs: Option<Documentation>, | 27 | docs: Option<hir::Documentation>, |
28 | bra: &'static str, | 28 | bra: &'static str, |
29 | ket: &'static str, | 29 | ket: &'static str, |
30 | } | 30 | } |
31 | 31 | ||
32 | impl<'a> MacroRender<'a> { | 32 | impl<'a> MacroRender<'a> { |
33 | fn new(ctx: RenderContext<'a>, name: String, macro_: hir::MacroDef) -> MacroRender<'a> { | 33 | fn new(ctx: RenderContext<'a>, name: hir::Name, macro_: hir::MacroDef) -> MacroRender<'a> { |
34 | let name = name.to_string(); | ||
34 | let docs = ctx.docs(macro_); | 35 | let docs = ctx.docs(macro_); |
35 | let docs_str = docs.as_ref().map_or("", |s| s.as_str()); | 36 | let docs_str = docs.as_ref().map_or("", |s| s.as_str()); |
36 | let (bra, ket) = guess_macro_braces(&name, docs_str); | 37 | let (bra, ket) = guess_macro_braces(&name, docs_str); |