Move trait_impl completion analysis into CompletionContext
This commit is contained in:
parent
2a60b8452e
commit
98c0578f15
@ -16,7 +16,6 @@ pub(crate) mod pattern;
|
||||
pub(crate) mod postfix;
|
||||
pub(crate) mod record;
|
||||
pub(crate) mod snippet;
|
||||
pub(crate) mod trait_impl;
|
||||
pub(crate) mod r#type;
|
||||
pub(crate) mod use_;
|
||||
pub(crate) mod vis;
|
||||
|
@ -6,9 +6,16 @@ use crate::{
|
||||
CompletionContext, Completions,
|
||||
};
|
||||
|
||||
mod trait_impl;
|
||||
|
||||
pub(crate) fn complete_item_list(acc: &mut Completions, ctx: &CompletionContext) {
|
||||
let _p = profile::span("complete_item_list");
|
||||
|
||||
if let Some(_) = ctx.name_ctx() {
|
||||
trait_impl::complete_trait_impl(acc, ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
let (&is_absolute_path, path_qualifier, kind) = match ctx.path_context() {
|
||||
Some(PathCompletionCtx {
|
||||
kind: PathKind::Item { kind },
|
||||
@ -24,7 +31,6 @@ pub(crate) fn complete_item_list(acc: &mut Completions, ctx: &CompletionContext)
|
||||
}) => (is_absolute_path, qualifier, None),
|
||||
_ => return,
|
||||
};
|
||||
let mut add_keyword = |kw, snippet| acc.add_keyword_snippet(ctx, kw, snippet);
|
||||
|
||||
let in_item_list = matches!(kind, Some(ItemListKind::SourceFile | ItemListKind::Module) | None);
|
||||
let in_assoc_non_trait_impl = matches!(kind, Some(ItemListKind::Impl | ItemListKind::Trait));
|
||||
@ -35,6 +41,11 @@ pub(crate) fn complete_item_list(acc: &mut Completions, ctx: &CompletionContext)
|
||||
let no_qualifiers = ctx.qualifier_ctx.vis_node.is_none();
|
||||
let in_block = matches!(kind, None);
|
||||
|
||||
if in_trait_impl {
|
||||
trait_impl::complete_trait_impl(acc, ctx);
|
||||
}
|
||||
let mut add_keyword = |kw, snippet| acc.add_keyword_snippet(ctx, kw, snippet);
|
||||
|
||||
'block: loop {
|
||||
if ctx.is_non_trivial_path() {
|
||||
break 'block;
|
||||
|
@ -43,6 +43,7 @@ use syntax::{
|
||||
use text_edit::TextEdit;
|
||||
|
||||
use crate::{
|
||||
context::{ItemListKind, NameContext, NameKind, NameRefContext, PathCompletionCtx, PathKind},
|
||||
CompletionContext, CompletionItem, CompletionItemKind, CompletionRelevance, Completions,
|
||||
};
|
||||
|
||||
@ -54,7 +55,6 @@ enum ImplCompletionKind {
|
||||
Const,
|
||||
}
|
||||
|
||||
// FIXME: Make this a submodule of [`item_list`]
|
||||
pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) {
|
||||
if let Some((kind, replacement_range, impl_def)) = completion_match(ctx) {
|
||||
if let Some(hir_impl) = ctx.sema.to_def(&impl_def) {
|
||||
@ -77,74 +77,48 @@ pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: This should be lifted out so that we can do proper smart item keyword completions
|
||||
fn completion_match(ctx: &CompletionContext) -> Option<(ImplCompletionKind, TextRange, ast::Impl)> {
|
||||
let token = ctx.token.clone();
|
||||
|
||||
// For keyword without name like `impl .. { fn $0 }`, the current position is inside
|
||||
// the whitespace token, which is outside `FN` syntax node.
|
||||
// We need to follow the previous token in this case.
|
||||
let mut token_before_ws = token.clone();
|
||||
if token.kind() == SyntaxKind::WHITESPACE {
|
||||
token_before_ws = token.prev_token()?;
|
||||
}
|
||||
|
||||
let parent_kind = token_before_ws.parent().map_or(SyntaxKind::EOF, |it| it.kind());
|
||||
if token.parent().map(|n| n.kind()) == Some(SyntaxKind::ASSOC_ITEM_LIST)
|
||||
&& matches!(
|
||||
token_before_ws.kind(),
|
||||
SyntaxKind::SEMICOLON | SyntaxKind::R_CURLY | SyntaxKind::L_CURLY
|
||||
)
|
||||
if let Some(NameContext { name, kind, .. }) = ctx.name_ctx() {
|
||||
let kind = match kind {
|
||||
NameKind::Const => ImplCompletionKind::Const,
|
||||
NameKind::Function => ImplCompletionKind::Fn,
|
||||
NameKind::TypeAlias => ImplCompletionKind::TypeAlias,
|
||||
_ => return None,
|
||||
};
|
||||
let item = match name {
|
||||
Some(name) => name.syntax().parent(),
|
||||
None => {
|
||||
if token.kind() == SyntaxKind::WHITESPACE { token.prev_token()? } else { token }
|
||||
.parent()
|
||||
}
|
||||
}?;
|
||||
return Some((
|
||||
kind,
|
||||
replacement_range(ctx, &item),
|
||||
// item -> ASSOC_ITEM_LIST -> IMPL
|
||||
ast::Impl::cast(item.parent()?.parent()?)?,
|
||||
));
|
||||
} else if let Some(NameRefContext {
|
||||
nameref,
|
||||
path_ctx:
|
||||
Some(PathCompletionCtx { kind: PathKind::Item { kind: ItemListKind::TraitImpl }, .. }),
|
||||
..
|
||||
}) = ctx.nameref_ctx()
|
||||
{
|
||||
let impl_def = ast::Impl::cast(token.parent()?.parent()?)?;
|
||||
let kind = ImplCompletionKind::All;
|
||||
let replacement_range = TextRange::empty(ctx.position.offset);
|
||||
Some((kind, replacement_range, impl_def))
|
||||
} else {
|
||||
let impl_item_offset = match token_before_ws.kind() {
|
||||
// `impl .. { const $0 }`
|
||||
// ERROR 0
|
||||
// CONST_KW <- *
|
||||
T![const] => 0,
|
||||
// `impl .. { fn/type $0 }`
|
||||
// FN/TYPE_ALIAS 0
|
||||
// FN_KW <- *
|
||||
T![fn] | T![type] => 0,
|
||||
// `impl .. { fn/type/const foo$0 }`
|
||||
// FN/TYPE_ALIAS/CONST 1
|
||||
// NAME 0
|
||||
// IDENT <- *
|
||||
SyntaxKind::IDENT if parent_kind == SyntaxKind::NAME => 1,
|
||||
// `impl .. { foo$0 }`
|
||||
// MACRO_CALL 3
|
||||
// PATH 2
|
||||
// PATH_SEGMENT 1
|
||||
// NAME_REF 0
|
||||
// IDENT <- *
|
||||
SyntaxKind::IDENT if parent_kind == SyntaxKind::NAME_REF => 3,
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
let impl_item = token_before_ws.ancestors().nth(impl_item_offset)?;
|
||||
// Must directly belong to an impl block.
|
||||
// IMPL
|
||||
// ASSOC_ITEM_LIST
|
||||
// <item>
|
||||
let impl_def = ast::Impl::cast(impl_item.parent()?.parent()?)?;
|
||||
let kind = match impl_item.kind() {
|
||||
// `impl ... { const $0 fn/type/const }`
|
||||
_ if token_before_ws.kind() == T![const] => ImplCompletionKind::Const,
|
||||
SyntaxKind::CONST | SyntaxKind::ERROR => ImplCompletionKind::Const,
|
||||
SyntaxKind::TYPE_ALIAS => ImplCompletionKind::TypeAlias,
|
||||
SyntaxKind::FN => ImplCompletionKind::Fn,
|
||||
SyntaxKind::MACRO_CALL => ImplCompletionKind::All,
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
let replacement_range = replacement_range(ctx, &impl_item);
|
||||
|
||||
Some((kind, replacement_range, impl_def))
|
||||
if !ctx.is_non_trivial_path() {
|
||||
return Some((
|
||||
ImplCompletionKind::All,
|
||||
match nameref {
|
||||
Some(name) => name.syntax().text_range(),
|
||||
None => TextRange::empty(ctx.position.offset),
|
||||
},
|
||||
ctx.impl_def.clone()?,
|
||||
));
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn add_function_impl(
|
@ -101,8 +101,6 @@ pub(crate) struct PathCompletionCtx {
|
||||
pub(super) is_absolute_path: bool,
|
||||
/// The qualifier of the current path if it exists.
|
||||
pub(super) qualifier: Option<PathQualifierCtx>,
|
||||
#[allow(dead_code)]
|
||||
// FIXME: use this
|
||||
/// The parent of the path we are completing.
|
||||
pub(super) parent: Option<ast::Path>,
|
||||
pub(super) kind: PathKind,
|
||||
@ -110,6 +108,23 @@ pub(crate) struct PathCompletionCtx {
|
||||
pub(super) has_type_args: bool,
|
||||
}
|
||||
|
||||
impl PathCompletionCtx {
|
||||
fn is_trivial_path(&self) -> bool {
|
||||
matches!(
|
||||
self,
|
||||
PathCompletionCtx {
|
||||
has_call_parens: false,
|
||||
has_macro_bang: false,
|
||||
is_absolute_path: false,
|
||||
qualifier: None,
|
||||
parent: None,
|
||||
has_type_args: false,
|
||||
..
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct PathQualifierCtx {
|
||||
pub(crate) path: ast::Path,
|
||||
@ -365,13 +380,7 @@ impl<'a> CompletionContext<'a> {
|
||||
}
|
||||
|
||||
pub(crate) fn is_non_trivial_path(&self) -> bool {
|
||||
matches!(
|
||||
self.path_context(),
|
||||
Some(
|
||||
PathCompletionCtx { is_absolute_path: true, .. }
|
||||
| PathCompletionCtx { qualifier: Some(_), .. }
|
||||
)
|
||||
)
|
||||
self.path_context().as_ref().map_or(false, |it| !it.is_trivial_path())
|
||||
}
|
||||
|
||||
pub(crate) fn path_qual(&self) -> Option<&ast::Path> {
|
||||
@ -872,7 +881,7 @@ impl<'a> CompletionContext<'a> {
|
||||
find_node_at_offset(&file_with_fake_ident, offset)
|
||||
{
|
||||
let parent = name_ref.syntax().parent()?;
|
||||
let (mut nameref_ctx, _) =
|
||||
let (mut nameref_ctx, _, _) =
|
||||
Self::classify_name_ref(&self.sema, &original_file, name_ref, parent);
|
||||
if let Some(path_ctx) = &mut nameref_ctx.path_ctx {
|
||||
path_ctx.kind = PathKind::Derive;
|
||||
@ -920,13 +929,23 @@ impl<'a> CompletionContext<'a> {
|
||||
self.impl_def = self
|
||||
.sema
|
||||
.token_ancestors_with_macros(self.token.clone())
|
||||
.take_while(|it| it.kind() != SOURCE_FILE && it.kind() != MODULE)
|
||||
.find_map(ast::Impl::cast);
|
||||
.take_while(|it| it.kind() != SOURCE_FILE)
|
||||
.filter_map(ast::Item::cast)
|
||||
.take(2)
|
||||
.find_map(|it| match it {
|
||||
ast::Item::Impl(impl_) => Some(impl_),
|
||||
_ => None,
|
||||
});
|
||||
self.function_def = self
|
||||
.sema
|
||||
.token_ancestors_with_macros(self.token.clone())
|
||||
.take_while(|it| it.kind() != SOURCE_FILE && it.kind() != MODULE)
|
||||
.find_map(ast::Fn::cast);
|
||||
.filter_map(ast::Item::cast)
|
||||
.take(2)
|
||||
.find_map(|it| match it {
|
||||
ast::Item::Fn(fn_) => Some(fn_),
|
||||
_ => None,
|
||||
});
|
||||
|
||||
match name_like {
|
||||
ast::NameLike::Lifetime(lifetime) => {
|
||||
@ -938,50 +957,10 @@ impl<'a> CompletionContext<'a> {
|
||||
}
|
||||
ast::NameLike::NameRef(name_ref) => {
|
||||
let parent = name_ref.syntax().parent()?;
|
||||
let (nameref_ctx, pat_ctx) =
|
||||
let (nameref_ctx, pat_ctx, qualifier_ctx) =
|
||||
Self::classify_name_ref(&self.sema, &original_file, name_ref, parent.clone());
|
||||
|
||||
// Extract qualifiers
|
||||
if let Some(path_ctx) = &nameref_ctx.path_ctx {
|
||||
if path_ctx.qualifier.is_none() {
|
||||
let top = match path_ctx.kind {
|
||||
PathKind::Expr { in_block_expr: true, .. } => parent
|
||||
.ancestors()
|
||||
.find(|it| ast::PathExpr::can_cast(it.kind()))
|
||||
.and_then(|p| {
|
||||
let parent = p.parent()?;
|
||||
if ast::StmtList::can_cast(parent.kind()) {
|
||||
Some(p)
|
||||
} else if ast::ExprStmt::can_cast(parent.kind()) {
|
||||
Some(parent)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}),
|
||||
PathKind::Item { .. } => {
|
||||
parent.ancestors().find(|it| ast::MacroCall::can_cast(it.kind()))
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
if let Some(top) = top {
|
||||
if let Some(NodeOrToken::Node(error_node)) =
|
||||
syntax::algo::non_trivia_sibling(
|
||||
top.into(),
|
||||
syntax::Direction::Prev,
|
||||
)
|
||||
{
|
||||
if error_node.kind() == SyntaxKind::ERROR {
|
||||
self.qualifier_ctx.unsafe_tok = error_node
|
||||
.children_with_tokens()
|
||||
.filter_map(NodeOrToken::into_token)
|
||||
.find(|it| it.kind() == T![unsafe]);
|
||||
self.qualifier_ctx.vis_node =
|
||||
error_node.children().find_map(ast::Visibility::cast);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
self.qualifier_ctx = qualifier_ctx;
|
||||
self.ident_ctx = IdentContext::NameRef(nameref_ctx);
|
||||
self.pattern_ctx = pat_ctx;
|
||||
}
|
||||
@ -1070,40 +1049,44 @@ impl<'a> CompletionContext<'a> {
|
||||
original_file: &SyntaxNode,
|
||||
name_ref: ast::NameRef,
|
||||
parent: SyntaxNode,
|
||||
) -> (NameRefContext, Option<PatternContext>) {
|
||||
) -> (NameRefContext, Option<PatternContext>, QualifierCtx) {
|
||||
let nameref = find_node_at_offset(&original_file, name_ref.syntax().text_range().start());
|
||||
|
||||
let mut nameref_ctx = NameRefContext {
|
||||
dot_access: None,
|
||||
path_ctx: None,
|
||||
nameref,
|
||||
record_expr: None,
|
||||
keyword: None,
|
||||
};
|
||||
let mut res = (
|
||||
NameRefContext {
|
||||
dot_access: None,
|
||||
path_ctx: None,
|
||||
nameref,
|
||||
record_expr: None,
|
||||
keyword: None,
|
||||
},
|
||||
None,
|
||||
QualifierCtx::default(),
|
||||
);
|
||||
let (nameref_ctx, pattern_ctx, qualifier_ctx) = &mut res;
|
||||
|
||||
if let Some(record_field) = ast::RecordExprField::for_field_name(&name_ref) {
|
||||
nameref_ctx.record_expr =
|
||||
find_node_in_file_compensated(original_file, &record_field.parent_record_lit())
|
||||
.zip(Some(false));
|
||||
return (nameref_ctx, None);
|
||||
return res;
|
||||
}
|
||||
if let Some(record_field) = ast::RecordPatField::for_field_name_ref(&name_ref) {
|
||||
let pat_ctx =
|
||||
pattern_context_for(original_file, record_field.parent_record_pat().clone().into());
|
||||
return (
|
||||
nameref_ctx,
|
||||
Some(PatternContext {
|
||||
param_ctx: None,
|
||||
has_type_ascription: false,
|
||||
ref_token: None,
|
||||
mut_token: None,
|
||||
record_pat: find_node_in_file_compensated(
|
||||
original_file,
|
||||
&record_field.parent_record_pat(),
|
||||
),
|
||||
..pat_ctx
|
||||
}),
|
||||
);
|
||||
*pattern_ctx = Some(PatternContext {
|
||||
param_ctx: None,
|
||||
has_type_ascription: false,
|
||||
ref_token: None,
|
||||
mut_token: None,
|
||||
record_pat: find_node_in_file_compensated(
|
||||
original_file,
|
||||
&record_field.parent_record_pat(),
|
||||
),
|
||||
..pattern_context_for(
|
||||
original_file,
|
||||
record_field.parent_record_pat().clone().into(),
|
||||
)
|
||||
});
|
||||
return res;
|
||||
}
|
||||
|
||||
let segment = match_ast! {
|
||||
@ -1123,7 +1106,7 @@ impl<'a> CompletionContext<'a> {
|
||||
kind: DotAccessKind::Field { receiver_is_ambiguous_float_literal },
|
||||
receiver
|
||||
});
|
||||
return (nameref_ctx, None);
|
||||
return res;
|
||||
},
|
||||
ast::MethodCallExpr(method) => {
|
||||
let receiver = find_in_original_file(method.receiver(), original_file);
|
||||
@ -1132,9 +1115,9 @@ impl<'a> CompletionContext<'a> {
|
||||
kind: DotAccessKind::Method { has_parens: method.arg_list().map_or(false, |it| it.l_paren_token().is_some()) },
|
||||
receiver
|
||||
});
|
||||
return (nameref_ctx, None);
|
||||
return res;
|
||||
},
|
||||
_ => return (nameref_ctx, None),
|
||||
_ => return res,
|
||||
}
|
||||
};
|
||||
|
||||
@ -1148,7 +1131,6 @@ impl<'a> CompletionContext<'a> {
|
||||
kind: PathKind::Item { kind: ItemListKind::SourceFile },
|
||||
has_type_args: false,
|
||||
};
|
||||
let mut pat_ctx = None;
|
||||
|
||||
let is_in_block = |it: &SyntaxNode| {
|
||||
it.parent()
|
||||
@ -1205,9 +1187,9 @@ impl<'a> CompletionContext<'a> {
|
||||
None
|
||||
};
|
||||
|
||||
let kind = path.syntax().ancestors().find_map(|it| {
|
||||
// using Option<Option<PathKind>> as extra controlflow
|
||||
let kind = match_ast! {
|
||||
// Infer the path kind
|
||||
let kind = path.syntax().parent().and_then(|it| {
|
||||
match_ast! {
|
||||
match it {
|
||||
ast::PathType(it) => Some(PathKind::Type {
|
||||
in_tuple_struct: it.syntax().parent().map_or(false, |it| ast::TupleField::can_cast(it.kind()))
|
||||
@ -1217,7 +1199,7 @@ impl<'a> CompletionContext<'a> {
|
||||
if ast::ExprStmt::can_cast(p.kind()) {
|
||||
if let Some(kind) = inbetween_body_and_decl_check(p) {
|
||||
nameref_ctx.keyword = Some(kind);
|
||||
return Some(None);
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1233,22 +1215,22 @@ impl<'a> CompletionContext<'a> {
|
||||
},
|
||||
ast::TupleStructPat(it) => {
|
||||
path_ctx.has_call_parens = true;
|
||||
pat_ctx = Some(pattern_context_for(original_file, it.into()));
|
||||
*pattern_ctx = Some(pattern_context_for(original_file, it.into()));
|
||||
Some(PathKind::Pat)
|
||||
},
|
||||
ast::RecordPat(it) => {
|
||||
path_ctx.has_call_parens = true;
|
||||
pat_ctx = Some(pattern_context_for(original_file, it.into()));
|
||||
*pattern_ctx = Some(pattern_context_for(original_file, it.into()));
|
||||
Some(PathKind::Pat)
|
||||
},
|
||||
ast::PathPat(it) => {
|
||||
pat_ctx = Some(pattern_context_for(original_file, it.into()));
|
||||
*pattern_ctx = Some(pattern_context_for(original_file, it.into()));
|
||||
Some(PathKind::Pat)
|
||||
},
|
||||
ast::MacroCall(it) => {
|
||||
if let Some(kind) = inbetween_body_and_decl_check(it.syntax().clone()) {
|
||||
nameref_ctx.keyword = Some(kind);
|
||||
return Some(None);
|
||||
return None;
|
||||
}
|
||||
|
||||
path_ctx.has_macro_bang = it.excl_token().is_some();
|
||||
@ -1266,21 +1248,21 @@ impl<'a> CompletionContext<'a> {
|
||||
} else {
|
||||
ItemListKind::Impl
|
||||
},
|
||||
_ => return Some(None)
|
||||
_ => return None
|
||||
}
|
||||
},
|
||||
None => return Some(None),
|
||||
None => return None,
|
||||
} }),
|
||||
Some(SyntaxKind::EXTERN_ITEM_LIST) => Some(PathKind::Item { kind: ItemListKind::ExternBlock }),
|
||||
Some(SyntaxKind::SOURCE_FILE) => Some(PathKind::Item { kind: ItemListKind::SourceFile }),
|
||||
_ => {
|
||||
return Some(parent.and_then(ast::MacroExpr::cast).map(|it| {
|
||||
return parent.and_then(ast::MacroExpr::cast).map(|it| {
|
||||
let in_loop_body = is_in_loop_body(it.syntax());
|
||||
let in_block_expr = is_in_block(it.syntax());
|
||||
let after_if_expr = after_if_expr(it.syntax().clone());
|
||||
fill_record_expr(it.syntax());
|
||||
PathKind::Expr { in_block_expr, in_loop_body, after_if_expr }
|
||||
}));
|
||||
});
|
||||
},
|
||||
}
|
||||
},
|
||||
@ -1302,30 +1284,14 @@ impl<'a> CompletionContext<'a> {
|
||||
})(),
|
||||
ast::Visibility(it) => Some(PathKind::Vis { has_in_token: it.in_token().is_some() }),
|
||||
ast::UseTree(_) => Some(PathKind::Use),
|
||||
ast::ItemList(_) => Some(PathKind::Item { kind: ItemListKind::Module }),
|
||||
ast::AssocItemList(it) => Some(PathKind::Item { kind: {
|
||||
match_ast! {
|
||||
match (it.syntax().parent()?) {
|
||||
ast::Trait(_) => ItemListKind::Trait,
|
||||
ast::Impl(it) => if it.trait_().is_some() {
|
||||
ItemListKind::TraitImpl
|
||||
} else {
|
||||
ItemListKind::Impl
|
||||
},
|
||||
_ => return None
|
||||
}
|
||||
}
|
||||
}}),
|
||||
ast::ExternItemList(_) => Some(PathKind::Item { kind: ItemListKind::ExternBlock }),
|
||||
ast::SourceFile(_) => Some(PathKind::Item { kind: ItemListKind::SourceFile }),
|
||||
_ => return None,
|
||||
}
|
||||
};
|
||||
Some(kind)
|
||||
}).flatten();
|
||||
}
|
||||
});
|
||||
|
||||
match kind {
|
||||
Some(kind) => path_ctx.kind = kind,
|
||||
None => return (nameref_ctx, pat_ctx),
|
||||
None => return res,
|
||||
}
|
||||
path_ctx.has_type_args = segment.generic_arg_list().is_some();
|
||||
|
||||
@ -1367,8 +1333,62 @@ impl<'a> CompletionContext<'a> {
|
||||
path_ctx.is_absolute_path = true;
|
||||
}
|
||||
}
|
||||
|
||||
if path_ctx.is_trivial_path() {
|
||||
// fetch the full expression that may have qualifiers attached to it
|
||||
let top_node = match path_ctx.kind {
|
||||
PathKind::Expr { in_block_expr: true, .. } => {
|
||||
parent.ancestors().find(|it| ast::PathExpr::can_cast(it.kind())).and_then(|p| {
|
||||
let parent = p.parent()?;
|
||||
if ast::StmtList::can_cast(parent.kind()) {
|
||||
Some(p)
|
||||
} else if ast::ExprStmt::can_cast(parent.kind()) {
|
||||
Some(parent)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
PathKind::Item { .. } => {
|
||||
parent.ancestors().find(|it| ast::MacroCall::can_cast(it.kind()))
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
if let Some(top) = top_node {
|
||||
if let Some(NodeOrToken::Node(error_node)) =
|
||||
syntax::algo::non_trivia_sibling(top.clone().into(), syntax::Direction::Prev)
|
||||
{
|
||||
if error_node.kind() == SyntaxKind::ERROR {
|
||||
qualifier_ctx.unsafe_tok = error_node
|
||||
.children_with_tokens()
|
||||
.filter_map(NodeOrToken::into_token)
|
||||
.find(|it| it.kind() == T![unsafe]);
|
||||
qualifier_ctx.vis_node =
|
||||
error_node.children().find_map(ast::Visibility::cast);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(PathKind::Item { .. }) = kind {
|
||||
if qualifier_ctx.none() {
|
||||
if let Some(t) = top.first_token() {
|
||||
if let Some(prev) = t
|
||||
.prev_token()
|
||||
.and_then(|t| syntax::algo::skip_trivia_token(t, Direction::Prev))
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
nameref_ctx.path_ctx = Some(path_ctx);
|
||||
(nameref_ctx, pat_ctx)
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -173,7 +173,6 @@ pub fn completions(
|
||||
completions::record::complete_record(acc, ctx);
|
||||
completions::snippet::complete_expr_snippet(acc, ctx);
|
||||
completions::snippet::complete_item_snippet(acc, ctx);
|
||||
completions::trait_impl::complete_trait_impl(acc, ctx);
|
||||
completions::r#type::complete_type_path(acc, ctx);
|
||||
completions::r#type::complete_inferred_type(acc, ctx);
|
||||
completions::use_::complete_use_tree(acc, ctx);
|
||||
|
Loading…
x
Reference in New Issue
Block a user