Remove prev-sibling completion machinery

This commit is contained in:
Lukas Wirth 2022-06-03 16:25:37 +02:00
parent 6550a241fb
commit 522f66545f
3 changed files with 21 additions and 76 deletions

View file

@ -15,12 +15,12 @@ pub(crate) fn complete_expr_path(acc: &mut Completions, ctx: &CompletionContext)
return; return;
} }
let (is_absolute_path, qualifier, in_block_expr, in_loop_body, is_func_update) = let (is_absolute_path, qualifier, in_block_expr, in_loop_body, is_func_update, after_if_expr) =
match ctx.nameref_ctx() { match ctx.nameref_ctx() {
Some(NameRefContext { Some(NameRefContext {
path_ctx: path_ctx:
Some(PathCompletionCtx { Some(PathCompletionCtx {
kind: PathKind::Expr { in_block_expr, in_loop_body }, kind: PathKind::Expr { in_block_expr, in_loop_body, after_if_expr },
is_absolute_path, is_absolute_path,
qualifier, qualifier,
.. ..
@ -33,6 +33,7 @@ pub(crate) fn complete_expr_path(acc: &mut Completions, ctx: &CompletionContext)
*in_block_expr, *in_block_expr,
*in_loop_body, *in_loop_body,
record_expr.as_ref().map_or(false, |&(_, it)| it), record_expr.as_ref().map_or(false, |&(_, it)| it),
*after_if_expr,
), ),
_ => return, _ => return,
}; };
@ -202,7 +203,7 @@ pub(crate) fn complete_expr_path(acc: &mut Completions, ctx: &CompletionContext)
add_keyword("let", "let"); add_keyword("let", "let");
} }
if ctx.after_if() { if after_if_expr {
add_keyword("else", "else {\n $0\n}"); add_keyword("else", "else {\n $0\n}");
add_keyword("else if", "else if $1 {\n $0\n}"); add_keyword("else if", "else if $1 {\n $0\n}");
} }

View file

@ -15,7 +15,7 @@ use ide_db::{
use syntax::{ use syntax::{
algo::{find_node_at_offset, non_trivia_sibling}, algo::{find_node_at_offset, non_trivia_sibling},
ast::{self, AttrKind, HasArgList, HasName, NameOrNameRef}, ast::{self, AttrKind, HasArgList, HasName, NameOrNameRef},
match_ast, AstNode, AstToken, NodeOrToken, match_ast, AstNode, AstToken, Direction, NodeOrToken,
SyntaxKind::{self, *}, SyntaxKind::{self, *},
SyntaxNode, SyntaxToken, TextRange, TextSize, T, SyntaxNode, SyntaxToken, TextRange, TextSize, T,
}; };
@ -23,8 +23,8 @@ use text_edit::Indel;
use crate::{ use crate::{
patterns::{ patterns::{
determine_location, determine_prev_sibling, is_in_loop_body, is_in_token_of_for_loop, determine_location, is_in_loop_body, is_in_token_of_for_loop, previous_token,
previous_token, ImmediateLocation, ImmediatePrevSibling, ImmediateLocation,
}, },
CompletionConfig, CompletionConfig,
}; };
@ -48,6 +48,7 @@ pub(super) enum PathKind {
Expr { Expr {
in_block_expr: bool, in_block_expr: bool,
in_loop_body: bool, in_loop_body: bool,
after_if_expr: bool,
}, },
Type { Type {
in_tuple_struct: bool, in_tuple_struct: bool,
@ -264,7 +265,6 @@ pub(crate) struct CompletionContext<'a> {
pub(super) incomplete_let: bool, pub(super) incomplete_let: bool,
pub(super) completion_location: Option<ImmediateLocation>, pub(super) completion_location: Option<ImmediateLocation>,
pub(super) prev_sibling: Option<ImmediatePrevSibling>,
pub(super) previous_token: Option<SyntaxToken>, pub(super) previous_token: Option<SyntaxToken>,
pub(super) ident_ctx: IdentContext, pub(super) ident_ctx: IdentContext,
@ -345,10 +345,6 @@ impl<'a> CompletionContext<'a> {
matches!(self.completion_location, Some(ImmediateLocation::RefExpr)) matches!(self.completion_location, Some(ImmediateLocation::RefExpr))
} }
pub(crate) fn after_if(&self) -> bool {
matches!(self.prev_sibling, Some(ImmediatePrevSibling::IfExpr))
}
// FIXME: This shouldn't exist // FIXME: This shouldn't exist
pub(crate) fn is_path_disallowed(&self) -> bool { pub(crate) fn is_path_disallowed(&self) -> bool {
!self.qualifier_ctx.none() !self.qualifier_ctx.none()
@ -527,7 +523,6 @@ impl<'a> CompletionContext<'a> {
impl_def: None, impl_def: None,
incomplete_let: false, incomplete_let: false,
completion_location: None, completion_location: None,
prev_sibling: 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 },
@ -922,7 +917,6 @@ impl<'a> CompletionContext<'a> {
}; };
self.completion_location = self.completion_location =
determine_location(&self.sema, original_file, offset, &name_like); determine_location(&self.sema, original_file, offset, &name_like);
self.prev_sibling = determine_prev_sibling(&name_like);
self.impl_def = self self.impl_def = self
.sema .sema
.token_ancestors_with_macros(self.token.clone()) .token_ancestors_with_macros(self.token.clone())
@ -1169,6 +1163,13 @@ impl<'a> CompletionContext<'a> {
find_node_in_file_compensated(original_file, &record_expr).zip(Some(true)); find_node_in_file_compensated(original_file, &record_expr).zip(Some(true));
} }
}; };
let after_if_expr = |node: SyntaxNode| {
let prev_expr = (|| {
let prev_sibling = non_trivia_sibling(node.into(), Direction::Prev)?.into_node()?;
ast::ExprStmt::cast(prev_sibling)?.expr()
})();
matches!(prev_expr, Some(ast::Expr::IfExpr(_)))
};
// We do not want to generate path completions when we are sandwiched between an item decl signature and its body. // We do not want to generate path completions when we are sandwiched between an item decl signature and its body.
// ex. trait Foo $0 {} // ex. trait Foo $0 {}
@ -1226,7 +1227,9 @@ impl<'a> CompletionContext<'a> {
path_ctx.has_call_parens = it.syntax().parent().map_or(false, |it| ast::CallExpr::can_cast(it.kind())); path_ctx.has_call_parens = it.syntax().parent().map_or(false, |it| ast::CallExpr::can_cast(it.kind()));
let in_block_expr = is_in_block(it.syntax()); let in_block_expr = is_in_block(it.syntax());
let in_loop_body = is_in_loop_body(it.syntax()); let in_loop_body = is_in_loop_body(it.syntax());
Some(PathKind::Expr { in_block_expr, in_loop_body }) let after_if_expr = after_if_expr(it.syntax().clone());
Some(PathKind::Expr { in_block_expr, in_loop_body, after_if_expr })
}, },
ast::TupleStructPat(it) => { ast::TupleStructPat(it) => {
path_ctx.has_call_parens = true; path_ctx.has_call_parens = true;
@ -1274,8 +1277,9 @@ impl<'a> CompletionContext<'a> {
return Some(parent.and_then(ast::MacroExpr::cast).map(|it| { return Some(parent.and_then(ast::MacroExpr::cast).map(|it| {
let in_loop_body = is_in_loop_body(it.syntax()); let in_loop_body = is_in_loop_body(it.syntax());
let in_block_expr = is_in_block(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()); fill_record_expr(it.syntax());
PathKind::Expr { in_block_expr, in_loop_body } PathKind::Expr { in_block_expr, in_loop_body, after_if_expr }
})); }));
}, },
} }

View file

@ -7,9 +7,8 @@
use hir::Semantics; use hir::Semantics;
use ide_db::RootDatabase; use ide_db::RootDatabase;
use syntax::{ use syntax::{
algo::non_trivia_sibling,
ast::{self, HasLoopBody, HasName}, ast::{self, HasLoopBody, HasName},
match_ast, AstNode, Direction, SyntaxElement, match_ast, AstNode, SyntaxElement,
SyntaxKind::*, SyntaxKind::*,
SyntaxNode, SyntaxToken, TextRange, TextSize, SyntaxNode, SyntaxToken, TextRange, TextSize,
}; };
@ -17,12 +16,6 @@ use syntax::{
#[cfg(test)] #[cfg(test)]
use crate::tests::check_pattern_is_applicable; use crate::tests::check_pattern_is_applicable;
/// Immediate previous node to what we are completing.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub(crate) enum ImmediatePrevSibling {
IfExpr,
}
#[derive(Clone, Debug, PartialEq, Eq)] #[derive(Clone, Debug, PartialEq, Eq)]
pub(crate) enum TypeAnnotation { pub(crate) enum TypeAnnotation {
Let(Option<ast::Pat>), Let(Option<ast::Pat>),
@ -46,45 +39,6 @@ pub(crate) enum ImmediateLocation {
GenericArgList(ast::GenericArgList), GenericArgList(ast::GenericArgList),
} }
pub(crate) fn determine_prev_sibling(name_like: &ast::NameLike) -> Option<ImmediatePrevSibling> {
let node = match name_like {
ast::NameLike::NameRef(name_ref) => maximize_name_ref(name_ref),
ast::NameLike::Name(n) => n.syntax().clone(),
ast::NameLike::Lifetime(lt) => lt.syntax().clone(),
};
let node = match node.parent().and_then(ast::MacroCall::cast) {
// When a path is being typed after the name of a trait/type of an impl it is being
// parsed as a macro, so when the trait/impl has a block following it an we are between the
// name and block the macro will attach the block to itself so maximizing fails to take
// that into account
// FIXME path expr and statement have a similar problem with attrs
Some(call)
if call.excl_token().is_none()
&& call.token_tree().map_or(false, |t| t.l_curly_token().is_some())
&& call.semicolon_token().is_none() =>
{
call.syntax().clone()
}
_ => node,
};
let prev_sibling = non_trivia_sibling(node.into(), Direction::Prev)?.into_node()?;
let res = match_ast! {
match prev_sibling {
ast::ExprStmt(it) => {
let node = it.expr().filter(|_| it.semicolon_token().is_none())?.syntax().clone();
match_ast! {
match node {
ast::IfExpr(_) => ImmediatePrevSibling::IfExpr,
_ => return None,
}
}
},
_ => return None,
}
};
Some(res)
}
pub(crate) fn determine_location( pub(crate) fn determine_location(
sema: &Semantics<RootDatabase>, sema: &Semantics<RootDatabase>,
original_file: &SyntaxNode, original_file: &SyntaxNode,
@ -316,22 +270,8 @@ mod tests {
); );
} }
fn check_prev_sibling(code: &str, sibling: impl Into<Option<ImmediatePrevSibling>>) {
check_pattern_is_applicable(code, |e| {
let name = &e.parent().and_then(ast::NameLike::cast).expect("Expected a namelike");
assert_eq!(determine_prev_sibling(name), sibling.into());
true
});
}
#[test] #[test]
fn test_ref_expr_loc() { fn test_ref_expr_loc() {
check_location(r"fn my_fn() { let x = &m$0 foo; }", ImmediateLocation::RefExpr); check_location(r"fn my_fn() { let x = &m$0 foo; }", ImmediateLocation::RefExpr);
} }
#[test]
fn test_if_expr_prev_sibling() {
check_prev_sibling(r"fn foo() { if true {} w$0", ImmediatePrevSibling::IfExpr);
check_prev_sibling(r"fn foo() { if true {}; w$0", None);
}
} }