Move CompletionContext::impl_def into corresponding entities

This commit is contained in:
Lukas Wirth 2022-06-18 10:45:53 +02:00
parent 83e8f3ac30
commit c1446a2743
8 changed files with 97 additions and 48 deletions

View file

@ -24,6 +24,7 @@ use std::iter;
use hir::{db::HirDatabase, known, ScopeDef}; use hir::{db::HirDatabase, known, ScopeDef};
use ide_db::SymbolKind; use ide_db::SymbolKind;
use syntax::ast;
use crate::{ use crate::{
context::Visible, context::Visible,
@ -409,11 +410,12 @@ fn enum_variants_with_paths(
acc: &mut Completions, acc: &mut Completions,
ctx: &CompletionContext, ctx: &CompletionContext,
enum_: hir::Enum, enum_: hir::Enum,
impl_: &Option<ast::Impl>,
cb: impl Fn(&mut Completions, &CompletionContext, hir::Variant, hir::ModPath), cb: impl Fn(&mut Completions, &CompletionContext, hir::Variant, hir::ModPath),
) { ) {
let variants = enum_.variants(ctx.db); let variants = enum_.variants(ctx.db);
if let Some(impl_) = ctx.impl_def.as_ref().and_then(|impl_| ctx.sema.to_def(impl_)) { if let Some(impl_) = impl_.as_ref().and_then(|impl_| ctx.sema.to_def(impl_)) {
if impl_.self_ty(ctx.db).as_adt() == Some(hir::Adt::Enum(enum_)) { if impl_.self_ty(ctx.db).as_adt() == Some(hir::Adt::Enum(enum_)) {
for &variant in &variants { for &variant in &variants {
let self_path = hir::ModPath::from_segments( let self_path = hir::ModPath::from_segments(

View file

@ -27,6 +27,7 @@ pub(crate) fn complete_expr_path(
in_condition, in_condition,
ty, ty,
incomplete_let, incomplete_let,
impl_,
) = match path_ctx { ) = match path_ctx {
&PathCompletionCtx { &PathCompletionCtx {
kind: kind:
@ -39,6 +40,7 @@ pub(crate) fn complete_expr_path(
ref ref_expr_parent, ref ref_expr_parent,
ref is_func_update, ref is_func_update,
ref innermost_ret_ty, ref innermost_ret_ty,
ref impl_,
.. ..
}, },
ref qualified, ref qualified,
@ -53,6 +55,7 @@ pub(crate) fn complete_expr_path(
in_condition, in_condition,
innermost_ret_ty, innermost_ret_ty,
incomplete_let, incomplete_let,
impl_,
), ),
_ => return, _ => return,
}; };
@ -181,8 +184,7 @@ pub(crate) fn complete_expr_path(
if let Some(adt) = if let Some(adt) =
ctx.expected_type.as_ref().and_then(|ty| ty.strip_references().as_adt()) ctx.expected_type.as_ref().and_then(|ty| ty.strip_references().as_adt())
{ {
let self_ty = let self_ty = (|| ctx.sema.to_def(impl_.as_ref()?)?.self_ty(ctx.db).as_adt())();
(|| ctx.sema.to_def(ctx.impl_def.as_ref()?)?.self_ty(ctx.db).as_adt())();
let complete_self = self_ty == Some(adt); let complete_self = self_ty == Some(adt);
match adt { match adt {
@ -210,9 +212,15 @@ pub(crate) fn complete_expr_path(
} }
} }
hir::Adt::Enum(e) => { hir::Adt::Enum(e) => {
super::enum_variants_with_paths(acc, ctx, e, |acc, ctx, variant, path| { super::enum_variants_with_paths(
acc.add_qualified_enum_variant(ctx, variant, path) acc,
}); ctx,
e,
impl_,
|acc, ctx, variant, path| {
acc.add_qualified_enum_variant(ctx, variant, path)
},
);
} }
} }
} }

View file

@ -24,8 +24,8 @@ pub(crate) fn complete_fn_param(
ctx: &CompletionContext, ctx: &CompletionContext,
pattern_ctx: &PatternContext, pattern_ctx: &PatternContext,
) -> Option<()> { ) -> Option<()> {
let (param_list, _, param_kind) = match pattern_ctx { let ((param_list, _, param_kind), impl_) = match pattern_ctx {
PatternContext { param_ctx: Some(kind), .. } => kind, PatternContext { param_ctx: Some(kind), impl_, .. } => (kind, impl_),
_ => return None, _ => return None,
}; };
@ -45,7 +45,7 @@ pub(crate) fn complete_fn_param(
match param_kind { match param_kind {
ParamKind::Function(function) => { ParamKind::Function(function) => {
fill_fn_params(ctx, function, param_list, add_new_item_to_acc); fill_fn_params(ctx, function, param_list, impl_, add_new_item_to_acc);
} }
ParamKind::Closure(closure) => { ParamKind::Closure(closure) => {
let stmt_list = closure.syntax().ancestors().find_map(ast::StmtList::cast)?; let stmt_list = closure.syntax().ancestors().find_map(ast::StmtList::cast)?;
@ -62,6 +62,7 @@ fn fill_fn_params(
ctx: &CompletionContext, ctx: &CompletionContext,
function: &ast::Fn, function: &ast::Fn,
param_list: &ast::ParamList, param_list: &ast::ParamList,
impl_: &Option<ast::Impl>,
mut add_new_item_to_acc: impl FnMut(&str), mut add_new_item_to_acc: impl FnMut(&str),
) { ) {
let mut file_params = FxHashMap::default(); let mut file_params = FxHashMap::default();
@ -104,7 +105,7 @@ fn fill_fn_params(
} }
remove_duplicated(&mut file_params, param_list.params()); remove_duplicated(&mut file_params, param_list.params());
let self_completion_items = ["self", "&self", "mut self", "&mut self"]; let self_completion_items = ["self", "&self", "mut self", "&mut self"];
if should_add_self_completions(ctx, param_list) { if should_add_self_completions(param_list, impl_) {
self_completion_items.into_iter().for_each(|self_item| add_new_item_to_acc(self_item)); self_completion_items.into_iter().for_each(|self_item| add_new_item_to_acc(self_item));
} }
@ -155,11 +156,10 @@ fn remove_duplicated(
}) })
} }
fn should_add_self_completions(ctx: &CompletionContext, param_list: &ast::ParamList) -> bool { fn should_add_self_completions(param_list: &ast::ParamList, impl_: &Option<ast::Impl>) -> bool {
let inside_impl = ctx.impl_def.is_some();
let no_params = param_list.params().next().is_none() && param_list.self_param().is_none(); let no_params = param_list.params().next().is_none() && param_list.self_param().is_none();
inside_impl && no_params impl_.is_some() && no_params
} }
fn comma_wrapper(ctx: &CompletionContext) -> Option<(impl Fn(&str) -> String, TextRange)> { fn comma_wrapper(ctx: &CompletionContext) -> Option<(impl Fn(&str) -> String, TextRange)> {

View file

@ -66,7 +66,7 @@ fn add_keywords(acc: &mut Completions, ctx: &CompletionContext, kind: Option<&It
let in_assoc_non_trait_impl = matches!(kind, Some(ItemListKind::Impl | ItemListKind::Trait)); let in_assoc_non_trait_impl = matches!(kind, Some(ItemListKind::Impl | ItemListKind::Trait));
let in_extern_block = matches!(kind, Some(ItemListKind::ExternBlock)); let in_extern_block = matches!(kind, Some(ItemListKind::ExternBlock));
let in_trait = matches!(kind, Some(ItemListKind::Trait)); let in_trait = matches!(kind, Some(ItemListKind::Trait));
let in_trait_impl = matches!(kind, Some(ItemListKind::TraitImpl)); let in_trait_impl = matches!(kind, Some(ItemListKind::TraitImpl(_)));
let in_inherent_impl = matches!(kind, Some(ItemListKind::Impl)); let in_inherent_impl = matches!(kind, Some(ItemListKind::Impl));
let no_qualifiers = ctx.qualifier_ctx.vis_node.is_none(); let no_qualifiers = ctx.qualifier_ctx.vis_node.is_none();
let in_block = matches!(kind, None); let in_block = matches!(kind, None);

View file

@ -81,7 +81,7 @@ pub(crate) fn complete_trait_impl_name(
kind, kind,
replacement_range(ctx, &item), replacement_range(ctx, &item),
// item -> ASSOC_ITEM_LIST -> IMPL // item -> ASSOC_ITEM_LIST -> IMPL
ast::Impl::cast(item.parent()?.parent()?)?, &ast::Impl::cast(item.parent()?.parent()?)?,
); );
Some(()) Some(())
} }
@ -97,7 +97,7 @@ pub(crate) fn complete_trait_impl_name_ref(
kind: kind:
NameRefKind::Path( NameRefKind::Path(
path_ctx @ PathCompletionCtx { path_ctx @ PathCompletionCtx {
kind: PathKind::Item { kind: ItemListKind::TraitImpl }, kind: PathKind::Item { kind: ItemListKind::TraitImpl(Some(impl_)) },
.. ..
}, },
), ),
@ -109,7 +109,7 @@ pub(crate) fn complete_trait_impl_name_ref(
Some(name) => name.syntax().text_range(), Some(name) => name.syntax().text_range(),
None => ctx.source_range(), None => ctx.source_range(),
}, },
ctx.impl_def.clone()?, impl_,
), ),
_ => (), _ => (),
} }
@ -121,10 +121,10 @@ fn complete_trait_impl(
ctx: &CompletionContext, ctx: &CompletionContext,
kind: ImplCompletionKind, kind: ImplCompletionKind,
replacement_range: TextRange, replacement_range: TextRange,
impl_def: ast::Impl, impl_def: &ast::Impl,
) { ) {
if let Some(hir_impl) = ctx.sema.to_def(&impl_def) { if let Some(hir_impl) = ctx.sema.to_def(impl_def) {
get_missing_assoc_items(&ctx.sema, &impl_def).into_iter().for_each(|item| { get_missing_assoc_items(&ctx.sema, impl_def).into_iter().for_each(|item| {
use self::ImplCompletionKind::*; use self::ImplCompletionKind::*;
match (item, kind) { match (item, kind) {
(hir::AssocItem::Function(func), All | Fn) => { (hir::AssocItem::Function(func), All | Fn) => {

View file

@ -51,9 +51,15 @@ pub(crate) fn complete_pattern(
ctx.expected_type.as_ref().and_then(|ty| ty.strip_references().as_adt()) ctx.expected_type.as_ref().and_then(|ty| ty.strip_references().as_adt())
{ {
if refutable || single_variant_enum(e) { if refutable || single_variant_enum(e) {
super::enum_variants_with_paths(acc, ctx, e, |acc, ctx, variant, path| { super::enum_variants_with_paths(
acc.add_qualified_variant_pat(ctx, variant, path); acc,
}); ctx,
e,
&patctx.impl_,
|acc, ctx, variant, path| {
acc.add_qualified_variant_pat(ctx, variant, path);
},
);
} }
} }

View file

@ -98,6 +98,7 @@ pub(super) enum PathKind {
is_func_update: Option<ast::RecordExpr>, is_func_update: Option<ast::RecordExpr>,
self_param: Option<hir::SelfParam>, self_param: Option<hir::SelfParam>,
innermost_ret_ty: Option<hir::Type>, innermost_ret_ty: Option<hir::Type>,
impl_: Option<ast::Impl>,
}, },
Type { Type {
location: TypeLocation, location: TypeLocation,
@ -143,12 +144,12 @@ pub(crate) enum TypeAscriptionTarget {
} }
/// The kind of item list a [`PathKind::Item`] belongs to. /// The kind of item list a [`PathKind::Item`] belongs to.
#[derive(Copy, Clone, Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq)]
pub(super) enum ItemListKind { pub(super) enum ItemListKind {
SourceFile, SourceFile,
Module, Module,
Impl, Impl,
TraitImpl, TraitImpl(Option<ast::Impl>),
Trait, Trait,
ExternBlock, ExternBlock,
} }
@ -179,6 +180,7 @@ pub(super) struct PatternContext {
pub(super) mut_token: Option<SyntaxToken>, pub(super) mut_token: Option<SyntaxToken>,
/// The record pattern this name or ref is a field of /// The record pattern this name or ref is a field of
pub(super) record_pat: Option<ast::RecordPat>, pub(super) record_pat: Option<ast::RecordPat>,
pub(super) impl_: Option<ast::Impl>,
} }
/// The state of the lifetime we are completing. /// The state of the lifetime we are completing.
@ -320,10 +322,6 @@ pub(crate) struct CompletionContext<'a> {
/// The expected type of what we are completing. /// The expected type of what we are completing.
pub(super) expected_type: Option<Type>, pub(super) expected_type: Option<Type>,
/// The parent impl of the cursor position if it exists.
// FIXME: This probably doesn't belong here
pub(super) impl_def: Option<ast::Impl>,
// FIXME: This shouldn't exist // FIXME: This shouldn't exist
pub(super) previous_token: Option<SyntaxToken>, pub(super) previous_token: Option<SyntaxToken>,
@ -497,7 +495,6 @@ impl<'a> CompletionContext<'a> {
module, module,
expected_name: None, expected_name: None,
expected_type: None, expected_type: None,
impl_def: None,
previous_token: None, previous_token: None,
// dummy value, will be overwritten // dummy value, will be overwritten
ident_ctx: IdentContext::UnexpandedAttrTT { fake_attribute_under_caret: None }, ident_ctx: IdentContext::UnexpandedAttrTT { fake_attribute_under_caret: None },

View file

@ -389,16 +389,6 @@ impl<'a> CompletionContext<'a> {
return Some(()); return Some(());
} }
}; };
self.impl_def = self
.sema
.token_ancestors_with_macros(self.token.clone())
.take_while(|it| it.kind() != SyntaxKind::SOURCE_FILE)
.filter_map(ast::Item::cast)
.take(2)
.find_map(|it| match it {
ast::Item::Impl(impl_) => Some(impl_),
_ => None,
});
match name_like { match name_like {
ast::NameLike::Lifetime(lifetime) => { ast::NameLike::Lifetime(lifetime) => {
@ -452,7 +442,7 @@ impl<'a> CompletionContext<'a> {
} }
fn classify_name( fn classify_name(
_sema: &Semantics<RootDatabase>, sema: &Semantics<RootDatabase>,
original_file: &SyntaxNode, original_file: &SyntaxNode,
name: ast::Name, name: ast::Name,
) -> Option<NameContext> { ) -> Option<NameContext> {
@ -464,7 +454,7 @@ impl<'a> CompletionContext<'a> {
ast::Enum(_) => NameKind::Enum, ast::Enum(_) => NameKind::Enum,
ast::Fn(_) => NameKind::Function, ast::Fn(_) => NameKind::Function,
ast::IdentPat(bind_pat) => { ast::IdentPat(bind_pat) => {
let mut pat_ctx = pattern_context_for(original_file, bind_pat.into()); let mut pat_ctx = pattern_context_for(sema, original_file, bind_pat.into());
if let Some(record_field) = ast::RecordPatField::for_field_name(&name) { 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.record_pat = find_node_in_file_compensated(original_file, &record_field.parent_record_pat());
} }
@ -518,6 +508,7 @@ impl<'a> CompletionContext<'a> {
&record_field.parent_record_pat(), &record_field.parent_record_pat(),
), ),
..pattern_context_for( ..pattern_context_for(
sema,
original_file, original_file,
record_field.parent_record_pat().clone().into(), record_field.parent_record_pat().clone().into(),
) )
@ -766,6 +757,7 @@ impl<'a> CompletionContext<'a> {
.parent() .parent()
.and_then(ast::LetStmt::cast) .and_then(ast::LetStmt::cast)
.map_or(false, |it| it.semicolon_token().is_none()); .map_or(false, |it| it.semicolon_token().is_none());
let impl_ = fetch_immediate_impl(sema, original_file, &expr);
PathKind::Expr { PathKind::Expr {
in_block_expr, in_block_expr,
@ -777,6 +769,7 @@ impl<'a> CompletionContext<'a> {
innermost_ret_ty, innermost_ret_ty,
self_param, self_param,
incomplete_let, incomplete_let,
impl_,
} }
}; };
let make_path_kind_type = |ty: ast::Type| { let make_path_kind_type = |ty: ast::Type| {
@ -804,14 +797,14 @@ impl<'a> CompletionContext<'a> {
}, },
ast::TupleStructPat(it) => { ast::TupleStructPat(it) => {
path_ctx.has_call_parens = true; path_ctx.has_call_parens = true;
PathKind::Pat { pat_ctx: pattern_context_for(original_file, it.into())} PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())}
}, },
ast::RecordPat(it) => { ast::RecordPat(it) => {
path_ctx.has_call_parens = true; path_ctx.has_call_parens = true;
PathKind::Pat { pat_ctx: pattern_context_for(original_file, it.into())} PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())}
}, },
ast::PathPat(it) => { ast::PathPat(it) => {
PathKind::Pat { pat_ctx: pattern_context_for(original_file, it.into())} PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())}
}, },
ast::MacroCall(it) => { ast::MacroCall(it) => {
// A macro call in this position is usually a result of parsing recovery, so check that // A macro call in this position is usually a result of parsing recovery, so check that
@ -825,7 +818,7 @@ impl<'a> CompletionContext<'a> {
match_ast! { match_ast! {
match parent { match parent {
ast::MacroExpr(expr) => make_path_kind_expr(expr.into()), ast::MacroExpr(expr) => make_path_kind_expr(expr.into()),
ast::MacroPat(it) => PathKind::Pat { pat_ctx: pattern_context_for(original_file, it.into())}, ast::MacroPat(it) => PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())},
ast::MacroType(ty) => make_path_kind_type(ty.into()), ast::MacroType(ty) => make_path_kind_type(ty.into()),
ast::ItemList(_) => PathKind::Item { kind: ItemListKind::Module }, ast::ItemList(_) => PathKind::Item { kind: ItemListKind::Module },
ast::AssocItemList(_) => PathKind::Item { kind: match parent.parent() { ast::AssocItemList(_) => PathKind::Item { kind: match parent.parent() {
@ -833,7 +826,7 @@ impl<'a> CompletionContext<'a> {
match it { match it {
ast::Trait(_) => ItemListKind::Trait, ast::Trait(_) => ItemListKind::Trait,
ast::Impl(it) => if it.trait_().is_some() { ast::Impl(it) => if it.trait_().is_some() {
ItemListKind::TraitImpl ItemListKind::TraitImpl(find_node_in_file_compensated(original_file, &it))
} else { } else {
ItemListKind::Impl ItemListKind::Impl
}, },
@ -970,7 +963,11 @@ impl<'a> CompletionContext<'a> {
} }
} }
fn pattern_context_for(original_file: &SyntaxNode, pat: ast::Pat) -> PatternContext { fn pattern_context_for(
sema: &Semantics<RootDatabase>,
original_file: &SyntaxNode,
pat: ast::Pat,
) -> PatternContext {
let mut is_param = None; let mut is_param = None;
let (refutability, has_type_ascription) = let (refutability, has_type_ascription) =
pat pat
@ -1011,6 +1008,7 @@ fn pattern_context_for(original_file: &SyntaxNode, pat: ast::Pat) -> PatternCont
ast::Pat::IdentPat(it) => (it.ref_token(), it.mut_token()), ast::Pat::IdentPat(it) => (it.ref_token(), it.mut_token()),
_ => (None, None), _ => (None, None),
}; };
PatternContext { PatternContext {
refutability, refutability,
param_ctx: is_param, param_ctx: is_param,
@ -1019,6 +1017,44 @@ fn pattern_context_for(original_file: &SyntaxNode, pat: ast::Pat) -> PatternCont
mut_token, mut_token,
ref_token, ref_token,
record_pat: None, record_pat: None,
impl_: fetch_immediate_impl(sema, original_file, &pat),
}
}
fn fetch_immediate_impl(
sema: &Semantics<RootDatabase>,
original_file: &SyntaxNode,
node: &impl AstNode,
) -> Option<ast::Impl> {
// FIXME: The fallback here could be done better
let (f, s) = match find_node_in_file_compensated(original_file, node) {
Some(node) => {
let mut items = sema
.ancestors_with_macros(node.syntax().clone())
.filter_map(ast::Item::cast)
.filter(|it| !matches!(it, ast::Item::MacroCall(_)))
.take(2);
(items.next(), items.next())
}
None => {
let mut items = node
.syntax()
.ancestors()
.filter_map(ast::Item::cast)
.filter(|it| !matches!(it, ast::Item::MacroCall(_)))
.take(2);
(items.next(), items.next())
}
};
match f? {
ast::Item::Const(_) | ast::Item::Fn(_) | ast::Item::TypeAlias(_) => (),
ast::Item::Impl(it) => return Some(it),
_ => return None,
}
match s? {
ast::Item::Impl(it) => Some(it),
_ => None,
} }
} }