Repository: rust-lang/rust-analyzer
Pull request #12161 (2022-05-05 10:08:52)

internal: Lift out item list path completions from (un)qualified_path
cc https://github.com/rust-lang/rust-analyzer/issues/12144

Veykril: @bors r+
bors: :pushpin: Commit d0cd70d8e408360e3022efdd02bbd4f69d57edda has been approved by `Veykril`

<!-- @bors r=Veykril d0cd70d8e408360e3022efdd02bbd4f69d57edda -->
<!-- homu: {"type":"Approved","sha":"d0cd70d8e408360e3022efdd02bbd4f69d57edda","approver":"Veykril"} -->
bors: :hourglass: Testing commit d0cd70d8e408360e3022efdd02bbd4f69d57edda with merge 954dd30714f548b643a826c83873b82899584ce7...
<!-- homu: {"type":"BuildStarted","head_sha":"d0cd70d8e408360e3022efdd02bbd4f69d57edda","merge_sha":"954dd30714f548b643a826c83873b82899584ce7"} -->
bors: :broken_heart: Test failed - [checks-actions](https://github.com/rust-lang/rust-analyzer/runs/6304427804?check_suite_focus=true)
<!-- homu: {"type":"BuildFailed","builder_url":"https://github.com/rust-lang/rust-analyzer/runs/6304427804?check_suite_focus=true","builder_name":"checks-actions"} -->

Patch:
diff --git a/crates/ide-completion/src/completions.rs b/crates/ide-completion/src/completions.rs
index 36cee48aed..f8b1ff7310 100644
--- a/crates/ide-completion/src/completions.rs
+++ b/crates/ide-completion/src/completions.rs
@@ -6,6 +6,7 @@ pub(crate) mod extern_abi;
 pub(crate) mod flyimport;
 pub(crate) mod fn_param;
 pub(crate) mod format_string;
+pub(crate) mod item_list;
 pub(crate) mod keyword;
 pub(crate) mod lifetime;
 pub(crate) mod mod_;
diff --git a/crates/ide-completion/src/completions/item_list.rs b/crates/ide-completion/src/completions/item_list.rs
new file mode 100644
index 0000000000..5ae119c534
--- /dev/null
+++ b/crates/ide-completion/src/completions/item_list.rs
@@ -0,0 +1,48 @@
+//! Completion of paths and keywords at item list position.
+
+use crate::{
+    completions::module_or_fn_macro,
+    context::{PathCompletionCtx, PathKind, PathQualifierCtx},
+    CompletionContext, Completions,
+};
+
+pub(crate) fn complete_item_list(acc: &mut Completions, ctx: &CompletionContext) {
+    let _p = profile::span("complete_unqualified_path");
+    if ctx.is_path_disallowed() || ctx.has_unfinished_impl_or_trait_prev_sibling() {
+        return;
+    }
+
+    let (&is_absolute_path, qualifier) = match &ctx.path_context {
+        Some(PathCompletionCtx {
+            kind: Some(PathKind::Item), is_absolute_path, qualifier, ..
+        }) => (is_absolute_path, qualifier),
+        _ => return,
+    };
+
+    match qualifier {
+        Some(PathQualifierCtx { resolution, is_super_chain, .. }) => {
+            if let Some(hir::PathResolution::Def(hir::ModuleDef::Module(module))) = resolution {
+                for (name, def) in module.scope(ctx.db, Some(ctx.module)) {
+                    if let Some(def) = module_or_fn_macro(ctx.db, def) {
+                        acc.add_resolution(ctx, name, def);
+                    }
+                }
+            }
+
+            if *is_super_chain {
+                acc.add_keyword(ctx, "super::");
+            }
+        }
+        None if is_absolute_path => {
+            acc.add_crate_roots(ctx);
+        }
+        None => {
+            ctx.process_all_names(&mut |name, def| {
+                if let Some(def) = module_or_fn_macro(ctx.db, def) {
+                    acc.add_resolution(ctx, name, def);
+                }
+            });
+            acc.add_nameref_keywords_with_colon(ctx);
+        }
+    }
+}
diff --git a/crates/ide-completion/src/completions/keyword.rs b/crates/ide-completion/src/completions/keyword.rs
index 07cfad81d2..93bd346846 100644
--- a/crates/ide-completion/src/completions/keyword.rs
+++ b/crates/ide-completion/src/completions/keyword.rs
@@ -40,7 +40,7 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
     if let Some(PathKind::Vis { .. }) = ctx.path_kind() {
         return;
     }
-    if ctx.has_impl_or_trait_prev_sibling() {
+    if ctx.has_unfinished_impl_or_trait_prev_sibling() {
         add_keyword("where", "where");
         if ctx.has_impl_prev_sibling() {
             add_keyword("for", "for");
diff --git a/crates/ide-completion/src/completions/pattern.rs b/crates/ide-completion/src/completions/pattern.rs
index 16666eba45..a761eeebb2 100644
--- a/crates/ide-completion/src/completions/pattern.rs
+++ b/crates/ide-completion/src/completions/pattern.rs
@@ -196,12 +196,13 @@ fn pattern_path_completion(
         // qualifier can only be none here if we are in a TuplePat or RecordPat in which case special characters have to follow the path
         None if *is_absolute_path => acc.add_crate_roots(ctx),
         None => {
-            cov_mark::hit!(unqualified_path_only_modules_in_import);
             ctx.process_all_names(&mut |name, res| {
-                if let ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = res {
+                // FIXME: properly filter here
+                if let ScopeDef::ModuleDef(_) = res {
                     acc.add_resolution(ctx, name, res);
                 }
             });
+
             acc.add_nameref_keywords_with_colon(ctx);
         }
     }
diff --git a/crates/ide-completion/src/completions/qualified_path.rs b/crates/ide-completion/src/completions/qualified_path.rs
index ad92820bca..d12f8490bd 100644
--- a/crates/ide-completion/src/completions/qualified_path.rs
+++ b/crates/ide-completion/src/completions/qualified_path.rs
@@ -5,14 +5,12 @@ use ide_db::FxHashSet;
 use syntax::ast;
 
 use crate::{
-    completions::module_or_fn_macro,
     context::{PathCompletionCtx, PathKind},
-    patterns::ImmediateLocation,
     CompletionContext, Completions,
 };
 
 pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionContext) {
-    if ctx.is_path_disallowed() || ctx.has_impl_or_trait_prev_sibling() {
+    if ctx.is_path_disallowed() || ctx.has_unfinished_impl_or_trait_prev_sibling() {
         return;
     }
     if ctx.pattern_ctx.is_some() {
@@ -54,26 +52,13 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
         None => return,
     };
 
-    match ctx.completion_location {
-        Some(ImmediateLocation::ItemList | ImmediateLocation::Trait | ImmediateLocation::Impl) => {
-            if let hir::PathResolution::Def(hir::ModuleDef::Module(module)) = resolution {
-                for (name, def) in module.scope(ctx.db, Some(ctx.module)) {
-                    if let Some(def) = module_or_fn_macro(ctx.db, def) {
-                        acc.add_resolution(ctx, name, def);
-                    }
-                }
-            }
-            return;
-        }
-        _ => (),
-    }
-
     match kind {
         Some(
             PathKind::Pat
             | PathKind::Attr { .. }
             | PathKind::Vis { .. }
             | PathKind::Use
+            | PathKind::Item
             | PathKind::Derive,
         ) => {
             return;
diff --git a/crates/ide-completion/src/completions/snippet.rs b/crates/ide-completion/src/completions/snippet.rs
index c00de6ff50..a1675b896d 100644
--- a/crates/ide-completion/src/completions/snippet.rs
+++ b/crates/ide-completion/src/completions/snippet.rs
@@ -46,7 +46,7 @@ pub(crate) fn complete_item_snippet(acc: &mut Completions, ctx: &CompletionConte
     if !(ctx.expects_item() || ctx.has_block_expr_parent())
         || ctx.previous_token_is(T![unsafe])
         || ctx.path_qual().is_some()
-        || ctx.has_impl_or_trait_prev_sibling()
+        || ctx.has_unfinished_impl_or_trait_prev_sibling()
     {
         return;
     }
diff --git a/crates/ide-completion/src/completions/trait_impl.rs b/crates/ide-completion/src/completions/trait_impl.rs
index 80fbaffd71..d5272be882 100644
--- a/crates/ide-completion/src/completions/trait_impl.rs
+++ b/crates/ide-completion/src/completions/trait_impl.rs
@@ -547,12 +547,7 @@ impl Test for T {
     type Test = fn $0;
 }
 ",
-            expect![[r#"
-                sp Self
-                st T
-                tt Test
-                bt u32
-            "#]],
+            expect![[r#""#]],
         );
     }
 
diff --git a/crates/ide-completion/src/completions/unqualified_path.rs b/crates/ide-completion/src/completions/unqualified_path.rs
index c4d4c5549e..5de602e613 100644
--- a/crates/ide-completion/src/completions/unqualified_path.rs
+++ b/crates/ide-completion/src/completions/unqualified_path.rs
@@ -4,7 +4,6 @@ use hir::ScopeDef;
 use syntax::{ast, AstNode};
 
 use crate::{
-    completions::module_or_fn_macro,
     context::{PathCompletionCtx, PathKind},
     patterns::ImmediateLocation,
     CompletionContext, Completions,
@@ -12,14 +11,15 @@ use crate::{
 
 pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) {
     let _p = profile::span("complete_unqualified_path");
-    if ctx.is_path_disallowed() || ctx.has_impl_or_trait_prev_sibling() {
+    if ctx.is_path_disallowed() || ctx.has_unfinished_impl_or_trait_prev_sibling() {
         return;
     }
-    match ctx.path_context {
+
+    match &ctx.path_context {
         Some(PathCompletionCtx {
             is_absolute_path: false,
             qualifier: None,
-            kind: None | Some(PathKind::Expr | PathKind::Type | PathKind::Item),
+            kind: None | Some(PathKind::Expr | PathKind::Type),
             ..
         }) => (),
         _ => return,
@@ -28,15 +28,6 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC
     acc.add_nameref_keywords(ctx);
 
     match &ctx.completion_location {
-        Some(ImmediateLocation::ItemList | ImmediateLocation::Trait | ImmediateLocation::Impl) => {
-            // only show macros in {Assoc}ItemList
-            ctx.process_all_names(&mut |name, def| {
-                if let Some(def) = module_or_fn_macro(ctx.db, def) {
-                    acc.add_resolution(ctx, name, def);
-                }
-            });
-            return;
-        }
         Some(ImmediateLocation::TypeBound) => {
             ctx.process_all_names(&mut |name, res| {
                 let add_resolution = match res {
diff --git a/crates/ide-completion/src/context.rs b/crates/ide-completion/src/context.rs
index a41d89859a..6682bc56d1 100644
--- a/crates/ide-completion/src/context.rs
+++ b/crates/ide-completion/src/context.rs
@@ -270,13 +270,17 @@ impl<'a> CompletionContext<'a> {
             || matches!(self.name_ctx, Some(NameContext::RecordField))
     }
 
-    pub(crate) fn has_impl_or_trait_prev_sibling(&self) -> bool {
+    /// Whether the cursor is right after a trait or impl header.
+    /// trait Foo ident$0
+    // FIXME: This probably shouldn't exist
+    pub(crate) fn has_unfinished_impl_or_trait_prev_sibling(&self) -> bool {
         matches!(
             self.prev_sibling,
             Some(ImmediatePrevSibling::ImplDefType | ImmediatePrevSibling::TraitDefName)
         )
     }
 
+    // FIXME: This probably shouldn't exist
     pub(crate) fn has_impl_prev_sibling(&self) -> bool {
         matches!(self.prev_sibling, Some(ImmediatePrevSibling::ImplDefType))
     }
@@ -289,6 +293,7 @@ impl<'a> CompletionContext<'a> {
         matches!(self.prev_sibling, Some(ImmediatePrevSibling::IfExpr))
     }
 
+    // FIXME: This shouldn't exist
     pub(crate) fn is_path_disallowed(&self) -> bool {
         self.previous_token_is(T![unsafe])
             || matches!(
diff --git a/crates/ide-completion/src/lib.rs b/crates/ide-completion/src/lib.rs
index 6924ba1db6..473900397a 100644
--- a/crates/ide-completion/src/lib.rs
+++ b/crates/ide-completion/src/lib.rs
@@ -155,6 +155,7 @@ pub fn completions(
     completions::flyimport::import_on_the_fly(&mut acc, &ctx);
     completions::fn_param::complete_fn_param(&mut acc, &ctx);
     completions::format_string::format_string(&mut acc, &ctx);
+    completions::item_list::complete_item_list(&mut acc, &ctx);
     completions::inferred_type(&mut acc, &ctx);
     completions::keyword::complete_expr_keyword(&mut acc, &ctx);
     completions::lifetime::complete_label(&mut acc, &ctx);


Test patch:
diff --git a/crates/ide-completion/src/tests/item.rs b/crates/ide-completion/src/tests/item.rs
index 8f2f8a548a..5d324f0965 100644
--- a/crates/ide-completion/src/tests/item.rs
+++ b/crates/ide-completion/src/tests/item.rs
@@ -95,7 +95,7 @@ fn after_struct_name() {
             ma makro!(…)           macro_rules! makro
             md module
             kw const
-            kw crate
+            kw crate::
             kw enum
             kw extern
             kw fn
@@ -104,10 +104,10 @@ fn after_struct_name() {
             kw pub
             kw pub(crate)
             kw pub(super)
-            kw self
+            kw self::
             kw static
             kw struct
-            kw super
+            kw super::
             kw trait
             kw type
             kw union
@@ -129,7 +129,7 @@ fn after_fn_name() {
             ma makro!(…)           macro_rules! makro
             md module
             kw const
-            kw crate
+            kw crate::
             kw enum
             kw extern
             kw fn
@@ -138,10 +138,10 @@ fn after_fn_name() {
             kw pub
             kw pub(crate)
             kw pub(super)
-            kw self
+            kw self::
             kw static
             kw struct
-            kw super
+            kw super::
             kw trait
             kw type
             kw union
diff --git a/crates/ide-completion/src/tests/item_list.rs b/crates/ide-completion/src/tests/item_list.rs
index 40d3b90da9..f320812936 100644
--- a/crates/ide-completion/src/tests/item_list.rs
+++ b/crates/ide-completion/src/tests/item_list.rs
@@ -15,7 +15,7 @@ fn in_mod_item_list() {
         expect![[r#"
             ma makro!(…)           macro_rules! makro
             kw const
-            kw crate
+            kw crate::
             kw enum
             kw extern
             kw fn
@@ -24,10 +24,10 @@ fn in_mod_item_list() {
             kw pub
             kw pub(crate)
             kw pub(super)
-            kw self
+            kw self::
             kw static
             kw struct
-            kw super
+            kw super::
             kw trait
             kw type
             kw union
@@ -48,7 +48,7 @@ fn in_source_file_item_list() {
             ma makro!(…)           macro_rules! makro
             md module
             kw const
-            kw crate
+            kw crate::
             kw enum
             kw extern
             kw fn
@@ -57,10 +57,10 @@ fn in_source_file_item_list() {
             kw pub
             kw pub(crate)
             kw pub(super)
-            kw self
+            kw self::
             kw static
             kw struct
-            kw super
+            kw super::
             kw trait
             kw type
             kw union
@@ -166,13 +166,13 @@ fn in_impl_assoc_item_list() {
             ma makro!(…)  macro_rules! makro
             md module
             kw const
-            kw crate
+            kw crate::
             kw fn
             kw pub
             kw pub(crate)
             kw pub(super)
-            kw self
-            kw super
+            kw self::
+            kw super::
             kw type
             kw unsafe
         "#]],
@@ -203,10 +203,10 @@ fn in_trait_assoc_item_list() {
             ma makro!(…) macro_rules! makro
             md module
             kw const
-            kw crate
+            kw crate::
             kw fn
-            kw self
-            kw super
+            kw self::
+            kw super::
             kw type
             kw unsafe
         "#]],
@@ -240,13 +240,13 @@ impl Test for () {
             md module
             ta type Type1 =
             kw const
-            kw crate
+            kw crate::
             kw fn
             kw pub
             kw pub(crate)
             kw pub(super)
-            kw self
-            kw super
+            kw self::
+            kw super::
             kw type
             kw unsafe
         "#]],
diff --git a/crates/ide-completion/src/tests/pattern.rs b/crates/ide-completion/src/tests/pattern.rs
index b353883bc7..3ecb2f1637 100644
--- a/crates/ide-completion/src/tests/pattern.rs
+++ b/crates/ide-completion/src/tests/pattern.rs
@@ -394,6 +394,9 @@ fn foo() {
 }
 "#,
         expect![[r#"
+            fn foo()   fn()
+            st Bar
+            bt u32
             kw crate::
             kw self::
             kw super::
@@ -403,19 +406,18 @@ fn foo() {
         r#"
 struct Foo { bar: u32 }
 fn foo() {
-    match Foo { bar: 0 } {
+    match (Foo { bar: 0 }) {
         F$0 { bar } => {}
     }
 }
 "#,
         expect![[r#"
-            fn foo()  fn()
+            fn foo()   fn()
             st Foo
             bt u32
-            kw crate
-            kw return
-            kw self
-            kw super
+            kw crate::
+            kw self::
+            kw super::
         "#]],
     );
     check_empty(