Unnamed repository; edit this file 'description' to name the repository.
Auto merge of #12021 - Veykril:completion-ctx, r=Veykril
internal: Add a `NameContext` to `CompletionContext`, move out some ImmediateLocation variants Continues the completion rewrite I started some time ago (will merge tomorrow after stable since our completion tests still let a lot through)
bors 2022-04-18
parent ebf4658 · parent ff667c7 · commit e0d41bc
-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 b8a904a3a0..36cee48aed 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 c79a9816f4..eb887c3f73 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 4611811539..4f524dd73b 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 fb42e4e72f..7641086ff8 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 00f9bdfb51..a11bcc96fa 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 235d7870c7..94142e274a 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 3f757f9816..94df46efb0 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 ca6f6dff1e..338e003437 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 5f6b8f7db5..9c2e2e75de 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,
@@ -800,7 +820,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);
+ }
}
}
}
@@ -833,17 +858,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 5fd9602b46..6fdec78385 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);