Skip to content

Commit 9c0b727

Browse files
committed
Auto merge of rust-lang#12563 - Veykril:completion, r=Veykril
internal: Simplify
2 parents a69b17b + 85363d1 commit 9c0b727

File tree

4 files changed

+95
-65
lines changed

4 files changed

+95
-65
lines changed

crates/ide-completion/src/completions/expr.rs

+4-5
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
33
use hir::ScopeDef;
44
use ide_db::FxHashSet;
5-
use syntax::T;
65

76
use crate::{
87
context::{NameRefContext, NameRefKind, PathCompletionCtx, PathKind, PathQualifierCtx},
@@ -20,6 +19,7 @@ pub(crate) fn complete_expr_path(acc: &mut Completions, ctx: &CompletionContext)
2019
is_func_update,
2120
after_if_expr,
2221
wants_mut_token,
22+
in_condition,
2323
) = match ctx.nameref_ctx() {
2424
Some(&NameRefContext {
2525
kind:
@@ -29,6 +29,7 @@ pub(crate) fn complete_expr_path(acc: &mut Completions, ctx: &CompletionContext)
2929
in_block_expr,
3030
in_loop_body,
3131
after_if_expr,
32+
in_condition,
3233
ref ref_expr_parent,
3334
ref is_func_update,
3435
},
@@ -45,6 +46,7 @@ pub(crate) fn complete_expr_path(acc: &mut Completions, ctx: &CompletionContext)
4546
is_func_update.is_some(),
4647
after_if_expr,
4748
ref_expr_parent.as_ref().map(|it| it.mut_token().is_none()).unwrap_or(false),
49+
in_condition,
4850
),
4951
_ => return,
5052
};
@@ -235,10 +237,7 @@ pub(crate) fn complete_expr_path(acc: &mut Completions, ctx: &CompletionContext)
235237
add_keyword("true", "true");
236238
add_keyword("false", "false");
237239

238-
if ctx.previous_token_is(T![if])
239-
|| ctx.previous_token_is(T![while])
240-
|| in_block_expr
241-
{
240+
if (in_condition && !is_absolute_path) || in_block_expr {
242241
add_keyword("let", "let");
243242
}
244243

crates/ide-completion/src/completions/type.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ pub(crate) fn complete_type_path(acc: &mut Completions, ctx: &CompletionContext)
3434
matches!(location, TypeLocation::GenericArgList(_))
3535
}
3636
ScopeDef::ImplSelfType(_) => {
37-
!ctx.previous_token_is(syntax::T![impl]) && !ctx.previous_token_is(syntax::T![for])
37+
!matches!(location, TypeLocation::ImplTarget | TypeLocation::ImplTrait)
3838
}
3939
// Don't suggest attribute macros and derives.
4040
ScopeDef::ModuleDef(Macro(mac)) => mac.is_fn_like(ctx.db),

crates/ide-completion/src/context.rs

+4
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,8 @@ pub(super) enum PathKind {
9292
in_block_expr: bool,
9393
in_loop_body: bool,
9494
after_if_expr: bool,
95+
/// Whether this expression is the direct condition of an if or while expression
96+
in_condition: bool,
9597
ref_expr_parent: Option<ast::RefExpr>,
9698
is_func_update: Option<ast::RecordExpr>,
9799
},
@@ -121,6 +123,8 @@ pub(crate) enum TypeLocation {
121123
TypeAscription(TypeAscriptionTarget),
122124
GenericArgList(Option<ast::GenericArgList>),
123125
TypeBound,
126+
ImplTarget,
127+
ImplTrait,
124128
Other,
125129
}
126130

crates/ide-completion/src/context/analysis.rs

+86-59
Original file line numberDiff line numberDiff line change
@@ -327,7 +327,8 @@ impl<'a> CompletionContext<'a> {
327327
return None;
328328
}
329329

330-
self.previous_token = previous_token(syntax_element.clone());
330+
self.previous_token =
331+
syntax_element.clone().into_token().and_then(previous_non_trivia_token);
331332

332333
self.incomplete_let =
333334
syntax_element.ancestors().take(6).find_map(ast::LetStmt::cast).map_or(false, |it| {
@@ -647,8 +648,8 @@ impl<'a> CompletionContext<'a> {
647648
None
648649
};
649650

650-
let type_location = |it: Option<SyntaxNode>| {
651-
let parent = it?;
651+
let type_location = |node: &SyntaxNode| {
652+
let parent = node.parent()?;
652653
let res = match_ast! {
653654
match parent {
654655
ast::Const(it) => {
@@ -690,6 +691,15 @@ impl<'a> CompletionContext<'a> {
690691
}
691692
TypeLocation::TypeAscription(TypeAscriptionTarget::Let(find_opt_node_in_file(original_file, it.pat())))
692693
},
694+
ast::Impl(it) => {
695+
match it.trait_() {
696+
Some(t) if t.syntax() == node => TypeLocation::ImplTrait,
697+
_ => match it.self_ty() {
698+
Some(t) if t.syntax() == node => TypeLocation::ImplTarget,
699+
_ => return None,
700+
},
701+
}
702+
},
693703
ast::TypeBound(_) => TypeLocation::TypeBound,
694704
// is this case needed?
695705
ast::TypeBoundList(_) => TypeLocation::TypeBound,
@@ -703,16 +713,49 @@ impl<'a> CompletionContext<'a> {
703713
Some(res)
704714
};
705715

716+
let is_in_condition = |it: &ast::Expr| {
717+
(|| {
718+
let parent = it.syntax().parent()?;
719+
if let Some(expr) = ast::WhileExpr::cast(parent.clone()) {
720+
Some(expr.condition()? == *it)
721+
} else if let Some(expr) = ast::IfExpr::cast(parent) {
722+
Some(expr.condition()? == *it)
723+
} else {
724+
None
725+
}
726+
})()
727+
.unwrap_or(false)
728+
};
729+
730+
let make_path_kind_expr = |expr: ast::Expr| {
731+
let it = expr.syntax();
732+
let in_block_expr = is_in_block(it);
733+
let in_loop_body = is_in_loop_body(it);
734+
let after_if_expr = after_if_expr(it.clone());
735+
let ref_expr_parent =
736+
path.as_single_name_ref().and_then(|_| it.parent()).and_then(ast::RefExpr::cast);
737+
let is_func_update = func_update_record(it);
738+
let in_condition = is_in_condition(&expr);
739+
740+
PathKind::Expr {
741+
in_block_expr,
742+
in_loop_body,
743+
after_if_expr,
744+
in_condition,
745+
ref_expr_parent,
746+
is_func_update,
747+
}
748+
};
749+
let make_path_kind_type = |ty: ast::Type| {
750+
let location = type_location(ty.syntax());
751+
PathKind::Type { location: location.unwrap_or(TypeLocation::Other) }
752+
};
753+
706754
// Infer the path kind
707755
let kind = path.syntax().parent().and_then(|it| {
708756
match_ast! {
709757
match it {
710-
ast::PathType(it) => {
711-
let location = type_location(it.syntax().parent());
712-
Some(PathKind::Type {
713-
location: location.unwrap_or(TypeLocation::Other),
714-
})
715-
},
758+
ast::PathType(it) => Some(make_path_kind_type(it.into())),
716759
ast::PathExpr(it) => {
717760
if let Some(p) = it.syntax().parent() {
718761
if ast::ExprStmt::can_cast(p.kind()) {
@@ -724,14 +767,8 @@ impl<'a> CompletionContext<'a> {
724767
}
725768

726769
path_ctx.has_call_parens = it.syntax().parent().map_or(false, |it| ast::CallExpr::can_cast(it.kind()));
727-
let in_block_expr = is_in_block(it.syntax());
728-
let in_loop_body = is_in_loop_body(it.syntax());
729-
let after_if_expr = after_if_expr(it.syntax().clone());
730-
let ref_expr_parent = path.as_single_name_ref()
731-
.and_then(|_| it.syntax().parent()).and_then(ast::RefExpr::cast);
732-
let is_func_update = func_update_record(it.syntax());
733-
734-
Some(PathKind::Expr { in_block_expr, in_loop_body, after_if_expr, ref_expr_parent, is_func_update })
770+
771+
Some(make_path_kind_expr(it.into()))
735772
},
736773
ast::TupleStructPat(it) => {
737774
path_ctx.has_call_parens = true;
@@ -748,50 +785,41 @@ impl<'a> CompletionContext<'a> {
748785
Some(PathKind::Pat)
749786
},
750787
ast::MacroCall(it) => {
788+
// A macro call in this position is usually a result of parsing recovery, so check that
751789
if let Some(kind) = inbetween_body_and_decl_check(it.syntax().clone()) {
752790
nameref_ctx.kind = Some(NameRefKind::Keyword(kind));
753791
return None;
754792
}
755793

756794
path_ctx.has_macro_bang = it.excl_token().is_some();
757-
let parent = it.syntax().parent();
758-
match parent.as_ref().map(|it| it.kind()) {
759-
Some(SyntaxKind::MACRO_PAT) => Some(PathKind::Pat),
760-
Some(SyntaxKind::MACRO_TYPE) => {
761-
let location = type_location(parent.unwrap().parent());
762-
Some(PathKind::Type {
763-
location: location.unwrap_or(TypeLocation::Other),
764-
})
765-
},
766-
Some(SyntaxKind::ITEM_LIST) => Some(PathKind::Item { kind: ItemListKind::Module }),
767-
Some(SyntaxKind::ASSOC_ITEM_LIST) => Some(PathKind::Item { kind: match parent.and_then(|it| it.parent()) {
768-
Some(it) => match_ast! {
769-
match it {
770-
ast::Trait(_) => ItemListKind::Trait,
771-
ast::Impl(it) => if it.trait_().is_some() {
772-
ItemListKind::TraitImpl
773-
} else {
774-
ItemListKind::Impl
775-
},
776-
_ => return None
777-
}
778-
},
779-
None => return None,
780-
} }),
781-
Some(SyntaxKind::EXTERN_ITEM_LIST) => Some(PathKind::Item { kind: ItemListKind::ExternBlock }),
782-
Some(SyntaxKind::SOURCE_FILE) => Some(PathKind::Item { kind: ItemListKind::SourceFile }),
783-
_ => {
784-
return parent.and_then(ast::MacroExpr::cast).map(|it| {
785-
let in_loop_body = is_in_loop_body(it.syntax());
786-
let in_block_expr = is_in_block(it.syntax());
787-
let after_if_expr = after_if_expr(it.syntax().clone());
788-
let ref_expr_parent = path.as_single_name_ref()
789-
.and_then(|_| it.syntax().parent()).and_then(ast::RefExpr::cast);
790-
let is_func_update = func_update_record(it.syntax());
791-
PathKind::Expr { in_block_expr, in_loop_body, after_if_expr, ref_expr_parent, is_func_update }
792-
});
793-
},
794-
}
795+
let parent = it.syntax().parent()?;
796+
// Any path in an item list will be treated as a macro call by the parser
797+
let res = match_ast! {
798+
match parent {
799+
ast::MacroExpr(expr) => make_path_kind_expr(expr.into()),
800+
ast::MacroPat(_) => PathKind::Pat,
801+
ast::MacroType(ty) => make_path_kind_type(ty.into()),
802+
ast::ItemList(_) => PathKind::Item { kind: ItemListKind::Module },
803+
ast::AssocItemList(_) => PathKind::Item { kind: match parent.parent() {
804+
Some(it) => match_ast! {
805+
match it {
806+
ast::Trait(_) => ItemListKind::Trait,
807+
ast::Impl(it) => if it.trait_().is_some() {
808+
ItemListKind::TraitImpl
809+
} else {
810+
ItemListKind::Impl
811+
},
812+
_ => return None
813+
}
814+
},
815+
None => return None,
816+
} },
817+
ast::ExternItemList(_) => PathKind::Item { kind: ItemListKind::ExternBlock },
818+
ast::SourceFile(_) => PathKind::Item { kind: ItemListKind::SourceFile },
819+
_ => return None,
820+
}
821+
};
822+
Some(res)
795823
},
796824
ast::Meta(meta) => (|| {
797825
let attr = meta.parent_attr()?;
@@ -818,10 +846,13 @@ impl<'a> CompletionContext<'a> {
818846

819847
match kind {
820848
Some(kind) => path_ctx.kind = kind,
849+
// unresolved path kind, so this isn't really a path we should be completing,
850+
// just some random identifier which might be in keyword position
821851
None => return res,
822852
}
823853
path_ctx.has_type_args = segment.generic_arg_list().is_some();
824854

855+
// calculate the qualifier context
825856
if let Some((path, use_tree_parent)) = path_or_use_tree_qualifier(&path) {
826857
if !use_tree_parent {
827858
path_ctx.is_absolute_path =
@@ -1034,10 +1065,6 @@ fn has_ref(token: &SyntaxToken) -> bool {
10341065
token.kind() == T![&]
10351066
}
10361067

1037-
pub(crate) fn previous_token(element: SyntaxElement) -> Option<SyntaxToken> {
1038-
element.into_token().and_then(previous_non_trivia_token)
1039-
}
1040-
10411068
pub(crate) fn is_in_token_of_for_loop(element: SyntaxElement) -> bool {
10421069
// oh my ...
10431070
(|| {

0 commit comments

Comments
 (0)