Skip to content

Commit e0d41bc

Browse files
committed
Auto merge of rust-lang#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)
2 parents ebf4658 + ff667c7 commit e0d41bc

File tree

10 files changed

+96
-69
lines changed

10 files changed

+96
-69
lines changed

crates/ide_completion/src/completions.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,10 +103,14 @@ impl Completions {
103103
item.add_to(self);
104104
}
105105

106-
pub(crate) fn add_nameref_keywords(&mut self, ctx: &CompletionContext) {
106+
pub(crate) fn add_nameref_keywords_with_colon(&mut self, ctx: &CompletionContext) {
107107
["self::", "super::", "crate::"].into_iter().for_each(|kw| self.add_keyword(ctx, kw));
108108
}
109109

110+
pub(crate) fn add_nameref_keywords(&mut self, ctx: &CompletionContext) {
111+
["self", "super", "crate"].into_iter().for_each(|kw| self.add_keyword(ctx, kw));
112+
}
113+
110114
pub(crate) fn add_crate_roots(&mut self, ctx: &CompletionContext) {
111115
ctx.process_all_names(&mut |name, res| match res {
112116
ScopeDef::ModuleDef(hir::ModuleDef::Module(m)) if m.is_crate_root(ctx.db) => {

crates/ide_completion/src/completions/attribute.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ pub(crate) fn complete_attribute(acc: &mut Completions, ctx: &CompletionContext)
107107
acc.add_resolution(ctx, name, def);
108108
}
109109
});
110-
acc.add_nameref_keywords(ctx);
110+
acc.add_nameref_keywords_with_colon(ctx);
111111
}
112112
}
113113

crates/ide_completion/src/completions/attribute/derive.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ pub(crate) fn complete_derive(acc: &mut Completions, ctx: &CompletionContext) {
102102
None => acc.add_resolution(ctx, name, def),
103103
}
104104
});
105-
acc.add_nameref_keywords(ctx);
105+
acc.add_nameref_keywords_with_colon(ctx);
106106
}
107107
}
108108
}

crates/ide_completion/src/completions/mod_.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,16 @@ use ide_db::{
99
};
1010
use rustc_hash::FxHashSet;
1111

12-
use crate::{patterns::ImmediateLocation, CompletionItem};
12+
use crate::{context::NameContext, CompletionItem};
1313

1414
use crate::{context::CompletionContext, Completions};
1515

1616
/// Complete mod declaration, i.e. `mod $0;`
1717
pub(crate) fn complete_mod(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
18-
let mod_under_caret = match &ctx.completion_location {
19-
Some(ImmediateLocation::ModDeclaration(mod_under_caret)) => mod_under_caret,
18+
let mod_under_caret = match &ctx.name_ctx {
19+
Some(NameContext::Module(mod_under_caret)) if mod_under_caret.item_list().is_none() => {
20+
mod_under_caret
21+
}
2022
_ => return None,
2123
};
2224

crates/ide_completion/src/completions/pattern.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ fn pattern_path_completion(
202202
acc.add_resolution(ctx, name, res);
203203
}
204204
});
205-
acc.add_nameref_keywords(ctx);
205+
acc.add_nameref_keywords_with_colon(ctx);
206206
}
207207
}
208208
}

crates/ide_completion/src/completions/unqualified_path.rs

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,21 +17,15 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC
1717
}
1818
match ctx.path_context {
1919
Some(PathCompletionCtx {
20-
kind:
21-
Some(
22-
PathKind::Attr { .. }
23-
| PathKind::Derive
24-
| PathKind::Pat
25-
| PathKind::Use { .. }
26-
| PathKind::Vis { .. },
27-
),
20+
is_absolute_path: false,
21+
qualifier: None,
22+
kind: None | Some(PathKind::Expr | PathKind::Type | PathKind::Mac),
2823
..
29-
}) => return,
30-
Some(PathCompletionCtx { is_absolute_path: false, qualifier: None, .. }) => (),
24+
}) => (),
3125
_ => return,
3226
}
3327

34-
["self", "super", "crate"].into_iter().for_each(|kw| acc.add_keyword(ctx, kw));
28+
acc.add_nameref_keywords(ctx);
3529

3630
match &ctx.completion_location {
3731
Some(ImmediateLocation::ItemList | ImmediateLocation::Trait | ImmediateLocation::Impl) => {

crates/ide_completion/src/completions/use_.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ pub(crate) fn complete_use_tree(acc: &mut Completions, ctx: &CompletionContext)
113113
acc.add_resolution(ctx, name, res);
114114
}
115115
});
116-
acc.add_nameref_keywords(ctx);
116+
acc.add_nameref_keywords_with_colon(ctx);
117117
}
118118
}
119119
}

crates/ide_completion/src/completions/vis.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ pub(crate) fn complete_vis(acc: &mut Completions, ctx: &CompletionContext) {
4545
cov_mark::hit!(kw_completion_in);
4646
acc.add_keyword(ctx, "in");
4747
}
48-
["self", "super", "crate"].into_iter().for_each(|kw| acc.add_keyword(ctx, kw));
48+
acc.add_nameref_keywords(ctx);
4949
}
5050
_ => {}
5151
}

crates/ide_completion/src/context.rs

Lines changed: 75 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,30 @@ pub(super) enum LifetimeContext {
100100
LabelDef,
101101
}
102102

103+
#[derive(Debug)]
104+
#[allow(dead_code)]
105+
pub(super) enum NameContext {
106+
Const,
107+
ConstParam,
108+
Enum,
109+
Function,
110+
IdentPat,
111+
MacroDef,
112+
MacroRules,
113+
/// Fake node
114+
Module(ast::Module),
115+
RecordField,
116+
Rename,
117+
SelfParam,
118+
Static,
119+
Struct,
120+
Trait,
121+
TypeAlias,
122+
TypeParam,
123+
Union,
124+
Variant,
125+
}
126+
103127
#[derive(Clone, Debug, PartialEq, Eq)]
104128
pub(crate) enum ParamKind {
105129
Function(ast::Fn),
@@ -140,6 +164,7 @@ pub(crate) struct CompletionContext<'a> {
140164
pub(super) fake_attribute_under_caret: Option<ast::Attr>,
141165
pub(super) previous_token: Option<SyntaxToken>,
142166

167+
pub(super) name_ctx: Option<NameContext>,
143168
pub(super) lifetime_ctx: Option<LifetimeContext>,
144169
pub(super) pattern_ctx: Option<PatternContext>,
145170
pub(super) path_context: Option<PathCompletionCtx>,
@@ -197,7 +222,7 @@ impl<'a> CompletionContext<'a> {
197222
}
198223

199224
pub(crate) fn expects_variant(&self) -> bool {
200-
matches!(self.completion_location, Some(ImmediateLocation::Variant))
225+
matches!(self.name_ctx, Some(NameContext::Variant))
201226
}
202227

203228
pub(crate) fn expects_non_trait_assoc_item(&self) -> bool {
@@ -221,10 +246,8 @@ impl<'a> CompletionContext<'a> {
221246
}
222247

223248
pub(crate) fn expect_field(&self) -> bool {
224-
matches!(
225-
self.completion_location,
226-
Some(ImmediateLocation::RecordField | ImmediateLocation::TupleField)
227-
)
249+
matches!(self.completion_location, Some(ImmediateLocation::TupleField))
250+
|| matches!(self.name_ctx, Some(NameContext::RecordField))
228251
}
229252

230253
pub(crate) fn has_impl_or_trait_prev_sibling(&self) -> bool {
@@ -254,13 +277,9 @@ impl<'a> CompletionContext<'a> {
254277
)
255278
|| matches!(
256279
self.completion_location,
257-
Some(
258-
ImmediateLocation::ModDeclaration(_)
259-
| ImmediateLocation::RecordPat(_)
260-
| ImmediateLocation::RecordExpr(_)
261-
| ImmediateLocation::Rename
262-
)
280+
Some(ImmediateLocation::RecordPat(_) | ImmediateLocation::RecordExpr(_))
263281
)
282+
|| matches!(self.name_ctx, Some(NameContext::Module(_) | NameContext::Rename))
264283
}
265284

266285
pub(crate) fn expects_expression(&self) -> bool {
@@ -429,6 +448,7 @@ impl<'a> CompletionContext<'a> {
429448
name_syntax: None,
430449
lifetime_ctx: None,
431450
pattern_ctx: None,
451+
name_ctx: None,
432452
completion_location: None,
433453
prev_sibling: None,
434454
fake_attribute_under_caret: None,
@@ -800,7 +820,12 @@ impl<'a> CompletionContext<'a> {
800820
}
801821
}
802822
ast::NameLike::Name(name) => {
803-
self.pattern_ctx = Self::classify_name(&self.sema, original_file, name);
823+
if let Some((name_ctx, pat_ctx)) =
824+
Self::classify_name(&self.sema, original_file, name)
825+
{
826+
self.pattern_ctx = pat_ctx;
827+
self.name_ctx = Some(name_ctx);
828+
}
804829
}
805830
}
806831
}
@@ -833,17 +858,44 @@ impl<'a> CompletionContext<'a> {
833858
_sema: &Semantics<RootDatabase>,
834859
original_file: &SyntaxNode,
835860
name: ast::Name,
836-
) -> Option<PatternContext> {
837-
let bind_pat = name.syntax().parent().and_then(ast::IdentPat::cast)?;
838-
let is_name_in_field_pat = bind_pat
839-
.syntax()
840-
.parent()
841-
.and_then(ast::RecordPatField::cast)
842-
.map_or(false, |pat_field| pat_field.name_ref().is_none());
843-
if is_name_in_field_pat {
844-
return None;
845-
}
846-
Some(pattern_context_for(original_file, bind_pat.into()))
861+
) -> Option<(NameContext, Option<PatternContext>)> {
862+
let parent = name.syntax().parent()?;
863+
let mut pat_ctx = None;
864+
let name_ctx = match_ast! {
865+
match parent {
866+
ast::Const(_) => NameContext::Const,
867+
ast::ConstParam(_) => NameContext::ConstParam,
868+
ast::Enum(_) => NameContext::Enum,
869+
ast::Fn(_) => NameContext::Function,
870+
ast::IdentPat(bind_pat) => {
871+
let is_name_in_field_pat = bind_pat
872+
.syntax()
873+
.parent()
874+
.and_then(ast::RecordPatField::cast)
875+
.map_or(false, |pat_field| pat_field.name_ref().is_none());
876+
if !is_name_in_field_pat {
877+
pat_ctx = Some(pattern_context_for(original_file, bind_pat.into()));
878+
}
879+
880+
NameContext::IdentPat
881+
},
882+
ast::MacroDef(_) => NameContext::MacroDef,
883+
ast::MacroRules(_) => NameContext::MacroRules,
884+
ast::Module(module) => NameContext::Module(module),
885+
ast::RecordField(_) => NameContext::RecordField,
886+
ast::Rename(_) => NameContext::Rename,
887+
ast::SelfParam(_) => NameContext::SelfParam,
888+
ast::Static(_) => NameContext::Static,
889+
ast::Struct(_) => NameContext::Struct,
890+
ast::Trait(_) => NameContext::Trait,
891+
ast::TypeAlias(_) => NameContext::TypeAlias,
892+
ast::TypeParam(_) => NameContext::TypeParam,
893+
ast::Union(_) => NameContext::Union,
894+
ast::Variant(_) => NameContext::Variant,
895+
_ => return None,
896+
}
897+
};
898+
Some((name_ctx, pat_ctx))
847899
}
848900

849901
fn classify_name_ref(

crates/ide_completion/src/patterns.rs

Lines changed: 1 addition & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -41,21 +41,16 @@ pub(crate) enum TypeAnnotation {
4141
/// from which file the nodes are.
4242
#[derive(Clone, Debug, PartialEq, Eq)]
4343
pub(crate) enum ImmediateLocation {
44-
Rename,
4544
Impl,
4645
Trait,
47-
RecordField,
4846
TupleField,
4947
RefExpr,
5048
IdentPat,
5149
StmtList,
5250
ItemList,
5351
TypeBound,
54-
Variant,
5552
/// Original file ast node
5653
TypeAnnotation(TypeAnnotation),
57-
/// Fake file ast node
58-
ModDeclaration(ast::Module),
5954
/// Original file ast node
6055
MethodCall {
6156
receiver: Option<ast::Expr>,
@@ -80,6 +75,7 @@ pub(crate) enum ImmediateLocation {
8075
/// The record pat of the field name we are completing
8176
///
8277
/// Original file ast node
78+
// FIXME: This should be moved to pattern_ctx
8379
RecordPat(ast::RecordPat),
8480
}
8581

@@ -211,17 +207,10 @@ pub(crate) fn determine_location(
211207
let res = match_ast! {
212208
match parent {
213209
ast::IdentPat(_) => ImmediateLocation::IdentPat,
214-
ast::Rename(_) => ImmediateLocation::Rename,
215210
ast::StmtList(_) => ImmediateLocation::StmtList,
216211
ast::SourceFile(_) => ImmediateLocation::ItemList,
217212
ast::ItemList(_) => ImmediateLocation::ItemList,
218213
ast::RefExpr(_) => ImmediateLocation::RefExpr,
219-
ast::Variant(_) => ImmediateLocation::Variant,
220-
ast::RecordField(it) => if it.ty().map_or(false, |it| it.syntax().text_range().contains(offset)) {
221-
return None;
222-
} else {
223-
ImmediateLocation::RecordField
224-
},
225214
ast::RecordExprFieldList(_) => sema
226215
.find_node_at_offset_with_macros(original_file, offset)
227216
.map(ImmediateLocation::RecordExprUpdate)?,
@@ -237,13 +226,6 @@ pub(crate) fn determine_location(
237226
ast::GenericArgList(_) => sema
238227
.find_node_at_offset_with_macros(original_file, offset)
239228
.map(ImmediateLocation::GenericArgList)?,
240-
ast::Module(it) => {
241-
if it.item_list().is_none() {
242-
ImmediateLocation::ModDeclaration(it)
243-
} else {
244-
return None;
245-
}
246-
},
247229
ast::FieldExpr(it) => {
248230
let receiver = find_in_original_file(it.expr(), original_file);
249231
let receiver_is_ambiguous_float_literal = if let Some(ast::Expr::Literal(l)) = &receiver {
@@ -475,13 +457,6 @@ mod tests {
475457
check_location(r"impl A { fn f$0 }", None);
476458
}
477459

478-
#[test]
479-
fn test_record_field_loc() {
480-
check_location(r"struct Foo { f$0 }", ImmediateLocation::RecordField);
481-
check_location(r"struct Foo { f$0 pub f: i32}", ImmediateLocation::RecordField);
482-
check_location(r"struct Foo { pub f: i32, f$0 }", ImmediateLocation::RecordField);
483-
}
484-
485460
#[test]
486461
fn test_block_expr_loc() {
487462
check_location(r"fn my_fn() { let a = 2; f$0 }", ImmediateLocation::StmtList);

0 commit comments

Comments
 (0)