Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide-completion/src/context/analysis.rs')
-rw-r--r--crates/ide-completion/src/context/analysis.rs129
1 files changed, 54 insertions, 75 deletions
diff --git a/crates/ide-completion/src/context/analysis.rs b/crates/ide-completion/src/context/analysis.rs
index 0efeb85207..fc6ee70a0b 100644
--- a/crates/ide-completion/src/context/analysis.rs
+++ b/crates/ide-completion/src/context/analysis.rs
@@ -343,9 +343,9 @@ impl<'a> CompletionContext<'a> {
find_node_at_offset(&file_with_fake_ident, offset)
{
let parent = name_ref.syntax().parent()?;
- let (mut nameref_ctx, _, _) =
- Self::classify_name_ref(&self.sema, &original_file, name_ref, parent);
- if let Some(NameRefKind::Path(path_ctx)) = &mut nameref_ctx.kind {
+ let (mut nameref_ctx, _) =
+ Self::classify_name_ref(&self.sema, &original_file, name_ref, parent)?;
+ if let NameRefKind::Path(path_ctx) = &mut nameref_ctx.kind {
path_ctx.kind = PathKind::Derive {
existing_derives: self
.sema
@@ -427,19 +427,14 @@ impl<'a> CompletionContext<'a> {
}
ast::NameLike::NameRef(name_ref) => {
let parent = name_ref.syntax().parent()?;
- let (nameref_ctx, pat_ctx, qualifier_ctx) =
- Self::classify_name_ref(&self.sema, &original_file, name_ref, parent.clone());
+ let (nameref_ctx, qualifier_ctx) =
+ Self::classify_name_ref(&self.sema, &original_file, name_ref, parent.clone())?;
- if !matches!(nameref_ctx.kind, Some(NameRefKind::Path(_))) {
- // FIXME: Pattern context should probably be part of ident_ctx
- self.pattern_ctx = pat_ctx;
- }
self.qualifier_ctx = qualifier_ctx;
self.ident_ctx = IdentContext::NameRef(nameref_ctx);
}
ast::NameLike::Name(name) => {
- let (name_ctx, pat_ctx) = Self::classify_name(&self.sema, original_file, name)?;
- self.pattern_ctx = pat_ctx;
+ let name_ctx = Self::classify_name(&self.sema, original_file, name)?;
self.ident_ctx = IdentContext::Name(name_ctx);
}
}
@@ -477,9 +472,8 @@ impl<'a> CompletionContext<'a> {
_sema: &Semantics<RootDatabase>,
original_file: &SyntaxNode,
name: ast::Name,
- ) -> Option<(NameContext, Option<PatternContext>)> {
+ ) -> Option<NameContext> {
let parent = name.syntax().parent()?;
- let mut pat_ctx = None;
let kind = match_ast! {
match parent {
ast::Const(_) => NameKind::Const,
@@ -487,15 +481,12 @@ impl<'a> CompletionContext<'a> {
ast::Enum(_) => NameKind::Enum,
ast::Fn(_) => NameKind::Function,
ast::IdentPat(bind_pat) => {
- pat_ctx = Some({
- let mut pat_ctx = pattern_context_for(original_file, bind_pat.into());
- if let Some(record_field) = ast::RecordPatField::for_field_name(&name) {
- pat_ctx.record_pat = find_node_in_file_compensated(original_file, &record_field.parent_record_pat());
- }
- pat_ctx
- });
+ let mut pat_ctx = pattern_context_for(original_file, bind_pat.into());
+ if let Some(record_field) = ast::RecordPatField::for_field_name(&name) {
+ pat_ctx.record_pat = find_node_in_file_compensated(original_file, &record_field.parent_record_pat());
+ }
- NameKind::IdentPat
+ NameKind::IdentPat(pat_ctx)
},
ast::MacroDef(_) => NameKind::MacroDef,
ast::MacroRules(_) => NameKind::MacroRules,
@@ -514,7 +505,7 @@ impl<'a> CompletionContext<'a> {
}
};
let name = find_node_at_offset(&original_file, name.syntax().text_range().start());
- Some((NameContext { name, kind }, pat_ctx))
+ Some(NameContext { name, kind })
}
fn classify_name_ref(
@@ -522,20 +513,19 @@ impl<'a> CompletionContext<'a> {
original_file: &SyntaxNode,
name_ref: ast::NameRef,
parent: SyntaxNode,
- ) -> (NameRefContext, Option<PatternContext>, QualifierCtx) {
+ ) -> Option<(NameRefContext, QualifierCtx)> {
let nameref = find_node_at_offset(&original_file, name_ref.syntax().text_range().start());
- let mut res = (NameRefContext { nameref, kind: None }, None, QualifierCtx::default());
- let (nameref_ctx, pattern_ctx, qualifier_ctx) = &mut res;
+ let make_res =
+ |kind| (NameRefContext { nameref: nameref.clone(), kind }, Default::default());
if let Some(record_field) = ast::RecordExprField::for_field_name(&name_ref) {
- nameref_ctx.kind =
- find_node_in_file_compensated(original_file, &record_field.parent_record_lit())
- .map(NameRefKind::RecordExpr);
- return res;
+ return find_node_in_file_compensated(original_file, &record_field.parent_record_lit())
+ .map(NameRefKind::RecordExpr)
+ .map(make_res);
}
if let Some(record_field) = ast::RecordPatField::for_field_name_ref(&name_ref) {
- *pattern_ctx = Some(PatternContext {
+ let kind = NameRefKind::Pattern(PatternContext {
param_ctx: None,
has_type_ascription: false,
ref_token: None,
@@ -549,7 +539,7 @@ impl<'a> CompletionContext<'a> {
record_field.parent_record_pat().clone().into(),
)
});
- return res;
+ return Some(make_res(kind));
}
let segment = match_ast! {
@@ -564,23 +554,23 @@ impl<'a> CompletionContext<'a> {
},
_ => false,
};
- nameref_ctx.kind = Some(NameRefKind::DotAccess(DotAccess {
+ let kind = NameRefKind::DotAccess(DotAccess {
receiver_ty: receiver.as_ref().and_then(|it| sema.type_of_expr(it)),
kind: DotAccessKind::Field { receiver_is_ambiguous_float_literal },
receiver
- }));
- return res;
+ });
+ return Some(make_res(kind));
},
ast::MethodCallExpr(method) => {
let receiver = find_opt_node_in_file(original_file, method.receiver());
- nameref_ctx.kind = Some(NameRefKind::DotAccess(DotAccess {
+ let kind = NameRefKind::DotAccess(DotAccess {
receiver_ty: receiver.as_ref().and_then(|it| sema.type_of_expr(it)),
kind: DotAccessKind::Method { has_parens: method.arg_list().map_or(false, |it| it.l_paren_token().is_some()) },
receiver
- }));
- return res;
+ });
+ return Some(make_res(kind));
},
- _ => return res,
+ _ => return None,
}
};
@@ -755,52 +745,47 @@ impl<'a> CompletionContext<'a> {
};
// Infer the path kind
- let kind = path.syntax().parent().and_then(|it| {
- match_ast! {
- match it {
- ast::PathType(it) => Some(make_path_kind_type(it.into())),
+ let parent = path.syntax().parent()?;
+ let kind = match_ast! {
+ match parent {
+ ast::PathType(it) => make_path_kind_type(it.into()),
ast::PathExpr(it) => {
if let Some(p) = it.syntax().parent() {
if ast::ExprStmt::can_cast(p.kind()) {
if let Some(kind) = inbetween_body_and_decl_check(p) {
- nameref_ctx.kind = Some(NameRefKind::Keyword(kind));
- return None;
+ return Some(make_res(NameRefKind::Keyword(kind)));
}
}
}
path_ctx.has_call_parens = it.syntax().parent().map_or(false, |it| ast::CallExpr::can_cast(it.kind()));
- Some(make_path_kind_expr(it.into()))
+ make_path_kind_expr(it.into())
},
ast::TupleStructPat(it) => {
path_ctx.has_call_parens = true;
- *pattern_ctx = Some(pattern_context_for(original_file, it.into()));
- Some(PathKind::Pat)
+ PathKind::Pat { pat_ctx: pattern_context_for(original_file, it.into())}
},
ast::RecordPat(it) => {
path_ctx.has_call_parens = true;
- *pattern_ctx = Some(pattern_context_for(original_file, it.into()));
- Some(PathKind::Pat)
+ PathKind::Pat { pat_ctx: pattern_context_for(original_file, it.into())}
},
ast::PathPat(it) => {
- *pattern_ctx = Some(pattern_context_for(original_file, it.into()));
- Some(PathKind::Pat)
+ PathKind::Pat { pat_ctx: pattern_context_for(original_file, it.into())}
},
ast::MacroCall(it) => {
// A macro call in this position is usually a result of parsing recovery, so check that
if let Some(kind) = inbetween_body_and_decl_check(it.syntax().clone()) {
- nameref_ctx.kind = Some(NameRefKind::Keyword(kind));
- return None;
+ return Some(make_res(NameRefKind::Keyword(kind)));
}
path_ctx.has_macro_bang = it.excl_token().is_some();
let parent = it.syntax().parent()?;
// Any path in an item list will be treated as a macro call by the parser
- let res = match_ast! {
+ match_ast! {
match parent {
ast::MacroExpr(expr) => make_path_kind_expr(expr.into()),
- ast::MacroPat(_) => PathKind::Pat,
+ ast::MacroPat(it) => PathKind::Pat { pat_ctx: pattern_context_for(original_file, it.into())},
ast::MacroType(ty) => make_path_kind_type(ty.into()),
ast::ItemList(_) => PathKind::Item { kind: ItemListKind::Module },
ast::AssocItemList(_) => PathKind::Item { kind: match parent.parent() {
@@ -821,10 +806,9 @@ impl<'a> CompletionContext<'a> {
ast::SourceFile(_) => PathKind::Item { kind: ItemListKind::SourceFile },
_ => return None,
}
- };
- Some(res)
+ }
},
- ast::Meta(meta) => (|| {
+ ast::Meta(meta) => {
let attr = meta.parent_attr()?;
let kind = attr.kind();
let attached = attr.syntax().parent()?;
@@ -835,24 +819,19 @@ impl<'a> CompletionContext<'a> {
} else {
Some(attached.kind())
};
- Some(PathKind::Attr {
+ PathKind::Attr {
kind,
annotated_item_kind,
- })
- })(),
- ast::Visibility(it) => Some(PathKind::Vis { has_in_token: it.in_token().is_some() }),
- ast::UseTree(_) => Some(PathKind::Use),
+ }
+ },
+ ast::Visibility(it) => PathKind::Vis { has_in_token: it.in_token().is_some() },
+ ast::UseTree(_) => PathKind::Use,
_ => return None,
- }
+
}
- });
+ };
- match kind {
- Some(kind) => path_ctx.kind = kind,
- // unresolved path kind, so this isn't really a path we should be completing,
- // just some random identifier which might be in keyword position
- None => return res,
- }
+ path_ctx.kind = kind;
path_ctx.has_type_args = segment.generic_arg_list().is_some();
// calculate the qualifier context
@@ -893,6 +872,7 @@ impl<'a> CompletionContext<'a> {
}
}
+ let mut qualifier_ctx = QualifierCtx::default();
if path_ctx.is_trivial_path() {
// fetch the full expression that may have qualifiers attached to it
let top_node = match path_ctx.kind {
@@ -937,8 +917,8 @@ impl<'a> CompletionContext<'a> {
if ![T![;], T!['}'], T!['{']].contains(&prev.kind()) {
// This was inferred to be an item position path, but it seems
// to be part of some other broken node which leaked into an item
- // list, so return without setting the path context
- return res;
+ // list
+ return None;
}
}
}
@@ -946,8 +926,7 @@ impl<'a> CompletionContext<'a> {
}
}
}
- nameref_ctx.kind = Some(NameRefKind::Path(path_ctx));
- res
+ Some((NameRefContext { nameref, kind: NameRefKind::Path(path_ctx) }, qualifier_ctx))
}
}