Skip to content

Commit 5986d21

Browse files
committed
Auto merge of #12899 - Veykril:compl-qualifier, r=Veykril
fix: Do completions in path qualifier position Fixes #12566 Not too happy with the duplication needed for this, but it is what it is. Completions in path qualifiers will have to be filtered properly still, but its better to show too many completions for this than too few for now.
2 parents 02c240f + 74abd44 commit 5986d21

File tree

2 files changed

+118
-85
lines changed

2 files changed

+118
-85
lines changed

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

+9-7
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,14 @@ pub(crate) fn complete_expr_path(
1111
acc: &mut Completions,
1212
ctx: &CompletionContext<'_>,
1313
path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx,
14-
&ExprCtx {
14+
expr_ctx: &ExprCtx,
15+
) {
16+
let _p = profile::span("complete_expr_path");
17+
if !ctx.qualifier_ctx.none() {
18+
return;
19+
}
20+
21+
let &ExprCtx {
1522
in_block_expr,
1623
in_loop_body,
1724
after_if_expr,
@@ -23,12 +30,7 @@ pub(crate) fn complete_expr_path(
2330
ref impl_,
2431
in_match_guard,
2532
..
26-
}: &ExprCtx,
27-
) {
28-
let _p = profile::span("complete_expr_path");
29-
if !ctx.qualifier_ctx.none() {
30-
return;
31-
}
33+
} = expr_ctx;
3234

3335
let wants_mut_token =
3436
ref_expr_parent.as_ref().map(|it| it.mut_token().is_none()).unwrap_or(false);

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

+109-78
Original file line numberDiff line numberDiff line change
@@ -592,7 +592,7 @@ impl<'a> CompletionContext<'a> {
592592
has_call_parens: false,
593593
has_macro_bang: false,
594594
qualified: Qualified::No,
595-
parent: path.parent_path(),
595+
parent: None,
596596
path: path.clone(),
597597
kind: PathKind::Item { kind: ItemListKind::SourceFile },
598598
has_type_args: false,
@@ -827,92 +827,123 @@ impl<'a> CompletionContext<'a> {
827827
PathKind::Type { location: location.unwrap_or(TypeLocation::Other) }
828828
};
829829

830+
let mut kind_macro_call = |it: ast::MacroCall| {
831+
path_ctx.has_macro_bang = it.excl_token().is_some();
832+
let parent = it.syntax().parent()?;
833+
// Any path in an item list will be treated as a macro call by the parser
834+
let kind = match_ast! {
835+
match parent {
836+
ast::MacroExpr(expr) => make_path_kind_expr(expr.into()),
837+
ast::MacroPat(it) => PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())},
838+
ast::MacroType(ty) => make_path_kind_type(ty.into()),
839+
ast::ItemList(_) => PathKind::Item { kind: ItemListKind::Module },
840+
ast::AssocItemList(_) => PathKind::Item { kind: match parent.parent() {
841+
Some(it) => match_ast! {
842+
match it {
843+
ast::Trait(_) => ItemListKind::Trait,
844+
ast::Impl(it) => if it.trait_().is_some() {
845+
ItemListKind::TraitImpl(find_node_in_file_compensated(sema, original_file, &it))
846+
} else {
847+
ItemListKind::Impl
848+
},
849+
_ => return None
850+
}
851+
},
852+
None => return None,
853+
} },
854+
ast::ExternItemList(_) => PathKind::Item { kind: ItemListKind::ExternBlock },
855+
ast::SourceFile(_) => PathKind::Item { kind: ItemListKind::SourceFile },
856+
_ => return None,
857+
}
858+
};
859+
Some(kind)
860+
};
861+
let make_path_kind_attr = |meta: ast::Meta| {
862+
let attr = meta.parent_attr()?;
863+
let kind = attr.kind();
864+
let attached = attr.syntax().parent()?;
865+
let is_trailing_outer_attr = kind != AttrKind::Inner
866+
&& non_trivia_sibling(attr.syntax().clone().into(), syntax::Direction::Next)
867+
.is_none();
868+
let annotated_item_kind =
869+
if is_trailing_outer_attr { None } else { Some(attached.kind()) };
870+
Some(PathKind::Attr { attr_ctx: AttrCtx { kind, annotated_item_kind } })
871+
};
872+
830873
// Infer the path kind
831874
let parent = path.syntax().parent()?;
832875
let kind = match_ast! {
833-
match parent {
834-
ast::PathType(it) => make_path_kind_type(it.into()),
835-
ast::PathExpr(it) => {
836-
if let Some(p) = it.syntax().parent() {
837-
if ast::ExprStmt::can_cast(p.kind()) {
838-
if let Some(kind) = inbetween_body_and_decl_check(p) {
839-
return Some(make_res(NameRefKind::Keyword(kind)));
840-
}
876+
match parent {
877+
ast::PathType(it) => make_path_kind_type(it.into()),
878+
ast::PathExpr(it) => {
879+
if let Some(p) = it.syntax().parent() {
880+
if ast::ExprStmt::can_cast(p.kind()) {
881+
if let Some(kind) = inbetween_body_and_decl_check(p) {
882+
return Some(make_res(NameRefKind::Keyword(kind)));
841883
}
842884
}
885+
}
843886

844-
path_ctx.has_call_parens = it.syntax().parent().map_or(false, |it| ast::CallExpr::can_cast(it.kind()));
887+
path_ctx.has_call_parens = it.syntax().parent().map_or(false, |it| ast::CallExpr::can_cast(it.kind()));
845888

846-
make_path_kind_expr(it.into())
847-
},
848-
ast::TupleStructPat(it) => {
849-
path_ctx.has_call_parens = true;
850-
PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())}
851-
},
852-
ast::RecordPat(it) => {
853-
path_ctx.has_call_parens = true;
854-
PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())}
855-
},
856-
ast::PathPat(it) => {
857-
PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())}
858-
},
859-
ast::MacroCall(it) => {
860-
// A macro call in this position is usually a result of parsing recovery, so check that
861-
if let Some(kind) = inbetween_body_and_decl_check(it.syntax().clone()) {
862-
return Some(make_res(NameRefKind::Keyword(kind)));
863-
}
889+
make_path_kind_expr(it.into())
890+
},
891+
ast::TupleStructPat(it) => {
892+
path_ctx.has_call_parens = true;
893+
PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into()) }
894+
},
895+
ast::RecordPat(it) => {
896+
path_ctx.has_call_parens = true;
897+
PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into()) }
898+
},
899+
ast::PathPat(it) => {
900+
PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())}
901+
},
902+
ast::MacroCall(it) => {
903+
// A macro call in this position is usually a result of parsing recovery, so check that
904+
if let Some(kind) = inbetween_body_and_decl_check(it.syntax().clone()) {
905+
return Some(make_res(NameRefKind::Keyword(kind)));
906+
}
864907

865-
path_ctx.has_macro_bang = it.excl_token().is_some();
866-
let parent = it.syntax().parent()?;
867-
// Any path in an item list will be treated as a macro call by the parser
868-
match_ast! {
869-
match parent {
870-
ast::MacroExpr(expr) => make_path_kind_expr(expr.into()),
871-
ast::MacroPat(it) => PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())},
872-
ast::MacroType(ty) => make_path_kind_type(ty.into()),
873-
ast::ItemList(_) => PathKind::Item { kind: ItemListKind::Module },
874-
ast::AssocItemList(_) => PathKind::Item { kind: match parent.parent() {
875-
Some(it) => match_ast! {
876-
match it {
877-
ast::Trait(_) => ItemListKind::Trait,
878-
ast::Impl(it) => if it.trait_().is_some() {
879-
ItemListKind::TraitImpl(find_node_in_file_compensated(sema, original_file, &it))
880-
} else {
881-
ItemListKind::Impl
882-
},
883-
_ => return None
884-
}
885-
},
886-
None => return None,
887-
} },
888-
ast::ExternItemList(_) => PathKind::Item { kind: ItemListKind::ExternBlock },
889-
ast::SourceFile(_) => PathKind::Item { kind: ItemListKind::SourceFile },
890-
_ => return None,
891-
}
892-
}
893-
},
894-
ast::Meta(meta) => {
895-
let attr = meta.parent_attr()?;
896-
let kind = attr.kind();
897-
let attached = attr.syntax().parent()?;
898-
let is_trailing_outer_attr = kind != AttrKind::Inner
899-
&& non_trivia_sibling(attr.syntax().clone().into(), syntax::Direction::Next).is_none();
900-
let annotated_item_kind = if is_trailing_outer_attr {
901-
None
902-
} else {
903-
Some(attached.kind())
904-
};
905-
PathKind::Attr {
906-
attr_ctx: AttrCtx {
907-
kind,
908-
annotated_item_kind,
909-
}
908+
kind_macro_call(it)?
909+
},
910+
ast::Meta(meta) => make_path_kind_attr(meta)?,
911+
ast::Visibility(it) => PathKind::Vis { has_in_token: it.in_token().is_some() },
912+
ast::UseTree(_) => PathKind::Use,
913+
// completing inside a qualifier
914+
ast::Path(parent) => {
915+
path_ctx.parent = Some(parent.clone());
916+
let parent = iter::successors(Some(parent), |it| it.parent_path()).last()?.syntax().parent()?;
917+
match_ast! {
918+
match parent {
919+
ast::PathType(it) => make_path_kind_type(it.into()),
920+
ast::PathExpr(it) => {
921+
path_ctx.has_call_parens = it.syntax().parent().map_or(false, |it| ast::CallExpr::can_cast(it.kind()));
922+
923+
make_path_kind_expr(it.into())
924+
},
925+
ast::TupleStructPat(it) => {
926+
path_ctx.has_call_parens = true;
927+
PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into()) }
928+
},
929+
ast::RecordPat(it) => {
930+
path_ctx.has_call_parens = true;
931+
PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into()) }
932+
},
933+
ast::PathPat(it) => {
934+
PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())}
935+
},
936+
ast::MacroCall(it) => {
937+
kind_macro_call(it)?
938+
},
939+
ast::Meta(meta) => make_path_kind_attr(meta)?,
940+
ast::Visibility(it) => PathKind::Vis { has_in_token: it.in_token().is_some() },
941+
ast::UseTree(_) => PathKind::Use,
942+
_ => return None,
910943
}
911-
},
912-
ast::Visibility(it) => PathKind::Vis { has_in_token: it.in_token().is_some() },
913-
ast::UseTree(_) => PathKind::Use,
914-
_ => return None,
915-
944+
}
945+
},
946+
_ => return None,
916947
}
917948
};
918949

0 commit comments

Comments
 (0)