mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-28 04:44:57 +00:00
Simplify
This commit is contained in:
parent
f35a9a1dcc
commit
85363d18e8
4 changed files with 94 additions and 64 deletions
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
use hir::ScopeDef;
|
use hir::ScopeDef;
|
||||||
use ide_db::FxHashSet;
|
use ide_db::FxHashSet;
|
||||||
use syntax::T;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
context::{NameRefContext, NameRefKind, PathCompletionCtx, PathKind, PathQualifierCtx},
|
context::{NameRefContext, NameRefKind, PathCompletionCtx, PathKind, PathQualifierCtx},
|
||||||
|
@ -20,6 +19,7 @@ pub(crate) fn complete_expr_path(acc: &mut Completions, ctx: &CompletionContext)
|
||||||
is_func_update,
|
is_func_update,
|
||||||
after_if_expr,
|
after_if_expr,
|
||||||
wants_mut_token,
|
wants_mut_token,
|
||||||
|
in_condition,
|
||||||
) = match ctx.nameref_ctx() {
|
) = match ctx.nameref_ctx() {
|
||||||
Some(&NameRefContext {
|
Some(&NameRefContext {
|
||||||
kind:
|
kind:
|
||||||
|
@ -29,6 +29,7 @@ pub(crate) fn complete_expr_path(acc: &mut Completions, ctx: &CompletionContext)
|
||||||
in_block_expr,
|
in_block_expr,
|
||||||
in_loop_body,
|
in_loop_body,
|
||||||
after_if_expr,
|
after_if_expr,
|
||||||
|
in_condition,
|
||||||
ref ref_expr_parent,
|
ref ref_expr_parent,
|
||||||
ref is_func_update,
|
ref is_func_update,
|
||||||
},
|
},
|
||||||
|
@ -45,6 +46,7 @@ pub(crate) fn complete_expr_path(acc: &mut Completions, ctx: &CompletionContext)
|
||||||
is_func_update.is_some(),
|
is_func_update.is_some(),
|
||||||
after_if_expr,
|
after_if_expr,
|
||||||
ref_expr_parent.as_ref().map(|it| it.mut_token().is_none()).unwrap_or(false),
|
ref_expr_parent.as_ref().map(|it| it.mut_token().is_none()).unwrap_or(false),
|
||||||
|
in_condition,
|
||||||
),
|
),
|
||||||
_ => return,
|
_ => return,
|
||||||
};
|
};
|
||||||
|
@ -235,10 +237,7 @@ pub(crate) fn complete_expr_path(acc: &mut Completions, ctx: &CompletionContext)
|
||||||
add_keyword("true", "true");
|
add_keyword("true", "true");
|
||||||
add_keyword("false", "false");
|
add_keyword("false", "false");
|
||||||
|
|
||||||
if ctx.previous_token_is(T![if])
|
if (in_condition && !is_absolute_path) || in_block_expr {
|
||||||
|| ctx.previous_token_is(T![while])
|
|
||||||
|| in_block_expr
|
|
||||||
{
|
|
||||||
add_keyword("let", "let");
|
add_keyword("let", "let");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,7 @@ pub(crate) fn complete_type_path(acc: &mut Completions, ctx: &CompletionContext)
|
||||||
matches!(location, TypeLocation::GenericArgList(_))
|
matches!(location, TypeLocation::GenericArgList(_))
|
||||||
}
|
}
|
||||||
ScopeDef::ImplSelfType(_) => {
|
ScopeDef::ImplSelfType(_) => {
|
||||||
!ctx.previous_token_is(syntax::T![impl]) && !ctx.previous_token_is(syntax::T![for])
|
!matches!(location, TypeLocation::ImplTarget | TypeLocation::ImplTrait)
|
||||||
}
|
}
|
||||||
// Don't suggest attribute macros and derives.
|
// Don't suggest attribute macros and derives.
|
||||||
ScopeDef::ModuleDef(Macro(mac)) => mac.is_fn_like(ctx.db),
|
ScopeDef::ModuleDef(Macro(mac)) => mac.is_fn_like(ctx.db),
|
||||||
|
|
|
@ -92,6 +92,8 @@ pub(super) enum PathKind {
|
||||||
in_block_expr: bool,
|
in_block_expr: bool,
|
||||||
in_loop_body: bool,
|
in_loop_body: bool,
|
||||||
after_if_expr: bool,
|
after_if_expr: bool,
|
||||||
|
/// Whether this expression is the direct condition of an if or while expression
|
||||||
|
in_condition: bool,
|
||||||
ref_expr_parent: Option<ast::RefExpr>,
|
ref_expr_parent: Option<ast::RefExpr>,
|
||||||
is_func_update: Option<ast::RecordExpr>,
|
is_func_update: Option<ast::RecordExpr>,
|
||||||
},
|
},
|
||||||
|
@ -121,6 +123,8 @@ pub(crate) enum TypeLocation {
|
||||||
TypeAscription(TypeAscriptionTarget),
|
TypeAscription(TypeAscriptionTarget),
|
||||||
GenericArgList(Option<ast::GenericArgList>),
|
GenericArgList(Option<ast::GenericArgList>),
|
||||||
TypeBound,
|
TypeBound,
|
||||||
|
ImplTarget,
|
||||||
|
ImplTrait,
|
||||||
Other,
|
Other,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -327,7 +327,8 @@ impl<'a> CompletionContext<'a> {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.previous_token = previous_token(syntax_element.clone());
|
self.previous_token =
|
||||||
|
syntax_element.clone().into_token().and_then(previous_non_trivia_token);
|
||||||
|
|
||||||
self.incomplete_let =
|
self.incomplete_let =
|
||||||
syntax_element.ancestors().take(6).find_map(ast::LetStmt::cast).map_or(false, |it| {
|
syntax_element.ancestors().take(6).find_map(ast::LetStmt::cast).map_or(false, |it| {
|
||||||
|
@ -647,8 +648,8 @@ impl<'a> CompletionContext<'a> {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
let type_location = |it: Option<SyntaxNode>| {
|
let type_location = |node: &SyntaxNode| {
|
||||||
let parent = it?;
|
let parent = node.parent()?;
|
||||||
let res = match_ast! {
|
let res = match_ast! {
|
||||||
match parent {
|
match parent {
|
||||||
ast::Const(it) => {
|
ast::Const(it) => {
|
||||||
|
@ -690,6 +691,15 @@ impl<'a> CompletionContext<'a> {
|
||||||
}
|
}
|
||||||
TypeLocation::TypeAscription(TypeAscriptionTarget::Let(find_opt_node_in_file(original_file, it.pat())))
|
TypeLocation::TypeAscription(TypeAscriptionTarget::Let(find_opt_node_in_file(original_file, it.pat())))
|
||||||
},
|
},
|
||||||
|
ast::Impl(it) => {
|
||||||
|
match it.trait_() {
|
||||||
|
Some(t) if t.syntax() == node => TypeLocation::ImplTrait,
|
||||||
|
_ => match it.self_ty() {
|
||||||
|
Some(t) if t.syntax() == node => TypeLocation::ImplTarget,
|
||||||
|
_ => return None,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
ast::TypeBound(_) => TypeLocation::TypeBound,
|
ast::TypeBound(_) => TypeLocation::TypeBound,
|
||||||
// is this case needed?
|
// is this case needed?
|
||||||
ast::TypeBoundList(_) => TypeLocation::TypeBound,
|
ast::TypeBoundList(_) => TypeLocation::TypeBound,
|
||||||
|
@ -703,16 +713,49 @@ impl<'a> CompletionContext<'a> {
|
||||||
Some(res)
|
Some(res)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let is_in_condition = |it: &ast::Expr| {
|
||||||
|
(|| {
|
||||||
|
let parent = it.syntax().parent()?;
|
||||||
|
if let Some(expr) = ast::WhileExpr::cast(parent.clone()) {
|
||||||
|
Some(expr.condition()? == *it)
|
||||||
|
} else if let Some(expr) = ast::IfExpr::cast(parent) {
|
||||||
|
Some(expr.condition()? == *it)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})()
|
||||||
|
.unwrap_or(false)
|
||||||
|
};
|
||||||
|
|
||||||
|
let make_path_kind_expr = |expr: ast::Expr| {
|
||||||
|
let it = expr.syntax();
|
||||||
|
let in_block_expr = is_in_block(it);
|
||||||
|
let in_loop_body = is_in_loop_body(it);
|
||||||
|
let after_if_expr = after_if_expr(it.clone());
|
||||||
|
let ref_expr_parent =
|
||||||
|
path.as_single_name_ref().and_then(|_| it.parent()).and_then(ast::RefExpr::cast);
|
||||||
|
let is_func_update = func_update_record(it);
|
||||||
|
let in_condition = is_in_condition(&expr);
|
||||||
|
|
||||||
|
PathKind::Expr {
|
||||||
|
in_block_expr,
|
||||||
|
in_loop_body,
|
||||||
|
after_if_expr,
|
||||||
|
in_condition,
|
||||||
|
ref_expr_parent,
|
||||||
|
is_func_update,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let make_path_kind_type = |ty: ast::Type| {
|
||||||
|
let location = type_location(ty.syntax());
|
||||||
|
PathKind::Type { location: location.unwrap_or(TypeLocation::Other) }
|
||||||
|
};
|
||||||
|
|
||||||
// Infer the path kind
|
// Infer the path kind
|
||||||
let kind = path.syntax().parent().and_then(|it| {
|
let kind = path.syntax().parent().and_then(|it| {
|
||||||
match_ast! {
|
match_ast! {
|
||||||
match it {
|
match it {
|
||||||
ast::PathType(it) => {
|
ast::PathType(it) => Some(make_path_kind_type(it.into())),
|
||||||
let location = type_location(it.syntax().parent());
|
|
||||||
Some(PathKind::Type {
|
|
||||||
location: location.unwrap_or(TypeLocation::Other),
|
|
||||||
})
|
|
||||||
},
|
|
||||||
ast::PathExpr(it) => {
|
ast::PathExpr(it) => {
|
||||||
if let Some(p) = it.syntax().parent() {
|
if let Some(p) = it.syntax().parent() {
|
||||||
if ast::ExprStmt::can_cast(p.kind()) {
|
if ast::ExprStmt::can_cast(p.kind()) {
|
||||||
|
@ -724,14 +767,8 @@ 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_loop_body = is_in_loop_body(it.syntax());
|
|
||||||
let after_if_expr = after_if_expr(it.syntax().clone());
|
|
||||||
let ref_expr_parent = path.as_single_name_ref()
|
|
||||||
.and_then(|_| it.syntax().parent()).and_then(ast::RefExpr::cast);
|
|
||||||
let is_func_update = func_update_record(it.syntax());
|
|
||||||
|
|
||||||
Some(PathKind::Expr { in_block_expr, in_loop_body, after_if_expr, ref_expr_parent, is_func_update })
|
Some(make_path_kind_expr(it.into()))
|
||||||
},
|
},
|
||||||
ast::TupleStructPat(it) => {
|
ast::TupleStructPat(it) => {
|
||||||
path_ctx.has_call_parens = true;
|
path_ctx.has_call_parens = true;
|
||||||
|
@ -748,23 +785,22 @@ impl<'a> CompletionContext<'a> {
|
||||||
Some(PathKind::Pat)
|
Some(PathKind::Pat)
|
||||||
},
|
},
|
||||||
ast::MacroCall(it) => {
|
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()) {
|
if let Some(kind) = inbetween_body_and_decl_check(it.syntax().clone()) {
|
||||||
nameref_ctx.kind = Some(NameRefKind::Keyword(kind));
|
nameref_ctx.kind = Some(NameRefKind::Keyword(kind));
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
path_ctx.has_macro_bang = it.excl_token().is_some();
|
path_ctx.has_macro_bang = it.excl_token().is_some();
|
||||||
let parent = it.syntax().parent();
|
let parent = it.syntax().parent()?;
|
||||||
match parent.as_ref().map(|it| it.kind()) {
|
// Any path in an item list will be treated as a macro call by the parser
|
||||||
Some(SyntaxKind::MACRO_PAT) => Some(PathKind::Pat),
|
let res = match_ast! {
|
||||||
Some(SyntaxKind::MACRO_TYPE) => {
|
match parent {
|
||||||
let location = type_location(parent.unwrap().parent());
|
ast::MacroExpr(expr) => make_path_kind_expr(expr.into()),
|
||||||
Some(PathKind::Type {
|
ast::MacroPat(_) => PathKind::Pat,
|
||||||
location: location.unwrap_or(TypeLocation::Other),
|
ast::MacroType(ty) => make_path_kind_type(ty.into()),
|
||||||
})
|
ast::ItemList(_) => PathKind::Item { kind: ItemListKind::Module },
|
||||||
},
|
ast::AssocItemList(_) => PathKind::Item { kind: match parent.parent() {
|
||||||
Some(SyntaxKind::ITEM_LIST) => Some(PathKind::Item { kind: ItemListKind::Module }),
|
|
||||||
Some(SyntaxKind::ASSOC_ITEM_LIST) => Some(PathKind::Item { kind: match parent.and_then(|it| it.parent()) {
|
|
||||||
Some(it) => match_ast! {
|
Some(it) => match_ast! {
|
||||||
match it {
|
match it {
|
||||||
ast::Trait(_) => ItemListKind::Trait,
|
ast::Trait(_) => ItemListKind::Trait,
|
||||||
|
@ -777,21 +813,13 @@ impl<'a> CompletionContext<'a> {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
None => return None,
|
None => return None,
|
||||||
} }),
|
} },
|
||||||
Some(SyntaxKind::EXTERN_ITEM_LIST) => Some(PathKind::Item { kind: ItemListKind::ExternBlock }),
|
ast::ExternItemList(_) => PathKind::Item { kind: ItemListKind::ExternBlock },
|
||||||
Some(SyntaxKind::SOURCE_FILE) => Some(PathKind::Item { kind: ItemListKind::SourceFile }),
|
ast::SourceFile(_) => PathKind::Item { kind: ItemListKind::SourceFile },
|
||||||
_ => {
|
_ => return None,
|
||||||
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());
|
|
||||||
let ref_expr_parent = path.as_single_name_ref()
|
|
||||||
.and_then(|_| it.syntax().parent()).and_then(ast::RefExpr::cast);
|
|
||||||
let is_func_update = func_update_record(it.syntax());
|
|
||||||
PathKind::Expr { in_block_expr, in_loop_body, after_if_expr, ref_expr_parent, is_func_update }
|
|
||||||
});
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
Some(res)
|
||||||
},
|
},
|
||||||
ast::Meta(meta) => (|| {
|
ast::Meta(meta) => (|| {
|
||||||
let attr = meta.parent_attr()?;
|
let attr = meta.parent_attr()?;
|
||||||
|
@ -818,10 +846,13 @@ impl<'a> CompletionContext<'a> {
|
||||||
|
|
||||||
match kind {
|
match kind {
|
||||||
Some(kind) => path_ctx.kind = 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,
|
None => return res,
|
||||||
}
|
}
|
||||||
path_ctx.has_type_args = segment.generic_arg_list().is_some();
|
path_ctx.has_type_args = segment.generic_arg_list().is_some();
|
||||||
|
|
||||||
|
// calculate the qualifier context
|
||||||
if let Some((path, use_tree_parent)) = path_or_use_tree_qualifier(&path) {
|
if let Some((path, use_tree_parent)) = path_or_use_tree_qualifier(&path) {
|
||||||
if !use_tree_parent {
|
if !use_tree_parent {
|
||||||
path_ctx.is_absolute_path =
|
path_ctx.is_absolute_path =
|
||||||
|
@ -1034,10 +1065,6 @@ fn has_ref(token: &SyntaxToken) -> bool {
|
||||||
token.kind() == T![&]
|
token.kind() == T![&]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn previous_token(element: SyntaxElement) -> Option<SyntaxToken> {
|
|
||||||
element.into_token().and_then(previous_non_trivia_token)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn is_in_token_of_for_loop(element: SyntaxElement) -> bool {
|
pub(crate) fn is_in_token_of_for_loop(element: SyntaxElement) -> bool {
|
||||||
// oh my ...
|
// oh my ...
|
||||||
(|| {
|
(|| {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue