about summary refs log tree commit diff
diff options
context:
space:
mode:
authorLukas Wirth <lukastw97@gmail.com>2022-04-17 21:53:58 +0200
committerLukas Wirth <lukastw97@gmail.com>2022-04-17 21:53:58 +0200
commitff667c72284902fb8aff864c38d3a8ab23ba76fe (patch)
tree15d9c4191de6025702b99304fe26936ad583a747
parenta45a63e57742331d0a449089a47ac30794d008cd (diff)
downloadrust-ff667c72284902fb8aff864c38d3a8ab23ba76fe.tar.gz
rust-ff667c72284902fb8aff864c38d3a8ab23ba76fe.zip
internal: Add a `NameContext` to `CompletionContext`, move out some ImmediateLocation variants
-rw-r--r--crates/ide_completion/src/completions.rs6
-rw-r--r--crates/ide_completion/src/completions/attribute.rs2
-rw-r--r--crates/ide_completion/src/completions/attribute/derive.rs2
-rw-r--r--crates/ide_completion/src/completions/mod_.rs8
-rw-r--r--crates/ide_completion/src/completions/pattern.rs2
-rw-r--r--crates/ide_completion/src/completions/unqualified_path.rs16
-rw-r--r--crates/ide_completion/src/completions/use_.rs2
-rw-r--r--crates/ide_completion/src/completions/vis.rs2
-rw-r--r--crates/ide_completion/src/context.rs98
-rw-r--r--crates/ide_completion/src/patterns.rs27
10 files changed, 96 insertions, 69 deletions
diff --git a/crates/ide_completion/src/completions.rs b/crates/ide_completion/src/completions.rs
index b8a904a3a01..36cee48aed6 100644
--- a/crates/ide_completion/src/completions.rs
+++ b/crates/ide_completion/src/completions.rs
@@ -103,10 +103,14 @@ impl Completions {
         item.add_to(self);
     }
 
-    pub(crate) fn add_nameref_keywords(&mut self, ctx: &CompletionContext) {
+    pub(crate) fn add_nameref_keywords_with_colon(&mut self, ctx: &CompletionContext) {
         ["self::", "super::", "crate::"].into_iter().for_each(|kw| self.add_keyword(ctx, kw));
     }
 
+    pub(crate) fn add_nameref_keywords(&mut self, ctx: &CompletionContext) {
+        ["self", "super", "crate"].into_iter().for_each(|kw| self.add_keyword(ctx, kw));
+    }
+
     pub(crate) fn add_crate_roots(&mut self, ctx: &CompletionContext) {
         ctx.process_all_names(&mut |name, res| match res {
             ScopeDef::ModuleDef(hir::ModuleDef::Module(m)) if m.is_crate_root(ctx.db) => {
diff --git a/crates/ide_completion/src/completions/attribute.rs b/crates/ide_completion/src/completions/attribute.rs
index c79a9816f48..eb887c3f73e 100644
--- a/crates/ide_completion/src/completions/attribute.rs
+++ b/crates/ide_completion/src/completions/attribute.rs
@@ -107,7 +107,7 @@ pub(crate) fn complete_attribute(acc: &mut Completions, ctx: &CompletionContext)
                     acc.add_resolution(ctx, name, def);
                 }
             });
-            acc.add_nameref_keywords(ctx);
+            acc.add_nameref_keywords_with_colon(ctx);
         }
     }
 
diff --git a/crates/ide_completion/src/completions/attribute/derive.rs b/crates/ide_completion/src/completions/attribute/derive.rs
index 4611811539d..4f524dd73bb 100644
--- a/crates/ide_completion/src/completions/attribute/derive.rs
+++ b/crates/ide_completion/src/completions/attribute/derive.rs
@@ -102,7 +102,7 @@ pub(crate) fn complete_derive(acc: &mut Completions, ctx: &CompletionContext) {
                     None => acc.add_resolution(ctx, name, def),
                 }
             });
-            acc.add_nameref_keywords(ctx);
+            acc.add_nameref_keywords_with_colon(ctx);
         }
     }
 }
diff --git a/crates/ide_completion/src/completions/mod_.rs b/crates/ide_completion/src/completions/mod_.rs
index fb42e4e72f7..7641086ff8e 100644
--- a/crates/ide_completion/src/completions/mod_.rs
+++ b/crates/ide_completion/src/completions/mod_.rs
@@ -9,14 +9,16 @@ use ide_db::{
 };
 use rustc_hash::FxHashSet;
 
-use crate::{patterns::ImmediateLocation, CompletionItem};
+use crate::{context::NameContext, CompletionItem};
 
 use crate::{context::CompletionContext, Completions};
 
 /// Complete mod declaration, i.e. `mod $0;`
 pub(crate) fn complete_mod(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
-    let mod_under_caret = match &ctx.completion_location {
-        Some(ImmediateLocation::ModDeclaration(mod_under_caret)) => mod_under_caret,
+    let mod_under_caret = match &ctx.name_ctx {
+        Some(NameContext::Module(mod_under_caret)) if mod_under_caret.item_list().is_none() => {
+            mod_under_caret
+        }
         _ => return None,
     };
 
diff --git a/crates/ide_completion/src/completions/pattern.rs b/crates/ide_completion/src/completions/pattern.rs
index 00f9bdfb51a..a11bcc96fa7 100644
--- a/crates/ide_completion/src/completions/pattern.rs
+++ b/crates/ide_completion/src/completions/pattern.rs
@@ -202,7 +202,7 @@ fn pattern_path_completion(
                     acc.add_resolution(ctx, name, res);
                 }
             });
-            acc.add_nameref_keywords(ctx);
+            acc.add_nameref_keywords_with_colon(ctx);
         }
     }
 }
diff --git a/crates/ide_completion/src/completions/unqualified_path.rs b/crates/ide_completion/src/completions/unqualified_path.rs
index 235d7870c7c..94142e274ae 100644
--- a/crates/ide_completion/src/completions/unqualified_path.rs
+++ b/crates/ide_completion/src/completions/unqualified_path.rs
@@ -17,21 +17,15 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC
     }
     match ctx.path_context {
         Some(PathCompletionCtx {
-            kind:
-                Some(
-                    PathKind::Attr { .. }
-                    | PathKind::Derive
-                    | PathKind::Pat
-                    | PathKind::Use { .. }
-                    | PathKind::Vis { .. },
-                ),
+            is_absolute_path: false,
+            qualifier: None,
+            kind: None | Some(PathKind::Expr | PathKind::Type | PathKind::Mac),
             ..
-        }) => return,
-        Some(PathCompletionCtx { is_absolute_path: false, qualifier: None, .. }) => (),
+        }) => (),
         _ => return,
     }
 
-    ["self", "super", "crate"].into_iter().for_each(|kw| acc.add_keyword(ctx, kw));
+    acc.add_nameref_keywords(ctx);
 
     match &ctx.completion_location {
         Some(ImmediateLocation::ItemList | ImmediateLocation::Trait | ImmediateLocation::Impl) => {
diff --git a/crates/ide_completion/src/completions/use_.rs b/crates/ide_completion/src/completions/use_.rs
index 3f757f98161..94df46efb04 100644
--- a/crates/ide_completion/src/completions/use_.rs
+++ b/crates/ide_completion/src/completions/use_.rs
@@ -113,7 +113,7 @@ pub(crate) fn complete_use_tree(acc: &mut Completions, ctx: &CompletionContext)
                     acc.add_resolution(ctx, name, res);
                 }
             });
-            acc.add_nameref_keywords(ctx);
+            acc.add_nameref_keywords_with_colon(ctx);
         }
     }
 }
diff --git a/crates/ide_completion/src/completions/vis.rs b/crates/ide_completion/src/completions/vis.rs
index ca6f6dff1eb..338e003437b 100644
--- a/crates/ide_completion/src/completions/vis.rs
+++ b/crates/ide_completion/src/completions/vis.rs
@@ -45,7 +45,7 @@ pub(crate) fn complete_vis(acc: &mut Completions, ctx: &CompletionContext) {
                 cov_mark::hit!(kw_completion_in);
                 acc.add_keyword(ctx, "in");
             }
-            ["self", "super", "crate"].into_iter().for_each(|kw| acc.add_keyword(ctx, kw));
+            acc.add_nameref_keywords(ctx);
         }
         _ => {}
     }
diff --git a/crates/ide_completion/src/context.rs b/crates/ide_completion/src/context.rs
index 12747b3ce4a..40e23f4ab5a 100644
--- a/crates/ide_completion/src/context.rs
+++ b/crates/ide_completion/src/context.rs
@@ -100,6 +100,30 @@ pub(super) enum LifetimeContext {
     LabelDef,
 }
 
+#[derive(Debug)]
+#[allow(dead_code)]
+pub(super) enum NameContext {
+    Const,
+    ConstParam,
+    Enum,
+    Function,
+    IdentPat,
+    MacroDef,
+    MacroRules,
+    /// Fake node
+    Module(ast::Module),
+    RecordField,
+    Rename,
+    SelfParam,
+    Static,
+    Struct,
+    Trait,
+    TypeAlias,
+    TypeParam,
+    Union,
+    Variant,
+}
+
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub(crate) enum ParamKind {
     Function(ast::Fn),
@@ -140,6 +164,7 @@ pub(crate) struct CompletionContext<'a> {
     pub(super) fake_attribute_under_caret: Option<ast::Attr>,
     pub(super) previous_token: Option<SyntaxToken>,
 
+    pub(super) name_ctx: Option<NameContext>,
     pub(super) lifetime_ctx: Option<LifetimeContext>,
     pub(super) pattern_ctx: Option<PatternContext>,
     pub(super) path_context: Option<PathCompletionCtx>,
@@ -197,7 +222,7 @@ impl<'a> CompletionContext<'a> {
     }
 
     pub(crate) fn expects_variant(&self) -> bool {
-        matches!(self.completion_location, Some(ImmediateLocation::Variant))
+        matches!(self.name_ctx, Some(NameContext::Variant))
     }
 
     pub(crate) fn expects_non_trait_assoc_item(&self) -> bool {
@@ -221,10 +246,8 @@ impl<'a> CompletionContext<'a> {
     }
 
     pub(crate) fn expect_field(&self) -> bool {
-        matches!(
-            self.completion_location,
-            Some(ImmediateLocation::RecordField | ImmediateLocation::TupleField)
-        )
+        matches!(self.completion_location, Some(ImmediateLocation::TupleField))
+            || matches!(self.name_ctx, Some(NameContext::RecordField))
     }
 
     pub(crate) fn has_impl_or_trait_prev_sibling(&self) -> bool {
@@ -254,13 +277,9 @@ impl<'a> CompletionContext<'a> {
             )
             || matches!(
                 self.completion_location,
-                Some(
-                    ImmediateLocation::ModDeclaration(_)
-                        | ImmediateLocation::RecordPat(_)
-                        | ImmediateLocation::RecordExpr(_)
-                        | ImmediateLocation::Rename
-                )
+                Some(ImmediateLocation::RecordPat(_) | ImmediateLocation::RecordExpr(_))
             )
+            || matches!(self.name_ctx, Some(NameContext::Module(_) | NameContext::Rename))
     }
 
     pub(crate) fn expects_expression(&self) -> bool {
@@ -429,6 +448,7 @@ impl<'a> CompletionContext<'a> {
             name_syntax: None,
             lifetime_ctx: None,
             pattern_ctx: None,
+            name_ctx: None,
             completion_location: None,
             prev_sibling: None,
             fake_attribute_under_caret: None,
@@ -801,7 +821,12 @@ impl<'a> CompletionContext<'a> {
                 }
             }
             ast::NameLike::Name(name) => {
-                self.pattern_ctx = Self::classify_name(&self.sema, original_file, name);
+                if let Some((name_ctx, pat_ctx)) =
+                    Self::classify_name(&self.sema, original_file, name)
+                {
+                    self.pattern_ctx = pat_ctx;
+                    self.name_ctx = Some(name_ctx);
+                }
             }
         }
     }
@@ -834,17 +859,44 @@ impl<'a> CompletionContext<'a> {
         _sema: &Semantics<RootDatabase>,
         original_file: &SyntaxNode,
         name: ast::Name,
-    ) -> Option<PatternContext> {
-        let bind_pat = name.syntax().parent().and_then(ast::IdentPat::cast)?;
-        let is_name_in_field_pat = bind_pat
-            .syntax()
-            .parent()
-            .and_then(ast::RecordPatField::cast)
-            .map_or(false, |pat_field| pat_field.name_ref().is_none());
-        if is_name_in_field_pat {
-            return None;
-        }
-        Some(pattern_context_for(original_file, bind_pat.into()))
+    ) -> Option<(NameContext, Option<PatternContext>)> {
+        let parent = name.syntax().parent()?;
+        let mut pat_ctx = None;
+        let name_ctx = match_ast! {
+            match parent {
+                ast::Const(_) => NameContext::Const,
+                ast::ConstParam(_) => NameContext::ConstParam,
+                ast::Enum(_) => NameContext::Enum,
+                ast::Fn(_) => NameContext::Function,
+                ast::IdentPat(bind_pat) => {
+                    let is_name_in_field_pat = bind_pat
+                        .syntax()
+                        .parent()
+                        .and_then(ast::RecordPatField::cast)
+                        .map_or(false, |pat_field| pat_field.name_ref().is_none());
+                    if !is_name_in_field_pat {
+                        pat_ctx = Some(pattern_context_for(original_file, bind_pat.into()));
+                    }
+
+                    NameContext::IdentPat
+                },
+                ast::MacroDef(_) => NameContext::MacroDef,
+                ast::MacroRules(_) => NameContext::MacroRules,
+                ast::Module(module) => NameContext::Module(module),
+                ast::RecordField(_) => NameContext::RecordField,
+                ast::Rename(_) => NameContext::Rename,
+                ast::SelfParam(_) => NameContext::SelfParam,
+                ast::Static(_) => NameContext::Static,
+                ast::Struct(_) => NameContext::Struct,
+                ast::Trait(_) => NameContext::Trait,
+                ast::TypeAlias(_) => NameContext::TypeAlias,
+                ast::TypeParam(_) => NameContext::TypeParam,
+                ast::Union(_) => NameContext::Union,
+                ast::Variant(_) => NameContext::Variant,
+                _ => return None,
+            }
+        };
+        Some((name_ctx, pat_ctx))
     }
 
     fn classify_name_ref(
diff --git a/crates/ide_completion/src/patterns.rs b/crates/ide_completion/src/patterns.rs
index 5fd9602b46f..6fdec783854 100644
--- a/crates/ide_completion/src/patterns.rs
+++ b/crates/ide_completion/src/patterns.rs
@@ -41,21 +41,16 @@ pub(crate) enum TypeAnnotation {
 /// from which file the nodes are.
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub(crate) enum ImmediateLocation {
-    Rename,
     Impl,
     Trait,
-    RecordField,
     TupleField,
     RefExpr,
     IdentPat,
     StmtList,
     ItemList,
     TypeBound,
-    Variant,
     /// Original file ast node
     TypeAnnotation(TypeAnnotation),
-    /// Fake file ast node
-    ModDeclaration(ast::Module),
     /// Original file ast node
     MethodCall {
         receiver: Option<ast::Expr>,
@@ -80,6 +75,7 @@ pub(crate) enum ImmediateLocation {
     /// The record pat of the field name we are completing
     ///
     /// Original file ast node
+    // FIXME: This should be moved to pattern_ctx
     RecordPat(ast::RecordPat),
 }
 
@@ -211,17 +207,10 @@ pub(crate) fn determine_location(
     let res = match_ast! {
         match parent {
             ast::IdentPat(_) => ImmediateLocation::IdentPat,
-            ast::Rename(_) => ImmediateLocation::Rename,
             ast::StmtList(_) => ImmediateLocation::StmtList,
             ast::SourceFile(_) => ImmediateLocation::ItemList,
             ast::ItemList(_) => ImmediateLocation::ItemList,
             ast::RefExpr(_) => ImmediateLocation::RefExpr,
-            ast::Variant(_) => ImmediateLocation::Variant,
-            ast::RecordField(it) => if it.ty().map_or(false, |it| it.syntax().text_range().contains(offset)) {
-                return None;
-            } else {
-                ImmediateLocation::RecordField
-            },
             ast::RecordExprFieldList(_) => sema
                 .find_node_at_offset_with_macros(original_file, offset)
                 .map(ImmediateLocation::RecordExprUpdate)?,
@@ -237,13 +226,6 @@ pub(crate) fn determine_location(
             ast::GenericArgList(_) => sema
                 .find_node_at_offset_with_macros(original_file, offset)
                 .map(ImmediateLocation::GenericArgList)?,
-            ast::Module(it) => {
-                if it.item_list().is_none() {
-                    ImmediateLocation::ModDeclaration(it)
-                } else {
-                    return None;
-                }
-            },
             ast::FieldExpr(it) => {
                 let receiver = find_in_original_file(it.expr(), original_file);
                 let receiver_is_ambiguous_float_literal = if let Some(ast::Expr::Literal(l)) = &receiver {
@@ -476,13 +458,6 @@ mod tests {
     }
 
     #[test]
-    fn test_record_field_loc() {
-        check_location(r"struct Foo { f$0 }", ImmediateLocation::RecordField);
-        check_location(r"struct Foo { f$0 pub f: i32}", ImmediateLocation::RecordField);
-        check_location(r"struct Foo { pub f: i32, f$0 }", ImmediateLocation::RecordField);
-    }
-
-    #[test]
     fn test_block_expr_loc() {
         check_location(r"fn my_fn() { let a = 2; f$0 }", ImmediateLocation::StmtList);
         check_location(r"fn my_fn() { f$0 f }", ImmediateLocation::StmtList);