aboutsummaryrefslogtreecommitdiff
path: root/crates/ide_completion
diff options
context:
space:
mode:
authorLukas Wirth <[email protected]>2021-06-17 12:56:55 +0100
committerLukas Wirth <[email protected]>2021-06-17 12:56:55 +0100
commit2225db2eb48bd8c8fdf399c50652d3f95c851ace (patch)
tree31a419449dff7bb0112ae328de2e4fdec755326d /crates/ide_completion
parente14f5cfff04942f45a4af3b45152df9672b3458a (diff)
Refine `self`, `super` and `crate` completion in use paths
Diffstat (limited to 'crates/ide_completion')
-rw-r--r--crates/ide_completion/src/completions/flyimport.rs2
-rw-r--r--crates/ide_completion/src/completions/keyword.rs29
-rw-r--r--crates/ide_completion/src/completions/qualified_path.rs2
-rw-r--r--crates/ide_completion/src/completions/unqualified_path.rs2
-rw-r--r--crates/ide_completion/src/context.rs26
-rw-r--r--crates/ide_completion/src/patterns.rs7
-rw-r--r--crates/ide_completion/src/render/builder_ext.rs2
-rw-r--r--crates/ide_completion/src/render/macro_.rs2
-rw-r--r--crates/ide_completion/src/tests/use_tree.rs29
9 files changed, 47 insertions, 54 deletions
diff --git a/crates/ide_completion/src/completions/flyimport.rs b/crates/ide_completion/src/completions/flyimport.rs
index 4604feb5d..814c15653 100644
--- a/crates/ide_completion/src/completions/flyimport.rs
+++ b/crates/ide_completion/src/completions/flyimport.rs
@@ -109,7 +109,7 @@ pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext)
109 if !ctx.config.enable_imports_on_the_fly { 109 if !ctx.config.enable_imports_on_the_fly {
110 return None; 110 return None;
111 } 111 }
112 if ctx.use_item_syntax.is_some() 112 if ctx.in_use_tree()
113 || ctx.is_path_disallowed() 113 || ctx.is_path_disallowed()
114 || ctx.expects_item() 114 || ctx.expects_item()
115 || ctx.expects_assoc_item() 115 || ctx.expects_assoc_item()
diff --git a/crates/ide_completion/src/completions/keyword.rs b/crates/ide_completion/src/completions/keyword.rs
index b6f06a44f..9754122a0 100644
--- a/crates/ide_completion/src/completions/keyword.rs
+++ b/crates/ide_completion/src/completions/keyword.rs
@@ -18,17 +18,24 @@ pub(crate) fn complete_use_tree_keyword(acc: &mut Completions, ctx: &CompletionC
18 item 18 item
19 }; 19 };
20 20
21 if ctx.use_item_syntax.is_some() { 21 if ctx.in_use_tree() {
22 let qual = ctx.path_qual(); 22 match &ctx.path_context {
23 if qual.is_none() { 23 Some(PathCompletionContext { qualifier: Some(qual), use_tree_parent, .. }) => {
24 kw_completion("crate::").add_to(acc); 24 if iter::successors(Some(qual.clone()), |p| p.qualifier())
25 } 25 .all(|p| p.segment().and_then(|s| s.super_token()).is_some())
26 kw_completion("self").add_to(acc); 26 {
27 if iter::successors(qual.cloned(), |p| p.qualifier()) 27 kw_completion("super::").add_to(acc);
28 .all(|p| p.segment().and_then(|s| s.super_token()).is_some()) 28 }
29 { 29 if *use_tree_parent {
30 kw_completion("super::").add_to(acc); 30 kw_completion("self").add_to(acc);
31 } 31 }
32 }
33 _ => {
34 kw_completion("crate::").add_to(acc);
35 kw_completion("self::").add_to(acc);
36 kw_completion("super::").add_to(acc);
37 }
38 };
32 } 39 }
33 40
34 // Suggest .await syntax for types that implement Future trait 41 // Suggest .await syntax for types that implement Future trait
diff --git a/crates/ide_completion/src/completions/qualified_path.rs b/crates/ide_completion/src/completions/qualified_path.rs
index 5b49868e4..0597879ac 100644
--- a/crates/ide_completion/src/completions/qualified_path.rs
+++ b/crates/ide_completion/src/completions/qualified_path.rs
@@ -49,7 +49,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
49 hir::PathResolution::Def(hir::ModuleDef::Module(module)) => { 49 hir::PathResolution::Def(hir::ModuleDef::Module(module)) => {
50 let module_scope = module.scope(ctx.db, context_module); 50 let module_scope = module.scope(ctx.db, context_module);
51 for (name, def) in module_scope { 51 for (name, def) in module_scope {
52 if ctx.use_item_syntax.is_some() { 52 if ctx.in_use_tree() {
53 if let hir::ScopeDef::Unknown = def { 53 if let hir::ScopeDef::Unknown = def {
54 if let Some(name_ref) = ctx.name_ref_syntax.as_ref() { 54 if let Some(name_ref) = ctx.name_ref_syntax.as_ref() {
55 if name_ref.syntax().text() == name.to_string().as_str() { 55 if name_ref.syntax().text() == name.to_string().as_str() {
diff --git a/crates/ide_completion/src/completions/unqualified_path.rs b/crates/ide_completion/src/completions/unqualified_path.rs
index 83b9148b3..4bafc1bf8 100644
--- a/crates/ide_completion/src/completions/unqualified_path.rs
+++ b/crates/ide_completion/src/completions/unqualified_path.rs
@@ -25,7 +25,7 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC
25 return; 25 return;
26 } 26 }
27 27
28 if ctx.expects_use_tree() { 28 if ctx.expects_new_use_tree() {
29 // only show modules in a fresh UseTree 29 // only show modules in a fresh UseTree
30 cov_mark::hit!(only_completes_modules_in_import); 30 cov_mark::hit!(only_completes_modules_in_import);
31 ctx.scope.process_all_names(&mut |name, res| { 31 ctx.scope.process_all_names(&mut |name, res| {
diff --git a/crates/ide_completion/src/context.rs b/crates/ide_completion/src/context.rs
index 121909857..c3076f608 100644
--- a/crates/ide_completion/src/context.rs
+++ b/crates/ide_completion/src/context.rs
@@ -43,6 +43,8 @@ pub(crate) struct PathCompletionContext {
43 pub(super) is_trivial_path: bool, 43 pub(super) is_trivial_path: bool,
44 /// If not a trivial path, the prefix (qualifier). 44 /// If not a trivial path, the prefix (qualifier).
45 pub(super) qualifier: Option<ast::Path>, 45 pub(super) qualifier: Option<ast::Path>,
46 /// Whether the qualifier comes from a use tree parent or not
47 pub(super) use_tree_parent: bool,
46 pub(super) kind: Option<PathKind>, 48 pub(super) kind: Option<PathKind>,
47 /// Whether the path segment has type args or not. 49 /// Whether the path segment has type args or not.
48 pub(super) has_type_args: bool, 50 pub(super) has_type_args: bool,
@@ -79,7 +81,6 @@ pub(crate) struct CompletionContext<'a> {
79 /// The parent impl of the cursor position if it exists. 81 /// The parent impl of the cursor position if it exists.
80 pub(super) impl_def: Option<ast::Impl>, 82 pub(super) impl_def: Option<ast::Impl>,
81 pub(super) name_ref_syntax: Option<ast::NameRef>, 83 pub(super) name_ref_syntax: Option<ast::NameRef>,
82 pub(super) use_item_syntax: Option<ast::Use>,
83 84
84 // potentially set if we are completing a lifetime 85 // potentially set if we are completing a lifetime
85 pub(super) lifetime_syntax: Option<ast::Lifetime>, 86 pub(super) lifetime_syntax: Option<ast::Lifetime>,
@@ -151,7 +152,6 @@ impl<'a> CompletionContext<'a> {
151 function_def: None, 152 function_def: None,
152 impl_def: None, 153 impl_def: None,
153 name_ref_syntax: None, 154 name_ref_syntax: None,
154 use_item_syntax: None,
155 lifetime_syntax: None, 155 lifetime_syntax: None,
156 lifetime_param_syntax: None, 156 lifetime_param_syntax: None,
157 lifetime_allowed: false, 157 lifetime_allowed: false,
@@ -264,7 +264,7 @@ impl<'a> CompletionContext<'a> {
264 } 264 }
265 } 265 }
266 266
267 pub(crate) fn expects_use_tree(&self) -> bool { 267 pub(crate) fn expects_new_use_tree(&self) -> bool {
268 matches!(self.completion_location, Some(ImmediateLocation::Use)) 268 matches!(self.completion_location, Some(ImmediateLocation::Use))
269 } 269 }
270 270
@@ -295,6 +295,13 @@ impl<'a> CompletionContext<'a> {
295 matches!(self.completion_location, Some(ImmediateLocation::RecordField)) 295 matches!(self.completion_location, Some(ImmediateLocation::RecordField))
296 } 296 }
297 297
298 pub(crate) fn in_use_tree(&self) -> bool {
299 matches!(
300 self.completion_location,
301 Some(ImmediateLocation::Use) | Some(ImmediateLocation::UseTree)
302 )
303 }
304
298 pub(crate) fn has_impl_or_trait_prev_sibling(&self) -> bool { 305 pub(crate) fn has_impl_or_trait_prev_sibling(&self) -> bool {
299 matches!( 306 matches!(
300 self.prev_sibling, 307 self.prev_sibling,
@@ -578,9 +585,6 @@ impl<'a> CompletionContext<'a> {
578 self.name_ref_syntax = 585 self.name_ref_syntax =
579 find_node_at_offset(original_file, name_ref.syntax().text_range().start()); 586 find_node_at_offset(original_file, name_ref.syntax().text_range().start());
580 587
581 self.use_item_syntax =
582 self.sema.token_ancestors_with_macros(self.token.clone()).find_map(ast::Use::cast);
583
584 self.function_def = self 588 self.function_def = self
585 .sema 589 .sema
586 .token_ancestors_with_macros(self.token.clone()) 590 .token_ancestors_with_macros(self.token.clone())
@@ -600,6 +604,7 @@ impl<'a> CompletionContext<'a> {
600 has_type_args: false, 604 has_type_args: false,
601 can_be_stmt: false, 605 can_be_stmt: false,
602 in_loop_body: false, 606 in_loop_body: false,
607 use_tree_parent: false,
603 kind: None, 608 kind: None,
604 }); 609 });
605 path_ctx.in_loop_body = is_in_loop_body(name_ref.syntax()); 610 path_ctx.in_loop_body = is_in_loop_body(name_ref.syntax());
@@ -627,7 +632,8 @@ impl<'a> CompletionContext<'a> {
627 } 632 }
628 path_ctx.has_type_args = segment.generic_arg_list().is_some(); 633 path_ctx.has_type_args = segment.generic_arg_list().is_some();
629 634
630 if let Some(path) = path_or_use_tree_qualifier(&path) { 635 if let Some((path, use_tree_parent)) = path_or_use_tree_qualifier(&path) {
636 path_ctx.use_tree_parent = use_tree_parent;
631 path_ctx.qualifier = path 637 path_ctx.qualifier = path
632 .segment() 638 .segment()
633 .and_then(|it| { 639 .and_then(|it| {
@@ -681,13 +687,13 @@ fn is_node<N: AstNode>(node: &SyntaxNode) -> bool {
681 } 687 }
682} 688}
683 689
684fn path_or_use_tree_qualifier(path: &ast::Path) -> Option<ast::Path> { 690fn path_or_use_tree_qualifier(path: &ast::Path) -> Option<(ast::Path, bool)> {
685 if let Some(qual) = path.qualifier() { 691 if let Some(qual) = path.qualifier() {
686 return Some(qual); 692 return Some((qual, false));
687 } 693 }
688 let use_tree_list = path.syntax().ancestors().find_map(ast::UseTreeList::cast)?; 694 let use_tree_list = path.syntax().ancestors().find_map(ast::UseTreeList::cast)?;
689 let use_tree = use_tree_list.syntax().parent().and_then(ast::UseTree::cast)?; 695 let use_tree = use_tree_list.syntax().parent().and_then(ast::UseTree::cast)?;
690 use_tree.path() 696 use_tree.path().zip(Some(true))
691} 697}
692 698
693#[cfg(test)] 699#[cfg(test)]
diff --git a/crates/ide_completion/src/patterns.rs b/crates/ide_completion/src/patterns.rs
index 62e4334de..271409c38 100644
--- a/crates/ide_completion/src/patterns.rs
+++ b/crates/ide_completion/src/patterns.rs
@@ -27,6 +27,7 @@ pub(crate) enum ImmediatePrevSibling {
27#[derive(Clone, Debug, PartialEq, Eq)] 27#[derive(Clone, Debug, PartialEq, Eq)]
28pub(crate) enum ImmediateLocation { 28pub(crate) enum ImmediateLocation {
29 Use, 29 Use,
30 UseTree,
30 Impl, 31 Impl,
31 Trait, 32 Trait,
32 RecordField, 33 RecordField,
@@ -180,6 +181,8 @@ pub(crate) fn determine_location(
180 match parent { 181 match parent {
181 ast::IdentPat(_it) => ImmediateLocation::IdentPat, 182 ast::IdentPat(_it) => ImmediateLocation::IdentPat,
182 ast::Use(_it) => ImmediateLocation::Use, 183 ast::Use(_it) => ImmediateLocation::Use,
184 ast::UseTree(_it) => ImmediateLocation::UseTree,
185 ast::UseTreeList(_it) => ImmediateLocation::UseTree,
183 ast::BlockExpr(_it) => ImmediateLocation::BlockExpr, 186 ast::BlockExpr(_it) => ImmediateLocation::BlockExpr,
184 ast::SourceFile(_it) => ImmediateLocation::ItemList, 187 ast::SourceFile(_it) => ImmediateLocation::ItemList,
185 ast::ItemList(_it) => ImmediateLocation::ItemList, 188 ast::ItemList(_it) => ImmediateLocation::ItemList,
@@ -373,8 +376,8 @@ mod tests {
373 fn test_use_loc() { 376 fn test_use_loc() {
374 check_location(r"use f$0", ImmediateLocation::Use); 377 check_location(r"use f$0", ImmediateLocation::Use);
375 check_location(r"use f$0;", ImmediateLocation::Use); 378 check_location(r"use f$0;", ImmediateLocation::Use);
376 check_location(r"use f::{f$0}", None); 379 check_location(r"use f::{f$0}", ImmediateLocation::UseTree);
377 check_location(r"use {f$0}", None); 380 check_location(r"use {f$0}", ImmediateLocation::UseTree);
378 } 381 }
379 382
380 #[test] 383 #[test]
diff --git a/crates/ide_completion/src/render/builder_ext.rs b/crates/ide_completion/src/render/builder_ext.rs
index c54752d30..749dfc665 100644
--- a/crates/ide_completion/src/render/builder_ext.rs
+++ b/crates/ide_completion/src/render/builder_ext.rs
@@ -28,7 +28,7 @@ impl Builder {
28 if !ctx.config.add_call_parenthesis { 28 if !ctx.config.add_call_parenthesis {
29 return false; 29 return false;
30 } 30 }
31 if ctx.use_item_syntax.is_some() { 31 if ctx.in_use_tree() {
32 cov_mark::hit!(no_parens_in_use_item); 32 cov_mark::hit!(no_parens_in_use_item);
33 return false; 33 return false;
34 } 34 }
diff --git a/crates/ide_completion/src/render/macro_.rs b/crates/ide_completion/src/render/macro_.rs
index d5a1f45d3..4d5179c4f 100644
--- a/crates/ide_completion/src/render/macro_.rs
+++ b/crates/ide_completion/src/render/macro_.rs
@@ -69,7 +69,7 @@ impl<'a> MacroRender<'a> {
69 } 69 }
70 70
71 fn needs_bang(&self) -> bool { 71 fn needs_bang(&self) -> bool {
72 self.ctx.completion.use_item_syntax.is_none() 72 !self.ctx.completion.in_use_tree()
73 && !matches!(self.ctx.completion.path_call_kind(), Some(CallKind::Mac)) 73 && !matches!(self.ctx.completion.path_call_kind(), Some(CallKind::Mac))
74 } 74 }
75 75
diff --git a/crates/ide_completion/src/tests/use_tree.rs b/crates/ide_completion/src/tests/use_tree.rs
index 156ca244d..878bc42bf 100644
--- a/crates/ide_completion/src/tests/use_tree.rs
+++ b/crates/ide_completion/src/tests/use_tree.rs
@@ -20,10 +20,9 @@ mod foo {}
20//- /other_crate/lib.rs crate:other_crate 20//- /other_crate/lib.rs crate:other_crate
21// nothing here 21// nothing here
22"#, 22"#,
23 // FIXME: self in this case should also get the colons
24 expect![[r#" 23 expect![[r#"
25 kw crate:: 24 kw crate::
26 kw self 25 kw self::
27 kw super:: 26 kw super::
28 md foo 27 md foo
29 md other_crate 28 md other_crate
@@ -34,13 +33,7 @@ mod foo {}
34#[test] 33#[test]
35fn dont_complete_current_use() { 34fn dont_complete_current_use() {
36 cov_mark::check!(dont_complete_current_use); 35 cov_mark::check!(dont_complete_current_use);
37 // FIXME: self shouldn't be here 36 check(r#"use self::foo$0;"#, expect![[r#""#]]);
38 check(
39 r#"use self::foo$0;"#,
40 expect![[r#"
41 kw self
42 "#]],
43 );
44 check( 37 check(
45 r#" 38 r#"
46mod foo { pub struct S; } 39mod foo { pub struct S; }
@@ -56,7 +49,6 @@ use self::{foo::*, bar$0};
56 49
57#[test] 50#[test]
58fn nested_use_tree() { 51fn nested_use_tree() {
59 // FIXME: self shouldn't be here
60 check( 52 check(
61 r#" 53 r#"
62mod foo { 54mod foo {
@@ -67,7 +59,6 @@ mod foo {
67use foo::{bar::$0} 59use foo::{bar::$0}
68"#, 60"#,
69 expect![[r#" 61 expect![[r#"
70 kw self
71 st FooBar 62 st FooBar
72 "#]], 63 "#]],
73 ); 64 );
@@ -89,7 +80,6 @@ use foo::{$0}
89 80
90#[test] 81#[test]
91fn deeply_nested_use_tree() { 82fn deeply_nested_use_tree() {
92 // FIXME: self shouldn't be here
93 check( 83 check(
94 r#" 84 r#"
95mod foo { 85mod foo {
@@ -102,7 +92,6 @@ mod foo {
102use foo::{bar::{baz::$0}} 92use foo::{bar::{baz::$0}}
103"#, 93"#,
104 expect![[r#" 94 expect![[r#"
105 kw self
106 st FooBarBaz 95 st FooBarBaz
107 "#]], 96 "#]],
108 ); 97 );
@@ -126,7 +115,6 @@ use foo::{bar::{$0}}
126 115
127#[test] 116#[test]
128fn plain_qualified_use_tree() { 117fn plain_qualified_use_tree() {
129 // FIXME: self shouldn't be here
130 check( 118 check(
131 r#" 119 r#"
132use foo::$0 120use foo::$0
@@ -138,7 +126,6 @@ mod foo {
138struct Bar; 126struct Bar;
139"#, 127"#,
140 expect![[r#" 128 expect![[r#"
141 kw self
142 st Foo 129 st Foo
143 "#]], 130 "#]],
144 ); 131 );
@@ -146,7 +133,6 @@ struct Bar;
146 133
147#[test] 134#[test]
148fn self_qualified_use_tree() { 135fn self_qualified_use_tree() {
149 // FIXME: self shouldn't be here
150 check( 136 check(
151 r#" 137 r#"
152use self::$0 138use self::$0
@@ -155,7 +141,6 @@ mod foo {}
155struct Bar; 141struct Bar;
156"#, 142"#,
157 expect![[r#" 143 expect![[r#"
158 kw self
159 md foo 144 md foo
160 st Bar 145 st Bar
161 "#]], 146 "#]],
@@ -164,7 +149,6 @@ struct Bar;
164 149
165#[test] 150#[test]
166fn super_qualified_use_tree() { 151fn super_qualified_use_tree() {
167 // FIXME: self shouldn't be here
168 check( 152 check(
169 r#" 153 r#"
170mod bar { 154mod bar {
@@ -175,7 +159,6 @@ mod foo {}
175struct Bar; 159struct Bar;
176"#, 160"#,
177 expect![[r#" 161 expect![[r#"
178 kw self
179 kw super:: 162 kw super::
180 st Bar 163 st Bar
181 md bar 164 md bar
@@ -186,7 +169,6 @@ struct Bar;
186 169
187#[test] 170#[test]
188fn super_super_qualified_use_tree() { 171fn super_super_qualified_use_tree() {
189 // FIXME: self shouldn't be here
190 check( 172 check(
191 r#" 173 r#"
192mod a { 174mod a {
@@ -198,7 +180,6 @@ mod a {
198} 180}
199"#, 181"#,
200 expect![[r#" 182 expect![[r#"
201 kw self
202 kw super:: 183 kw super::
203 md b 184 md b
204 ct A 185 ct A
@@ -208,7 +189,6 @@ mod a {
208 189
209#[test] 190#[test]
210fn crate_qualified_use_tree() { 191fn crate_qualified_use_tree() {
211 // FIXME: self shouldn't be here
212 check( 192 check(
213 r#" 193 r#"
214use crate::$0 194use crate::$0
@@ -217,7 +197,6 @@ mod foo {}
217struct Bar; 197struct Bar;
218"#, 198"#,
219 expect![[r#" 199 expect![[r#"
220 kw self
221 md foo 200 md foo
222 st Bar 201 st Bar
223 "#]], 202 "#]],
@@ -226,7 +205,6 @@ struct Bar;
226 205
227#[test] 206#[test]
228fn extern_crate_qualified_use_tree() { 207fn extern_crate_qualified_use_tree() {
229 // FIXME: self shouldn't be here
230 check( 208 check(
231 r#" 209 r#"
232//- /lib.rs crate:main deps:other_crate 210//- /lib.rs crate:main deps:other_crate
@@ -236,7 +214,6 @@ pub struct Foo;
236pub mod foo {} 214pub mod foo {}
237"#, 215"#,
238 expect![[r#" 216 expect![[r#"
239 kw self
240 st Foo 217 st Foo
241 md foo 218 md foo
242 "#]], 219 "#]],
@@ -253,7 +230,7 @@ pub use $0;
253"#, 230"#,
254 expect![[r#" 231 expect![[r#"
255 kw crate:: 232 kw crate::
256 kw self 233 kw self::
257 kw super:: 234 kw super::
258 md bar 235 md bar
259 "#]], 236 "#]],